Skip to content

Commit

Permalink
add various optional helpers
Browse files Browse the repository at this point in the history
  • Loading branch information
taylorotwell committed Aug 24, 2017
1 parent d64cf19 commit 06de9b2
Show file tree
Hide file tree
Showing 5 changed files with 276 additions and 4 deletions.
37 changes: 34 additions & 3 deletions src/Illuminate/Http/Resources/Json/Resource.php
Original file line number Diff line number Diff line change
Expand Up @@ -173,13 +173,13 @@ public function withResponse($request, $response)
* @param mixed $value
* @return \Illuminate\Http\Resources\MissingValue|mixed
*/
protected function when($condition, $value)
protected function when($condition, $value, $default = null)
{
if ($condition) {
return value($value);
}

return new MissingValue;
return func_num_args() === 3 ? value($default) : new MissingValue;
}

/**
Expand All @@ -188,7 +188,7 @@ protected function when($condition, $value)
* @param string $relationship
* @return \Illuminate\Http\Resources\MissingValue|mixed
*/
protected function optional($relationship)
protected function whenLoaded($relationship)
{
if ($this->resource->relationLoaded($relationship)) {
return $this->resource->{$relationship};
Expand All @@ -197,6 +197,37 @@ protected function optional($relationship)
return new MissingValue;
}

/**
* Execute a callback if the given pivot table has been loaded.
*
* @param string $table
* @param callable $value
* @param mixed $default
* @return \Illuminate\Http\Resources\MissingValue|mixed
*/
protected function whenPivotLoaded($table, callable $value, $default = null)
{
return $this->when(
$this->pivot && ($this->pivot instanceof $table || $this->pivot->getTable() === $table),
...array_filter([$value, $default])
);
}

/**
* Transform the given value if it is present.
*
* @param mixed $value
* @param callable $callback
* @param mixed $default
* @return mixed
*/
protected function transform($value, callable $callback, $default = null)
{
return transform(
$value, $callback, func_num_args() === 3 ? $default : new MissingValue
);
}

/**
* Set the string that should wrap the outer-most resource array.
*
Expand Down
53 changes: 53 additions & 0 deletions src/Illuminate/Support/Optional.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?php

namespace Illuminate\Support;

class Optional
{
use Traits\Macroable;

/**
* The underlying object.
*
* @var mixed
*/
protected $value;

/**
* Create a new optional instance.
*
* @param mixed $value
* @return void
*/
public function __construct($value)
{
$this->value = $value;
}

/**
* Dynamically access a property on the underlying object.
*
* @param string $key
* @return mixed
*/
public function __get($key)
{
if (is_object($this->value)) {
return $this->value->{$key};
}
}

/**
* Dynamically pass a method to the underlying object.
*
* @param string $method
* @param array $parameters
* @return mixed
*/
public function __call($method, $parameters)
{
if (is_object($this->value)) {
return $this->value->{$method}(...$parameters);
}
}
}
85 changes: 85 additions & 0 deletions src/Illuminate/Support/helpers.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

use Illuminate\Support\Arr;
use Illuminate\Support\Str;
use Illuminate\Support\Optional;
use Illuminate\Support\Collection;
use Illuminate\Support\Debug\Dumper;
use Illuminate\Contracts\Support\Htmlable;
Expand Down Expand Up @@ -330,6 +331,37 @@ function array_wrap($value)
}
}

if (! function_exists('blank')) {
/**
* Determine if the given value is "blank".
*
* @author Derek MacDonald (https://github.com/derekmd)
*
* @param mixed $value
* @return bool
*/
function blank($value)
{
if (is_null($value)) {
return true;
}

if (is_string($value)) {
return trim($value) === '';
}

if (is_numeric($value) || is_bool($value)) {
return false;
}

if ($value instanceof Countable) {
return count($value) === 0;
}

return empty($value);
}
}

if (! function_exists('camel_case')) {
/**
* Convert a value to camel case.
Expand Down Expand Up @@ -667,6 +699,19 @@ function object_get($object, $key, $default = null)
}
}

if (! function_exists('optional')) {
/**
* Provide access to optional objects.
*
* @param mixed $value
* @return mixed
*/
function optional($value)
{
return new Optional($value);
}
}

