Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

API Resources #20710

Merged
merged 48 commits into from
Aug 23, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
b2ab8f2
initial pass at resources
taylorotwell Aug 21, 2017
ff521c9
tweak how resources are passed
taylorotwell Aug 21, 2017
c6ccc20
formatting
taylorotwell Aug 21, 2017
47912ef
tests for resources
taylorotwell Aug 21, 2017
178473c
work on tests
taylorotwell Aug 21, 2017
51b171c
fix test
taylorotwell Aug 21, 2017
8e3d9fe
more tests
taylorotwell Aug 21, 2017
1ef2b4c
fix macro call
taylorotwell Aug 21, 2017
e81c47a
no macroable setup for resource
taylorotwell Aug 21, 2017
2c20b84
wip
taylorotwell Aug 21, 2017
3014d93
no longer needed after orchestra fix
taylorotwell Aug 22, 2017
18b2039
auto pass resource if not set
taylorotwell Aug 22, 2017
a604b6b
working on resourceS
taylorotwell Aug 22, 2017
5f10a52
extract resource collection
taylorotwell Aug 22, 2017
12262fb
extract method
taylorotwell Aug 22, 2017
b8bdce1
reverse check
taylorotwell Aug 22, 2017
cc06b53
try to guess collect object
taylorotwell Aug 22, 2017
a0b97c5
cli commands
taylorotwell Aug 22, 2017
acd5a81
tweak iterator implementation
taylorotwell Aug 22, 2017
c793726
404 for not found resource types
taylorotwell Aug 22, 2017
8cf4fef
fix
taylorotwell Aug 22, 2017
5771ee7
use 406 status code
taylorotwell Aug 22, 2017
26949d7
tweak cli
taylorotwell Aug 22, 2017
53e1f4f
allow appending to already generated additions
taylorotwell Aug 22, 2017
8c13f43
Merge branch 'master' into resource
taylorotwell Aug 22, 2017
cd6ecd0
Merge branch 'master' into resource
taylorotwell Aug 22, 2017
14ded2c
Merge branch 'master' into resource
taylorotwell Aug 22, 2017
6189949
refactor response handling
taylorotwell Aug 22, 2017
35baf7a
wip
taylorotwell Aug 23, 2017
99f3e41
wip
taylorotwell Aug 23, 2017
4f095ab
wip
taylorotwell Aug 23, 2017
4dad05d
wip
taylorotwell Aug 23, 2017
48eeb7a
wip
taylorotwell Aug 23, 2017
7f51eb7
wip
taylorotwell Aug 23, 2017
2a833ac
wip
taylorotwell Aug 23, 2017
d027bcc
wip
taylorotwell Aug 23, 2017
0a8dcc5
wip
taylorotwell Aug 23, 2017
7bbc698
wip
taylorotwell Aug 23, 2017
4c39b1a
wip
taylorotwell Aug 23, 2017
5116933
wip
taylorotwell Aug 23, 2017
9500417
add method
taylorotwell Aug 23, 2017
7f0bfcf
wip
taylorotwell Aug 23, 2017
d26149d
wip
taylorotwell Aug 23, 2017
92c8bcd
wip
taylorotwell Aug 23, 2017
e69667d
wip
taylorotwell Aug 23, 2017
8526b5d
remove visible and hidden
taylorotwell Aug 23, 2017
d7108c3
tweak stub
taylorotwell Aug 23, 2017
7eaa192
remove loading
taylorotwell Aug 23, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions src/Illuminate/Contracts/Database/CastsToResource.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

namespace Illuminate\Contracts\Database;

interface CastsToResource
{
/**
* Cast the given model into a resource.
*
* @param \Illuminate\Http\Request $request
* @param mixed $model
* @return mixed
*/
public static function castToResource($request, $model);

/**
* Cast the given paginator or collection into a resource.
*
* @param \Illuminate\Http\Request $request
* @param mixed $collection
* @return mixed
*/
public static function castCollectionToResource($request, $collection);
}
57 changes: 57 additions & 0 deletions src/Illuminate/Database/Eloquent/DetectsResource.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<?php

