diff --git a/app/JsonApi/IngredientAmounts/Adapter.php b/app/JsonApi/IngredientAmounts/Adapter.php new file mode 100644 index 0000000..46d0cf9 --- /dev/null +++ b/app/JsonApi/IngredientAmounts/Adapter.php @@ -0,0 +1,58 @@ +filterWithScopes($query, $filters); + } + + protected function ingredient(): BelongsTo + { + return $this->belongsTo(); + } + + protected function recipe(): BelongsTo + { + return $this->belongsTo(); + } + +} diff --git a/app/JsonApi/IngredientAmounts/Schema.php b/app/JsonApi/IngredientAmounts/Schema.php new file mode 100644 index 0000000..07ab271 --- /dev/null +++ b/app/JsonApi/IngredientAmounts/Schema.php @@ -0,0 +1,70 @@ +getRouteKey(); + } + + /** + * @param \App\Models\IngredientAmount $resource + * + * @return array + */ + public function getAttributes($resource): array + { + return [ + 'amount' => $resource->amount, + 'unit' => $resource->unit, + 'weight' => $resource->weight, + 'calories' => $resource->calories(), + 'carbohydrates' => $resource->carbohydrates(), + 'cholesterol' => $resource->cholesterol(), + 'fat' => $resource->fat(), + 'protein' => $resource->protein(), + 'sodium' => $resource->sodium(), + 'createdAt' => $resource->created_at, + 'updatedAt' => $resource->updated_at, + ]; + } + + /** + * @inheritdoc + */ + public function getRelationships($resource, $isPrimary, array $includeRelationships): array + { + return [ + 'ingredient' => [ + self::SHOW_SELF => true, + self::SHOW_RELATED => true, + self::SHOW_DATA => isset($includeRelationships['ingredient']), + self::DATA => function () use ($resource) { + return $resource->ingredient; + }, + ], + 'recipe' => [ + self::SHOW_SELF => true, + self::SHOW_RELATED => true, + self::SHOW_DATA => isset($includeRelationships['recipe']), + self::DATA => function () use ($resource) { + return $resource->recipe; + }, + ] + ]; + } + +} diff --git a/app/JsonApi/Ingredients/Adapter.php b/app/JsonApi/Ingredients/Adapter.php new file mode 100644 index 0000000..25d98e8 --- /dev/null +++ b/app/JsonApi/Ingredients/Adapter.php @@ -0,0 +1,47 @@ +filterWithScopes($query, $filters); + } + +} diff --git a/app/JsonApi/Ingredients/Schema.php b/app/JsonApi/Ingredients/Schema.php new file mode 100644 index 0000000..0e31f5e --- /dev/null +++ b/app/JsonApi/Ingredients/Schema.php @@ -0,0 +1,45 @@ +getRouteKey(); + } + + /** + * @param \App\Models\Ingredient $resource + * + * @return array + */ + public function getAttributes($resource): array + { + return [ + 'name' => $resource->name, + 'detail' => $resource->detail, + 'calories' => $resource->calories, + 'carbohydrates' => $resource->carbohydrates, + 'cholesterol' => $resource->cholesterol, + 'fat' => $resource->fat, + 'protein' => $resource->protein, + 'sodium' => $resource->sodium, + 'unitWeight' => $resource->unit_weight, + 'cupWeight' => $resource->cup_weight, + 'createdAt' => $resource->created_at, + 'updatedAt' => $resource->updated_at, + ]; + } +} diff --git a/app/JsonApi/RecipeSteps/Adapter.php b/app/JsonApi/RecipeSteps/Adapter.php new file mode 100644 index 0000000..e0d604c --- /dev/null +++ b/app/JsonApi/RecipeSteps/Adapter.php @@ -0,0 +1,53 @@ +filterWithScopes($query, $filters); + } + + protected function recipe(): BelongsTo + { + return $this->belongsTo(); + } + +} diff --git a/app/JsonApi/RecipeSteps/Schema.php b/app/JsonApi/RecipeSteps/Schema.php new file mode 100644 index 0000000..6bc1f1f --- /dev/null +++ b/app/JsonApi/RecipeSteps/Schema.php @@ -0,0 +1,50 @@ +getRouteKey(); + } + + /** + * @param \App\Models\RecipeStep $resource + * + * @return array + */ + public function getAttributes($resource): array + { + return [ + 'number' => $resource->number, + 'step' => $resource->step, + 'createdAt' => $resource->created_at, + 'updatedAt' => $resource->updated_at, + ]; + } + + /** + * @inheritdoc + */ + public function getRelationships($resource, $isPrimary, array $includeRelationships): array + { + return [ + 'recipe' => [ + self::SHOW_SELF => true, + self::SHOW_RELATED => true, + ] + ]; + } +} diff --git a/app/JsonApi/Recipes/Adapter.php b/app/JsonApi/Recipes/Adapter.php new file mode 100644 index 0000000..446d1fb --- /dev/null +++ b/app/JsonApi/Recipes/Adapter.php @@ -0,0 +1,58 @@ +filterWithScopes($query, $filters); + } + + protected function ingredientAmounts(): HasMany + { + return $this->hasMany(); + } + + protected function steps(): HasMany + { + return $this->hasMany(); + } + +} diff --git a/app/JsonApi/Recipes/Schema.php b/app/JsonApi/Recipes/Schema.php new file mode 100644 index 0000000..741d0f5 --- /dev/null +++ b/app/JsonApi/Recipes/Schema.php @@ -0,0 +1,75 @@ +getRouteKey(); + } + + /** + * @param \App\Models\Recipe $resource + * + * @return array + */ + public function getAttributes($resource) + { + return [ + 'name' => $resource->name, + 'description' => $resource->description, + 'servings' => $resource->servings, + 'caloriesPerServing' => $resource->caloriesPerServing(), + 'caloriesTotal' => $resource->caloriesTotal(), + 'carbohydratesPerServing' => $resource->carbohydratesPerServing(), + 'carbohydratesTotal' => $resource->carbohydratesTotal(), + 'cholesterolPerServing' => $resource->cholesterolPerServing(), + 'cholesterolTotal' => $resource->cholesterolTotal(), + 'fatPerServing' => $resource->fatPerServing(), + 'fatTotal' => $resource->fatTotal(), + 'proteinPerServing' => $resource->proteinPerServing(), + 'proteinTotal' => $resource->proteinTotal(), + 'sodiumPerServing' => $resource->sodiumPerServing(), + 'sodiumTotal' => $resource->sodiumTotal(), + 'createdAt' => $resource->created_at, + 'updatedAt' => $resource->updated_at, + ]; + } + + /** + * @inheritdoc + */ + public function getRelationships($resource, $isPrimary, array $includeRelationships): array + { + return [ + 'steps' => [ + self::SHOW_SELF => true, + self::SHOW_RELATED => true, + self::SHOW_DATA => isset($includeRelationships['steps']), + self::DATA => function () use ($resource) { + return $resource->steps; + }, + ], + 'ingredient-amounts' => [ + self::SHOW_SELF => true, + self::SHOW_RELATED => true, + self::SHOW_DATA => isset($includeRelationships['ingredient-amounts']), + self::DATA => function () use ($resource) { + return $resource->ingredientAmounts; + }, + ] + ]; + } +} diff --git a/app/Models/Ingredient.php b/app/Models/Ingredient.php index 47ca476..5a58d59 100644 --- a/app/Models/Ingredient.php +++ b/app/Models/Ingredient.php @@ -17,6 +17,8 @@ use Illuminate\Database\Eloquent\Model; * @property float sodium (per 100g). * @property ?float unit_weight Weight of one cup of the ingredient. * @property ?float cup_weight Weight of one "unit" (e.g. an egg, onion, etc.) of the ingredient. + * @property \Illuminate\Support\Carbon created_at + * @property \Illuminate\Support\Carbon updated_at */ class Ingredient extends Model { @@ -25,7 +27,7 @@ class Ingredient extends Model /** * @inheritdoc */ - protected array $fillable = [ + protected $fillable = [ 'name', 'detail', 'calories', @@ -41,7 +43,7 @@ class Ingredient extends Model /** * The attributes that should be cast. */ - protected array $casts = [ + protected $casts = [ 'calories' => 'float', 'carbohydrates' => 'float', 'cholesterol' => 'float', diff --git a/app/Models/IngredientAmount.php b/app/Models/IngredientAmount.php index 561a35a..284e222 100644 --- a/app/Models/IngredientAmount.php +++ b/app/Models/IngredientAmount.php @@ -13,6 +13,8 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo; * @property int weight Weight of ingredient in full ingredient list (lowest first). * @property \App\Models\Ingredient ingredient * @property \App\Models\Recipe recipe + * @property \Illuminate\Support\Carbon created_at + * @property \Illuminate\Support\Carbon updated_at * @method float calories Get total calories. * @method float carbohydrates Get total carbohydrates. * @method float cholesterol Get total cholesterol. @@ -27,7 +29,7 @@ class IngredientAmount extends Model /** * @inheritdoc */ - protected array $fillable = [ + protected $fillable = [ 'amount', 'unit', 'weight', @@ -36,7 +38,7 @@ class IngredientAmount extends Model /** * The attributes that should be cast. */ - protected array $casts = [ + protected $casts = [ 'amount' => 'float', 'weight' => 'int', ]; @@ -44,7 +46,7 @@ class IngredientAmount extends Model /** * @inheritdoc */ - protected array $with = ['ingredient']; + protected $with = ['ingredient']; /** * Nutrient calculation methods. diff --git a/app/Models/Recipe.php b/app/Models/Recipe.php index 007809b..89c565e 100644 --- a/app/Models/Recipe.php +++ b/app/Models/Recipe.php @@ -13,6 +13,8 @@ use Illuminate\Database\Eloquent\Relations\HasMany; * @property int servings * @property \App\Models\RecipeStep[] steps * @property \App\Models\IngredientAmount[] ingredientAmounts + * @property \Illuminate\Support\Carbon created_at + * @property \Illuminate\Support\Carbon updated_at * @method float caloriesTotal Get total calories. * @method float caloriesPerServing Get per serving calories. * @method float carbohydratesTotal Get total carbohydrates. @@ -33,7 +35,7 @@ class Recipe extends Model /** * @inheritdoc */ - protected array $fillable = [ + protected $fillable = [ 'name', 'description', 'servings', @@ -42,14 +44,14 @@ class Recipe extends Model /** * The attributes that should be cast. */ - protected array $casts = [ + protected $casts = [ 'servings' => 'int', ]; /** * @inheritdoc */ - protected array $with = ['steps', 'ingredientAmounts']; + protected $with = ['steps', 'ingredientAmounts']; /** * Nutrient total calculation methods. diff --git a/app/Models/RecipeStep.php b/app/Models/RecipeStep.php index 16be8bc..57e4e88 100644 --- a/app/Models/RecipeStep.php +++ b/app/Models/RecipeStep.php @@ -11,6 +11,8 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo; * @property int number * @property string step * @property \App\Models\Recipe recipe + * @property \Illuminate\Support\Carbon created_at + * @property \Illuminate\Support\Carbon updated_at */ class RecipeStep extends Model { @@ -19,7 +21,7 @@ class RecipeStep extends Model /** * @inheritdoc */ - protected array $fillable = [ + protected $fillable = [ 'number', 'step', ]; @@ -27,7 +29,7 @@ class RecipeStep extends Model /** * The attributes that should be cast. */ - protected array $casts = [ + protected $casts = [ 'number' => 'int', ]; diff --git a/app/Providers/RouteServiceProvider.php b/app/Providers/RouteServiceProvider.php index 3bd3c81..f318ac3 100644 --- a/app/Providers/RouteServiceProvider.php +++ b/app/Providers/RouteServiceProvider.php @@ -38,8 +38,7 @@ class RouteServiceProvider extends ServiceProvider $this->configureRateLimiting(); $this->routes(function () { - Route::prefix('api') - ->middleware('api') + Route::middleware('api') ->namespace($this->namespace) ->group(base_path('routes/api.php')); diff --git a/composer.json b/composer.json index b6cb95f..0c6b894 100644 --- a/composer.json +++ b/composer.json @@ -2,14 +2,10 @@ "name": "prndb/prndb", "type": "project", "description": "Personal Recipe Nutrition Database.", - "keywords": [ - "food", - "nutrition", - "recipe" - ], "license": "MPL-2.0", "require": { "php": "^8.0", + "cloudcreativity/laravel-json-api": "^3.2", "fideloper/proxy": "^4.4", "fruitcake/laravel-cors": "^2.0", "guzzlehttp/guzzle": "^7.0.1", @@ -46,8 +42,6 @@ "Tests\\": "tests/" } }, - "minimum-stability": "dev", - "prefer-stable": true, "scripts": { "post-autoload-dump": [ "Illuminate\\Foundation\\ComposerScripts::postAutoloadDump", diff --git a/composer.lock b/composer.lock index 9564a31..3382024 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "56abc574c9c50fc6e4b7f5ef2a76cd50", + "content-hash": "23560c9daf2e130bfc747f3041ae4979", "packages": [ { "name": "asm89/stack-cors", @@ -118,6 +118,97 @@ ], "time": "2020-08-18T23:57:15+00:00" }, + { + "name": "cloudcreativity/laravel-json-api", + "version": "v3.2.0", + "source": { + "type": "git", + "url": "https://github.com/cloudcreativity/laravel-json-api.git", + "reference": "2189d7d358f2a3b818542eebc36c1e0c7b3e6be6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/cloudcreativity/laravel-json-api/zipball/2189d7d358f2a3b818542eebc36c1e0c7b3e6be6", + "reference": "2189d7d358f2a3b818542eebc36c1e0c7b3e6be6", + "shasum": "" + }, + "require": { + "ext-json": "*", + "illuminate/console": "^8.0", + "illuminate/contracts": "^8.0", + "illuminate/database": "^8.0", + "illuminate/filesystem": "^8.0", + "illuminate/http": "^8.0", + "illuminate/pagination": "^8.0", + "illuminate/support": "^8.0", + "neomerx/json-api": "^1.0.3", + "nyholm/psr7": "^1.2", + "php": "^7.3|^8.0", + "ramsey/uuid": "^3.0|^4.0", + "symfony/psr-http-message-bridge": "^2.0" + }, + "require-dev": { + "cloudcreativity/json-api-testing": "^3.1", + "ext-sqlite3": "*", + "guzzlehttp/guzzle": "^7.0", + "laravel/legacy-factories": "^1.0.4", + "laravel/ui": "^3.0", + "mockery/mockery": "^1.1", + "orchestra/testbench": "^6.0", + "phpunit/phpunit": "^9.0" + }, + "suggest": { + "cloudcreativity/json-api-testing": "Required to use the test helpers." + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-develop": "3.x-dev" + }, + "laravel": { + "providers": [ + "CloudCreativity\\LaravelJsonApi\\ServiceProvider" + ], + "aliases": { + "JsonApi": "CloudCreativity\\LaravelJsonApi\\Facades\\JsonApi" + } + } + }, + "autoload": { + "psr-4": { + "CloudCreativity\\LaravelJsonApi\\": "src/" + }, + "files": [ + "helpers.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Cloud Creativity Ltd", + "email": "info@cloudcreativity.co.uk" + } + ], + "description": "JSON API (jsonapi.org) support for Laravel applications.", + "homepage": "https://github.com/cloudcreativity/laravel-json-api", + "keywords": [ + "JSON-API", + "api", + "cloudcreativity", + "json", + "jsonapi", + "jsonapi.org", + "laravel" + ], + "support": { + "issues": "https://github.com/cloudcreativity/laravel-json-api/issues", + "source": "https://github.com/cloudcreativity/laravel-json-api/tree/v3.2.0" + }, + "time": "2020-11-26T11:02:55+00:00" + }, { "name": "dnoegel/php-xdg-base-dir", "version": "v0.1.1", @@ -894,16 +985,16 @@ }, { "name": "laravel/framework", - "version": "v8.19.0", + "version": "v8.20.1", "source": { "type": "git", "url": "https://github.com/laravel/framework.git", - "reference": "f5f331cee60f1bbe672503b7eb9ba5b22b2ceacb" + "reference": "b5d8573ab16027867eaa1ac148893833434f9b02" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/f5f331cee60f1bbe672503b7eb9ba5b22b2ceacb", - "reference": "f5f331cee60f1bbe672503b7eb9ba5b22b2ceacb", + "url": "https://api.github.com/repos/laravel/framework/zipball/b5d8573ab16027867eaa1ac148893833434f9b02", + "reference": "b5d8573ab16027867eaa1ac148893833434f9b02", "shasum": "" }, "require": { @@ -1057,7 +1148,7 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2020-12-15T16:16:31+00:00" + "time": "2020-12-22T21:21:19+00:00" }, { "name": "laravel/tinker", @@ -1474,6 +1565,65 @@ ], "time": "2020-12-14T13:15:25+00:00" }, + { + "name": "neomerx/json-api", + "version": "v1.0.9", + "source": { + "type": "git", + "url": "https://github.com/neomerx/json-api.git", + "reference": "c911b7494496e79f9de72ee40d6a2b791caaf95b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/neomerx/json-api/zipball/c911b7494496e79f9de72ee40d6a2b791caaf95b", + "reference": "c911b7494496e79f9de72ee40d6a2b791caaf95b", + "shasum": "" + }, + "require": { + "php": ">=5.5.0", + "psr/http-message": "^1.0", + "psr/log": "^1.0" + }, + "require-dev": { + "mockery/mockery": "~0.9.4", + "monolog/monolog": "^1.18", + "phpmd/phpmd": "^2.6", + "phpunit/phpunit": "^4.6 || ^5.0 || ^6.0", + "scrutinizer/ocular": "^1.3", + "squizlabs/php_codesniffer": "^2.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "Neomerx\\JsonApi\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "neomerx", + "email": "info@neomerx.com" + } + ], + "description": "Framework agnostic JSON API (jsonapi.org) implementation", + "homepage": "https://github.com/neomerx/json-api", + "keywords": [ + "JSON-API", + "api", + "json", + "jsonapi", + "jsonapi.org", + "neomerx" + ], + "support": { + "issues": "https://github.com/neomerx/json-api/issues", + "source": "https://github.com/neomerx/json-api/tree/v1.x" + }, + "time": "2018-02-21T13:45:30+00:00" + }, { "name": "nesbot/carbon", "version": "2.43.0", @@ -1623,6 +1773,83 @@ }, "time": "2020-12-20T10:01:03+00:00" }, + { + "name": "nyholm/psr7", + "version": "1.3.2", + "source": { + "type": "git", + "url": "https://github.com/Nyholm/psr7.git", + "reference": "a272953743c454ac4af9626634daaf5ab3ce1173" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Nyholm/psr7/zipball/a272953743c454ac4af9626634daaf5ab3ce1173", + "reference": "a272953743c454ac4af9626634daaf5ab3ce1173", + "shasum": "" + }, + "require": { + "php": ">=7.1", + "php-http/message-factory": "^1.0", + "psr/http-factory": "^1.0", + "psr/http-message": "^1.0" + }, + "provide": { + "psr/http-factory-implementation": "1.0", + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "http-interop/http-factory-tests": "^0.8", + "php-http/psr7-integration-tests": "^1.0", + "phpunit/phpunit": "^7.5 || 8.5 || 9.4", + "symfony/error-handler": "^4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "psr-4": { + "Nyholm\\Psr7\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com" + }, + { + "name": "Martijn van der Ven", + "email": "martijn@vanderven.se" + } + ], + "description": "A fast PHP7 implementation of PSR-7", + "homepage": "https://tnyholm.se", + "keywords": [ + "psr-17", + "psr-7" + ], + "support": { + "issues": "https://github.com/Nyholm/psr7/issues", + "source": "https://github.com/Nyholm/psr7/tree/1.3.2" + }, + "funding": [ + { + "url": "https://github.com/Zegnat", + "type": "github" + }, + { + "url": "https://github.com/nyholm", + "type": "github" + } + ], + "time": "2020-11-14T17:35:34+00:00" + }, { "name": "opis/closure", "version": "3.6.1", @@ -1688,6 +1915,60 @@ }, "time": "2020-11-07T02:01:34+00:00" }, + { + "name": "php-http/message-factory", + "version": "v1.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-http/message-factory.git", + "reference": "a478cb11f66a6ac48d8954216cfed9aa06a501a1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-http/message-factory/zipball/a478cb11f66a6ac48d8954216cfed9aa06a501a1", + "reference": "a478cb11f66a6ac48d8954216cfed9aa06a501a1", + "shasum": "" + }, + "require": { + "php": ">=5.4", + "psr/http-message": "^1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "psr-4": { + "Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com" + } + ], + "description": "Factory interfaces for PSR-7 HTTP Message", + "homepage": "http://php-http.org", + "keywords": [ + "factory", + "http", + "message", + "stream", + "uri" + ], + "support": { + "issues": "https://github.com/php-http/message-factory/issues", + "source": "https://github.com/php-http/message-factory/tree/master" + }, + "time": "2015-12-19T14:08:53+00:00" + }, { "name": "phpoption/phpoption", "version": "1.7.5", @@ -1912,6 +2193,61 @@ }, "time": "2020-06-29T06:28:15+00:00" }, + { + "name": "psr/http-factory", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-factory.git", + "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-factory/zipball/12ac7fcd07e5b077433f5f2bee95b3a771bf61be", + "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be", + "shasum": "" + }, + "require": { + "php": ">=7.0.0", + "psr/http-message": "^1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interfaces for PSR-7 HTTP message factories", + "keywords": [ + "factory", + "http", + "message", + "psr", + "psr-17", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-factory/tree/master" + }, + "time": "2019-04-30T12:38:16+00:00" + }, { "name": "psr/http-message", "version": "1.0.1", @@ -4084,6 +4420,88 @@ ], "time": "2020-12-08T17:03:37+00:00" }, + { + "name": "symfony/psr-http-message-bridge", + "version": "v2.0.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/psr-http-message-bridge.git", + "reference": "51a21cb3ba3927d4b4bf8f25cc55763351af5f2e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/psr-http-message-bridge/zipball/51a21cb3ba3927d4b4bf8f25cc55763351af5f2e", + "reference": "51a21cb3ba3927d4b4bf8f25cc55763351af5f2e", + "shasum": "" + }, + "require": { + "php": ">=7.1", + "psr/http-message": "^1.0", + "symfony/http-foundation": "^4.4 || ^5.0" + }, + "require-dev": { + "nyholm/psr7": "^1.1", + "symfony/phpunit-bridge": "^4.4 || ^5.0" + }, + "suggest": { + "nyholm/psr7": "For a super lightweight PSR-7/17 implementation" + }, + "type": "symfony-bridge", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Bridge\\PsrHttpMessage\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + } + ], + "description": "PSR HTTP message bridge", + "homepage": "http://symfony.com", + "keywords": [ + "http", + "http-message", + "psr-17", + "psr-7" + ], + "support": { + "issues": "https://github.com/symfony/psr-http-message-bridge/issues", + "source": "https://github.com/symfony/psr-http-message-bridge/tree/v2.0.2" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-09-29T08:17:46+00:00" + }, { "name": "symfony/routing", "version": "v5.2.1", @@ -7339,12 +7757,12 @@ } ], "aliases": [], - "minimum-stability": "dev", + "minimum-stability": "stable", "stability-flags": [], - "prefer-stable": true, + "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": "^7.3|^8.0" + "php": "^8.0" }, "platform-dev": [], "plugin-api-version": "2.0.0" diff --git a/config/json-api-default.php b/config/json-api-default.php new file mode 100644 index 0000000..96e2bb3 --- /dev/null +++ b/config/json-api-default.php @@ -0,0 +1,207 @@ + \CloudCreativity\LaravelJsonApi\Resolver\ResolverFactory::class, + + /* + |-------------------------------------------------------------------------- + | Root Namespace + |-------------------------------------------------------------------------- + | + | The root namespace for JSON API classes for this API. If `null`, the + | namespace will default to `JsonApi` within your application's root + | namespace (obtained via Laravel's `Application::getNamespace()` + | method). + | + | The `by-resource` setting determines how your units are organised within + | your root namespace. + | + | - true: + | - e.g. App\JsonApi\Posts\{Adapter, Schema, Validators} + | - e.g. App\JsonApi\Comments\{Adapter, Schema, Validators} + | - false: + | - e.g. App\JsonApi\Adapters\PostAdapter, CommentAdapter} + | - e.g. App\JsonApi\Schemas\{PostSchema, CommentSchema} + | - e.g. App\JsonApi\Validators\{PostValidator, CommentValidator} + | + */ + 'namespace' => null, + 'by-resource' => true, + + /* + |-------------------------------------------------------------------------- + | Model Namespace + |-------------------------------------------------------------------------- + | + | Here you can decide where your api models live. + | By default (i.e. set to null), the package assumes they will live in + | your application's root namespace, but you could set it to something + | different here. E.g. `App\Models`. + | + */ + 'model-namespace' => "App\Models", + + /* + |-------------------------------------------------------------------------- + | Resources + |-------------------------------------------------------------------------- + | + | Here you map the list of JSON API resources in your API to the actual + | record (model/entity) classes they relate to. + | + | For example, if you had a `posts` JSON API resource, that related to + | an Eloquent model `App\Post`, your mapping would be: + | + | `'posts' => App\Post::class` + */ + 'resources' => [ + 'ingredients' => \App\Models\Ingredient::class, + 'ingredient-amounts' => \App\Models\IngredientAmount::class, + 'recipes' => \App\Models\Recipe::class, + 'recipe-steps' => \App\Models\RecipeStep::class, + ], + + /* + |-------------------------------------------------------------------------- + | Eloquent + |-------------------------------------------------------------------------- + | + | Whether your JSON API resources predominantly relate to Eloquent models. + | This is used by the package's generators. + | + | You can override the setting here when running a generator. If the + | setting here is `true` running a generator with `--no-eloquent` will + | override it; if the setting is `false`, then `--eloquent` is the override. + | + */ + 'use-eloquent' => true, + + /* + |-------------------------------------------------------------------------- + | URL + |-------------------------------------------------------------------------- + | + | The API's url, made up of a host, URL namespace and route name prefix. + | + | If a JSON API is handling an inbound request, the host will always be + | detected from the inbound HTTP request. In other circumstances + | (e.g. broadcasting), the host will be taken from the setting here. + | If it is `null`, the `app.url` config setting is used as the default. + | If you set `host` to `false`, the host will never be appended to URLs + | for inbound requests. + | + | The name setting is the prefix for route names within this API. + | + */ + 'url' => [ + 'host' => null, + 'namespace' => '/api/v1', + 'name' => 'api:v1:', + ], + + /* + |-------------------------------------------------------------------------- + | Controllers + |-------------------------------------------------------------------------- + | + | The default JSON API controller wraps write operations in transactions. + | You can customise the connection for the transaction here. Or if you + | want to turn transactions off, set `transactions` to `false`. + | + */ + 'controllers' => [ + 'transactions' => true, + 'connection' => null, + ], + + /* + |-------------------------------------------------------------------------- + | Jobs + |-------------------------------------------------------------------------- + | + | Defines settings for the asynchronous processing feature. We recommend + | referring to the documentation on asynchronous processing if you are + | using this feature. + | + | Note that if you use a different model class, it must implement the + | asynchronous process interface. + | + */ + 'jobs' => [ + 'resource' => 'queue-jobs', + 'model' => \CloudCreativity\LaravelJsonApi\Queue\ClientJob::class, + ], + + /* + |-------------------------------------------------------------------------- + | Encoding Media Types + |-------------------------------------------------------------------------- + | + | This defines the JSON API encoding used for particular media + | types supported by your API. This array can contain either + | media types as values, or can be keyed by a media type with the value + | being the options that are passed to the `json_encode` method. + | + | These values are also used for Content Negotiation. If a client requests + | via the HTTP Accept header a media type that is not listed here, + | a 406 Not Acceptable response will be sent. + | + | If you want to support media types that do not return responses with JSON + | API encoded data, you can do this at runtime. Refer to the + | Content Negotiation chapter in the docs for details. + | + */ + 'encoding' => [ + 'application/vnd.api+json', + ], + + /* + |-------------------------------------------------------------------------- + | Decoding Media Types + |-------------------------------------------------------------------------- + | + | This defines the media types that your API can receive from clients. + | This array is keyed by expected media types, with the value being the + | service binding that decodes the media type. + | + | These values are also used for Content Negotiation. If a client sends + | a content type not listed here, it will receive a + | 415 Unsupported Media Type response. + | + | Decoders can also be calculated at runtime, and/or you can add support + | for media types for specific resources or requests. Refer to the + | Content Negotiation chapter in the docs for details. + | + */ + 'decoding' => [ + 'application/vnd.api+json', + ], + + /* + |-------------------------------------------------------------------------- + | Providers + |-------------------------------------------------------------------------- + | + | Providers allow vendor packages to include resources in your API. E.g. + | a Shopping Cart vendor package might define the `orders` and `payments` + | JSON API resources. + | + | A package author will define a provider class in their package that you + | can add here. E.g. for our shopping cart example, the provider could be + | `Vendor\ShoppingCart\JsonApi\ResourceProvider`. + | + */ + 'providers' => [], + +]; diff --git a/routes/api.php b/routes/api.php index bcb8b18..63d7624 100644 --- a/routes/api.php +++ b/routes/api.php @@ -1,5 +1,6 @@ get('/user', function (Request $request) { return $request->user(); }); + +JsonApi::register('default')->routes(function ($api) { + $api->resource('ingredient-amounts')->relationships(function ($relations) { + $relations->hasOne('ingredient'); + $relations->hasOne('recipe'); + }); + $api->resource('ingredients'); + $api->resource('recipes')->relationships(function ($relations) { + $relations->hasMany('ingredient-amounts'); + $relations->hasOne('steps'); + }); + $api->resource('recipe-steps')->relationships(function ($relations) { + $relations->hasOne('recipe'); + }); +});