diff --git a/.env.ci b/.env.ci index 4ff177a5d..1ebd57367 100644 --- a/.env.ci +++ b/.env.ci @@ -10,3 +10,5 @@ DB_DATABASE=":memory:" REDIS_HOST=localhost REDIS_PASSWORD=null REDIS_PORT=6379 + +QUEUE_CONNECTION=sync diff --git a/packages/api/src/ApiServiceProvider.php b/packages/api/src/ApiServiceProvider.php index 55586f772..edb433e65 100644 --- a/packages/api/src/ApiServiceProvider.php +++ b/packages/api/src/ApiServiceProvider.php @@ -5,8 +5,6 @@ use Dystore\Api\Api as DystoreApi; use Dystore\Api\Domain\Carts\Actions\CheckoutCart; use Dystore\Api\Domain\Carts\Actions\CreateUserFromCart; -use Dystore\Api\Domain\Payments\Contracts\PaymentIntent as PaymentIntentContract; -use Dystore\Api\Domain\Payments\Data\PaymentIntent; use Dystore\Api\Domain\Prices\Http\Middleware\SetApiPricing; use Dystore\Api\Domain\Users\Actions\CreateUser; use Dystore\Api\Domain\Users\Actions\RegisterUser; @@ -50,10 +48,7 @@ public function register(): void }); // Register the main class to use with the facade. - $this->app->singleton( - 'dystore', - fn () => new DystoreApi, - ); + $this->app->singleton('dystore', fn () => new DystoreApi); $this->bindControllers(); $this->bindModels(); @@ -83,8 +78,8 @@ public function register(): void ); $this->app->bind( - PaymentIntentContract::class, - PaymentIntent::class, + \Dystore\Api\Domain\Payments\Contracts\PaymentIntent::class, + \Dystore\Api\Domain\Payments\Data\PaymentIntent::class ); } diff --git a/packages/api/src/Base/Contracts/Extension.php b/packages/api/src/Base/Contracts/Extension.php deleted file mode 100644 index 636d9b912..000000000 --- a/packages/api/src/Base/Contracts/Extension.php +++ /dev/null @@ -1,24 +0,0 @@ - $class - */ - public static function extend(string $class): Extension; -} diff --git a/packages/api/src/Base/Contracts/Repository.php b/packages/api/src/Base/Contracts/Repository.php new file mode 100644 index 000000000..88fa6f85c --- /dev/null +++ b/packages/api/src/Base/Contracts/Repository.php @@ -0,0 +1,5 @@ + $class - * - * @method ExtensionValueCollection attributes() - * @method self setAttributes(iterable|callable $value) - * @method ExtensionValueCollection relationships() - * @method iterable setRelationships(iterable|callable $value) - */ -interface ResourceExtension extends Extension -{ - /** {@inheritdoc} */ - public function set(string $property, iterable|Closure $extension): Extension; - - /** {@inheritdoc} */ - public function get(string $key): iterable; -} diff --git a/packages/api/src/Base/Contracts/ResourceManifest.php b/packages/api/src/Base/Contracts/ResourceManifest.php deleted file mode 100644 index a681d8981..000000000 --- a/packages/api/src/Base/Contracts/ResourceManifest.php +++ /dev/null @@ -1,24 +0,0 @@ - $class - * - * @deprecated Use ResourceManifest::extend() instead. - */ - public static function for(string $class): ResourceExtension; - - /** - * Get resource extension for a given resouce class. - * - * @param class-string $class - */ - public static function extend(string $class): ResourceExtension; -} diff --git a/packages/api/src/Base/Contracts/ResourceRepository.php b/packages/api/src/Base/Contracts/ResourceRepository.php new file mode 100644 index 000000000..fd1554ad7 --- /dev/null +++ b/packages/api/src/Base/Contracts/ResourceRepository.php @@ -0,0 +1,5 @@ + $class - * - * @method ExtensionValueCollection with() - * @method self setWith(iterable|callable $value) - * @method ExtensionValueCollection includePaths() - * @method self setIncludePaths(iterable|callable $value) - * @method ExtensionValueCollection fields() - * @method self setFields(iterable|callable $value) - * @method ExtensionValueCollection filters() - * @method self setFilters(iterable|callable $value) - * @method ExtensionValueCollection sortables() - * @method self setSortables(iterable|callable $value) - * @method ExtensionValueCollection showRelated() - * @method self setShowRelated(iterable|callable $value) - * @method ExtensionValueCollection showRelationship() - * @method self setShowRelationship(iterable|callable $value) - */ -interface SchemaExtension extends Extension -{ - /** {@inheritdoc} */ - public function set(string $property, iterable|Relation|Closure $extension): self; - - /** {@inheritdoc} */ - public function get(string $key): iterable; -} diff --git a/packages/api/src/Base/Contracts/SchemaManifest.php b/packages/api/src/Base/Contracts/SchemaManifest.php deleted file mode 100644 index 1e3fbc4f6..000000000 --- a/packages/api/src/Base/Contracts/SchemaManifest.php +++ /dev/null @@ -1,59 +0,0 @@ - $class - * - * @deprecated Use SchemaManifest::extend() instead. - */ - public static function for(string $class): SchemaExtension; - - /** - * Get schema extension for a given schema class. - * - * @param class-string $class - */ - public static function extend(string $class): SchemaExtension; - - /** - * Register schemas. - * - * @param Collection $schemas - */ - public function register(Collection $schemas): void; - - /** - * Register single schema. - * - * @param class-string $schemaClass - */ - public function registerSchema(string $schemaClass): void; - - /** - * Get the registered schema for a base schema class. - */ - public function getRegisteredSchema(string $baseSchemaClass): SchemaContract; - - /** - * Get list of registered schema types. - */ - public function getSchemaTypes(): Collection; - - /** - * Removes schema from manifest. - */ - public function removeSchema(string $baseSchemaClass): void; - - /** - * Get list of all registered models. - */ - public function getRegisteredSchemas(): Collection; -} diff --git a/packages/api/src/Base/Contracts/SchemaRepository.php b/packages/api/src/Base/Contracts/SchemaRepository.php new file mode 100644 index 000000000..442026509 --- /dev/null +++ b/packages/api/src/Base/Contracts/SchemaRepository.php @@ -0,0 +1,5 @@ +value; - } - - /** - * Create new instance from value. - */ - public static function from(string|Closure|Relation|Field|Filter|SortField $value): self - { - return new self($value); - } - - /** - * Resolve value. - */ - public function resolve(?Extendable $extendable = null): string|array|Relation|Field|Filter|SortField - { - return $this->value instanceof Closure - ? ($this->value)($extendable) - : $this->value; - } - - /** - * Get value. - */ - public function value(): string|Closure - { - return $this->value; - } -} diff --git a/packages/api/src/Base/Data/ExtensionValueCollection.php b/packages/api/src/Base/Data/ExtensionValueCollection.php deleted file mode 100644 index 4dd88e734..000000000 --- a/packages/api/src/Base/Data/ExtensionValueCollection.php +++ /dev/null @@ -1,104 +0,0 @@ - - */ -class ExtensionValueCollection implements IteratorAggregate -{ - /** - * Extension values. - * - * @param array - */ - protected array $values = []; - - /** - * Check if value exists. - */ - public function exists(string $property): bool - { - return isset($this->values[$property]); - } - - /** - * Check if values are empty. - */ - public function empty(): bool - { - return empty($this->values); - } - - /** - * Get all values - */ - public function all(): array - { - return $this->values; - } - - /** - * Get value. - */ - public function get(string $property): ?ExtensionValue - { - return isset($this->values[$property]) ? $this->values[$property] : null; - } - - /** - * Set value. - */ - public function set(string $property, ExtensionValue $value): void - { - if (is_null($property)) { - $this->values[] = $value; - } else { - $this->values[$property] = $value; - } - } - - /** - * Push value. - */ - public function push(ExtensionValue $value): self - { - $this->values[] = $value; - - return $this; - } - - /** - * Forget value. - */ - public function forget(ExtensionValue $value): void - { - unset($this->values[$value]); - } - - /** - * Get iterator. - */ - public function getIterator(): Traversable - { - return new ArrayIterator($this->values); - } - - /** - * Resolve all values. - * - * @return array - */ - public function resolve(?Extendable $extendable = null): array - { - return array_map( - fn (ExtensionValue $value) => $value->resolve($extendable), - $this->values, - ); - } -} diff --git a/packages/api/src/Base/Extensions/Extension.php b/packages/api/src/Base/Extensions/Extension.php deleted file mode 100644 index 5989dfdba..000000000 --- a/packages/api/src/Base/Extensions/Extension.php +++ /dev/null @@ -1,117 +0,0 @@ - $class - */ - public function __construct(string $class) - { - $this->setExtendable($class); - } - - /** - * Dynamically call setter or getter. - */ - public function __call(string $method, $arguments): mixed - { - - $property = Str::of($method)->after('set')->camel()->toString(); - $action = $property === $method ? $action = 'get' : 'set'; - - if (! property_exists($this, $property)) { - throw new BadMethodCallException("{$property} is not extendable."); - } - - if ($action === 'set' && empty($arguments)) { - throw new BadMethodCallException("You are trying to set property {$property} without a value."); - } - - return $this->forwardCallTo($this, $action, [$property, ...$arguments]); - } - - /** - * Get manifest caller. - */ - public static function caller(): string - { - return debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 3)[2]['class']; - } - - /** - * Set extension value. - * - * Closure will be called with Extendable - * instance as argument and Closure will be bound to its scope, - * so you can use $this to refference the Extendable instance. - * - * @param iterable|Closure(ExtendableContract):((array)) $value - */ - public function set(string $property, iterable|Closure $extension): self - { - /** @var ExtensionValueCollection $collection */ - $collection = $this->{$property}; - - if (is_iterable($extension)) { - foreach ($extension as $value) { - throw_if(is_iterable($value), new InvalidArgumentException('Extension value cannot be nested.')); - - $collection->push(ExtensionValue::from($value)); - } - - return $this; - } - - $collection->push(ExtensionValue::from($extension)); - - return $this; - } - - /** - * Get property extension values. - */ - public function get(string $property): ExtensionValueCollection - { - /** @var ExtensionValueCollection $collection */ - $collection = $this->{$property}; - - return $collection; - } - - /** - * Set extendable class. - * - * @param class-string $class - */ - protected function setExtendable(string $class): void - { - if (is_subclass_of($class, ExtendableContract::class)) { - $this->class = $class; - - return; - } - - throw new InvalidArgumentException("{$class} cannot be extended."); - } -} diff --git a/packages/api/src/Base/Extensions/ResourceExtension.php b/packages/api/src/Base/Extensions/ResourceExtension.php deleted file mode 100644 index 7aae4a939..000000000 --- a/packages/api/src/Base/Extensions/ResourceExtension.php +++ /dev/null @@ -1,34 +0,0 @@ - $class - * - * @method ExtensionValueCollection attributes() - * @method self setAttributes(iterable|callable $value) - * @method ExtensionValueCollection relationships() - * @method iterable setRelationships(iterable|callable $value) - */ -class ResourceExtension extends Extension implements ResourceExtensionContract -{ - public function __construct( - protected string $class, - - /** - * Attributes method extensions. - */ - protected ExtensionValueCollection $attributes = new ExtensionValueCollection, - - /** - * Relationships method extensions. - */ - protected ExtensionValueCollection $relationships = new ExtensionValueCollection, - ) { - parent::__construct($class); - } -} diff --git a/packages/api/src/Base/Extensions/SchemaExtension.php b/packages/api/src/Base/Extensions/SchemaExtension.php deleted file mode 100644 index 15fb3add2..000000000 --- a/packages/api/src/Base/Extensions/SchemaExtension.php +++ /dev/null @@ -1,105 +0,0 @@ - $class - * - * @method ExtensionValueCollection with() - * @method self setWith(iterable|callable $value) - * @method ExtensionValueCollection includePaths() - * @method self setIncludePaths(iterable|callable $value) - * @method ExtensionValueCollection fields() - * @method self setFields(iterable|callable $value) - * @method ExtensionValueCollection filters() - * @method self setFilters(iterable|callable $value) - * @method ExtensionValueCollection sortables() - * @method self setSortables(iterable|callable $value) - * @method ExtensionValueCollection showRelated() - * @method self setShowRelated(iterable|callable $value) - * @method ExtensionValueCollection showRelationship() - * @method self setShowRelationship(iterable|callable $value) - */ -class SchemaExtension extends Extension implements SchemaExtensionContract -{ - /** - * @param class-string $class - */ - public function __construct( - protected string $class, - /** - * With property extensions. - */ - protected ExtensionValueCollection $with = new ExtensionValueCollection, - - /** - * IncludePaths method extensions. - */ - protected ExtensionValueCollection $includePaths = new ExtensionValueCollection, - - /** - * Fields method extensions. - */ - protected ExtensionValueCollection $fields = new ExtensionValueCollection, - - /** - * Filters method extensions. - */ - protected ExtensionValueCollection $filters = new ExtensionValueCollection, - - /** - * Sortables method extensions. - */ - protected ExtensionValueCollection $sortables = new ExtensionValueCollection, - - /** - * ShowRelated extensions. - */ - protected ExtensionValueCollection $showRelated = new ExtensionValueCollection, - - /** - * ShowRelationship extensions. - */ - protected ExtensionValueCollection $showRelationship = new ExtensionValueCollection, - ) { - parent::__construct($class); - } - - /** - * Set extension value. - * - * Closure will be called with Extendable - * instance as argument and Closure will be bound to its scope, - * so you can use $this to refference the Extendable instance. - * - * @param iterable|Relation|Closure(ExtendableContract):((array)) $value - */ - public function set(string $property, iterable|Relation|Closure $extension): self - { - // dump($property, $extension); - /** @var ExtensionValueCollection $collection */ - $collection = $this->{$property}; - - if (is_iterable($extension)) { - foreach ($extension as $value) { - throw_if(is_iterable($value), new InvalidArgumentException('Extension value cannot be nested.')); - - $collection->push(ExtensionValue::from($value)); - } - - return $this; - } - - $collection->push(ExtensionValue::from($extension)); - - return $this; - } -} diff --git a/packages/api/src/Base/Facades/JsonApiManifest.php b/packages/api/src/Base/Facades/JsonApiManifest.php new file mode 100644 index 000000000..55538cb0c --- /dev/null +++ b/packages/api/src/Base/Facades/JsonApiManifest.php @@ -0,0 +1,29 @@ +registerBaseSchemas(); + $this->registerBaseResources(); + } + + private function registerBaseSchemas(): void + { + $config = DomainConfigCollection::fromConfig('dystore.domains'); + + $config->getSchemas()->each(fn (string $schema) => $this->addSchema($schema)); + } + + private function registerBaseResources(): void + { + $config = DomainConfigCollection::fromConfig('dystore.domains') + ->getResources() + ->each(fn (string $resource) => $this->addResource($resource)); + } + + public function schemas(): array + { + return $this->schemas; + } + + public function getSchemas(): array + { + return array_map( + fn (SchemaStorage $storage) => $storage->schema(), + $this->schemas() + ); + } + + /** + * @param class-string<\Dystore\Api\Domain\JsonApi\Eloquent\Schema|\Dystore\Api\Domain\JsonApi\Core\Schema\Schema> $schema + */ + public function schema(string $schema): ?SchemaStorage + { + return Arr::get($this->schemas(), $schema::type()); + } + + public function schemaByType(string $type): ?SchemaStorage + { + return Arr::get($this->schemas(), $type); + } + + public function addSchema(string $schema, ?SchemaStorage $storage = null): self + { + $this->schemas[$schema::type()] = $storage ?? SchemaStorage::fromSchema($schema); + + return $this; + } + + public function resources(): array + { + return $this->resources; + } + + public function resource(string $resource): ?ResourceStorage + { + return Arr::get($this->resources(), $resource); + } + + public function addResource(string $resource, ?ResourceStorage $storage = null): self + { + $this->resources[$resource] = $storage ?? ResourceStorage::fromResource($resource); + + return $this; + } +} diff --git a/packages/api/src/Base/Manifests/Manifest.php b/packages/api/src/Base/Manifests/Manifest.php deleted file mode 100644 index fc64da6ae..000000000 --- a/packages/api/src/Base/Manifests/Manifest.php +++ /dev/null @@ -1,13 +0,0 @@ -, Extension> - */ - public array $extensions = []; -} diff --git a/packages/api/src/Base/Manifests/ResourceManifest.php b/packages/api/src/Base/Manifests/ResourceManifest.php deleted file mode 100644 index 484a04b80..000000000 --- a/packages/api/src/Base/Manifests/ResourceManifest.php +++ /dev/null @@ -1,40 +0,0 @@ - $extensions - */ -class ResourceManifest extends Manifest implements ResourceManifestContract -{ - /** - * Get resource extension for a given resource class. - * - * @param class-string $class - * - * @deprecated Use ResourceManifest::extend() instead. - */ - public static function for(string $class): ResourceExtensionContract - { - return self::extend($class); - } - - /** - * Get resource extension for a given resource class. - * - * @param class-string $class - */ - public static function extend(string $class): ResourceExtensionContract - { - $self = App::make(ResourceManifestContract::class); - - $extension = $self->extensions[$class] ??= App::make(ResourceExtensionContract::class, ['class' => $class]); - - return $extension; - } -} diff --git a/packages/api/src/Base/Manifests/SchemaManifest.php b/packages/api/src/Base/Manifests/SchemaManifest.php deleted file mode 100644 index f4e50d8a2..000000000 --- a/packages/api/src/Base/Manifests/SchemaManifest.php +++ /dev/null @@ -1,155 +0,0 @@ - $extensions - */ -class SchemaManifest extends Manifest implements SchemaManifestContract -{ - /** - * @var Dystore\Api\Base\Contracts\SchemaExtension[] - */ - public array $extensions; - - /** - * Collection of registered schemas. - */ - protected Collection $schemas; - - /** - * The schema manifest instance. - */ - public function __construct() - { - $this->schemas = new Collection([]); - - $this->registerBaseSchemas(); - } - - /** - * Get schema extension for a given schema class. - * - * @param class-string $class - * - * @deprecated Use SchemaManifest::extend() instead. - */ - public static function for(string $class): SchemaExtensionContract - { - return self::extend($class); - } - - /** - * Get schema extension for a given schema class. - * - * @param class-string $class - */ - public static function extend(string $class): SchemaExtensionContract - { - $self = App::make(SchemaManifestContract::class); - - $extension = $self->extensions[$class] ??= App::make(SchemaExtensionContract::class, ['class' => $class]); - - return $extension; - } - - /** - * Register schemas. - * - * @param Collection $schemas - */ - public function register(Collection $schemas): void - { - foreach ($schemas as $schemaClass) { - $this->registerSchema($schemaClass); - } - } - - /** - * Register single schema. - * - * @param class-string $schemaClass - */ - public function registerSchema(string $schemaClass): void - { - /** @var Schema $schemaClass */ - $this->validateClassIsSchema($schemaClass); - - $this->schemas->put($schemaClass::type(), $schemaClass); - } - - /** - * Get list of all registered schemas. - */ - public function getRegisteredSchemas(): Collection - { - return $this->schemas; - } - - /** - * Get all server schemas. - */ - public function getServerSchemas(): array - { - return $this - ->getRegisteredSchemas() - ->values() - ->toArray(); - } - - /** - * Get list of registered schema types. - */ - public function getSchemaTypes(): Collection - { - return $this->schemas->keys(); - } - - /** - * Get the registered schema for a base schema class. - */ - public function getRegisteredSchema(string $schemaType): SchemaContract - { - return App::make($this->schemas->get($schemaType) ?? $schemaType); - } - - /** - * Removes schema from manifest. - */ - public function removeSchema(string $schemaType): void - { - $this->schemas = $this->schemas->flip()->forget($schemaType); - } - - /** - * Register base schemas from config. - */ - private function registerBaseSchemas(): void - { - $schemas = DomainConfigCollection::make() - ->getSchemas(); - - $this->register($schemas); - } - - /** - * Validate class is a schema. - * - * @throws InvalidArgumentException - */ - private function validateClassIsSchema(string $class): void - { - if (! class_implements($class, SchemaContract::class)) { - throw new InvalidArgumentException(sprintf('Given [%s] is not a subclass of [%s].', $class, Schema::class)); - } - } -} diff --git a/packages/api/src/Base/Repositories/Repository.php b/packages/api/src/Base/Repositories/Repository.php new file mode 100644 index 000000000..2faad1ad4 --- /dev/null +++ b/packages/api/src/Base/Repositories/Repository.php @@ -0,0 +1,31 @@ + + */ +abstract class Repository extends Collection +{ + public function resolve(?Extendable $extendable = null): iterable + { + return $this + ->map(function (mixed $value) use ($extendable) { + if ($value instanceof Closure) { + $value = Closure::bind($value, $extendable, get_parent_class($extendable)); + + $value = $value($extendable); + } + + return $value; + }) + ->toArray(); + } +} diff --git a/packages/api/src/Base/Repositories/ResourceRepository.php b/packages/api/src/Base/Repositories/ResourceRepository.php new file mode 100644 index 000000000..660bf07f2 --- /dev/null +++ b/packages/api/src/Base/Repositories/ResourceRepository.php @@ -0,0 +1,5 @@ + $resource + */ +class ResourceStorage extends Storage +{ + final public function __construct( + protected string $resource, + protected AttributeRepository $attributes = new AttributeRepository, + protected RelationshipRepository $relationships = new RelationshipRepository, + ) { + // + } + + /** + * @param class-string<\Dystore\Api\Domain\JsonApi\Resources\JsonApiResource> $resource + */ + public static function fromResource(string $resource): static + { + return new static( + resource: $resource, + attributes: new AttributeRepository($resource::defaultAttributes()), + relationships: new RelationshipRepository($resource::defaultRelationships()), + ); + } + + public function attributes(): AttributeRepository + { + return $this->attributes; + } + + public function relationships(): RelationshipRepository + { + return $this->relationships; + } +} diff --git a/packages/api/src/Base/Repositories/SchemaRepository.php b/packages/api/src/Base/Repositories/SchemaRepository.php new file mode 100644 index 000000000..1194bfbb6 --- /dev/null +++ b/packages/api/src/Base/Repositories/SchemaRepository.php @@ -0,0 +1,5 @@ +items as $key => $value) { + yield clone $value; + } + } +} diff --git a/packages/api/src/Base/Repositories/SchemaRepository/FilterRepository.php b/packages/api/src/Base/Repositories/SchemaRepository/FilterRepository.php new file mode 100644 index 000000000..1e501f315 --- /dev/null +++ b/packages/api/src/Base/Repositories/SchemaRepository/FilterRepository.php @@ -0,0 +1,7 @@ + $schema + */ + public static function fromSchema(string $schema): static + { + return new static( + schema: $schema, + type: $schema::type(), + with: new EagerLoadRepository($schema::defaultWith()), + includePaths: new IncludePathRepository($schema::defaultIncludePaths()), + fields: new FieldRepository($schema::defaultFields()), + sparseFields: new SparseFieldRepository($schema::defaultSparseFields()), + filters: new FilterRepository($schema::defaultFilters()), + sortables: new SortableRepository($schema::defaultSortables()), + showRelated: new RelatedRepository($schema::defaultShowRelated()), + showRelationships: new RelationshipRepository($schema::defaultShowRelationships()), + ); + } + + /** + * @return class-string<\Dystore\Api\Domain\JsonApi\Contracts\Schema> + */ + public function schema(): string + { + return $this->schema; + } + + public function with(): EagerLoadRepository + { + return $this->with; + } + + /** + * @param string|string[] $with + */ + public function setWith(string|array $with): SchemaStorage + { + $this->with = new EagerLoadRepository(Arr::wrap($with)); + + return $this; + } + + /** + * @param string|string[] $with + */ + public function addWith(string|array $with): SchemaStorage + { + $this->setWith( + $this->with()->merge(array_unique(Arr::wrap($with)))->toArray() + ); + + return $this; + } + + /** + * @param string|string[] $with + */ + public function removeWith(string|array $with): SchemaStorage + { + $this->setWith( + $this->with()->reject(fn (string $item) => in_array($item, Arr::wrap($with)))->toArray() + ); + + return $this; + } + + public function includePaths(): IncludePathRepository + { + return $this->includePaths; + } + + /** + * @param string[] $includePaths + */ + public function setIncludePaths(string ...$includePaths): SchemaStorage + { + $this->includePaths = new IncludePathRepository(...$includePaths); + + return $this; + } + + /** + * @param string|string[] $includePaths + */ + public function addIncludePaths(string|array $includePaths): SchemaStorage + { + $this->setIncludePaths( + $this->includePaths()->merge(array_unique(Arr::wrap($includePaths)))->toArray() + ); + + return $this; + } + + /** + * @param string|string[] $includePaths + */ + public function removeIncludePaths(string ...$includePaths): SchemaStorage + { + $this->setIncludePaths( + $this->includePaths()->reject(fn (string $item) => in_array($item, Arr::wrap($includePaths)))->toArray() + ); + + return $this; + } + + public function fields(): FieldRepository + { + return $this->fields; + } + + /** + * @param Field[] $fields + */ + public function setFields(array $fields): SchemaStorage + { + $this->fields = new FieldRepository($fields); + + return $this; + } + + /** + * @param Field|Field[] $fields + */ + public function addFields(Field|array $fields): SchemaStorage + { + $this->fields()->push(...Arr::wrap($fields)); + + return $this; + } + + /** + * @param string|string[] $names + */ + public function removeFields(string|array $names): SchemaStorage + { + $this->setFields( + $this->fields()->reject(fn (Field $field) => in_array($field->name(), Arr::wrap($names)))->toArray() + ); + + return $this; + } + + public function sparseFields(): SparseFieldRepository + { + return $this->sparseFields; + } + + /** + * @param string|string[] $sparseFields + */ + public function setSparseFields(string|array $sparseFields): SchemaStorage + { + $this->sparseFields = new SparseFieldRepository(Arr::wrap($sparseFields)); + + return $this; + } + + /** + * @param string|string[] $sparseFields + */ + public function addSparseFields(string|array $sparseFields): SchemaStorage + { + $this->sparseFields()->push(Arr::wrap($sparseFields)); + + return $this; + } + + /** + * @param string|string[] $sparseFields + */ + public function removeSparseFields(string|array $sparseFields): SchemaStorage + { + $this->setSparseFields( + $this->sparseFields()->reject(fn (string $field) => in_array($field, Arr::wrap($sparseFields)))->toArray() + ); + + return $this; + } + + public function filters(): FilterRepository + { + return $this->filters; + } + + /** + * @param Filter[] $filters + */ + public function setFilters(array $filters): SchemaStorage + { + $this->filters = new FilterRepository(...$filters); + + return $this; + } + + /** + * @param Filter|Filter[] $filters + */ + public function addFilters(Filter|array $filters): SchemaStorage + { + $this->filters()->push(...Arr::wrap($filters)); + + return $this; + } + + /** + * @param string|string[] $keys + */ + public function removeFilters(string|array $keys): SchemaStorage + { + $this->setFilters( + $this->filters()->reject(fn (Filter $filter) => in_array($filter->key(), Arr::wrap($keys)))->toArray() + ); + + return $this; + } + + public function sortables(): SortableRepository + { + return $this->sortables; + } + + /** + * @param string|SortField|SortField[] $sortables + */ + public function setSortables(string|SortField|array $sortables): SchemaStorage + { + $this->sortables = new SortableRepository(Arr::wrap($sortables)); + + return $this; + } + + /** + * @param string|SortField|SortField[] $sortables + */ + public function addSortables(string|SortField|array $sortables): SchemaStorage + { + $this->sortables()->push(...Arr::wrap($sortables)); + + return $this; + } + + /** + * @param string|string[] $names + */ + public function removeSortables(string|array $names): SchemaStorage + { + $this->setSortables( + $this->sortables()->reject(fn (SortField $sortable) => in_array($sortable->sortField(), Arr::wrap($names)))->toArray() + ); + + return $this; + } + + public function showRelated(): RelatedRepository + { + return $this->showRelated; + } + + /** + * @param string|string[] $related + */ + public function setShowRelated(string|array $related): SchemaStorage + { + $this->showRelated = new RelatedRepository(Arr::wrap($related)); + + return $this; + } + + /** + * @param string|string[] $related + */ + public function addShowRelated(string|array $related): SchemaStorage + { + $this->showRelated()->push(...Arr::wrap($related)); + + return $this; + } + + /** + * @param string|string[] $related + */ + public function removeShowRelated(string|array $related): SchemaStorage + { + $this->setShowRelated( + $this->showRelated()->reject(fn (string $item) => in_array($item, Arr::wrap($related)))->toArray() + ); + + return $this; + } + + public function showRelationships(): RelationshipRepository + { + return $this->showRelationships; + } + + /** + * @param string|string[] $relationships + */ + public function setShowRelationships(string|array $relationships): SchemaStorage + { + $this->showRelationships = new RelationshipRepository(Arr::wrap($relationships)); + + return $this; + } + + /** + * @param string|string[] $relationships + */ + public function addShowRelationships(string|array $relationships): SchemaStorage + { + $this->showRelationships()->push(...Arr::wrap($relationships)); + + return $this; + } + + /** + * @param string|string[] $relationships + */ + public function removeShowRelationships(string|array $relationships): SchemaStorage + { + $this->setShowRelationships( + $this->showRelationships()->reject(fn (string $item) => in_array($item, Arr::wrap($relationships)))->toArray() + ); + + return $this; + } +} diff --git a/packages/api/src/Base/Repositories/SchemaRepository/SortableRepository.php b/packages/api/src/Base/Repositories/SchemaRepository/SortableRepository.php new file mode 100644 index 000000000..75d7b3ac9 --- /dev/null +++ b/packages/api/src/Base/Repositories/SchemaRepository/SortableRepository.php @@ -0,0 +1,20 @@ +items as $key => $value) { + if (is_object($value)) { + yield clone $value; + } + + yield $value; + } + } +} diff --git a/packages/api/src/Base/Repositories/SchemaRepository/SparseFieldRepository.php b/packages/api/src/Base/Repositories/SchemaRepository/SparseFieldRepository.php new file mode 100644 index 000000000..ec8c71787 --- /dev/null +++ b/packages/api/src/Base/Repositories/SchemaRepository/SparseFieldRepository.php @@ -0,0 +1,7 @@ +idField(), + static::idField(), Str::make('title'), Str::make('first_name'), @@ -85,8 +83,6 @@ public function fields(): array BelongsTo::make('country') ->serializeUsing(static fn (Relation $relation) => $relation->withoutLinks()), - - ...parent::fields(), ]; } } diff --git a/packages/api/src/Domain/AttributeGroups/JsonApi/V1/AttributeGroupSchema.php b/packages/api/src/Domain/AttributeGroups/JsonApi/V1/AttributeGroupSchema.php index 0728f6d64..8257d889d 100644 --- a/packages/api/src/Domain/AttributeGroups/JsonApi/V1/AttributeGroupSchema.php +++ b/packages/api/src/Domain/AttributeGroups/JsonApi/V1/AttributeGroupSchema.php @@ -15,12 +15,10 @@ class AttributeGroupSchema extends Schema /** * {@inheritDoc} */ - public function fields(): iterable + public static function defaultFields(): array { return [ - $this->idField(), - - ...parent::fields(), + static::idField(), ]; } } diff --git a/packages/api/src/Domain/Attributes/JsonApi/V1/AttributeSchema.php b/packages/api/src/Domain/Attributes/JsonApi/V1/AttributeSchema.php index b63a76b8d..8183e79f6 100644 --- a/packages/api/src/Domain/Attributes/JsonApi/V1/AttributeSchema.php +++ b/packages/api/src/Domain/Attributes/JsonApi/V1/AttributeSchema.php @@ -19,29 +19,25 @@ class AttributeSchema extends Schema /** * {@inheritDoc} */ - public function includePaths(): iterable + public static function defaultIncludePaths(): array { return [ 'attribute_group', - - ...parent::includePaths(), ]; } /** * {@inheritDoc} */ - public function fields(): iterable + public static function defaultFields(): array { return [ - $this->idField(), + static::idField(), BelongsTo::make('attribute_group', 'attributeGroup') ->retainFieldName() ->type(SchemaType::get(AttributeGroup::class)) ->serializeUsing(static fn (Relation $relation) => $relation->withoutLinks()), - - ...parent::fields(), ]; } } diff --git a/packages/api/src/Domain/Auth/JsonApi/V1/AuthSchema.php b/packages/api/src/Domain/Auth/JsonApi/V1/AuthSchema.php index 45d078f3e..64ce8b148 100644 --- a/packages/api/src/Domain/Auth/JsonApi/V1/AuthSchema.php +++ b/packages/api/src/Domain/Auth/JsonApi/V1/AuthSchema.php @@ -5,7 +5,6 @@ use Dystore\Api\Domain\Auth\JsonApi\Proxies\AuthUser; use Dystore\Api\Domain\JsonApi\Eloquent\ProxySchema; use Dystore\Api\Domain\Users\JsonApi\V1\UserSchema; -use Illuminate\Support\Facades\App; class AuthSchema extends ProxySchema { @@ -23,16 +22,12 @@ public static function type(): string } /** - * Get the resource fields. + * {@inheritDoc} */ - public function fields(): array + public static function defaultFields(): array { - $userSchema = App::make(UserSchema::class); - return [ - ...$userSchema->fields(), - - ...parent::fields(), + ...UserSchema::defaultFields(), ]; } diff --git a/packages/api/src/Domain/Brands/JsonApi/V1/BrandSchema.php b/packages/api/src/Domain/Brands/JsonApi/V1/BrandSchema.php index 2120961cd..19d8e34cb 100644 --- a/packages/api/src/Domain/Brands/JsonApi/V1/BrandSchema.php +++ b/packages/api/src/Domain/Brands/JsonApi/V1/BrandSchema.php @@ -9,7 +9,6 @@ use LaravelJsonApi\Eloquent\Fields\Str; use LaravelJsonApi\Eloquent\Filters\Where; use LaravelJsonApi\Eloquent\Filters\WhereHas; -use LaravelJsonApi\Eloquent\Filters\WhereIdIn; use LaravelJsonApi\Eloquent\Filters\WhereIn; use LaravelJsonApi\Eloquent\Resources\Relation; use Lunar\Models\Contracts\Brand; @@ -26,24 +25,22 @@ class BrandSchema extends Schema /** * {@inheritDoc} */ - public function includePaths(): iterable + public static function defaultIncludePaths(): array { return [ 'default_url', 'urls', 'thumbnail', - - ...parent::includePaths(), ]; } /** * {@inheritDoc} */ - public function fields(): array + public static function defaultFields(): array { return [ - $this->idField(), + static::idField(), Str::make('name'), @@ -58,29 +55,19 @@ public function fields(): array HasMany::make('urls') ->serializeUsing(static fn (Relation $relation) => $relation->withoutLinks()), - - ...parent::fields(), ]; } /** * {@inheritDoc} */ - public function filters(): array + public static function defaultFilters(): array { return [ - WhereIdIn::make($this)->delimiter(','), - Where::make('name'), - WhereIn::make('names', 'name')->delimiter(','), - - WhereHas::make($this, 'urls', 'url') - ->singular(), - - WhereHas::make($this, 'urls', 'urls'), - - ...parent::filters(), + fn (Schema $schema) => WhereHas::make($schema, 'urls', 'url')->singular(), + fn (Schema $schema) => WhereHas::make($schema, 'urls', 'urls'), ]; } } diff --git a/packages/api/src/Domain/CartAddresses/JsonApi/V1/CartAddressSchema.php b/packages/api/src/Domain/CartAddresses/JsonApi/V1/CartAddressSchema.php index 9e1b63dd0..e6c82e139 100644 --- a/packages/api/src/Domain/CartAddresses/JsonApi/V1/CartAddressSchema.php +++ b/packages/api/src/Domain/CartAddresses/JsonApi/V1/CartAddressSchema.php @@ -20,23 +20,22 @@ class CartAddressSchema extends Schema /** * {@inheritDoc} */ - public function includePaths(): iterable + public static function defaultIncludePaths(): array { return [ 'cart', 'country', - ...parent::includePaths(), ]; } /** * {@inheritDoc} */ - public function fields(): array + public static function defaultFields(): array { return [ - $this->idField(), + static::idField(), Str::make('title'), Str::make('first_name'), @@ -73,7 +72,6 @@ public function fields(): array BelongsTo::make('cart') ->serializeUsing(static fn (Relation $relation) => $relation->withoutLinks()), - ...parent::fields(), ]; } } diff --git a/packages/api/src/Domain/CartLines/JsonApi/V1/CartLineSchema.php b/packages/api/src/Domain/CartLines/JsonApi/V1/CartLineSchema.php index 534715a67..27a00f7d1 100644 --- a/packages/api/src/Domain/CartLines/JsonApi/V1/CartLineSchema.php +++ b/packages/api/src/Domain/CartLines/JsonApi/V1/CartLineSchema.php @@ -25,7 +25,7 @@ class CartLineSchema extends Schema /** * {@inheritDoc} */ - public function includePaths(): iterable + public static function defaultIncludePaths(): array { return [ 'purchasable', @@ -38,18 +38,16 @@ public function includePaths(): iterable 'purchasable.product_option_values', 'purchasable.product_option_values.images', 'purchasable.product_option_values.product_option', - - ...parent::includePaths(), ]; } /** * {@inheritDoc} */ - public function fields(): array + public static function defaultFields(): array { return [ - $this->idField(), + static::idField(), Number::make('purchasable_id'), Str::make('purchasable_type'), @@ -95,8 +93,6 @@ public function fields(): array SchemaType::get(ProductVariant::class), ) ->serializeUsing(static fn (Relation $relation) => $relation->withoutLinks()), - - ...parent::fields(), ]; } } diff --git a/packages/api/src/Domain/Carts/JsonApi/V1/CartSchema.php b/packages/api/src/Domain/Carts/JsonApi/V1/CartSchema.php index a1b3a9fab..ec2540b6b 100644 --- a/packages/api/src/Domain/Carts/JsonApi/V1/CartSchema.php +++ b/packages/api/src/Domain/Carts/JsonApi/V1/CartSchema.php @@ -34,7 +34,7 @@ class CartSchema extends Schema /** * {@inheritDoc} */ - public function includePaths(): iterable + public static function defaultIncludePaths(): array { return [ 'cart_lines', @@ -71,18 +71,16 @@ public function includePaths(): iterable 'billing_address', 'billing_address.country', - - ...parent::includePaths(), ]; } /** * {@inheritDoc} */ - public function fields(): array + public static function defaultFields(): array { return [ - $this->idField(), + static::idField(), Map::make('prices', [ Number::make('sub_total', 'subTotal') @@ -164,8 +162,6 @@ public function fields(): array ->type(SchemaType::get(CartAddress::class)) ->retainFieldName() ->serializeUsing(static fn (Relation $relation) => $relation->withoutLinks()), - - ...parent::fields(), ]; } } diff --git a/packages/api/src/Domain/Channels/JsonApi/V1/ChannelSchema.php b/packages/api/src/Domain/Channels/JsonApi/V1/ChannelSchema.php index d9d1ca6b9..d99150277 100644 --- a/packages/api/src/Domain/Channels/JsonApi/V1/ChannelSchema.php +++ b/packages/api/src/Domain/Channels/JsonApi/V1/ChannelSchema.php @@ -5,7 +5,6 @@ use Dystore\Api\Domain\JsonApi\Eloquent\Schema; use LaravelJsonApi\Eloquent\Fields\Str; use LaravelJsonApi\Eloquent\Filters\Where; -use LaravelJsonApi\Eloquent\Filters\WhereIdIn; use Lunar\Models\Contracts\Channel; class ChannelSchema extends Schema @@ -18,42 +17,32 @@ class ChannelSchema extends Schema /** * {@inheritDoc} */ - public function includePaths(): iterable + public static function defaultIncludePaths(): array { - return [ - ...parent::includePaths(), - ]; + return []; } /** * {@inheritDoc} */ - public function fields(): array + public static function defaultFields(): array { return [ - $this->idField(), + static::idField(), Str::make('name'), - Str::make('handle'), - Str::make('url'), - - ...parent::fields(), ]; } /** * {@inheritDoc} */ - public function filters(): array + public static function defaultFilters(): array { return [ - WhereIdIn::make($this)->delimiter(','), - Where::make('handle'), - - ...parent::filters(), ]; } } diff --git a/packages/api/src/Domain/CollectionGroups/JsonApi/V1/CollectionGroupSchema.php b/packages/api/src/Domain/CollectionGroups/JsonApi/V1/CollectionGroupSchema.php index 7a407a357..5c727304d 100644 --- a/packages/api/src/Domain/CollectionGroups/JsonApi/V1/CollectionGroupSchema.php +++ b/packages/api/src/Domain/CollectionGroups/JsonApi/V1/CollectionGroupSchema.php @@ -5,7 +5,6 @@ use Dystore\Api\Domain\JsonApi\Eloquent\Schema; use LaravelJsonApi\Eloquent\Fields\Str; use LaravelJsonApi\Eloquent\Filters\Where; -use LaravelJsonApi\Eloquent\Filters\WhereIdIn; use Lunar\Models\Contracts\CollectionGroup; class CollectionGroupSchema extends Schema @@ -18,32 +17,24 @@ class CollectionGroupSchema extends Schema /** * {@inheritDoc} */ - public function fields(): array + public static function defaultFields(): array { return [ - $this->idField(), + static::idField(), Str::make('name'), - Str::make('handle'), - - ...parent::fields(), ]; } /** * {@inheritDoc} */ - public function filters(): array + public static function defaultFilters(): array { return [ - WhereIdIn::make($this), - Where::make('name', 'name'), - Where::make('handle', 'handle'), - - ...parent::filters(), ]; } } diff --git a/packages/api/src/Domain/Collections/JsonApi/V1/CollectionSchema.php b/packages/api/src/Domain/Collections/JsonApi/V1/CollectionSchema.php index 16452620b..506436321 100644 --- a/packages/api/src/Domain/Collections/JsonApi/V1/CollectionSchema.php +++ b/packages/api/src/Domain/Collections/JsonApi/V1/CollectionSchema.php @@ -12,7 +12,6 @@ use LaravelJsonApi\Eloquent\Fields\Relations\HasOne; use LaravelJsonApi\Eloquent\Filters\Has; use LaravelJsonApi\Eloquent\Filters\WhereHas; -use LaravelJsonApi\Eloquent\Filters\WhereIdIn; use LaravelJsonApi\Eloquent\Filters\WhereNull; use LaravelJsonApi\Eloquent\Resources\Relation; use Lunar\Models\Contracts\Collection; @@ -35,20 +34,18 @@ class CollectionSchema extends Schema /** * {@inheritDoc} */ - public function with(): array + public static function defaultWith(): array { return [ 'attributes', 'attributes.attributeGroup', - - ...parent::with(), ]; } /** * {@inheritDoc} */ - public function includePaths(): iterable + public static function defaultIncludePaths(): array { return [ 'default_url', @@ -65,18 +62,16 @@ public function includePaths(): iterable 'products.prices', 'products.thumbnail', 'products.urls', - - ...parent::includePaths(), ]; } /** * {@inheritDoc} */ - public function fields(): array + public static function defaultFields(): array { return [ - $this->idField(), + static::idField(), AttributeData::make('attribute_data') ->groupAttributes(), @@ -110,19 +105,15 @@ public function fields(): array HasMany::make('urls') ->serializeUsing(static fn (Relation $relation) => $relation->withoutLinks()), - - ...parent::fields(), ]; } /** * {@inheritDoc} */ - public function sortables(): iterable + public static function defaultSortables(): array { return [ - ...parent::sortables(), - InDefaultOrder::make('ordered'), ]; } @@ -130,23 +121,14 @@ public function sortables(): iterable /** * {@inheritDoc} */ - public function filters(): array + public static function defaultFilters(): array { return [ - WhereIdIn::make($this), - - WhereHas::make($this, 'urls', 'url') - ->singular(), - - WhereHas::make($this, 'urls', 'urls'), - - WhereHas::make($this, 'group', 'group'), - - WhereNull::make('root', 'parent_id'), - - Has::make($this, 'products', 'has_products'), - - ...parent::filters(), + fn (Schema $schema) => WhereHas::make($schema, 'urls', 'url')->singular(), + fn (Schema $schema) => WhereHas::make($schema, 'urls', 'urls'), + fn (Schema $schema) => WhereHas::make($schema, 'group', 'group'), + fn (Schema $schema) => WhereNull::make('root', 'parent_id'), + fn (Schema $schema) => Has::make($schema, 'products', 'has_products'), ]; } } diff --git a/packages/api/src/Domain/Countries/JsonApi/V1/CountrySchema.php b/packages/api/src/Domain/Countries/JsonApi/V1/CountrySchema.php index 2c6a12103..7ec376fc9 100644 --- a/packages/api/src/Domain/Countries/JsonApi/V1/CountrySchema.php +++ b/packages/api/src/Domain/Countries/JsonApi/V1/CountrySchema.php @@ -18,10 +18,10 @@ class CountrySchema extends Schema /** * {@inheritDoc} */ - public function fields(): array + public static function defaultFields(): array { return [ - $this->idField(), + static::idField(), Str::make('name'), Str::make('iso2'), @@ -32,8 +32,6 @@ public function fields(): array Str::make('native'), Str::make('emoji'), Str::make('emoji_u'), - - ...parent::fields(), ]; } diff --git a/packages/api/src/Domain/Currencies/JsonApi/V1/CurrencySchema.php b/packages/api/src/Domain/Currencies/JsonApi/V1/CurrencySchema.php index 044d5aadf..7efb610e3 100644 --- a/packages/api/src/Domain/Currencies/JsonApi/V1/CurrencySchema.php +++ b/packages/api/src/Domain/Currencies/JsonApi/V1/CurrencySchema.php @@ -19,10 +19,10 @@ class CurrencySchema extends Schema /** * {@inheritDoc} */ - public function fields(): array + public static function defaultFields(): array { return [ - $this->idField(), + static::idField(), Str::make('code'), Str::make('name'), diff --git a/packages/api/src/Domain/CustomerGroups/JsonApi/V1/CustomerGroupSchema.php b/packages/api/src/Domain/CustomerGroups/JsonApi/V1/CustomerGroupSchema.php index af61f9b98..d08b74d4b 100644 --- a/packages/api/src/Domain/CustomerGroups/JsonApi/V1/CustomerGroupSchema.php +++ b/packages/api/src/Domain/CustomerGroups/JsonApi/V1/CustomerGroupSchema.php @@ -17,26 +17,24 @@ class CustomerGroupSchema extends Schema /** * {@inheritDoc} */ - public function includePaths(): iterable + public static function defaultIncludePaths(): array { return [ - ...parent::includePaths(), + ]; } /** * {@inheritDoc} */ - public function fields(): array + public static function defaultFields(): array { return [ - $this->idField(), + static::idField(), Str::make('name'), Str::make('handle'), Boolean::make('default'), - - ...parent::fields(), ]; } } diff --git a/packages/api/src/Domain/Customers/JsonApi/V1/CustomerSchema.php b/packages/api/src/Domain/Customers/JsonApi/V1/CustomerSchema.php index d602d1e6f..4425eb27e 100644 --- a/packages/api/src/Domain/Customers/JsonApi/V1/CustomerSchema.php +++ b/packages/api/src/Domain/Customers/JsonApi/V1/CustomerSchema.php @@ -25,7 +25,7 @@ class CustomerSchema extends Schema /** * {@inheritDoc} */ - public function includePaths(): iterable + public static function defaultIncludePaths(): array { return [ 'orders', @@ -33,18 +33,16 @@ public function includePaths(): iterable 'orders.lines.purchasable', 'addresses', 'addresses.country', - - ...parent::includePaths(), ]; } /** * {@inheritDoc} */ - public function fields(): array + public static function defaultFields(): array { return [ - $this->idField(), + static::idField(), AttributeData::make('attribute_data') ->groupAttributes(), @@ -77,7 +75,6 @@ public function fields(): array ->countAs('customer_groups_count') ->serializeUsing(static fn (Relation $relation) => $relation->withoutLinks()), - ...parent::fields(), ]; } } diff --git a/packages/api/src/Domain/JsonApi/Contracts/JsonApiResource.php b/packages/api/src/Domain/JsonApi/Contracts/JsonApiResource.php new file mode 100644 index 000000000..c1ff2cee4 --- /dev/null +++ b/packages/api/src/Domain/JsonApi/Contracts/JsonApiResource.php @@ -0,0 +1,16 @@ + + */ + public static function defaultWith(): array; + + /** + * Get the default include paths for the schema. + * + * @return array + */ + public static function defaultIncludePaths(): array; + + /** + * Get the default fields for the schema. + * + * @return array + */ + public static function defaultFields(): iterable; + + /** + * Get the default sparse fields for the schema. + * + * @return array + */ + public static function defaultSparseFields(): iterable; + + /** + * Get the default filters for the schema. + * + * @return array + */ + public static function defaultFilters(): iterable; + + /** + * Get the default sortables for the schema. + * + * @return array + */ + public static function defaultSortables(): iterable; + /** * Allow specific related resources to be accessed. + * + * @return array */ public function showRelated(): array; + /** + * Get the default allowed related resource. + * + * @return array + */ + public static function defaultShowRelated(): array; + /** * Allow specific relationships to be accessed. + * + * @return array + */ + public function showRelationships(): array; + + /** + * Get the default allowed relationships. + * + * @return array */ - public function showRelationship(): array; + public static function defaultShowRelationships(): array; } diff --git a/packages/api/src/Domain/JsonApi/Core/Schema/Schema.php b/packages/api/src/Domain/JsonApi/Core/Schema/Schema.php new file mode 100644 index 000000000..2fb8b02e6 --- /dev/null +++ b/packages/api/src/Domain/JsonApi/Core/Schema/Schema.php @@ -0,0 +1,138 @@ +fields()->resolve($this); + } + + /** + * {@inheritDoc} + */ + public static function defaultFields(): iterable + { + return []; + } + + /** + * {@inheritDoc} + */ + public function sparseFields(): iterable + { + return JsonApiManifest::schema(static::class)->sparseFields()->resolve($this); + } + + /** + * {@inheritDoc} + */ + public static function defaultSparseFields(): iterable + { + return []; + } + + /** + * {@inheritDoc} + */ + public function filters(): iterable + { + return JsonApiManifest::schema(static::class)->filters()->resolve($this); + } + + /** + * {@inheritDoc} + */ + public static function defaultFilters(): iterable + { + return []; + } + + /** + * {@inheritDoc} + */ + public function sortables(): iterable + { + yield from JsonApiManifest::schema(static::class)->sortables()->resolve($this); + } + + /** + * {@inheritDoc} + */ + public static function defaultSortables(): iterable + { + return []; + } + + /** + * {@inheritDoc} + */ + public function showRelated(): array + { + return JsonApiManifest::schema(static::class)->showRelated()->resolve($this); + } + + /** + * {@inheritDoc} + */ + public static function defaultShowRelated(): array + { + return []; + } + + /** + * {@inheritDoc} + */ + public function showRelationships(): array + { + return JsonApiManifest::schema(static::class)->showRelationships()->resolve($this); + } + + /** + * {@inheritDoc} + */ + public static function defaultShowRelationships(): array + { + return []; + } +} diff --git a/packages/api/src/Domain/JsonApi/Eloquent/Schema.php b/packages/api/src/Domain/JsonApi/Eloquent/Schema.php index a45902aa6..71c9c15cf 100644 --- a/packages/api/src/Domain/JsonApi/Eloquent/Schema.php +++ b/packages/api/src/Domain/JsonApi/Eloquent/Schema.php @@ -3,8 +3,7 @@ namespace Dystore\Api\Domain\JsonApi\Eloquent; use Dystore\Api\Base\Contracts\Extendable as ExtendableContract; -use Dystore\Api\Base\Contracts\SchemaExtension as SchemaExtensionContract; -use Dystore\Api\Base\Contracts\SchemaManifest as SchemaManifestContract; +use Dystore\Api\Base\Facades\JsonApiManifest; use Dystore\Api\Domain\JsonApi\Contracts\Schema as SchemaContract; use Dystore\Api\Domain\JsonApi\Core\Schema\TypeResolver; use Dystore\Api\Facades\Api; @@ -13,11 +12,11 @@ use Illuminate\Support\Facades\App; use Illuminate\Support\Facades\Config; use Illuminate\Support\Str; -use LaravelJsonApi\Contracts\Server\Server; use LaravelJsonApi\Core\Schema\IncludePathIterator; use LaravelJsonApi\Eloquent\Contracts\Paginator; use LaravelJsonApi\Eloquent\Fields\ID; use LaravelJsonApi\Eloquent\Filters\WhereIdIn; +use LaravelJsonApi\Eloquent\Filters\WhereIdNotIn; use LaravelJsonApi\Eloquent\Pagination\PagePagination; use LaravelJsonApi\Eloquent\Schema as BaseSchema; use LaravelJsonApi\HashIds\HashId; @@ -51,32 +50,21 @@ abstract class Schema extends BaseSchema implements ExtendableContract, SchemaCo /** * Allow viewing of relationships. * - * @property string[] $showRelationship + * @property string[] $showRelationships */ - protected array $showRelationship = []; + protected array $showRelationships = []; /** - * Schema extension. + * @var callable|null */ - protected SchemaExtensionContract $extension; - - /** - * Schema constructor. - */ - public function __construct( - Server $server, - ) { - $this->extension = App::make(SchemaManifestContract::class)::for(static::class); - - $this->server = $server; - } + private static $resourceTypeResolver; /** * {@inheritDoc} */ public static function type(): string { - $resolver = new TypeResolver; + $resolver = static::$resourceTypeResolver ?: new TypeResolver; return $resolver(static::class); } @@ -99,7 +87,6 @@ public static function model(): string } return static::$model; - } /** @@ -146,9 +133,9 @@ public function uriType(): string public function repository(): Repository { return new Repository( - $this, - $this->driver(), - $this->parser(), + schema: $this, + driver: $this->driver(), + parser: $this->parser(), ); } @@ -160,40 +147,78 @@ public function with(): array $paths = array_merge( parent::with(), Arr::wrap($this->with), - Arr::wrap($this->extension->with()->resolve($this)), + Arr::wrap(JsonApiManifest::schema(static::class)->with()->resolve($this)), ); return array_values(array_unique($paths)); } + /** + * {@inheritDoc} + */ + public static function defaultWith(): array + { + return []; + } + /** * {@inheritDoc} */ public function includePaths(): iterable { + $includePaths = JsonApiManifest::schema(static::class)->includePaths()->resolve($this); + if ($this->maxDepth > 0) { - return new IncludePathIterator( - $this->server->schemas(), - $this, - $this->maxDepth - ); + return [ + ...$includePaths, + ...new IncludePathIterator($this->server->schemas(), $this, $this->maxDepth), + ]; } - $extendedIncludePaths = $this->extension->includePaths()->resolve($this); - return [ - ...$extendedIncludePaths, - + ...$includePaths, ...parent::includePaths(), ]; } + /** + * {@inheritDoc} + */ + public static function defaultIncludePaths(): array + { + return []; + } + /** * {@inheritDoc} */ public function fields(): iterable { - return $this->extension->fields()->resolve($this); + yield from JsonApiManifest::schema(static::class)->fields()->resolve($this); + } + + /** + * {@inheritDoc} + */ + public static function defaultFields(): iterable + { + return []; + } + + /** + * {@inheritDoc} + */ + public function sparseFields(): iterable + { + return JsonApiManifest::schema(static::class)->sparseFields()->resolve($this); + } + + /** + * {@inheritDoc} + */ + public static function defaultSparseFields(): iterable + { + return []; } /** @@ -202,18 +227,35 @@ public function fields(): iterable public function filters(): iterable { return [ - WhereIdIn::make($this), + WhereIdIn::make($this)->delimiter(','), + WhereIdNotIn::make($this, 'except')->delimiter(','), - ...$this->extension->filters()->resolve($this), + ...JsonApiManifest::schema(static::class)->filters()->resolve($this), ]; } + /** + * {@inheritDoc} + */ + public static function defaultFilters(): iterable + { + return []; + } + /** * {@inheritDoc} */ public function sortables(): iterable { - return $this->extension->sortables()->resolve($this); + yield from JsonApiManifest::schema(static::class)->sortables()->resolve($this); + } + + /** + * {@inheritDoc} + */ + public static function defaultSortables(): iterable + { + return []; } /** @@ -234,37 +276,49 @@ public function showRelated(): array { $relations = array_merge( Arr::wrap($this->showRelated), - Arr::wrap($this->extension->showRelated()->resolve($this)), + JsonApiManifest::schema(static::class)->showRelated()->resolve($this) ); return array_values(array_unique($relations)); } /** - * Allow specific relationships to be accessed. + * {@inheritDoc} */ - public function showRelationship(): array + public static function defaultShowRelated(): array { - if (empty($this->showRelationship)) { - return $this->showRelated(); - } + return []; + } + /** + * Allow specific relationships to be accessed. + */ + public function showRelationships(): array + { $paths = array_merge( - Arr::wrap($this->showRelationship), - Arr::wrap($this->extension->showRelationship()->resolve($this)), + Arr::wrap($this->showRelationships), + JsonApiManifest::schema(static::class)->showRelationships()->resolve($this), ); return array_values(array_unique($paths)); } + /** + * {@inheritDoc} + */ + public static function defaultShowRelationships(): array + { + return []; + } + /** * Get id or hashid field based on configuration. */ - protected function idField(?string $column = null): ID // ID|HashId + public static function idField(?string $column = null): ID // ID|HashId { if (Api::usesHashids()) { return HashId::make($column) - ->useConnection(ModelKey::get(self::model())) + ->useConnection(ModelKey::get(static::model())) ->alreadyHashed(); } diff --git a/packages/api/src/Domain/JsonApi/Resources/JsonApiResource.php b/packages/api/src/Domain/JsonApi/Resources/JsonApiResource.php index d99c1f888..1d7d60e85 100644 --- a/packages/api/src/Domain/JsonApi/Resources/JsonApiResource.php +++ b/packages/api/src/Domain/JsonApi/Resources/JsonApiResource.php @@ -2,29 +2,20 @@ namespace Dystore\Api\Domain\JsonApi\Resources; -use Closure; use Dystore\Api\Base\Contracts\Extendable as ExtendableContract; -use Dystore\Api\Base\Contracts\ResourceExtension as ResourceExtensionContract; -use Dystore\Api\Base\Contracts\ResourceManifest as ResourceManifestContract; +use Dystore\Api\Base\Facades\JsonApiManifest; +use Dystore\Api\Domain\JsonApi\Contracts\JsonApiResource as ResourceContract; use Dystore\Api\Domain\JsonApi\Eloquent\Fields\AttributeData; use Illuminate\Database\Eloquent\Model; use Illuminate\Http\Request; -use Illuminate\Support\Facades\App; use LaravelJsonApi\Contracts\Resources\Serializer\Attribute as SerializableAttribute; use LaravelJsonApi\Contracts\Resources\Serializer\Relation as SerializableRelation; use LaravelJsonApi\Contracts\Schema\Schema; use LaravelJsonApi\Core\Resources\JsonApiResource as BaseApiResource; use LaravelJsonApi\Core\Resources\Relation; -use RecursiveArrayIterator; -use RecursiveIteratorIterator; -class JsonApiResource extends BaseApiResource implements ExtendableContract +class JsonApiResource extends BaseApiResource implements ExtendableContract, ResourceContract { - /** - * Resource extension. - */ - protected ResourceExtensionContract $extension; - /** * JsonApiResource constructor. */ @@ -32,8 +23,6 @@ public function __construct( protected Schema $schema, public object $resource, ) { - $this->extension = App::make(ResourceManifestContract::class)::for(static::class); - parent::__construct($schema, $resource); } @@ -98,10 +87,18 @@ protected function allAttributes($request): iterable { return [ ...$this->schema->attributes(), - ...$this->extendedFields($this->extension->attributes()->all()), + ...JsonApiManifest::resource(static::class)->attributes()->resolve($this), ]; } + /** + * {@inheritDoc} + */ + public static function defaultAttributes(): array + { + return []; + } + /** * Get all resource's relationships. * @@ -112,32 +109,15 @@ protected function allRelationships($request): iterable { return [ ...$this->schema->relationships(), - ...$this->extendedFields($this->extension->relationships()->all()), + ...JsonApiManifest::resource(static::class)->relationships()->resolve($this), ]; } /** - * Get extended resource's relationships. - * - * @param array $fields + * {@inheritDoc} */ - protected function extendedFields(array $fields): array + public static function defaultRelationships(): array { - $fields = array_map(function ($field) { - $field = $field->value(); - - if ($field instanceof Closure) { - $field = Closure::bind($field, $this, parent::class); - - return $field($this); - } - - return $field; - }, $fields); - - $recursiveArrayIterator = new RecursiveArrayIterator($fields, RecursiveArrayIterator::CHILD_ARRAYS_ONLY); - $iterator = new RecursiveIteratorIterator($recursiveArrayIterator); - - return iterator_to_array($iterator); + return []; } } diff --git a/packages/api/src/Domain/JsonApi/Servers/Server.php b/packages/api/src/Domain/JsonApi/Servers/Server.php index 4584c87fc..600f76edc 100644 --- a/packages/api/src/Domain/JsonApi/Servers/Server.php +++ b/packages/api/src/Domain/JsonApi/Servers/Server.php @@ -2,7 +2,7 @@ namespace Dystore\Api\Domain\JsonApi\Servers; -use Dystore\Api\Base\Facades\SchemaManifest; +use Dystore\Api\Base\Facades\JsonApiManifest; use Illuminate\Support\Facades\Config; use LaravelJsonApi\Core\Server\Server as BaseServer; use LaravelJsonApi\Core\Support\AppResolver; @@ -34,6 +34,6 @@ protected function setBaseUri(string $path = 'v1'): void */ protected function allSchemas(): array { - return SchemaManifest::getServerSchemas(); + return JsonApiManifest::getSchemas(); } } diff --git a/packages/api/src/Domain/Media/JsonApi/V1/MediaSchema.php b/packages/api/src/Domain/Media/JsonApi/V1/MediaSchema.php index a3c5df598..d3cc75594 100644 --- a/packages/api/src/Domain/Media/JsonApi/V1/MediaSchema.php +++ b/packages/api/src/Domain/Media/JsonApi/V1/MediaSchema.php @@ -24,7 +24,7 @@ class MediaSchema extends Schema /** * {@inheritDoc} */ - public function fields(): array + public static function defaultFields(): array { return [ ID::make(), @@ -51,19 +51,15 @@ public function fields(): array ), ArrayHash::make('custom_properties'), - - ...parent::fields(), ]; } /** * {@inheritDoc} */ - public function sortables(): iterable + public static function defaultSortables(): array { return [ - ...parent::sortables(), - InDefaultOrder::make('ordered'), ]; } diff --git a/packages/api/src/Domain/OrderAddresses/JsonApi/V1/OrderAddressSchema.php b/packages/api/src/Domain/OrderAddresses/JsonApi/V1/OrderAddressSchema.php index 717fc5755..a729b29d0 100644 --- a/packages/api/src/Domain/OrderAddresses/JsonApi/V1/OrderAddressSchema.php +++ b/packages/api/src/Domain/OrderAddresses/JsonApi/V1/OrderAddressSchema.php @@ -20,23 +20,22 @@ class OrderAddressSchema extends Schema /** * {@inheritDoc} */ - public function includePaths(): iterable + public static function defaultIncludePaths(): array { return [ 'order', 'country', - ...parent::includePaths(), ]; } /** * {@inheritDoc} */ - public function fields(): array + public static function defaultFields(): array { return [ - $this->idField(), + static::idField(), Str::make('title'), Str::make('first_name'), @@ -72,8 +71,6 @@ public function fields(): array BelongsTo::make('country') ->serializeUsing(static fn (Relation $relation) => $relation->withoutLinks()), - - ...parent::fields(), ]; } } diff --git a/packages/api/src/Domain/OrderLines/JsonApi/V1/OrderLineSchema.php b/packages/api/src/Domain/OrderLines/JsonApi/V1/OrderLineSchema.php index 8caeee686..a11ee2f19 100644 --- a/packages/api/src/Domain/OrderLines/JsonApi/V1/OrderLineSchema.php +++ b/packages/api/src/Domain/OrderLines/JsonApi/V1/OrderLineSchema.php @@ -31,7 +31,7 @@ class OrderLineSchema extends Schema /** * {@inheritDoc} */ - public function includePaths(): iterable + public static function defaultIncludePaths(): array { return [ 'currency', @@ -44,17 +44,16 @@ public function includePaths(): iterable 'purchasable.product', 'purchasable.product.thumbnail', - ...parent::includePaths(), ]; } /** * {@inheritDoc} */ - public function fields(): array + public static function defaultFields(): array { return [ - $this->idField(), + static::idField(), Number::make('purchasable_id'), Str::make('purchasable_type'), @@ -109,8 +108,6 @@ public function fields(): array SchemaType::get(ShippingOption::class), ) ->serializeUsing(static fn (Relation $relation) => $relation->withoutLinks()), - - ...parent::fields(), ]; } } diff --git a/packages/api/src/Domain/Orders/JsonApi/V1/OrderSchema.php b/packages/api/src/Domain/Orders/JsonApi/V1/OrderSchema.php index 06ec97a35..f6755ae7e 100644 --- a/packages/api/src/Domain/Orders/JsonApi/V1/OrderSchema.php +++ b/packages/api/src/Domain/Orders/JsonApi/V1/OrderSchema.php @@ -14,7 +14,6 @@ use LaravelJsonApi\Eloquent\Fields\Relations\HasOne; use LaravelJsonApi\Eloquent\Fields\Str; use LaravelJsonApi\Eloquent\Filters\Where; -use LaravelJsonApi\Eloquent\Filters\WhereIdIn; use LaravelJsonApi\Eloquent\Resources\Relation; use Lunar\Models\Contracts\Order; use Lunar\Models\Contracts\OrderAddress; @@ -35,7 +34,7 @@ class OrderSchema extends Schema * * @return string[]|iterable */ - public function includePaths(): iterable + public static function defaultIncludePaths(): array { return [ // Addresses @@ -108,17 +107,16 @@ public function includePaths(): iterable // User 'user', - ...parent::includePaths(), ]; } /** * {@inheritDoc} */ - public function fields(): array + public static function defaultFields(): array { return [ - $this->idField(), + static::idField(), Boolean::make('new_customer'), Str::make('status'), @@ -247,23 +245,17 @@ public function fields(): array HasMany::make('transactions') ->type(SchemaType::get(Transaction::class)) ->serializeUsing(static fn (Relation $relation) => $relation->withoutLinks()), - - ...parent::fields(), ]; } /** * {@inheritDoc} */ - public function filters(): array + public static function defaultFilters(): array { return [ - WhereIdIn::make($this), - Where::make('user_id'), Where::make('reference')->singular(), - - ...parent::filters(), ]; } } diff --git a/packages/api/src/Domain/PaymentOptions/Facades/PaymentManifest.php b/packages/api/src/Domain/PaymentOptions/Facades/PaymentManifest.php index ca54acd04..17fbbe9c1 100644 --- a/packages/api/src/Domain/PaymentOptions/Facades/PaymentManifest.php +++ b/packages/api/src/Domain/PaymentOptions/Facades/PaymentManifest.php @@ -2,12 +2,8 @@ namespace Dystore\Api\Domain\PaymentOptions\Facades; -use Closure; use Dystore\Api\Domain\PaymentOptions\Contracts\PaymentManifest as PaymentManifestContract; -use Dystore\Api\Domain\PaymentOptions\Entities\PaymentOption; -use Illuminate\Support\Collection; use Illuminate\Support\Facades\Facade; -use Lunar\Models\Contracts\Cart as CartContract; /** * @method static \Dystore\Api\Domain\PaymentOptions\Manifests\PaymentManifest addOption(\Dystore\Api\Domain\PaymentOptions\Entities\PaymentOption $option) diff --git a/packages/api/src/Domain/PaymentOptions/JsonApi/V1/PaymentOptionSchema.php b/packages/api/src/Domain/PaymentOptions/JsonApi/V1/PaymentOptionSchema.php index 7f810c1d8..0e0b76dab 100644 --- a/packages/api/src/Domain/PaymentOptions/JsonApi/V1/PaymentOptionSchema.php +++ b/packages/api/src/Domain/PaymentOptions/JsonApi/V1/PaymentOptionSchema.php @@ -2,9 +2,9 @@ namespace Dystore\Api\Domain\PaymentOptions\JsonApi\V1; +use Dystore\Api\Domain\JsonApi\Core\Schema\Schema; use Dystore\Api\Domain\JsonApi\Core\Schema\TypeResolver; use Dystore\Api\Domain\PaymentOptions\Entities\PaymentOption; -use LaravelJsonApi\Core\Schema\Schema; use LaravelJsonApi\Eloquent\Fields\ArrayHash; use LaravelJsonApi\NonEloquent\Fields\Attribute; use LaravelJsonApi\NonEloquent\Fields\ID; @@ -35,6 +35,14 @@ public static function type(): string * {@inheritDoc} */ public function fields(): iterable + { + return self::defaultFields(); + } + + /** + * {@inheritDoc} + */ + public static function defaultFields(): array { return [ ID::make(), diff --git a/packages/api/src/Domain/Prices/JsonApi/V1/PriceSchema.php b/packages/api/src/Domain/Prices/JsonApi/V1/PriceSchema.php index 3d550b952..85a168e84 100644 --- a/packages/api/src/Domain/Prices/JsonApi/V1/PriceSchema.php +++ b/packages/api/src/Domain/Prices/JsonApi/V1/PriceSchema.php @@ -16,7 +16,6 @@ use LaravelJsonApi\Eloquent\Fields\Number; use LaravelJsonApi\Eloquent\Fields\Relations\BelongsTo; use LaravelJsonApi\Eloquent\Fields\Str; -use LaravelJsonApi\Eloquent\Filters\WhereIdIn; use LaravelJsonApi\Eloquent\Resources\Relation; use Lunar\Models\Contracts\Currency; use Lunar\Models\Contracts\CustomerGroup; @@ -50,35 +49,33 @@ public function relatableQuery(?Request $request, EloquentRelation $query): Eloq /** * {@inheritDoc} */ - public function with(): array + public static function defaultWith(): array { return [ 'currency', - ...parent::with(), ]; } /** * {@inheritDoc} */ - public function includePaths(): iterable + public static function defaultIncludePaths(): array { return [ 'currency', 'customer_group', - ...parent::includePaths(), ]; } /** * {@inheritDoc} */ - public function fields(): array + public static function defaultFields(): array { return [ - $this->idField(), + static::idField(), Map::make('base_price', [ Str::make('formatted')->extractUsing(static fn (Price $model) => (new GetPrice)($model)->formatted()), @@ -136,24 +133,17 @@ public function fields(): array BelongsTo::make('customer_group', 'customerGroup') ->type(SchemaType::get(CustomerGroup::class)) ->serializeUsing(static fn (Relation $relation) => $relation->withoutLinks()), - - ...parent::fields(), ]; } /** * {@inheritDoc} */ - public function filters(): array + public static function defaultFilters(): array { return [ - WhereIdIn::make($this), - MinPriceFilter::make('min_price', 'price'), - MaxPriceFilter::make('max_price', 'price'), - - ...parent::filters(), ]; } } diff --git a/packages/api/src/Domain/ProductAssociations/JsonApi/V1/ProductAssociationSchema.php b/packages/api/src/Domain/ProductAssociations/JsonApi/V1/ProductAssociationSchema.php index 0499e83d8..61d2d793d 100644 --- a/packages/api/src/Domain/ProductAssociations/JsonApi/V1/ProductAssociationSchema.php +++ b/packages/api/src/Domain/ProductAssociations/JsonApi/V1/ProductAssociationSchema.php @@ -7,7 +7,6 @@ use LaravelJsonApi\Eloquent\Fields\Relations\HasOne; use LaravelJsonApi\Eloquent\Fields\Str; use LaravelJsonApi\Eloquent\Filters\Where; -use LaravelJsonApi\Eloquent\Filters\WhereIdIn; use LaravelJsonApi\Eloquent\Resources\Relation; use Lunar\Models\Contracts\Product; use Lunar\Models\Contracts\ProductAssociation; @@ -22,20 +21,18 @@ class ProductAssociationSchema extends Schema /** * {@inheritDoc} */ - public function includePaths(): iterable + public static function defaultIncludePaths(): array { - return [ - ...parent::includePaths(), - ]; + return []; } /** * {@inheritDoc} */ - public function fields(): array + public static function defaultFields(): array { return [ - $this->idField(), + static::idField(), Str::make('type'), @@ -46,22 +43,16 @@ public function fields(): array HasOne::make('parent') ->type(SchemaType::get(Product::class)) ->serializeUsing(static fn (Relation $relation) => $relation->withoutLinks()), - - ...parent::fields(), ]; } /** * {@inheritDoc} */ - public function filters(): array + public static function defaultFilters(): array { return [ - WhereIdIn::make($this), - Where::make('type'), - - ...parent::filters(), ]; } } diff --git a/packages/api/src/Domain/ProductOptionValues/JsonApi/V1/ProductOptionValueSchema.php b/packages/api/src/Domain/ProductOptionValues/JsonApi/V1/ProductOptionValueSchema.php index 6988d885a..3ccab5593 100644 --- a/packages/api/src/Domain/ProductOptionValues/JsonApi/V1/ProductOptionValueSchema.php +++ b/packages/api/src/Domain/ProductOptionValues/JsonApi/V1/ProductOptionValueSchema.php @@ -22,35 +22,33 @@ class ProductOptionValueSchema extends Schema /** * {@inheritDoc} */ - public function with(): array + public static function defaultWith(): array { return [ 'option', - ...parent::with(), ]; } /** * {@inheritDoc} */ - public function includePaths(): iterable + public static function defaultIncludePaths(): array { return [ 'images', 'product_option', - ...parent::includePaths(), ]; } /** * {@inheritDoc} */ - public function fields(): iterable + public static function defaultFields(): array { return [ - $this->idField(), + static::idField(), Str::make('name') ->readOnly() @@ -72,18 +70,14 @@ public function fields(): iterable ->canCount() ->countAs('images_count') ->serializeUsing(static fn (Relation $relation) => $relation->withoutLinks()), - - ...parent::fields(), ]; } /** * {@inheritDoc} */ - public function filters(): array + public static function defaultFilters(): array { - return [ - ...parent::filters(), - ]; + return []; } } diff --git a/packages/api/src/Domain/ProductOptions/JsonApi/V1/ProductOptionSchema.php b/packages/api/src/Domain/ProductOptions/JsonApi/V1/ProductOptionSchema.php index 33820af10..703e2650a 100644 --- a/packages/api/src/Domain/ProductOptions/JsonApi/V1/ProductOptionSchema.php +++ b/packages/api/src/Domain/ProductOptions/JsonApi/V1/ProductOptionSchema.php @@ -20,23 +20,22 @@ class ProductOptionSchema extends Schema /** * {@inheritDoc} */ - public function includePaths(): iterable + public static function defaultIncludePaths(): array { return [ 'product_option_values', 'product_option_values.images', - ...parent::includePaths(), ]; } /** * {@inheritDoc} */ - public function fields(): iterable + public static function defaultFields(): array { return [ - $this->idField(), + static::idField(), Str::make('name') ->readOnly() @@ -58,18 +57,14 @@ public function fields(): iterable ->canCount() ->countAs('product_option_values_count') ->serializeUsing(static fn (Relation $relation) => $relation->withoutLinks()), - - ...parent::fields(), ]; } /** * {@inheritDoc} */ - public function filters(): array + public static function defaultFilters(): array { - return [ - ...parent::filters(), - ]; + return []; } } diff --git a/packages/api/src/Domain/ProductTypes/JsonApi/V1/ProductTypeSchema.php b/packages/api/src/Domain/ProductTypes/JsonApi/V1/ProductTypeSchema.php index 50422cd8d..8349f4dab 100644 --- a/packages/api/src/Domain/ProductTypes/JsonApi/V1/ProductTypeSchema.php +++ b/packages/api/src/Domain/ProductTypes/JsonApi/V1/ProductTypeSchema.php @@ -19,23 +19,22 @@ class ProductTypeSchema extends Schema /** * {@inheritDoc} */ - public function includePaths(): iterable + public static function defaultIncludePaths(): array { return [ // 'mapped_attributes', // 'mapped_attributes.attribute_group', - ...parent::includePaths(), ]; } /** * {@inheritDoc} */ - public function fields(): iterable + public static function defaultFields(): array { return [ - $this->idField(), + static::idField(), Str::make('name'), @@ -45,17 +44,14 @@ public function fields(): iterable // static fn ($relation) => $relation->withoutLinks() // ), - ...parent::fields(), ]; } /** * {@inheritDoc} */ - public function filters(): array + public static function defaultFilters(): array { - return [ - ...parent::filters(), - ]; + return []; } } diff --git a/packages/api/src/Domain/ProductVariants/JsonApi/V1/ProductVariantSchema.php b/packages/api/src/Domain/ProductVariants/JsonApi/V1/ProductVariantSchema.php index 931048710..267439154 100644 --- a/packages/api/src/Domain/ProductVariants/JsonApi/V1/ProductVariantSchema.php +++ b/packages/api/src/Domain/ProductVariants/JsonApi/V1/ProductVariantSchema.php @@ -16,8 +16,6 @@ use LaravelJsonApi\Eloquent\Fields\Relations\HasOneThrough; use LaravelJsonApi\Eloquent\Fields\Str; use LaravelJsonApi\Eloquent\Filters\WhereHas; -use LaravelJsonApi\Eloquent\Filters\WhereIdIn; -use LaravelJsonApi\Eloquent\Filters\WhereIdNotIn; use LaravelJsonApi\Eloquent\Resources\Relation; use Lunar\Models\Contracts\Attribute; use Lunar\Models\Contracts\Price; @@ -54,20 +52,18 @@ public function relatableQuery(?Request $request, EloquentRelation $query): Eloq /** * {@inheritDoc} */ - public function with(): array + public static function defaultWith(): array { return [ 'attributes', 'attributes.attributeGroup', - - ...parent::with(), ]; } /** * {@inheritDoc} */ - public function includePaths(): iterable + public static function defaultIncludePaths(): array { return [ 'default_url', @@ -81,18 +77,16 @@ public function includePaths(): iterable 'product_option_values', 'product_option_values.images', 'product_option_values.product_option', - - ...parent::includePaths(), ]; } /** * {@inheritDoc} */ - public function fields(): array + public static function defaultFields(): array { return [ - $this->idField(), + static::idField(), AttributeData::make('attribute_data') ->groupAttributes(), @@ -169,27 +163,17 @@ public function fields(): array HasOneThrough::make('thumbnail') ->type(SchemaType::get(Media::class)) ->serializeUsing(static fn (Relation $relation) => $relation->withoutLinks()), - - ...parent::fields(), ]; } /** * {@inheritDoc} */ - public function filters(): array + public static function defaultFilters(): array { return [ - WhereIdIn::make($this), - - WhereIdNotIn::make($this, 'except'), - - WhereHas::make($this, 'urls', 'url') - ->singular(), - - WhereHas::make($this, 'urls', 'urls'), - - ...parent::filters(), + fn (Schema $schema) => WhereHas::make($schema, 'urls', 'url')->singular(), + fn (Schema $schema) => WhereHas::make($schema, 'urls', 'urls'), ]; } } diff --git a/packages/api/src/Domain/Products/JsonApi/Filters/ProductFilterCollection.php b/packages/api/src/Domain/Products/JsonApi/Filters/ProductFilterCollection.php deleted file mode 100644 index 9991a09a8..000000000 --- a/packages/api/src/Domain/Products/JsonApi/Filters/ProductFilterCollection.php +++ /dev/null @@ -1,46 +0,0 @@ - $attributes */ - $attributes = Attribute::modelClass()::query() - ->where('attribute_type', Product::modelClass()) - ->where('filterable', true) - ->get(); - - $filters = $attributes->map(function (AttributeContract $attribute) { - return match (true) { - $this->hasConfigKey($attribute, 'richtext') => Where::make($attribute->handle), - $this->hasConfigKey($attribute, 'on_value') => AttributeBoolFilter::make($attribute->handle), - $this->hasConfigKey($attribute, 'lookups') => AttributeWhereInFilter::make($attribute->handle)->delimiter(','), - default => Where::make($attribute->handle), - }; - }); - - return [ - ...$filters->toArray(), - ]; - } - - /** - * Check if Attribute has certain config key. - */ - protected function hasConfigKey(AttributeContract $attribute, string $key): bool - { - return array_key_exists($key, $attribute->configuration->toArray()); - } -} diff --git a/packages/api/src/Domain/Products/JsonApi/V1/ProductSchema.php b/packages/api/src/Domain/Products/JsonApi/V1/ProductSchema.php index cf453c939..047f88579 100644 --- a/packages/api/src/Domain/Products/JsonApi/V1/ProductSchema.php +++ b/packages/api/src/Domain/Products/JsonApi/V1/ProductSchema.php @@ -7,7 +7,6 @@ use Dystore\Api\Domain\JsonApi\Eloquent\Sorts\InDefaultOrder; use Dystore\Api\Domain\JsonApi\Eloquent\Sorts\InRandomOrder; use Dystore\Api\Domain\Products\JsonApi\Filters\InStockFilter; -use Dystore\Api\Domain\Products\JsonApi\Filters\ProductFilterCollection; use Dystore\Api\Support\Models\Actions\SchemaType; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Relations\Relation as EloquentRelation; @@ -21,7 +20,6 @@ use LaravelJsonApi\Eloquent\Fields\Relations\HasOneThrough; use LaravelJsonApi\Eloquent\Fields\Str; use LaravelJsonApi\Eloquent\Filters\WhereHas; -use LaravelJsonApi\Eloquent\Filters\WhereIdIn; use LaravelJsonApi\Eloquent\Filters\WhereIdNotIn; use LaravelJsonApi\Eloquent\Resources\Relation; use Lunar\Models\Contracts\Attribute; @@ -68,21 +66,19 @@ public function relatableQuery(?Request $request, EloquentRelation $query): Eloq /** * {@inheritDoc} */ - public function with(): array + public static function defaultWith(): array { return [ 'productType', 'productType.mappedAttributes', 'productType.mappedAttributes.attributeGroup', - - ...parent::with(), ]; } /** * {@inheritDoc} */ - public function includePaths(): iterable + public static function defaultIncludePaths(): array { return [ 'default_url', @@ -121,18 +117,16 @@ public function includePaths(): iterable 'product_type', 'tags', - - ...parent::includePaths(), ]; } /** * {@inheritDoc} */ - public function fields(): iterable + public static function defaultFields(): iterable { return [ - $this->idField(), + static::idField(), AttributeData::make('attribute_data') ->groupAttributes(), @@ -256,21 +250,16 @@ public function fields(): iterable ->canCount() ->countAs('product_option_values_count') ->serializeUsing(static fn (Relation $relation) => $relation->withoutLinks()), - - ...parent::fields(), ]; } /** * {@inheritDoc} */ - public function sortables(): iterable + public static function defaultSortables(): array { return [ - ...parent::sortables(), - InDefaultOrder::make('ordered'), - InRandomOrder::make('random'), ]; } @@ -278,36 +267,20 @@ public function sortables(): iterable /** * {@inheritDoc} */ - public function filters(): array + public static function defaultFilters(): array { return [ - WhereIdIn::make($this), - - WhereIdNotIn::make($this, 'except'), - + fn (Schema $schema) => WhereIdNotIn::make($schema, 'except'), InStockFilter::make('in_stock'), - - WhereHas::make($this, 'prices'), - - WhereHas::make($this, 'brand'), - - WhereHas::make($this, 'urls', 'url')->singular(), - - WhereHas::make($this, 'urls', 'urls'), - - WhereHas::make($this, 'product_type'), - - WhereHas::make($this, 'channels'), - - WhereHas::make($this, 'status'), - - WhereHas::make($this, 'collections'), - - WhereHas::make($this, 'tags'), - - ...(new ProductFilterCollection)->toArray(), - - ...parent::filters(), + fn (Schema $schema) => WhereHas::make($schema, 'prices'), + fn (Schema $schema) => WhereHas::make($schema, 'brand'), + fn (Schema $schema) => WhereHas::make($schema, 'urls', 'url')->singular(), + fn (Schema $schema) => WhereHas::make($schema, 'urls', 'urls'), + fn (Schema $schema) => WhereHas::make($schema, 'product_type'), + fn (Schema $schema) => WhereHas::make($schema, 'channels'), + fn (Schema $schema) => WhereHas::make($schema, 'status'), + fn (Schema $schema) => WhereHas::make($schema, 'collections'), + fn (Schema $schema) => WhereHas::make($schema, 'tags'), ]; } } diff --git a/packages/api/src/Domain/ShippingOptions/JsonApi/V1/ShippingOptionSchema.php b/packages/api/src/Domain/ShippingOptions/JsonApi/V1/ShippingOptionSchema.php index fb9e44cdd..e3aac102a 100644 --- a/packages/api/src/Domain/ShippingOptions/JsonApi/V1/ShippingOptionSchema.php +++ b/packages/api/src/Domain/ShippingOptions/JsonApi/V1/ShippingOptionSchema.php @@ -2,9 +2,9 @@ namespace Dystore\Api\Domain\ShippingOptions\JsonApi\V1; +use Dystore\Api\Domain\JsonApi\Core\Schema\Schema; use Dystore\Api\Domain\JsonApi\Core\Schema\TypeResolver; use Dystore\Api\Domain\ShippingOptions\Entities\ShippingOption; -use LaravelJsonApi\Core\Schema\Schema; use LaravelJsonApi\Eloquent\Fields\ArrayHash; use LaravelJsonApi\Eloquent\Fields\ID; use LaravelJsonApi\NonEloquent\Fields\Attribute; @@ -30,6 +30,14 @@ public static function type(): string * {@inheritDoc} */ public function fields(): iterable + { + return self::defaultFields(); + } + + /** + * {@inheritDoc} + */ + public static function defaultFields(): array { return [ ID::make(), diff --git a/packages/api/src/Domain/Storefront/JsonApi/V1/StorefrontSchema.php b/packages/api/src/Domain/Storefront/JsonApi/V1/StorefrontSchema.php index b50ae8db0..d80c9518c 100644 --- a/packages/api/src/Domain/Storefront/JsonApi/V1/StorefrontSchema.php +++ b/packages/api/src/Domain/Storefront/JsonApi/V1/StorefrontSchema.php @@ -2,10 +2,9 @@ namespace Dystore\Api\Domain\Storefront\JsonApi\V1; -use Dystore\Api\Domain\JsonApi\Core\Schema\TypeResolver; +use Dystore\Api\Domain\JsonApi\Core\Schema\Schema; use Dystore\Api\Domain\Storefront\Entities\Storefront; use Dystore\Api\Support\Models\Actions\SchemaType; -use LaravelJsonApi\Core\Schema\Schema; use LaravelJsonApi\NonEloquent\Fields\ID; use LaravelJsonApi\NonEloquent\Fields\ToMany; use LaravelJsonApi\NonEloquent\Fields\ToOne; @@ -24,17 +23,7 @@ class StorefrontSchema extends Schema /** * {@inheritDoc} */ - public static function type(): string - { - $resolver = new TypeResolver; - - return $resolver(static::class); - } - - /** - * {@inheritDoc} - */ - public function fields(): iterable + public static function defaultFields(): array { return [ ID::make() diff --git a/packages/api/src/Domain/Tags/JsonApi/V1/TagSchema.php b/packages/api/src/Domain/Tags/JsonApi/V1/TagSchema.php index 68a96e142..0a323e156 100644 --- a/packages/api/src/Domain/Tags/JsonApi/V1/TagSchema.php +++ b/packages/api/src/Domain/Tags/JsonApi/V1/TagSchema.php @@ -7,7 +7,6 @@ use LaravelJsonApi\Eloquent\Fields\Relations\MorphTo; use LaravelJsonApi\Eloquent\Fields\Str; use LaravelJsonApi\Eloquent\Filters\Where; -use LaravelJsonApi\Eloquent\Filters\WhereIdIn; use LaravelJsonApi\Eloquent\Filters\WhereIn; use Lunar\Models\Contracts\Tag; use Lunar\Models\Contracts\Url; @@ -22,45 +21,37 @@ class TagSchema extends Schema /** * {@inheritDoc} */ - public function includePaths(): iterable + public static function defaultIncludePaths(): array { return [ // 'taggables', - ...parent::includePaths(), ]; } /** * {@inheritDoc} */ - public function fields(): array + public static function defaultFields(): array { return [ - $this->idField(), + static::idField(), Str::make('value'), // MorphTo::make('taggables', 'taggables') // ->type(SchemaType::get(Url::class)), - - ...parent::fields(), ]; } /** * {@inheritDoc} */ - public function filters(): array + public static function defaultFilters(): array { return [ - WhereIdIn::make($this)->delimiter(','), - Where::make('value'), - WhereIn::make('values', 'value')->delimiter(','), - - ...parent::filters(), ]; } } diff --git a/packages/api/src/Domain/TaxZones/JsonApi/V1/TaxZoneSchema.php b/packages/api/src/Domain/TaxZones/JsonApi/V1/TaxZoneSchema.php index 559121f3d..7d29beea2 100644 --- a/packages/api/src/Domain/TaxZones/JsonApi/V1/TaxZoneSchema.php +++ b/packages/api/src/Domain/TaxZones/JsonApi/V1/TaxZoneSchema.php @@ -3,7 +3,6 @@ namespace Dystore\Api\Domain\TaxZones\JsonApi\V1; use Dystore\Api\Domain\JsonApi\Eloquent\Schema; -use LaravelJsonApi\Eloquent\Filters\WhereIdIn; use Lunar\Models\Contracts\TaxZone; class TaxZoneSchema extends Schema @@ -16,34 +15,26 @@ class TaxZoneSchema extends Schema /** * {@inheritDoc} */ - public function includePaths(): iterable + public static function defaultIncludePaths(): array { - return [ - ...parent::includePaths(), - ]; + return []; } /** * {@inheritDoc} */ - public function fields(): array + public static function defaultFields(): array { return [ - $this->idField(), - - ...parent::fields(), + static::idField(), ]; } /** * {@inheritDoc} */ - public function filters(): array + public static function defaultFilters(): array { - return [ - WhereIdIn::make($this)->delimiter(','), - - ...parent::filters(), - ]; + return []; } } diff --git a/packages/api/src/Domain/Transactions/JsonApi/V1/TransactionSchema.php b/packages/api/src/Domain/Transactions/JsonApi/V1/TransactionSchema.php index a37d3ff51..af70fc13a 100644 --- a/packages/api/src/Domain/Transactions/JsonApi/V1/TransactionSchema.php +++ b/packages/api/src/Domain/Transactions/JsonApi/V1/TransactionSchema.php @@ -8,7 +8,6 @@ use LaravelJsonApi\Eloquent\Fields\Number; use LaravelJsonApi\Eloquent\Fields\Relations\BelongsTo; use LaravelJsonApi\Eloquent\Fields\Str; -use LaravelJsonApi\Eloquent\Filters\WhereIdIn; use LaravelJsonApi\Eloquent\Resources\Relation; use Lunar\Models\Contracts\Transaction; @@ -22,20 +21,20 @@ class TransactionSchema extends Schema /** * {@inheritDoc} */ - public function includePaths(): iterable + public static function defaultIncludePaths(): array { return [ - ...parent::includePaths(), + ]; } /** * {@inheritDoc} */ - public function fields(): array + public static function defaultFields(): array { return [ - $this->idField(), + static::idField(), Str::make('type'), Str::make('driver'), @@ -57,19 +56,14 @@ public function fields(): array BelongsTo::make('currency') ->serializeUsing(static fn (Relation $relation) => $relation->withoutLinks()), - ...parent::fields(), ]; } /** * {@inheritDoc} */ - public function filters(): array + public static function defaultFilters(): array { - return [ - WhereIdIn::make($this)->delimiter(','), - - ...parent::filters(), - ]; + return []; } } diff --git a/packages/api/src/Domain/Urls/JsonApi/V1/UrlSchema.php b/packages/api/src/Domain/Urls/JsonApi/V1/UrlSchema.php index 838ffb331..b6043fa5e 100644 --- a/packages/api/src/Domain/Urls/JsonApi/V1/UrlSchema.php +++ b/packages/api/src/Domain/Urls/JsonApi/V1/UrlSchema.php @@ -6,7 +6,6 @@ use LaravelJsonApi\Eloquent\Fields\Boolean; use LaravelJsonApi\Eloquent\Fields\Str; use LaravelJsonApi\Eloquent\Filters\Where; -use LaravelJsonApi\Eloquent\Filters\WhereIdIn; use Lunar\Models\Contracts\Url; class UrlSchema extends Schema @@ -19,30 +18,23 @@ class UrlSchema extends Schema /** * {@inheritDoc} */ - public function fields(): array + public static function defaultFields(): array { return [ - $this->idField(), + static::idField(), Str::make('slug'), - Boolean::make('default'), - - ...parent::fields(), ]; } /** * {@inheritDoc} */ - public function filters(): array + public static function defaultFilters(): array { return [ - WhereIdIn::make($this), - Where::make('slug'), - - ...parent::filters(), ]; } } diff --git a/packages/api/src/Domain/Users/JsonApi/V1/UserSchema.php b/packages/api/src/Domain/Users/JsonApi/V1/UserSchema.php index 84b76143e..69c19556f 100644 --- a/packages/api/src/Domain/Users/JsonApi/V1/UserSchema.php +++ b/packages/api/src/Domain/Users/JsonApi/V1/UserSchema.php @@ -24,11 +24,9 @@ class UserSchema extends Schema /** * The relationships that should always be eager loaded. */ - public function with(): array + public static function defaultWith(): array { - return [ - ...parent::with(), - ]; + return []; } /** @@ -36,20 +34,18 @@ public function with(): array * * @return string[]|iterable */ - public function includePaths(): iterable + public static function defaultIncludePaths(): array { - return [ - ...parent::includePaths(), - ]; + return []; } /** * Get the resource fields. */ - public function fields(): array + public static function defaultFields(): array { return [ - $this->idField(), + static::idField(), Str::make('name'), Str::make('first_name'), @@ -79,8 +75,6 @@ public function fields(): array ->type(SchemaType::get(Customer::class)) ->readOnly() ->serializeUsing(static fn (Relation $relation) => $relation->withoutLinks()), - - ...parent::fields(), ]; } } diff --git a/packages/api/src/Hashids/Facades/HashidsConnections.php b/packages/api/src/Hashids/Facades/HashidsConnections.php index 8b9cdaeb2..71dc82bbd 100644 --- a/packages/api/src/Hashids/Facades/HashidsConnections.php +++ b/packages/api/src/Hashids/Facades/HashidsConnections.php @@ -3,7 +3,6 @@ namespace Dystore\Api\Hashids\Facades; use Dystore\Api\Hashids\Contracts\HashidsConnectionsManager; -use Illuminate\Support\Collection; use Illuminate\Support\Facades\Facade; /** diff --git a/packages/api/src/JsonApiServiceProvider.php b/packages/api/src/JsonApiServiceProvider.php index a0ea4df8a..e77c1cd04 100644 --- a/packages/api/src/JsonApiServiceProvider.php +++ b/packages/api/src/JsonApiServiceProvider.php @@ -12,21 +12,11 @@ class JsonApiServiceProvider extends ServiceProvider */ public function boot(): void { - \LaravelJsonApi\Laravel\LaravelJsonApi::defaultResource( - Domain\JsonApi\Resources\JsonApiResource::class, - ); - \LaravelJsonApi\Laravel\LaravelJsonApi::defaultAuthorizer( - Domain\JsonApi\Authorizers\Authorizer::class, - ); - \LaravelJsonApi\Laravel\LaravelJsonApi::defaultQuery( - Domain\JsonApi\Queries\Query::class, - ); - \LaravelJsonApi\Laravel\LaravelJsonApi::defaultCollectionQuery( - Domain\JsonApi\Queries\CollectionQuery::class, - ); - \LaravelJsonApi\Laravel\LaravelJsonApi::withCountQueryParameter( - 'with_count', - ); + \LaravelJsonApi\Laravel\LaravelJsonApi::defaultResource(Domain\JsonApi\Resources\JsonApiResource::class); + \LaravelJsonApi\Laravel\LaravelJsonApi::defaultAuthorizer(Domain\JsonApi\Authorizers\Authorizer::class); + \LaravelJsonApi\Laravel\LaravelJsonApi::defaultQuery(Domain\JsonApi\Queries\Query::class); + \LaravelJsonApi\Laravel\LaravelJsonApi::defaultCollectionQuery(Domain\JsonApi\Queries\CollectionQuery::class); + \LaravelJsonApi\Laravel\LaravelJsonApi::withCountQueryParameter('with_count'); } /** @@ -40,28 +30,10 @@ public function register(): void fn () => Domain\JsonApi\Eloquent\Repository::class, ); - // Register schema extension implementation - $this->app->bind( - Base\Contracts\SchemaExtension::class, - fn (Application $app, mixed $params) => new Base\Extensions\SchemaExtension(...$params), - ); - - // Register schema manifest implementation - $this->app->singleton( - Base\Contracts\SchemaManifest::class, - fn (Application $app) => new Base\Manifests\SchemaManifest, - ); - - // Register resource extension implementation - $this->app->bind( - Base\Contracts\ResourceExtension::class, - fn (Application $app, mixed $params) => new Base\Extensions\ResourceExtension(...$params), - ); - - // Register resource manifest implementation + // Register the JSON:API manifest. $this->app->singleton( - Base\Contracts\ResourceManifest::class, - fn (Application $app) => new Base\Manifests\ResourceManifest, + \Dystore\Api\Base\Contracts\JsonApiManifest::class, + fn (Application $app) => $app->make(\Dystore\Api\Base\Manifests\JsonApiManifest::class), ); } } diff --git a/packages/api/src/Support/Config/Collections/DomainConfigCollection.php b/packages/api/src/Support/Config/Collections/DomainConfigCollection.php index e374bc2fd..782a56391 100644 --- a/packages/api/src/Support/Config/Collections/DomainConfigCollection.php +++ b/packages/api/src/Support/Config/Collections/DomainConfigCollection.php @@ -8,9 +8,6 @@ final class DomainConfigCollection extends Collection { - /** - * Create domain config collection. - */ public static function make($items = []): self { if (! empty($items)) { @@ -32,23 +29,22 @@ public static function fromConfig(string $configKey): self return new self($items); } - /** - * Get schemas from domain config. - */ public function getSchemas(): self { - return $this->mapWithKeys(function (DomainConfig $domain) { - if (! $domain->hasSchema()) { - return []; - } + return $this + ->map(fn (DomainConfig $domain) => $domain->schema) + ->filter() + ->values(); + } - return [$domain->schema::type() => $domain->schema]; - }); + public function getResources(): self + { + return $this + ->map(fn (DomainConfig $domain) => $domain->resource) + ->filter() + ->values(); } - /** - * Get schemas from domain config. - */ public function getSchemaByType(string $type): string { return $this->firstWhere( @@ -56,9 +52,6 @@ public function getSchemaByType(string $type): string ); } - /** - * Get routes from domain config. - */ public function getRoutes(): self { return $this->mapWithKeys(function (DomainConfig $domain) { @@ -70,9 +63,6 @@ public function getRoutes(): self }); } - /** - * Get models for Lunar model manifest. - */ public function getModelsForModelManifest(): self { return $this->mapWithKeys(function (DomainConfig $domain) { @@ -84,9 +74,6 @@ public function getModelsForModelManifest(): self }); } - /** - * Get policies from domain config. - */ public function getPolicies(): self { return $this->mapWithKeys(function (DomainConfig $domain) { diff --git a/packages/api/src/Support/Config/Data/DomainConfig.php b/packages/api/src/Support/Config/Data/DomainConfig.php index 5deb26696..4711b55d2 100644 --- a/packages/api/src/Support/Config/Data/DomainConfig.php +++ b/packages/api/src/Support/Config/Data/DomainConfig.php @@ -49,6 +49,14 @@ public function hasSchema(): bool return ! is_null($this->schema); } + /** + * Check if domain has resource. + */ + public function hasResource(): bool + { + return ! is_null($this->resource); + } + /** * Check if domain has model. */ diff --git a/packages/newsletter/src/Domain/Newsletter/JsonApi/V1/NewsletterSchema.php b/packages/newsletter/src/Domain/Newsletter/JsonApi/V1/NewsletterSchema.php index fcd70b380..4e74cb34d 100644 --- a/packages/newsletter/src/Domain/Newsletter/JsonApi/V1/NewsletterSchema.php +++ b/packages/newsletter/src/Domain/Newsletter/JsonApi/V1/NewsletterSchema.php @@ -24,7 +24,7 @@ public static function type(): string /** * Get the resource fields. */ - public function fields(): array + public static function defaultFields(): array { return [ Str::make('email'), diff --git a/packages/newsletter/src/NewsletterServiceProvider.php b/packages/newsletter/src/NewsletterServiceProvider.php index aa181a0e3..15d44871e 100644 --- a/packages/newsletter/src/NewsletterServiceProvider.php +++ b/packages/newsletter/src/NewsletterServiceProvider.php @@ -2,7 +2,8 @@ namespace Dystore\Newsletter; -use Dystore\Api\Base\Facades\SchemaManifest; +use Dystore\Api\Base\Facades\JsonApiManifest; +use Dystore\Newsletter\Domain\Newsletter\JsonApi\V1\NewsletterResource; use Dystore\Newsletter\Domain\Newsletter\JsonApi\V1\NewsletterSchema; use Illuminate\Support\ServiceProvider; @@ -17,8 +18,6 @@ public function register(): void { $this->registerConfig(); - $this->registerSchemas(); - $this->loadTranslationsFrom( "{$this->root}/lang", 'dystore-newsletter', @@ -28,6 +27,9 @@ public function register(): void $this->app->singleton('dystore-newsletter', function () { return new Newsletter; }); + + JsonApiManifest::addSchema(NewsletterSchema::class); + JsonApiManifest::addResource(NewsletterResource::class); } /** @@ -41,19 +43,9 @@ public function boot(): void $this->publishConfig(); $this->publishTranslations(); } - } - /** - * Register schemas. - */ - public function registerSchemas(): void - { - SchemaManifest::registerSchema(NewsletterSchema::class); } - /** - * Register config files. - */ protected function registerConfig(): void { $this->mergeConfigFrom( @@ -62,9 +54,6 @@ protected function registerConfig(): void ); } - /** - * Publish config files. - */ protected function publishConfig(): void { $this->publishes([ @@ -72,9 +61,6 @@ protected function publishConfig(): void ], 'dystore-newsletter'); } - /** - * Publish translations. - */ protected function publishTranslations(): void { $this->publishes([ diff --git a/packages/product-notifications/src/Domain/ProductNotifications/JsonApi/V1/ProductNotificationSchema.php b/packages/product-notifications/src/Domain/ProductNotifications/JsonApi/V1/ProductNotificationSchema.php index b9a9e22c9..aaddb9812 100644 --- a/packages/product-notifications/src/Domain/ProductNotifications/JsonApi/V1/ProductNotificationSchema.php +++ b/packages/product-notifications/src/Domain/ProductNotifications/JsonApi/V1/ProductNotificationSchema.php @@ -11,14 +11,14 @@ class ProductNotificationSchema extends Schema { /** - * The model the schema corresponds to. + * {@inheritDoc} */ public static string $model = ProductNotification::class; /** - * Get the resource fields. + * {$@inheritDoc} */ - public function fields(): array + public static function defaultFields(): array { return [ ID::make(), diff --git a/packages/product-notifications/src/ProductNotificationsServiceProvider.php b/packages/product-notifications/src/ProductNotificationsServiceProvider.php index fa30874c5..bd0501736 100644 --- a/packages/product-notifications/src/ProductNotificationsServiceProvider.php +++ b/packages/product-notifications/src/ProductNotificationsServiceProvider.php @@ -2,8 +2,9 @@ namespace Dystore\ProductNotifications; -use Dystore\Api\Base\Facades\SchemaManifest; +use Dystore\Api\Base\Facades\JsonApiManifest; use Dystore\Api\Support\Config\Collections\DomainConfigCollection; +use Dystore\ProductNotifications\Domain\ProductNotifications\JsonApi\V1\ProductNotificationResource; use Dystore\ProductNotifications\Domain\ProductNotifications\JsonApi\V1\ProductNotificationSchema; use Dystore\ProductNotifications\Domain\ProductNotifications\Models\ProductNotification; use Dystore\ProductNotifications\Domain\ProductNotifications\Observers\ProductVariantObserver; @@ -22,8 +23,6 @@ public function register(): void { $this->registerConfig(); - $this->registerSchemas(); - $this->booting(function () { $this->registerPolicies(); }); @@ -32,6 +31,9 @@ public function register(): void "{$this->root}/lang", 'dystore-product-notifications', ); + + JsonApiManifest::addSchema(ProductNotificationSchema::class); + JsonApiManifest::addResource(ProductNotificationResource::class); } /** @@ -58,14 +60,6 @@ public function registerObservers(): void ProductVariant::observe(ProductVariantObserver::class); } - /** - * Register schemas. - */ - public function registerSchemas(): void - { - SchemaManifest::registerSchema(ProductNotificationSchema::class); - } - /** * Register the application's policies. */ diff --git a/packages/product-views/src/ProductViewsServiceProvider.php b/packages/product-views/src/ProductViewsServiceProvider.php index 9349ea598..b57d9690b 100644 --- a/packages/product-views/src/ProductViewsServiceProvider.php +++ b/packages/product-views/src/ProductViewsServiceProvider.php @@ -2,8 +2,7 @@ namespace Dystore\ProductViews; -use Dystore\Api\Base\Extensions\SchemaExtension; -use Dystore\Api\Base\Facades\SchemaManifest; +use Dystore\Api\Base\Facades\JsonApiManifest; use Dystore\Api\Domain\Products\JsonApi\V1\ProductSchema; use Dystore\ProductViews\Domain\Products\JsonApi\Sorts\RecentlyViewedSort; use Illuminate\Support\ServiceProvider; @@ -17,14 +16,11 @@ class ProductViewsServiceProvider extends ServiceProvider */ public function register(): void { - $this->registerConfig(); + // Register the main class to use with the facade + $this->app->singleton('dystore-product-views', fn () => new ProductViews); + $this->registerConfig(); $this->extendSchemas(); - - // Register the main class to use with the facade - $this->app->singleton('dystore-product-views', function () { - return new ProductViews; - }); } /** @@ -48,9 +44,6 @@ protected function registerConfig(): void ); } - /** - * Publish config files. - */ protected function publishConfig(): void { $this->publishes([ @@ -58,16 +51,10 @@ protected function publishConfig(): void ], 'dystore-product-views'); } - /** - * Extend schemas. - */ protected function extendSchemas(): void { - /** @var SchemaExtension $productSchemaExtenstion */ - $productSchemaExtenstion = SchemaManifest::extend(ProductSchema::class); - - $productSchemaExtenstion->setSortables([ - RecentlyViewedSort::make('recently_viewed'), - ]); + JsonApiManifest::schema(ProductSchema::class) + ->sortables() + ->add(RecentlyViewedSort::make('recently_viewed')); } } diff --git a/packages/reviews/src/Domain/Reviews/JsonApi/V1/ReviewSchema.php b/packages/reviews/src/Domain/Reviews/JsonApi/V1/ReviewSchema.php index 574e0fa60..de2115f24 100644 --- a/packages/reviews/src/Domain/Reviews/JsonApi/V1/ReviewSchema.php +++ b/packages/reviews/src/Domain/Reviews/JsonApi/V1/ReviewSchema.php @@ -5,7 +5,6 @@ use Dystore\Api\Domain\JsonApi\Eloquent\Schema; use Dystore\Api\Domain\Products\JsonApi\V1\ProductSchema; use Dystore\Api\Domain\ProductVariants\JsonApi\V1\ProductVariantSchema; -use Dystore\Reviews\Domain\Reviews\Builders\ReviewBuilder; use Dystore\Reviews\Domain\Reviews\Models\Review; use Illuminate\Database\Eloquent\Builder; use Illuminate\Http\Request; @@ -24,14 +23,6 @@ class ReviewSchema extends Schema */ public static string $model = Review::class; - /** - * {@inheritDoc} - */ - protected array $with = [ - 'user', - 'user.customers', - ]; - /** * Default sort. */ @@ -40,13 +31,22 @@ class ReviewSchema extends Schema /** * {@inheritDoc} */ - public function includePaths(): iterable + public static function defaultWith(): array { return [ 'user', 'user.customers', + ]; + } - ...parent::includePaths(), + /** + * {@inheritDoc} + */ + public static function defaultIncludePaths(): array + { + return [ + 'user', + 'user.customers', ]; } @@ -55,19 +55,17 @@ public function includePaths(): iterable */ public function indexQuery(?Request $request, Builder $query): Builder { - /** @var ReviewBuilder $query */ + /** @var \Dystore\Reviews\Domain\Reviews\Builders\ReviewBuilder $query */ return $query->published(); } /** * Get the resource fields. - * - * @return array */ - public function fields(): iterable + public static function defaultFields(): iterable { return [ - $this->idField(), + static::idField(), Str::make('name') ->extractUsing( @@ -101,19 +99,15 @@ public function fields(): iterable ProductSchema::type(), ProductVariantSchema::type(), ), - - ...parent::fields(), ]; } /** * {@inheritDoc} */ - public function sortables(): iterable + public static function defaultSortables(): array { return [ - ...parent::sortables(), - SortColumn::make('id', 'id'), SortColumn::make('published_at', 'published_at'), diff --git a/packages/reviews/src/Domain/Reviews/Models/Review.php b/packages/reviews/src/Domain/Reviews/Models/Review.php index 93b054487..dbc11d7b6 100644 --- a/packages/reviews/src/Domain/Reviews/Models/Review.php +++ b/packages/reviews/src/Domain/Reviews/Models/Review.php @@ -8,6 +8,7 @@ use Illuminate\Database\Eloquent\Casts\AsArrayObject; use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Factories\HasFactory; +use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\MorphTo; use Illuminate\Support\Facades\Config; @@ -55,6 +56,8 @@ public function name(): Attribute /** * Purchasable relation. + * + * @return MorphTo */ public function purchasable(): MorphTo { @@ -63,6 +66,8 @@ public function purchasable(): MorphTo /** * User relation. + * + * @return BelongsTo */ public function user(): BelongsTo { diff --git a/packages/reviews/src/ReviewsServiceProvider.php b/packages/reviews/src/ReviewsServiceProvider.php index 45f8fda3e..94a8c3017 100644 --- a/packages/reviews/src/ReviewsServiceProvider.php +++ b/packages/reviews/src/ReviewsServiceProvider.php @@ -2,17 +2,13 @@ namespace Dystore\Reviews; -use Dystore\Api\Base\Contracts\ResourceManifest; -use Dystore\Api\Base\Contracts\SchemaManifest; -use Dystore\Api\Base\Extensions\ResourceExtension; -use Dystore\Api\Base\Extensions\SchemaExtension; -use Dystore\Api\Base\Facades\SchemaManifest as SchemaManifestFacade; +use Dystore\Api\Base\Facades\JsonApiManifest; use Dystore\Api\Domain\Products\JsonApi\V1\ProductResource; use Dystore\Api\Domain\Products\JsonApi\V1\ProductSchema; use Dystore\Api\Domain\ProductVariants\JsonApi\V1\ProductVariantResource; use Dystore\Api\Domain\ProductVariants\JsonApi\V1\ProductVariantSchema; use Dystore\Api\Support\Config\Collections\DomainConfigCollection; -use Dystore\Reviews\Domain\Hub\Components\Slots\ReviewsSlot; +use Dystore\Reviews\Domain\Reviews\JsonApi\V1\ReviewResource; use Dystore\Reviews\Domain\Reviews\JsonApi\V1\ReviewSchema; use Dystore\Reviews\Domain\Reviews\Models\Review; use Dystore\Reviews\Domain\Reviews\Observers\ReviewObserver; @@ -21,8 +17,7 @@ use LaravelJsonApi\Eloquent\Fields\Number; use LaravelJsonApi\Eloquent\Fields\Relations\HasMany; use LaravelJsonApi\Eloquent\Fields\Relations\HasManyThrough; -use Livewire\Livewire; -use Lunar\Hub\Facades\Slot; +use LaravelJsonApi\Eloquent\Resources\Relation; use Lunar\Models\Product; use Lunar\Models\ProductVariant; @@ -42,14 +37,14 @@ public function register(): void 'dystore-reviews', ); - $this->registerSchemas(); - $this->booting(function () { $this->registerPolicies(); }); - $this->registerDynamicRelations(); + JsonApiManifest::addSchema(ReviewSchema::class); + JsonApiManifest::addResource(ReviewResource::class); + $this->registerDynamicRelations(); $this->extendSchemas(); } @@ -62,17 +57,6 @@ public function boot(): void $this->loadViewsFrom(__DIR__.'/Domain/Hub/resources/views', 'dystore-reviews'); $this->loadRoutesFrom("{$this->root}/routes/api.php"); - // TODO: Add slots to Filament - // Livewire::component( - // 'dystore-reviews::reviews-slot', - // ReviewsSlot::class, - // ); - // - // Slot::register( - // 'product.show', - // ReviewsSlot::class, - // ); - Review::observe(ReviewObserver::class); if ($this->app->runningInConsole()) { @@ -82,29 +66,13 @@ public function boot(): void } } - /** - * Register schemas. - */ - public function registerSchemas(): void - { - SchemaManifestFacade::registerSchema(ReviewSchema::class); - } - - /** - * Register the application's policies. - */ public function registerPolicies(): void { DomainConfigCollection::fromConfig('dystore.reviews.domains') ->getPolicies() - ->each( - fn (string $policy, string $model) => Gate::policy($model, $policy), - ); + ->each(fn (string $policy, string $model) => Gate::policy($model, $policy)); } - /** - * Register config files. - */ protected function registerConfig(): void { $this->mergeConfigFrom( @@ -113,9 +81,6 @@ protected function registerConfig(): void ); } - /** - * Publish config files. - */ protected function publishConfig(): void { $this->publishes([ @@ -123,9 +88,6 @@ protected function publishConfig(): void ], 'dystore-reviews'); } - /** - * Publish translations. - */ protected function publishTranslations(): void { $this->publishes([ @@ -133,9 +95,6 @@ protected function publishTranslations(): void ], 'dystore-reviews.translations'); } - /** - * Register dynamic relations. - */ protected function registerDynamicRelations(): void { Product::resolveRelationUsing('variantReviews', function ($model) { @@ -153,86 +112,57 @@ protected function registerDynamicRelations(): void }); } - /** - * Extend schemas. - */ protected function extendSchemas(): void { - /** @var SchemaManifest $schemaManifest */ - $schemaManifest = $this->app->make(SchemaManifest::class); - - /** @var ResourceManifest $resourceManifest */ - $resourceManifest = $this->app->make(ResourceManifest::class); - - /** @var SchemaExtension $productSchemaExtenstion */ - $productSchemaExtenstion = $schemaManifest::extend(ProductSchema::class); - - $productSchemaExtenstion - ->setWith([ - 'reviews', - ]) - ->setIncludePaths([ - 'reviews', - 'reviews.user', - 'reviews.user.customers', - 'variants.reviews', - 'variants.reviews.user', - 'variants.reviews.user.customers', - ]) - ->setFields([ - fn () => Number::make('rating', 'review_rating'), - fn () => Number::make('review_count') - ->extractUsing( - static fn ($model) => $model->relationLoaded('reviews') - ? $model->reviews->count() - : $model->reviews()->count(), - ), - fn () => HasManyThrough::make('reviews')->serializeUsing( - static fn ($relation) => $relation->withoutLinks(), + $productSchema = JsonApiManifest::schema(ProductSchema::class); + + $productSchema->with()->add('reviews'); + $productSchema->includePaths()->push(...[ + 'reviews', + 'reviews.user', + 'reviews.user.customers', + 'variants.reviews', + 'variants.reviews.user', + 'variants.reviews.user.customers', + ]); + $productSchema->fields()->push(...[ + Number::make('review_count') + ->extractUsing( + static fn (Product $model) => $model->relationLoaded('reviews') + ? $model->reviews->count() + : $model->reviews()->count(), ), - ]) - ->setShowRelated([ - 'reviews', - ]) - ->setShowRelationship([ - 'reviews', - ]); - - /** @var ResourceExtension $productResourceExtension */ - $productResourceExtension = $resourceManifest::extend(ProductResource::class); - - $productResourceExtension - ->setRelationships(fn ($resource) => [ - $resource->relation('reviews'), - ]); - - /** @var SchemaExtension $productVariantSchemaExtenstion */ - $productVariantSchemaExtenstion = $schemaManifest::extend(ProductVariantSchema::class); - - $productVariantSchemaExtenstion - ->setIncludePaths([ - 'reviews', - 'reviews.user', - 'reviews.user.customers', - ]) - ->setFields([ - fn () => HasMany::make('reviews')->serializeUsing( + HasManyThrough::make('reviews')->serializeUsing(static fn (Relation $relation) => $relation->withoutLinks()), + ]); + $productSchema->showRelated()->add('reviews'); + $productSchema->showRelationships()->add('reviews'); + + JsonApiManifest::resource(ProductResource::class) + ->relationships() + ->add(fn (ProductResource $resource) => $resource->relation('reviews')); + + $variantSchema = JsonApiManifest::schema(ProductVariantSchema::class); + + $variantSchema->includePaths()->push(...[ + 'reviews', + 'reviews.user', + 'reviews.user.customers', + ]); + + $variantSchema->fields()->push(...[ + HasMany::make('reviews') + ->serializeUsing( static fn ($relation) => $relation->withoutLinks(), ), - ]) - ->setShowRelated([ - 'reviews', - ]) - ->setShowRelationship([ - 'reviews', - ]); - - /** @var ResourceExtension $productVariantResourceExtension */ - $productVariantResourceExtension = $resourceManifest::extend(ProductVariantResource::class); - - $productVariantResourceExtension - ->setRelationships(fn ($resource) => [ - 'reviews' => $resource->relation('reviews'), - ]); + ]); + + $variantSchema->showRelated()->add('reviews'); + $variantSchema->showRelationships()->add('reviews'); + + $variantResource = JsonApiManifest::resource(ProductVariantResource::class); + + $variantResource + ->relationships() + ->add(fn (ProductVariantResource $resource) => $resource->relation('reviews')); } } diff --git a/tests/api/Feature/Domain/JsonApi/Extensions/ExtendableResourceTest.php b/tests/api/Feature/Domain/JsonApi/Base/ExtendableResourceTest.php similarity index 83% rename from tests/api/Feature/Domain/JsonApi/Extensions/ExtendableResourceTest.php rename to tests/api/Feature/Domain/JsonApi/Base/ExtendableResourceTest.php index d2b1453bc..3159da45a 100644 --- a/tests/api/Feature/Domain/JsonApi/Extensions/ExtendableResourceTest.php +++ b/tests/api/Feature/Domain/JsonApi/Base/ExtendableResourceTest.php @@ -1,6 +1,6 @@ setAttributes(fn (JsonApiResource $resource) => [ 'secret_id' => $resource->resource->id, 'nazdar' => 'cau', 'ahoj' => 'zdar', ]); - expect(ResourceManifest::extend(ProductResourceMock::class)->attributes()->all()[0]) + expect(ResourceRepository::extend(ProductResourceMock::class)->attributes()->all()[0]) ->value() ->toBeInstanceOf(Closure::class); @@ -39,15 +39,15 @@ 'nazdar' => 'cau', 'ahoj' => 'zdar', ]); -}); +})->todo(); test('a resource relationships can be extended', function () { - ResourceManifest::extend(ProductResourceMock::class) + ResourceRepository::extend(ProductResourceMock::class) ->setRelationships(fn (JsonApiResource $resource) => [ $resource->relation('golden_chocolate'), ]); - expect(ResourceManifest::extend(ProductResourceMock::class)->relationships()->all()[0]) + expect(ResourceRepository::extend(ProductResourceMock::class)->relationships()->all()[0]) ->value() ->toBeInstanceOf(Closure::class); @@ -61,4 +61,4 @@ expect(iterator_to_array($productResourceInstance->relationships(null))['golden_chocolate']) ->toBeInstanceOf(Relation::class); -}); +})->todo(); diff --git a/tests/api/Feature/Domain/JsonApi/Extensions/ExtendableSchemasTest.php b/tests/api/Feature/Domain/JsonApi/Base/JsonApiManifestSchemasTest.php similarity index 50% rename from tests/api/Feature/Domain/JsonApi/Extensions/ExtendableSchemasTest.php rename to tests/api/Feature/Domain/JsonApi/Base/JsonApiManifestSchemasTest.php index 208da7df0..661ae2136 100644 --- a/tests/api/Feature/Domain/JsonApi/Extensions/ExtendableSchemasTest.php +++ b/tests/api/Feature/Domain/JsonApi/Base/JsonApiManifestSchemasTest.php @@ -1,24 +1,27 @@ group('manifests', 'extending'); beforeEach(function () { /** @var TestCase $this */ $this->server = App::make(ServerMock::class, ['name' => 'v1']); + + JsonApiManifest::addSchema(EloquentSchemaMock::class); }); test('schema eager loading can be extended', function () { /** @var TestCase $this */ - $mockSchemaInstance = $this->server->schemas()->schemaFor('products'); + $mockSchemaInstance = $this->server->schemas()->schemaFor('tags'); expect($mockSchemaInstance) ->with() @@ -26,111 +29,107 @@ ->toContain('else') ->toHaveCount(1); - SchemaManifest::extend(ExtendableSchemasMock::class)->setWith([ - 'something', - 'else', - 'else', - ]); + JsonApiManifest::schema(EloquentSchemaMock::class) + ->addWith([ + 'something', + 'else', + 'else', + 'other', + ]) + ->removeWith('else'); - expect(SchemaManifest::extend(ExtendableSchemasMock::class)) - ->with()->resolve() - ->toContain('something', 'else'); + expect(JsonApiManifest::schema(EloquentSchemaMock::class)) + ->with() + ->resolve() + ->toContain('something', 'other'); expect($mockSchemaInstance) ->with() ->toBe([ 'something', - 'else', + 'other', ]); }); test('schema fields can be extended', function () { /** @var TestCase $this */ - $mockSchemaInstance = $this->server->schemas()->schemaFor('products'); + $mockSchemaInstance = $this->server->schemas()->schemaFor('tags'); - $field = Str::make('my_product_name'); + $field = Str::make('nazdar'); - expect($mockSchemaInstance) - ->fields() + expect(iterator_to_array($mockSchemaInstance->fields())) ->not ->toContain($field) ->toHaveCount(2); - SchemaManifest::extend(ExtendableSchemasMock::class) - ->setFields([ - $field, - ]); + JsonApiManifest::schema(EloquentSchemaMock::class) + ->addFields($field); - expect(SchemaManifest::extend(ExtendableSchemasMock::class)) - ->fields()->resolve() - ->toContain($field) - ->toHaveCount(1); - - expect($mockSchemaInstance) + expect(JsonApiManifest::schema(EloquentSchemaMock::class)) ->fields() ->toContain($field) ->toHaveCount(3); + + expect(iterator_to_array($mockSchemaInstance->fields())) + ->toContainEqual($field) + ->toHaveCount(3); }); test('schema filters can be extended', function () { /** @var TestCase $this */ - $mockSchemaInstance = $this->server->schemas()->schemaFor('products'); + $mockSchemaInstance = $this->server->schemas()->schemaFor('tags'); - $filter = Where::make('price'); + $filter = Where::make('new_filter'); expect($mockSchemaInstance) ->filters() ->not ->toContain($filter) - ->toHaveCount(2); + ->toHaveCount(3); - SchemaManifest::extend(ExtendableSchemasMock::class) - ->setFilters([ + JsonApiManifest::schema(EloquentSchemaMock::class) + ->addFilters([ $filter, ]); - expect(SchemaManifest::extend(ExtendableSchemasMock::class)) - ->filters()->resolve() + expect(JsonApiManifest::schema(EloquentSchemaMock::class)) + ->filters() ->toContain($filter) - ->toHaveCount(1); + ->toHaveCount(2); expect($mockSchemaInstance) ->filters() - ->toContain($filter) - ->toHaveCount(3); + ->toContainEqual($filter) + ->toHaveCount(4); }); test('schema sortables can be extended', function () { /** @var TestCase $this */ - $mockSchemaInstance = $this->server->schemas()->schemaFor('products'); + $mockSchemaInstance = $this->server->schemas()->schemaFor('tags'); $sortables = ['nazdar', 'cau']; - expect($mockSchemaInstance) - ->sortables() + expect(iterator_to_array($mockSchemaInstance->sortables())) ->not ->toContain('nazdar', 'cau') ->toHaveCount(1); - SchemaManifest::extend(ExtendableSchemasMock::class) - ->setSortables( - $sortables, - ); + JsonApiManifest::schema(EloquentSchemaMock::class) + ->addSortables($sortables); - expect(SchemaManifest::extend(ExtendableSchemasMock::class)) - ->sortables()->resolve() - ->toContain('nazdar', 'cau') - ->toHaveCount(2); - - expect($mockSchemaInstance) + expect(JsonApiManifest::schema(EloquentSchemaMock::class)) ->sortables() ->toContain('ahoj', 'nazdar', 'cau') ->toHaveCount(3); + + expect(iterator_to_array($mockSchemaInstance->sortables())) + ->toContain('ahoj', 'nazdar', 'cau') + ->toHaveCount(3); }); test('schema related gate ability can be extended', function () { /** @var TestCase $this */ - $mockSchemaInstance = $this->server->schemas()->schemaFor('products'); + $mockSchemaInstance = $this->server->schemas()->schemaFor('tags'); $related = ['two', 'three', 'four', 'one']; @@ -141,13 +140,13 @@ ->toHaveCount(1) ->toContain('one'); - SchemaManifest::extend(ExtendableSchemasMock::class) - ->setShowRelated( - $related, + JsonApiManifest::schema(EloquentSchemaMock::class) + ->addShowRelated( + $related ); - expect(SchemaManifest::extend(ExtendableSchemasMock::class)) - ->showRelated()->resolve() + expect(JsonApiManifest::schema(EloquentSchemaMock::class)) + ->showRelated() ->toContain('two', 'three', 'four', 'one') ->toHaveCount(4); @@ -159,28 +158,28 @@ test('schema relationships gate ability can be extended', function () { /** @var TestCase $this */ - $mockSchemaInstance = $this->server->schemas()->schemaFor('products'); + $mockSchemaInstance = $this->server->schemas()->schemaFor('tags'); $relationships = ['pear', 'peach']; expect($mockSchemaInstance) - ->showRelationship() + ->showRelationships() ->not ->toContain('pear', 'peach') ->toHaveCount(1); - SchemaManifest::extend(ExtendableSchemasMock::class) - ->setShowRelationship( - $relationships, + JsonApiManifest::schema(EloquentSchemaMock::class) + ->setShowRelationships( + $relationships ); - expect(SchemaManifest::extend(ExtendableSchemasMock::class)) - ->showRelationship()->resolve() + expect(JsonApiManifest::schema(EloquentSchemaMock::class)) + ->showRelationships() ->toContain('pear', 'peach') ->toHaveCount(2); expect($mockSchemaInstance) - ->showRelationship() + ->showRelationships() ->toContain('apple', 'pear', 'peach') ->toHaveCount(3); }); diff --git a/tests/api/Feature/Domain/JsonApi/Extensions/ProductResourceMock.php b/tests/api/Feature/Domain/JsonApi/Base/ProductResourceMock.php similarity index 84% rename from tests/api/Feature/Domain/JsonApi/Extensions/ProductResourceMock.php rename to tests/api/Feature/Domain/JsonApi/Base/ProductResourceMock.php index dd6f2ac94..aad5c6d0d 100644 --- a/tests/api/Feature/Domain/JsonApi/Extensions/ProductResourceMock.php +++ b/tests/api/Feature/Domain/JsonApi/Base/ProductResourceMock.php @@ -1,6 +1,6 @@ 'homestead', 'password' => 'secret', ]); + + $config->set('queue.default', 'sync'); }); } diff --git a/tests/newsletter/TestCase.php b/tests/newsletter/TestCase.php index 40550474e..c7b27daf2 100644 --- a/tests/newsletter/TestCase.php +++ b/tests/newsletter/TestCase.php @@ -84,6 +84,8 @@ protected function defineEnvironment($app): void 'database' => ':memory:', 'prefix' => '', ]); + + $config->set('queue.default', 'sync'); }); } diff --git a/tests/product-notifications/Feature/SubscribesToProductStockNotificationTest.php b/tests/product-notifications/Feature/SubscribesToProductStockNotificationTest.php index 7d780398b..6f3188abb 100644 --- a/tests/product-notifications/Feature/SubscribesToProductStockNotificationTest.php +++ b/tests/product-notifications/Feature/SubscribesToProductStockNotificationTest.php @@ -9,7 +9,8 @@ use function Pest\Faker\fake; -uses(TestCase::class, RefreshDatabase::class); +uses(TestCase::class, RefreshDatabase::class) + ->group('product_notifications'); test('user can subscribe to product stock notification', function () { /** @var TestCase $this */ diff --git a/tests/product-notifications/Stubs/ProductVariants/ProductVariantSchema.php b/tests/product-notifications/Stubs/ProductVariants/ProductVariantSchema.php index 7e8f2e7c5..e9b93443a 100644 --- a/tests/product-notifications/Stubs/ProductVariants/ProductVariantSchema.php +++ b/tests/product-notifications/Stubs/ProductVariants/ProductVariantSchema.php @@ -25,7 +25,7 @@ public static function type(): string /** * Get the resource fields. */ - public function fields(): array + public static function defaultFields(): array { return [ ID::make(), diff --git a/tests/product-notifications/Stubs/Users/UserSchema.php b/tests/product-notifications/Stubs/Users/UserSchema.php index ebf476c6a..5fd06c4c1 100644 --- a/tests/product-notifications/Stubs/Users/UserSchema.php +++ b/tests/product-notifications/Stubs/Users/UserSchema.php @@ -2,18 +2,18 @@ namespace Dystore\Tests\ProductNotifications\Stubs\Users; +use Dystore\Api\Domain\JsonApi\Eloquent\Schema; use LaravelJsonApi\Eloquent\Fields\ID; -use LaravelJsonApi\Eloquent\Schema; class UserSchema extends Schema { /** - * The model the schema corresponds to. + * {@inheritDoc} */ public static string $model = User::class; /** - * Get the JSON:API resource type. + * {@inheritDoc} */ public static function type(): string { @@ -21,9 +21,9 @@ public static function type(): string } /** - * Get the resource fields. + * {@inheritDoc} */ - public function fields(): array + public static function defaultFields(): array { return [ ID::make(), diff --git a/tests/product-notifications/TestCase.php b/tests/product-notifications/TestCase.php index 8a4a176e2..db9f599df 100644 --- a/tests/product-notifications/TestCase.php +++ b/tests/product-notifications/TestCase.php @@ -2,7 +2,7 @@ namespace Dystore\Tests\ProductNotifications; -use Dystore\Api\Base\Facades\SchemaManifest; +use Dystore\Api\Base\Facades\JsonApiManifest; use Dystore\Tests\ProductNotifications\Stubs\Users\User; use Dystore\Tests\ProductNotifications\Stubs\Users\UserSchema; use Illuminate\Contracts\Config\Repository; @@ -35,10 +35,7 @@ protected function setUp(): void 'model' => User::class, ]); - /** - * Schema configuration. - */ - SchemaManifest::registerSchema(UserSchema::class); + JsonApiManifest::addSchema(UserSchema::class); activity()->disableLogging(); } @@ -114,6 +111,8 @@ protected function defineEnvironment($app): void 'username' => 'homestead', 'password' => 'secret', ]); + + $config->set('queue.default', 'sync'); }); } diff --git a/tests/product-views/Feature/IncreasesProductViewsTest.php b/tests/product-views/Feature/IncreasesProductViewsTest.php index 18d706713..ccbc916b2 100644 --- a/tests/product-views/Feature/IncreasesProductViewsTest.php +++ b/tests/product-views/Feature/IncreasesProductViewsTest.php @@ -1,15 +1,16 @@ group('product_views'); it('records a view each time the product is shown', function () { /** @var TestCase $this */ - $product = ProductFactory::new()->create(['id' => 5]); + $product = Product::factory()->create(['id' => 5]); $self = 'http://localhost/api/v1/products/'.$product->getRouteKey(); @@ -18,7 +19,7 @@ ->expects('products') ->get($self); - $hits = Redis::zCount("product:views:{$product->id}", -INF, +INF); + $hits = Redis::command('zcount', ["product:views:{$product->id}", -INF, +INF]); expect($hits)->toBe(1); @@ -27,7 +28,7 @@ ->expects('products') ->get($self); - $hits = Redis::zCount("product:views:{$product->id}", -INF, +INF); + $hits = Redis::command('zcount', ["product:views:{$product->id}", -INF, +INF]); expect($hits)->toBe(2); -})->group('product-views'); +}); diff --git a/tests/product-views/Stubs/Users/JsonApi/V1/UserSchema.php b/tests/product-views/Stubs/Users/JsonApi/V1/UserSchema.php index 127f327f5..720b9a4ea 100644 --- a/tests/product-views/Stubs/Users/JsonApi/V1/UserSchema.php +++ b/tests/product-views/Stubs/Users/JsonApi/V1/UserSchema.php @@ -3,7 +3,7 @@ namespace Dystore\Tests\ProductViews\Stubs\Users\JsonApi\V1; use Dystore\Api\Domain\JsonApi\Eloquent\Schema; -use Dystore\Tests\ProductViews\Stubs\User; +use Dystore\Tests\ProductViews\Stubs\Users\User; use LaravelJsonApi\Eloquent\Fields\ID; class UserSchema extends Schema @@ -24,7 +24,7 @@ public static function type(): string /** * {@inheritDoc} */ - public function fields(): array + public static function defaultFields(): array { return [ ID::make(), diff --git a/tests/product-views/TestCase.php b/tests/product-views/TestCase.php index d99a071e3..bb175afb6 100644 --- a/tests/product-views/TestCase.php +++ b/tests/product-views/TestCase.php @@ -103,6 +103,8 @@ protected function defineEnvironment($app): void 'database' => ':memory:', 'prefix' => '', ]); + + $config->set('queue.default', 'sync'); }); } diff --git a/tests/product-views/Unit/ProductViewsTest.php b/tests/product-views/Unit/ProductViewsTest.php index 64a1d13df..fb4861d05 100644 --- a/tests/product-views/Unit/ProductViewsTest.php +++ b/tests/product-views/Unit/ProductViewsTest.php @@ -7,7 +7,7 @@ use Illuminate\Support\Str; uses(TestCase::class, RefreshDatabase::class) - ->group('product-views'); + ->group('product_views'); it('can record a view', function () { /** @var TestCase $this */ @@ -16,24 +16,24 @@ app(ProductViews::class)->record($productId); app(ProductViews::class)->record($productId); - expect(Redis::zRange("product:views:{$productId}", 0, -1)) + expect(Redis::command('zrange', ["product:views:{$productId}", 0, -1])) ->toHaveCount(2); -})->todo(); +}); it('removes old entries', function () { /** @var TestCase $this */ $productId = 2; - Redis::zAdd("product:views:{$productId}", time() - 60 * 60, Str::uuid()->toString()); + Redis::command('zadd', ["product:views:{$productId}", time() - 60 * 60, Str::uuid()->toString()]); - expect(Redis::zRange("product:views:{$productId}", 0, -1)) + expect(Redis::command('zrange', ["product:views:{$productId}", 0, -1])) ->toHaveCount(1); app(ProductViews::class)->record($productId); - expect(Redis::zRange("product:views:{$productId}", 0, -1)) + expect(Redis::command('zrange', ["product:views:{$productId}", 0, -1])) ->toHaveCount(1); -})->todo(); +}); it('returns a list of product ids sorted by most viewed', function () { /** @var TestCase $this */ @@ -44,4 +44,4 @@ $sorted = app(ProductViews::class)->sorted(); expect($sorted)->toBe([4, 3]); -})->todo(); +}); diff --git a/tests/reviews/Feature/CanCreateReviewsForPurchasableTest.php b/tests/reviews/Feature/CanCreateReviewsForPurchasableTest.php index cd246592a..ab803a081 100644 --- a/tests/reviews/Feature/CanCreateReviewsForPurchasableTest.php +++ b/tests/reviews/Feature/CanCreateReviewsForPurchasableTest.php @@ -9,7 +9,8 @@ use Illuminate\Foundation\Testing\RefreshDatabase; use Illuminate\Support\Facades\Config; -uses(TestCase::class, RefreshDatabase::class); +uses(TestCase::class, RefreshDatabase::class) + ->group('reviews'); it('requires logged in user to create a review', function () { /** @var TestCase $this */ @@ -33,14 +34,14 @@ ->jsonApi() ->expects('reviews') ->withData($data) - ->post('/api/v1/reviews'); + ->post(serverUrl('/reviews')); $response->assertErrorStatus([ 'detail' => 'Unauthenticated.', 'status' => '401', 'title' => 'Unauthorized', ]); -})->group('reviews'); +}); it('can save a review with name and meta', function () { /** @var TestCase $this */ @@ -70,7 +71,7 @@ ->jsonApi() ->expects('reviews') ->withData($data) - ->post('/api/v1/reviews'); + ->post(serverUrl('/reviews')); $id = $response ->assertCreatedWithServerId('http://localhost/api/v1/reviews', $data) @@ -86,7 +87,7 @@ 'name' => $review->name, 'meta' => json_encode($review->meta), ]); -})->group('reviews'); +}); it('requires a rating and comment, but also a name in order to be saved', function () { @@ -111,7 +112,7 @@ ->jsonApi() ->expects('reviews') ->withData($data) - ->post('/api/v1/reviews'); + ->post(serverUrl('/reviews')); $response ->assertErrors(422, [ @@ -119,7 +120,7 @@ ['detail' => __('dystore-reviews::validations.name.required'), 'status' => '422'], ]); -})->group('reviews'); +}); it('can store anonymous review when configured', function () { /** @var TestCase $this */ @@ -144,7 +145,7 @@ ->jsonApi() ->expects('reviews') ->withData($data) - ->post('/api/v1/reviews'); + ->post(serverUrl('/reviews')); $id = $response ->assertCreatedWithServerId('http://localhost/api/v1/reviews', $data) @@ -158,7 +159,7 @@ 'comment' => $review->comment, 'rating' => $review->rating, ]); -})->todo()->group('reviews'); +})->todo(); it('can create a review for a product', function () { /** @var TestCase $this */ @@ -186,7 +187,7 @@ ->jsonApi() ->expects('reviews') ->withData($data) - ->post('/api/v1/reviews'); + ->post(serverUrl('/reviews')); $id = $response ->assertCreatedWithServerId('http://localhost/api/v1/reviews', $data) @@ -200,7 +201,7 @@ 'comment' => $review->comment, 'rating' => $review->rating, ]); -})->group('reviews'); +}); it('can create a review for a product variant', function () { /** @var TestCase $this */ @@ -228,7 +229,7 @@ ->jsonApi() ->expects('reviews') ->withData($data) - ->post('/api/v1/reviews'); + ->post(serverUrl('/reviews')); $id = $response ->assertCreatedWithServerId('http://localhost/api/v1/reviews', $data) @@ -242,4 +243,4 @@ 'comment' => $review->comment, 'rating' => $review->rating, ]); -})->group('reviews'); +}); diff --git a/tests/reviews/Feature/ExtendsSchemasTest.php b/tests/reviews/Feature/ExtendsSchemasTest.php index b11b9a0bf..683ea1c2d 100644 --- a/tests/reviews/Feature/ExtendsSchemasTest.php +++ b/tests/reviews/Feature/ExtendsSchemasTest.php @@ -6,7 +6,8 @@ use Dystore\Tests\Reviews\TestCase; use Illuminate\Foundation\Testing\RefreshDatabase; -uses(TestCase::class, RefreshDatabase::class); +uses(TestCase::class, RefreshDatabase::class) + ->group('reviews', 'manifests', 'extending'); it('reviews extend "ProductSchema" with reviews relationship', function () { /** @var TestCase $this */ @@ -24,10 +25,10 @@ $response = $this ->jsonApi() ->expects('reviews') - ->get("/api/v1/products/{$product->getRouteKey()}/reviews"); + ->get(serverUrl("/products/{$product->getRouteKey()}/reviews")); $response->assertFetchedMany($product->reviews); -})->todo(); +}); it('reviews extend "ProductVariantSchema" with reviews relationship', function () { /** @var TestCase $this */ @@ -41,7 +42,7 @@ $response = $this ->jsonApi() ->expects('reviews') - ->get("/api/v1/variants/{$productVariant->getRouteKey()}/reviews"); + ->get(serverUrl("/product_variants/{$productVariant->getRouteKey()}/reviews")); $response->assertFetchedMany($productVariant->reviews); -})->todo(); +}); diff --git a/tests/reviews/Stubs/Users/UserSchema.php b/tests/reviews/Stubs/Users/UserSchema.php index 610cc304e..8d0bab269 100644 --- a/tests/reviews/Stubs/Users/UserSchema.php +++ b/tests/reviews/Stubs/Users/UserSchema.php @@ -2,8 +2,8 @@ namespace Dystore\Tests\Reviews\Stubs\Users; +use Dystore\Api\Domain\JsonApi\Eloquent\Schema; use LaravelJsonApi\Eloquent\Fields\ID; -use LaravelJsonApi\Eloquent\Schema; class UserSchema extends Schema { @@ -23,7 +23,7 @@ public static function type(): string /** * Get the resource fields. */ - public function fields(): array + public static function defaultFields(): array { return [ ID::make(), diff --git a/tests/stripe/TestCase.php b/tests/stripe/TestCase.php index bf30b4867..07c79fa10 100644 --- a/tests/stripe/TestCase.php +++ b/tests/stripe/TestCase.php @@ -75,6 +75,8 @@ public function getEnvironmentSetUp($app): void 'prefix' => '', ]); + $config->set('queue.default', 'sync'); + $config->set('services.stripe', [ 'public_key' => env('STRIPE_PUBLIC_KEY'), 'key' => env('STRIPE_SECRET_KEY'),