namespace Illuminate\Database\Eloquent;

use Exception;

trait DetectsResource
{
/**
* Cast the given model into a resource.
*
* @param \Illuminate\Http\Request $request
* @param mixed $model
* @return mixed
*/
public static function castToResource($request, $model)
{
$class = $model->detectResourceName();

return new $class($model);
}

/**
* Cast the given paginator or collection into a resource.
*
* @param \Illuminate\Http\Request $request
* @param \Illuminate\Support\Collection $collection
* @return mixed
*/
public static function castCollectionToResource($request, $collection)
{
$class = $collection->first()->detectResourceName('Collection');

return new $class($collection);
}

/**
* Detect the resource name for the model.
*
* @param string $suffix
* @return string
*/
public function detectResourceName($suffix = '')
{
$segments = explode('\\', get_class($this));

$base = array_pop($segments);

if (class_exists($class = implode('\\', $segments).'\\Http\\Resources\\'.$base.$suffix)) {
return $class;
}

throw new Exception(
"Unable to detect the resource for the [".get_class($this)."] model."
);
}
}
91 changes: 91 additions & 0 deletions src/Illuminate/Foundation/Console/ResourceMakeCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
<?php

namespace Illuminate\Foundation\Console;

use Illuminate\Support\Str;
use Illuminate\Console\GeneratorCommand;
use Symfony\Component\Console\Input\InputOption;

class ResourceMakeCommand extends GeneratorCommand
{
/**
* The console command name.
*
* @var string
*/
protected $name = 'make:resource';

/**
* The console command description.
*
* @var string
*/
protected $description = 'Create a new resource';

/**
* The type of class being generated.
*
* @var string
*/
protected $type = 'Resource';

/**
* Execute the console command.
*
* @return bool|null
*/
public function handle()
{
if ($this->collection()) {
$this->type = 'Resource collection';
}

parent::handle();
}

/**
* Get the stub file for the generator.
*
* @return string
*/
protected function getStub()
{
return $this->collection()
? __DIR__.'/stubs/resource-collection.stub'
: __DIR__.'/stubs/resource.stub';
}

/**
* Determine if the command is generating a resource collection.
*
* @return bool
*/
protected function collection()
{
return $this->option('collection') ||
Str::endsWith($this->argument('name'), 'Collection');
}

/**
* Get the default namespace for the class.
*
* @param string $rootNamespace
* @return string
*/
protected function getDefaultNamespace($rootNamespace)
{
return $rootNamespace.'\Http\Resources';
}

/**
* Get the console command options.
*
* @return array
*/
protected function getOptions()
{
return [
['collection', 'c', InputOption::VALUE_NONE, 'Create a resource collection.'],
];
}
}
19 changes: 19 additions & 0 deletions src/Illuminate/Foundation/Console/stubs/resource-collection.stub
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

namespace DummyNamespace;

use Illuminate\Http\Resources\Json\ResourceCollection;

class DummyClass extends ResourceCollection
{
/**
* Transform the resource collection into an array.
*
* @param \Illuminate\Http\Request
* @return array
*/
public function toArray($request)
{
return parent::toArray($request);
}
}
19 changes: 19 additions & 0 deletions src/Illuminate/Foundation/Console/stubs/resource.stub
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

namespace DummyNamespace;

use Illuminate\Http\Resources\Json\Resource;