if (! function_exists('preg_replace_array')) {
/**
* Replace a given pattern with each value in the array in sequentially.
Expand All @@ -686,6 +731,21 @@ function preg_replace_array($pattern, array $replacements, $subject)
}
}

if (! function_exists('present')) {
/**
* Determine if a value is "present".
*
* @author Derek MacDonald (https://github.com/derekmd)
*
* @param mixed $value
* @return bool
*/
function present($value)
{
return ! blank($value);
}
}

if (! function_exists('retry')) {
/**
* Retry an operation a given number of times.
Expand Down Expand Up @@ -1048,6 +1108,31 @@ function trait_uses_recursive($trait)
}
}

if (! function_exists('transform')) {
/**
* Transform the given value if it is present.
*
* @author Derek MacDonald (https://github.com/derekmd)
*
* @param mixed $value
* @param callable $callback
* @param mixed $default
* @return mixed|null
*/
function transform($value, callable $callback, $default = null)
{
if (present($value)) {
return $callback($value);
}

if (is_callable($default)) {
return $default($value);
}

return $default;
}
}

if (! function_exists('value')) {
/**
* Return the default value of the given value.
Expand Down
82 changes: 81 additions & 1 deletion tests/Integration/Http/ResourceTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,29 @@ public function test_resources_may_be_converted_to_json()
]);
}

public function test_resources_may_have_optional_values()
{
Route::get('/', function () {
return new PostResourceWithOptionalData(new Post([
'id' => 5,
]));
});

$response = $this->withoutExceptionHandling()->get(
'/', ['Accept' => 'application/json']
);

$response->assertStatus(200);

$response->assertJson([
'data' => [
'id' => 5,
'second' => 'value',
'third' => 'value',
],
]);
}

public function test_resources_may_have_optional_relationships()
{
Route::get('/', function () {
Expand All @@ -60,6 +83,31 @@ public function test_resources_may_have_optional_relationships()
]);
}

public function test_resources_may_have_optional_pivot_relationships()
{
Route::get('/', function () {
$post = new Post(['id' => 5]);
$post->setRelation('pivot', new Subscription);

return new PostResourceWithOptionalPivotRelationship($post);
});

$response = $this->withoutExceptionHandling()->get(
'/', ['Accept' => 'application/json']
);

$response->assertStatus(200);

$response->assertExactJson([
'data' => [
'id' => 5,
'subscription' => [
'foo' => 'bar',
],
],
]);
}

public function test_resource_is_url_routable()
{
$post = new PostResource(new Post([
Expand Down Expand Up @@ -339,17 +387,49 @@ public function withResponse($request, $response)
}
}

class PostResourceWithOptionalData extends Resource
{
public function toArray($request)
{
return [
'id' => $this->id,
'first' => $this->when(false, 'value'),
'second' => $this->when(true, 'value'),
'third' => $this->when(true, function () {
return 'value';
}),
];
}
}

class PostResourceWithOptionalRelationship extends PostResource
{
public function toArray($request)
{
return [
'id' => $this->id,
'comments' => new CommentCollection($this->optional('comments')),
'comments' => new CommentCollection($this->whenLoaded('comments')),
];
}
}

class PostResourceWithOptionalPivotRelationship extends PostResource
{
public function toArray($request)
{
return [
'id' => $this->id,
'subscription' => $this->whenPivotLoaded(Subscription::class, function () {
return [
'foo' => 'bar',
];
}),
];
}
}

class Subscription {}

class CommentCollection extends ResourceCollection
{
//
Expand Down
23 changes: 23 additions & 0 deletions tests/Support/SupportHelpersTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -755,6 +755,29 @@ public function testThrowWithString()
{
throw_if(true, RuntimeException::class, 'Test Message');
}

public function testOptional()
{
$this->assertNull(optional(null)->something());

$this->assertEquals(10, optional(new class {
public function something()
{
return 10;
}
})->something());
}

public function testTransform()
{
$this->assertEquals(10, transform(5, function ($value) {
return $value * 2;
}));

$this->assertNull(transform(null, function () {
return 10;
}));
}
}

trait SupportTestTraitOne
Expand Down

0 comments on commit 06de9b2

Please sign in to comment.