diff --git a/src/Illuminate/Http/Resources/JsonApi/Concerns/ResolvesJsonApiElements.php b/src/Illuminate/Http/Resources/JsonApi/Concerns/ResolvesJsonApiElements.php index 67469fd9c656..5f5cc717d44e 100644 --- a/src/Illuminate/Http/Resources/JsonApi/Concerns/ResolvesJsonApiElements.php +++ b/src/Illuminate/Http/Resources/JsonApi/Concerns/ResolvesJsonApiElements.php @@ -235,8 +235,10 @@ protected static function resourceTypeFromModel(Model $model): string $morphMap = Relation::getMorphAlias($modelClassName); - return Str::of( - $morphMap !== $modelClassName ? $morphMap : class_basename($modelClassName) - )->snake()->pluralStudly(); + if ($morphMap !== $modelClassName) { + return Str::of($morphMap)->pluralStudly(); + } + + return Str::of($modelClassName)->classBasename()->snake()->pluralStudly(); } } diff --git a/tests/Http/Resources/JsonApi/JsonApiResourceTest.php b/tests/Http/Resources/JsonApi/JsonApiResourceTest.php index 9f3fc8a94d6f..6beb29009508 100644 --- a/tests/Http/Resources/JsonApi/JsonApiResourceTest.php +++ b/tests/Http/Resources/JsonApi/JsonApiResourceTest.php @@ -3,16 +3,40 @@ namespace Illuminate\Tests\Http\Resources\JsonApi; use BadMethodCallException; +use Illuminate\Container\Container; +use Illuminate\Contracts\Routing\ResponseFactory as ResponseFactoryContract; +use Illuminate\Contracts\View\Factory as ViewFactory; +use Illuminate\Database\Eloquent\Model; +use Illuminate\Database\Eloquent\Relations\Relation; +use Illuminate\Http\Request; use Illuminate\Http\Resources\Json\JsonResource; use Illuminate\Http\Resources\JsonApi\JsonApiResource; +use Illuminate\Routing\Redirector; +use Illuminate\Routing\ResponseFactory; +use Mockery as m; use PHPUnit\Framework\TestCase; class JsonApiResourceTest extends TestCase { + protected function setUp(): void + { + Relation::morphMap(['json-api-model' => JsonApiModel::class]); + + $container = Container::setInstance(new Container); + $container->instance(ResponseFactoryContract::class, new ResponseFactory( + m::mock(ViewFactory::class), + m::mock(Redirector::class) + )); + } + protected function tearDown(): void { JsonResource::flushState(); JsonApiResource::flushState(); + Relation::morphMap([], false); + + Container::setInstance(null); + m::close(); } public function testResponseWrapperIsHardCodedToData() @@ -37,4 +61,54 @@ public function testUnableToUnsetWrapper() JsonApiResource::withoutWrapping(); } + + public function testResourceTypeIsPickedFromMorph() + { + $model = new JsonApiModel(['id' => 1, 'name' => 'User']); + + $responseData = $this->fakeJsonApiResponseForModel($model)['data']; + + $this->assertArrayHasKey('type', $responseData); + $this->assertSame('json-api-models', $responseData['type']); + } + + public function testIncludedResourceDoesNotContainPrimaryKey() + { + $model = new JsonApiModel(['id' => 1, 'name' => 'User']); + $model->setRelation('manager', new JsonApiModel(['id' => 2, 'name' => 'Manager'])); + $model->setRelation('deputy', new JsonApiModel(['id' => 2, 'email' => 'deputy@example.com'])); + + $responseData = $this->fakeJsonApiResponseForModel($model); + $this->assertArrayNotHasKey('id', $responseData['included'][0]['attributes']); + } + + public function testIncludedMatchingResourceAttributesAreMerged() + { + $model = new JsonApiModel(['id' => 1, 'name' => 'User']); + $model->setRelation('manager', new JsonApiModel(['id' => 2, 'name' => 'Manager'])); + $model->setRelation('deputy', new JsonApiModel(['id' => 2, 'email' => 'deputy@example.com'])); + + $responseData = $this->fakeJsonApiResponseForModel($model); + + $this->assertEquals([ + 'id' => '2', + 'type' => 'json-api-models', + 'attributes' => [ + 'name' => 'Manager', + 'email' => 'deputy@example.com', + ], + ], $responseData['included'][0]); + } + + protected function fakeJsonApiResponseForModel(Model $model): array + { + return (new JsonApiResource($model)) + ->toResponse(new Request) + ->getData(true); + } +} + +class JsonApiModel extends Model +{ + protected $guarded = []; }