class DummyClass extends Resource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request
* @return array
*/
public function toArray($request)
{
return parent::toArray($request);
}
}
14 changes: 14 additions & 0 deletions src/Illuminate/Foundation/Providers/ArtisanServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
use Illuminate\Foundation\Console\StorageLinkCommand;
use Illuminate\Routing\Console\ControllerMakeCommand;
use Illuminate\Routing\Console\MiddlewareMakeCommand;
use Illuminate\Foundation\Console\ResourceMakeCommand;
use Illuminate\Foundation\Console\ListenerMakeCommand;
use Illuminate\Foundation\Console\ProviderMakeCommand;
use Illuminate\Foundation\Console\ClearCompiledCommand;
Expand Down Expand Up @@ -145,6 +146,7 @@ class ArtisanServiceProvider extends ServiceProvider
'QueueFailedTable' => 'command.queue.failed-table',
'QueueTable' => 'command.queue.table',
'RequestMake' => 'command.request.make',
'ResourceMake' => 'command.resource.make',
'RuleMake' => 'command.rule.make',
'SeederMake' => 'command.seeder.make',
'SessionTable' => 'command.session.table',
Expand Down Expand Up @@ -727,6 +729,18 @@ protected function registerRequestMakeCommand()
});
}

/**
* Register the command.
*
* @return void
*/
protected function registerResourceMakeCommand()
{
$this->app->singleton('command.resource.make', function ($app) {
return new ResourceMakeCommand($app['files']);
});
}

/**
* Register the command.
*
Expand Down
89 changes: 89 additions & 0 deletions src/Illuminate/Http/Middleware/CastToResource.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
<?php

namespace Illuminate\Http\Middleware;

use Closure;
use Illuminate\Support\Collection;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Pagination\AbstractPaginator;
use Illuminate\Contracts\Database\CastsToResource;

class CastToResource
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
$response = $next($request);

if (! isset($response->original)) {
return $response;
}

if ($response->original instanceof Model &&
$response->original instanceof CastsToResource) {
return $this->castModelToResource($request, $response);
}

if ($response->original instanceof Collection &&
$response->original->first() instanceof CastsToResource) {
return $this->castCollectionToResource($request, $response);
}

if ($response->original instanceof AbstractPaginator &&
$response->original->getCollection()->first() instanceof CastsToResource) {
return $this->castPaginatorToResource($request, $response);
}

return $response;
}

/**
* Cast the model sent within the response to a resource response.
*
* @param \Illuminate\Http\Request $request
* @param \Illuminate\Http\Response $response
* @return \Illuminate\Http\Response
*/
protected function castModelToResource($request, $response)
{
return $response->original->castToResource(
$request, $response->original
)->toResponse($request);
}

/**
* Cast the collection sent within the response to a resource response.
*
* @param \Illuminate\Http\Request $request
* @param \Illuminate\Http\Response $response
* @return \Illuminate\Http\Response
*/
protected function castCollectionToResource($request, $response)
{
return $response->original->first()->castCollectionToResource(
$request, $response->original
)->toResponse($request);
}

/**
* Cast the collection sent within the response to a resource response.
*
* @param \Illuminate\Http\Request $request
* @param \Illuminate\Http\Response $response
* @return \Illuminate\Http\Response
*/
protected function castPaginatorToResource($request, $response)
{
$collection = $response->original->getCollection();

return $collection->first()->castCollectionToResource(
$request, $response->original
)->toResponse($request);
}
}
56 changes: 56 additions & 0 deletions src/Illuminate/Http/Resources/CollectsResources.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<?php

namespace Illuminate\Http\Resources;

use Illuminate\Support\Str;
use Illuminate\Support\Collection;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Pagination\AbstractPaginator;
use Illuminate\Database\Eloquent\Collection as EloquentCollection;

trait CollectsResources
{
/**
* Map the given collection resource into its individual resources.
*
* @param mixed $resource
* @return mixed
*/
protected function collectResource($resource)
{
$this->collection = $resource->mapInto($this->collects());

return $resource instanceof AbstractPaginator
? $resource->setCollection($this->collection)
: $this->collection;
}

/**
* Get the resource that this resource collects.
*
* @return string
*/
protected function collects()
{
if ($this->collects) {
return $this->collects;
}

if (Str::endsWith(class_basename($this), 'Collection') &&
class_exists($class = Str::replaceLast('Collection', '', get_class($this)))) {
return $class;
}

throw new UnknownCollectionException($this);
}

/**
* Get an iterator for the resource collection.
*
* @return \ArrayIterator
*/
public function getIterator()
{
return $this->collection->getIterator();
}
}
Loading