mirror of
https://github.com/getgrav/grav.git
synced 2025-10-26 07:56:07 +01:00
Added classes for defining relationships
This commit is contained in:
@@ -12,7 +12,7 @@
|
||||
"homepage": "https://getgrav.org",
|
||||
"license": "MIT",
|
||||
"require": {
|
||||
"php": "^7.3.6 || ^8.0",
|
||||
"php": "^7.4.1 || ^8.0",
|
||||
"ext-json": "*",
|
||||
"ext-openssl": "*",
|
||||
"ext-curl": "*",
|
||||
@@ -89,7 +89,7 @@
|
||||
"config": {
|
||||
"apcu-autoloader": true,
|
||||
"platform": {
|
||||
"php": "7.3.6"
|
||||
"php": "7.4.1"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
|
||||
110
composer.lock
generated
110
composer.lock
generated
@@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "f0530b0fd3e574fef0852376653da5a0",
|
||||
"content-hash": "7645535ce7348e38bad6dad9ce8b2fdb",
|
||||
"packages": [
|
||||
{
|
||||
"name": "composer/ca-bundle",
|
||||
@@ -1655,20 +1655,20 @@
|
||||
},
|
||||
{
|
||||
"name": "psr/container",
|
||||
"version": "1.1.1",
|
||||
"version": "1.1.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/php-fig/container.git",
|
||||
"reference": "8622567409010282b7aeebe4bb841fe98b58dcaf"
|
||||
"reference": "513e0666f7216c7459170d56df27dfcefe1689ea"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/php-fig/container/zipball/8622567409010282b7aeebe4bb841fe98b58dcaf",
|
||||
"reference": "8622567409010282b7aeebe4bb841fe98b58dcaf",
|
||||
"url": "https://api.github.com/repos/php-fig/container/zipball/513e0666f7216c7459170d56df27dfcefe1689ea",
|
||||
"reference": "513e0666f7216c7459170d56df27dfcefe1689ea",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.2.0"
|
||||
"php": ">=7.4.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
@@ -1697,9 +1697,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/php-fig/container/issues",
|
||||
"source": "https://github.com/php-fig/container/tree/1.1.1"
|
||||
"source": "https://github.com/php-fig/container/tree/1.1.2"
|
||||
},
|
||||
"time": "2021-03-05T17:36:06+00:00"
|
||||
"time": "2021-11-05T16:50:12+00:00"
|
||||
},
|
||||
{
|
||||
"name": "psr/http-factory",
|
||||
@@ -2224,16 +2224,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v4.4.40",
|
||||
"version": "v4.4.41",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/console.git",
|
||||
"reference": "bdcc66f3140421038f495e5b50e3ca6ffa14c773"
|
||||
"reference": "0e1e62083b20ccb39c2431293de060f756af905c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/bdcc66f3140421038f495e5b50e3ca6ffa14c773",
|
||||
"reference": "bdcc66f3140421038f495e5b50e3ca6ffa14c773",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/0e1e62083b20ccb39c2431293de060f756af905c",
|
||||
"reference": "0e1e62083b20ccb39c2431293de060f756af905c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -2294,7 +2294,7 @@
|
||||
"description": "Eases the creation of beautiful and testable command line interfaces",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/console/tree/v4.4.40"
|
||||
"source": "https://github.com/symfony/console/tree/v4.4.41"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -2310,7 +2310,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-03-26T22:12:04+00:00"
|
||||
"time": "2022-04-12T15:19:55+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/contracts",
|
||||
@@ -2492,16 +2492,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/http-client",
|
||||
"version": "v4.4.40",
|
||||
"version": "v4.4.41",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/http-client.git",
|
||||
"reference": "c66fc3b60900359ea10a7b22921c797446783bb3"
|
||||
"reference": "bad7c3296590c5a69a9ed89e8a51f13c07c34b54"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/http-client/zipball/c66fc3b60900359ea10a7b22921c797446783bb3",
|
||||
"reference": "c66fc3b60900359ea10a7b22921c797446783bb3",
|
||||
"url": "https://api.github.com/repos/symfony/http-client/zipball/bad7c3296590c5a69a9ed89e8a51f13c07c34b54",
|
||||
"reference": "bad7c3296590c5a69a9ed89e8a51f13c07c34b54",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -2553,7 +2553,7 @@
|
||||
"description": "Provides powerful methods to fetch HTTP resources synchronously or asynchronously",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/http-client/tree/v4.4.40"
|
||||
"source": "https://github.com/symfony/http-client/tree/v4.4.41"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -2569,7 +2569,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-04-01T12:25:39+00:00"
|
||||
"time": "2022-04-12T15:19:55+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-ctype",
|
||||
@@ -3063,16 +3063,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/process",
|
||||
"version": "v4.4.40",
|
||||
"version": "v4.4.41",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/process.git",
|
||||
"reference": "54e9d763759268e07eb13b921d8631fc2816206f"
|
||||
"reference": "9eedd60225506d56e42210a70c21bb80ca8456ce"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/process/zipball/54e9d763759268e07eb13b921d8631fc2816206f",
|
||||
"reference": "54e9d763759268e07eb13b921d8631fc2816206f",
|
||||
"url": "https://api.github.com/repos/symfony/process/zipball/9eedd60225506d56e42210a70c21bb80ca8456ce",
|
||||
"reference": "9eedd60225506d56e42210a70c21bb80ca8456ce",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -3105,7 +3105,7 @@
|
||||
"description": "Executes commands in sub-processes",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/process/tree/v4.4.40"
|
||||
"source": "https://github.com/symfony/process/tree/v4.4.41"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -3121,20 +3121,20 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-03-18T16:18:39+00:00"
|
||||
"time": "2022-04-04T10:19:07+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/var-dumper",
|
||||
"version": "v4.4.39",
|
||||
"version": "v4.4.41",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/var-dumper.git",
|
||||
"reference": "35237c5e5dcb6593a46a860ba5b29c1d4683d80e"
|
||||
"reference": "58eb36075c04aaf92a7a9f38ee9a8b97e24eb481"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/35237c5e5dcb6593a46a860ba5b29c1d4683d80e",
|
||||
"reference": "35237c5e5dcb6593a46a860ba5b29c1d4683d80e",
|
||||
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/58eb36075c04aaf92a7a9f38ee9a8b97e24eb481",
|
||||
"reference": "58eb36075c04aaf92a7a9f38ee9a8b97e24eb481",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -3194,7 +3194,7 @@
|
||||
"dump"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/var-dumper/tree/v4.4.39"
|
||||
"source": "https://github.com/symfony/var-dumper/tree/v4.4.41"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -3210,7 +3210,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-02-25T10:38:15+00:00"
|
||||
"time": "2022-04-25T21:15:06+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/yaml",
|
||||
@@ -3862,20 +3862,24 @@
|
||||
},
|
||||
{
|
||||
"name": "codeception/stub",
|
||||
"version": "3.7.0",
|
||||
"version": "4.0.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Codeception/Stub.git",
|
||||
"reference": "468dd5fe659f131fc997f5196aad87512f9b1304"
|
||||
"reference": "18a148dacd293fc7b044042f5aa63a82b08bff5d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/Codeception/Stub/zipball/468dd5fe659f131fc997f5196aad87512f9b1304",
|
||||
"reference": "468dd5fe659f131fc997f5196aad87512f9b1304",
|
||||
"url": "https://api.github.com/repos/Codeception/Stub/zipball/18a148dacd293fc7b044042f5aa63a82b08bff5d",
|
||||
"reference": "18a148dacd293fc7b044042f5aa63a82b08bff5d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"phpunit/phpunit": "^8.4 | ^9.0"
|
||||
"php": "^7.4 | ^8.0",
|
||||
"phpunit/phpunit": "^8.4 | ^9.0 | ^10.0 | 10.0.x-dev"
|
||||
},
|
||||
"require-dev": {
|
||||
"consolidation/robo": "^3.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
@@ -3890,9 +3894,9 @@
|
||||
"description": "Flexible Stub wrapper for PHPUnit's Mock Builder",
|
||||
"support": {
|
||||
"issues": "https://github.com/Codeception/Stub/issues",
|
||||
"source": "https://github.com/Codeception/Stub/tree/3.7.0"
|
||||
"source": "https://github.com/Codeception/Stub/tree/4.0.2"
|
||||
},
|
||||
"time": "2020-07-03T15:54:43+00:00"
|
||||
"time": "2022-01-31T19:25:15+00:00"
|
||||
},
|
||||
{
|
||||
"name": "doctrine/instantiator",
|
||||
@@ -4679,16 +4683,16 @@
|
||||
},
|
||||
{
|
||||
"name": "phpstan/phpstan",
|
||||
"version": "1.6.0",
|
||||
"version": "1.6.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpstan/phpstan.git",
|
||||
"reference": "b480ba2ae0699a72d43a340c20b9c00ede91ee3e"
|
||||
"reference": "becb9603a31d70f5007d505877a7b812598dfe46"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/b480ba2ae0699a72d43a340c20b9c00ede91ee3e",
|
||||
"reference": "b480ba2ae0699a72d43a340c20b9c00ede91ee3e",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/becb9603a31d70f5007d505877a7b812598dfe46",
|
||||
"reference": "becb9603a31d70f5007d505877a7b812598dfe46",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -4714,7 +4718,7 @@
|
||||
"description": "PHPStan - PHP Static Analysis Tool",
|
||||
"support": {
|
||||
"issues": "https://github.com/phpstan/phpstan/issues",
|
||||
"source": "https://github.com/phpstan/phpstan/tree/1.6.0"
|
||||
"source": "https://github.com/phpstan/phpstan/tree/1.6.2"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -4734,7 +4738,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-04-26T05:43:03+00:00"
|
||||
"time": "2022-04-27T11:05:24+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpstan/phpstan-deprecation-rules",
|
||||
@@ -6505,16 +6509,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/finder",
|
||||
"version": "v5.4.3",
|
||||
"version": "v5.4.8",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/finder.git",
|
||||
"reference": "231313534dded84c7ecaa79d14bc5da4ccb69b7d"
|
||||
"reference": "9b630f3427f3ebe7cd346c277a1408b00249dad9"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/finder/zipball/231313534dded84c7ecaa79d14bc5da4ccb69b7d",
|
||||
"reference": "231313534dded84c7ecaa79d14bc5da4ccb69b7d",
|
||||
"url": "https://api.github.com/repos/symfony/finder/zipball/9b630f3427f3ebe7cd346c277a1408b00249dad9",
|
||||
"reference": "9b630f3427f3ebe7cd346c277a1408b00249dad9",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -6548,7 +6552,7 @@
|
||||
"description": "Finds files and directories via an intuitive fluent interface",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/finder/tree/v5.4.3"
|
||||
"source": "https://github.com/symfony/finder/tree/v5.4.8"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -6564,7 +6568,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-01-26T16:34:36+00:00"
|
||||
"time": "2022-04-15T08:07:45+00:00"
|
||||
},
|
||||
{
|
||||
"name": "theseer/tokenizer",
|
||||
@@ -6681,7 +6685,7 @@
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": {
|
||||
"php": "^7.3.6 || ^8.0",
|
||||
"php": "^7.4.1 || ^8.0",
|
||||
"ext-json": "*",
|
||||
"ext-openssl": "*",
|
||||
"ext-curl": "*",
|
||||
@@ -6691,7 +6695,7 @@
|
||||
},
|
||||
"platform-dev": [],
|
||||
"platform-overrides": {
|
||||
"php": "7.3.6"
|
||||
"php": "7.4.1"
|
||||
},
|
||||
"plugin-api-version": "2.2.0"
|
||||
}
|
||||
|
||||
@@ -50,6 +50,13 @@ interface MediaObjectInterface extends \Grav\Framework\Media\Interfaces\MediaObj
|
||||
*/
|
||||
public function metadata();
|
||||
|
||||
/**
|
||||
* Returns an array containing the file metadata
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getMeta();
|
||||
|
||||
/**
|
||||
* Add meta file for the medium.
|
||||
*
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Grav\Framework\Contracts\Media;
|
||||
|
||||
use Grav\Framework\Contracts\Object\IdentifierInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
||||
/**
|
||||
* Media Object Interface
|
||||
*/
|
||||
interface MediaObjectInterface extends IdentifierInterface
|
||||
{
|
||||
/**
|
||||
* Returns true if the object exists.
|
||||
*
|
||||
* @return bool
|
||||
* @phpstan-pure
|
||||
*/
|
||||
public function exists(): bool;
|
||||
|
||||
/**
|
||||
* Get metadata associated to the media object.
|
||||
*
|
||||
* @return array
|
||||
* @phpstan-pure
|
||||
*/
|
||||
public function getMeta(): array;
|
||||
|
||||
/**
|
||||
* @param string $field
|
||||
* @return mixed
|
||||
* @phpstan-pure
|
||||
*/
|
||||
public function get(string $field);
|
||||
|
||||
/**
|
||||
* Return URL pointing to the media object.
|
||||
*
|
||||
* @return string
|
||||
* @phpstan-pure
|
||||
*/
|
||||
public function getUrl(): string;
|
||||
|
||||
/**
|
||||
* Create media response.
|
||||
*
|
||||
* @param array $actions
|
||||
* @return ResponseInterface
|
||||
* @phpstan-pure
|
||||
*/
|
||||
public function createResponse(array $actions): ResponseInterface;
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Grav\Framework\Contracts\Object;
|
||||
|
||||
use JsonSerializable;
|
||||
|
||||
/**
|
||||
* Interface IdentifierInterface
|
||||
*/
|
||||
interface IdentifierInterface extends JsonSerializable
|
||||
{
|
||||
/**
|
||||
* Get identifier's ID.
|
||||
*
|
||||
* @return string
|
||||
* @phpstan-pure
|
||||
*/
|
||||
public function getId(): string;
|
||||
|
||||
/**
|
||||
* Get identifier's type.
|
||||
*
|
||||
* @return string
|
||||
* @phpstan-pure
|
||||
*/
|
||||
public function getType(): string;
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Grav\Framework\Contracts\Relationships;
|
||||
|
||||
use ArrayAccess;
|
||||
use Grav\Framework\Contracts\Object\IdentifierInterface;
|
||||
|
||||
/**
|
||||
* Interface RelationshipIdentifierInterface
|
||||
*/
|
||||
interface RelationshipIdentifierInterface extends IdentifierInterface
|
||||
{
|
||||
/**
|
||||
* If identifier has meta.
|
||||
*
|
||||
* @return bool
|
||||
* @phpstan-pure
|
||||
*/
|
||||
public function hasIdentifierMeta(): bool;
|
||||
|
||||
/**
|
||||
* Get identifier meta.
|
||||
*
|
||||
* @return array|ArrayAccess
|
||||
* @phpstan-pure
|
||||
*/
|
||||
public function getIdentifierMeta();
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Grav\Framework\Contracts\Relationships;
|
||||
|
||||
use Countable;
|
||||
use Grav\Framework\Contracts\Object\IdentifierInterface;
|
||||
use IteratorAggregate;
|
||||
use JsonSerializable;
|
||||
use Serializable;
|
||||
|
||||
/**
|
||||
* Interface Relationship
|
||||
*
|
||||
* @template T of IdentifierInterface
|
||||
* @template P of IdentifierInterface
|
||||
*/
|
||||
interface RelationshipInterface extends Countable, IteratorAggregate, JsonSerializable, Serializable
|
||||
{
|
||||
/**
|
||||
* @return string
|
||||
* @phpstan-pure
|
||||
*/
|
||||
public function getName(): string;
|
||||
|
||||
/**
|
||||
* @return string
|
||||
* @phpstan-pure
|
||||
*/
|
||||
public function getType(): string;
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
* @phpstan-pure
|
||||
*/
|
||||
public function isModified(): bool;
|
||||
|
||||
/**
|
||||
* @return string
|
||||
* @phpstan-pure
|
||||
*/
|
||||
public function getCardinality(): string;
|
||||
|
||||
/**
|
||||
* @return P
|
||||
* @phpstan-pure
|
||||
*/
|
||||
public function getParent(): IdentifierInterface;
|
||||
|
||||
/**
|
||||
* @param string $id
|
||||
* @param string|null $type
|
||||
* @return bool
|
||||
* @phpstan-pure
|
||||
*/
|
||||
public function has(string $id, string $type = null): bool;
|
||||
|
||||
/**
|
||||
* @param T $identifier
|
||||
* @return bool
|
||||
* @phpstan-pure
|
||||
*/
|
||||
public function hasIdentifier(IdentifierInterface $identifier): bool;
|
||||
|
||||
/**
|
||||
* @param T $identifier
|
||||
* @return bool
|
||||
*/
|
||||
public function addIdentifier(IdentifierInterface $identifier): bool;
|
||||
|
||||
/**
|
||||
* @param T|null $identifier
|
||||
* @return bool
|
||||
*/
|
||||
public function removeIdentifier(IdentifierInterface $identifier = null): bool;
|
||||
|
||||
/**
|
||||
* @return iterable<T>
|
||||
*/
|
||||
public function getIterator(): iterable;
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Grav\Framework\Contracts\Relationships;
|
||||
|
||||
use ArrayAccess;
|
||||
use Countable;
|
||||
use Iterator;
|
||||
use JsonSerializable;
|
||||
|
||||
/**
|
||||
* Interface RelationshipsInterface
|
||||
*/
|
||||
interface RelationshipsInterface extends Countable, ArrayAccess, Iterator, JsonSerializable
|
||||
{
|
||||
/**
|
||||
* @return bool
|
||||
* @phpstan-pure
|
||||
*/
|
||||
public function isModified(): bool;
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getModified(): array;
|
||||
|
||||
/**
|
||||
* @return int
|
||||
* @phpstan-pure
|
||||
*/
|
||||
public function count(): int;
|
||||
|
||||
/**
|
||||
* @param string $offset
|
||||
* @return RelationshipInterface|null
|
||||
*/
|
||||
public function offsetGet($offset): ?RelationshipInterface;
|
||||
|
||||
/**
|
||||
* @return RelationshipInterface|null
|
||||
*/
|
||||
public function current(): ?RelationshipInterface;
|
||||
|
||||
/**
|
||||
* @return string
|
||||
* @phpstan-pure
|
||||
*/
|
||||
public function key(): string;
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Grav\Framework\Contracts\Relationships;
|
||||
|
||||
use Grav\Framework\Contracts\Object\IdentifierInterface;
|
||||
|
||||
/**
|
||||
* Interface ToManyRelationshipInterface
|
||||
*
|
||||
* @template T of IdentifierInterface
|
||||
* @template P of IdentifierInterface
|
||||
* @template-extends RelationshipInterface<T,P>
|
||||
*/
|
||||
interface ToManyRelationshipInterface extends RelationshipInterface
|
||||
{
|
||||
/**
|
||||
* @param string $id
|
||||
* @param string|null $type
|
||||
* @return T|null
|
||||
* @phpstan-pure
|
||||
*/
|
||||
public function getIdentifier(string $id, string $type = null): ?IdentifierInterface;
|
||||
|
||||
/**
|
||||
* @param string $id
|
||||
* @param string|null $type
|
||||
* @return T|null
|
||||
* @phpstan-pure
|
||||
*/
|
||||
public function getObject(string $id, string $type = null): ?object;
|
||||
|
||||
/**
|
||||
* @param iterable<T> $identifiers
|
||||
* @return bool
|
||||
*/
|
||||
public function addIdentifiers(iterable $identifiers): bool;
|
||||
|
||||
/**
|
||||
* @param iterable<T> $identifiers
|
||||
* @return bool
|
||||
*/
|
||||
public function replaceIdentifiers(iterable $identifiers): bool;
|
||||
|
||||
/**
|
||||
* @param iterable<T> $identifiers
|
||||
* @return bool
|
||||
*/
|
||||
public function removeIdentifiers(iterable $identifiers): bool;
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Grav\Framework\Contracts\Relationships;
|
||||
|
||||
use Grav\Framework\Contracts\Object\IdentifierInterface;
|
||||
|
||||
/**
|
||||
* Interface ToOneRelationshipInterface
|
||||
*
|
||||
* @template T of IdentifierInterface
|
||||
* @template P of IdentifierInterface
|
||||
* @template-extends RelationshipInterface<T,P>
|
||||
*/
|
||||
interface ToOneRelationshipInterface extends RelationshipInterface
|
||||
{
|
||||
/**
|
||||
* @param string|null $id
|
||||
* @param string|null $type
|
||||
* @return T|null
|
||||
* @phpstan-pure
|
||||
*/
|
||||
public function getIdentifier(string $id = null, string $type = null): ?IdentifierInterface;
|
||||
|
||||
/**
|
||||
* @param string|null $id
|
||||
* @param string|null $type
|
||||
* @return T|null
|
||||
* @phpstan-pure
|
||||
*/
|
||||
public function getObject(string $id = null, string $type = null): ?object;
|
||||
|
||||
/**
|
||||
* @param T|null $identifier
|
||||
* @return bool
|
||||
*/
|
||||
public function replaceIdentifier(IdentifierInterface $identifier = null): bool;
|
||||
}
|
||||
72
system/src/Grav/Framework/Flex/FlexIdentifier.php
Normal file
72
system/src/Grav/Framework/Flex/FlexIdentifier.php
Normal file
@@ -0,0 +1,72 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Grav\Framework\Flex;
|
||||
|
||||
use Grav\Common\Grav;
|
||||
use Grav\Framework\Flex\Interfaces\FlexObjectInterface;
|
||||
use Grav\Framework\Object\Identifiers\Identifier;
|
||||
use RuntimeException;
|
||||
|
||||
/**
|
||||
* Interface IdentifierInterface
|
||||
*
|
||||
* @template T of FlexObjectInterface
|
||||
*/
|
||||
class FlexIdentifier extends Identifier
|
||||
{
|
||||
private string $keyField;
|
||||
private ?FlexObjectInterface $object = null;
|
||||
|
||||
/**
|
||||
* @param FlexObjectInterface $object
|
||||
* @return FlexIdentifier
|
||||
*/
|
||||
public static function createFromObject(FlexObjectInterface $object): FlexIdentifier
|
||||
{
|
||||
$instance = new static($object->getKey(), $object->getFlexType(), 'key');
|
||||
$instance->setObject($object);
|
||||
|
||||
return $instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* IdentifierInterface constructor.
|
||||
* @param string $id
|
||||
* @param string $type
|
||||
* @param string $keyField
|
||||
*/
|
||||
public function __construct(string $id, string $type, string $keyField = 'key')
|
||||
{
|
||||
parent::__construct($id, $type);
|
||||
|
||||
$this->keyField = $keyField;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return T
|
||||
*/
|
||||
public function getObject(): ?FlexObjectInterface
|
||||
{
|
||||
if (!isset($this->object)) {
|
||||
/** @var Flex $flex */
|
||||
$flex = Grav::instance()['flex'];
|
||||
|
||||
$this->object = $flex->getObject($this->getId(), $this->getType(), $this->keyField);
|
||||
}
|
||||
|
||||
return $this->object;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param T $object
|
||||
*/
|
||||
public function setObject(FlexObjectInterface $object): void
|
||||
{
|
||||
$type = $this->getType();
|
||||
if ($type !== $object->getFlexType()) {
|
||||
throw new RuntimeException(sprintf('Object has to be type %s, %s given', $type, $object->getFlexType()));
|
||||
}
|
||||
|
||||
$this->object = $object;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Grav\Framework\Flex\Traits;
|
||||
|
||||
use Grav\Framework\Contracts\Relationships\RelationshipInterface;
|
||||
use Grav\Framework\Contracts\Relationships\RelationshipsInterface;
|
||||
use Grav\Framework\Flex\FlexIdentifier;
|
||||
use Grav\Framework\Relationships\Relationships;
|
||||
|
||||
trait FlexRelationshipsTrait
|
||||
{
|
||||
private ?RelationshipsInterface $_relationships = null;
|
||||
|
||||
/**
|
||||
* @return Relationships
|
||||
*/
|
||||
public function getRelationships(): Relationships
|
||||
{
|
||||
if (!isset($this->_relationships)) {
|
||||
$blueprint = $this->getBlueprint();
|
||||
$options = $blueprint->get('config/relationships', []);
|
||||
$parent = FlexIdentifier::createFromObject($this);
|
||||
|
||||
$this->_relationships = new Relationships($parent, $options);
|
||||
}
|
||||
|
||||
return $this->_relationships;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @return RelationshipInterface|null
|
||||
*/
|
||||
public function getRelationship(string $name): ?RelationshipInterface
|
||||
{
|
||||
return $this->getRelationships()[$name];
|
||||
}
|
||||
|
||||
protected function resetRelationships(): void
|
||||
{
|
||||
$this->_relationships = null;
|
||||
}
|
||||
}
|
||||
135
system/src/Grav/Framework/Media/MediaIdentifier.php
Normal file
135
system/src/Grav/Framework/Media/MediaIdentifier.php
Normal file
@@ -0,0 +1,135 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Grav\Framework\Media;
|
||||
|
||||
use Grav\Common\Grav;
|
||||
use Grav\Common\User\Interfaces\UserInterface;
|
||||
use Grav\Framework\Contracts\Media\MediaObjectInterface;
|
||||
use Grav\Framework\Flex\Flex;
|
||||
use Grav\Framework\Flex\FlexFormFlash;
|
||||
use Grav\Framework\Flex\Interfaces\FlexObjectInterface;
|
||||
use Grav\Framework\Object\Identifiers\Identifier;
|
||||
|
||||
/**
|
||||
* Interface IdentifierInterface
|
||||
*
|
||||
* @template T of MediaObjectInterface
|
||||
*/
|
||||
class MediaIdentifier extends Identifier
|
||||
{
|
||||
private ?MediaObjectInterface $object = null;
|
||||
|
||||
/**
|
||||
* @param MediaObjectInterface $object
|
||||
* @return MediaIdentifier
|
||||
*/
|
||||
public static function createFromObject(MediaObjectInterface $object): MediaIdentifier
|
||||
{
|
||||
$instance = new static($object->getId());
|
||||
$instance->setObject($object);
|
||||
|
||||
return $instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $id
|
||||
*/
|
||||
public function __construct(string $id)
|
||||
{
|
||||
parent::__construct($id, 'media');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return T
|
||||
*/
|
||||
public function getObject(): ?MediaObjectInterface
|
||||
{
|
||||
if (!isset($this->object)) {
|
||||
$type = $this->getType();
|
||||
$id = $this->getId();
|
||||
|
||||
$parts = explode('/', $id);
|
||||
if ($type === 'media' && str_starts_with($id, 'uploads/')) {
|
||||
array_shift($parts);
|
||||
$type = array_shift($parts);
|
||||
$uniqueId = array_shift($parts);
|
||||
$field = array_shift($parts);
|
||||
$filename = implode('/', $parts);
|
||||
|
||||
$flash = $this->getFlash($type, $uniqueId);
|
||||
if ($flash->exists()) {
|
||||
$uploadedFile = $flash->getFilesByField($field)[$filename] ?? null;
|
||||
|
||||
$this->object = new UploadedMediaObject($field, $filename, $flash, $uploadedFile);
|
||||
}
|
||||
} else {
|
||||
$type = array_shift($parts);
|
||||
$key = array_shift($parts);
|
||||
$field = array_shift($parts);
|
||||
$filename = implode('/', $parts);
|
||||
|
||||
$flexObject = $this->getFlexObject($type, $key);
|
||||
if ($flexObject && method_exists($flexObject, 'getMediaField') && method_exists($flexObject, 'getMedia')) {
|
||||
$media = $field !== 'media' ? $flexObject->getMediaField($field) : $flexObject->getMedia();
|
||||
$image = null;
|
||||
if ($media) {
|
||||
$image = $media[$filename];
|
||||
}
|
||||
|
||||
$this->object = new MediaObject($field, $filename, $image, $flexObject);
|
||||
}
|
||||
}
|
||||
|
||||
if (!isset($this->object)) {
|
||||
throw new \RuntimeException(sprintf('Object not found for identifier {type: "%s", id: "%s"}', $type, $id));
|
||||
}
|
||||
}
|
||||
|
||||
return $this->object;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param T $object
|
||||
*/
|
||||
public function setObject(MediaObjectInterface $object): void
|
||||
{
|
||||
$type = $this->getType();
|
||||
$objectType = $object->getType();
|
||||
|
||||
if ($type !== $objectType) {
|
||||
throw new \RuntimeException(sprintf('Object has to be type %s, %s given', $type, $objectType));
|
||||
}
|
||||
|
||||
$this->object = $object;
|
||||
}
|
||||
|
||||
protected function getFlash(string $type, string $uniqueId): FlexFormFlash
|
||||
{
|
||||
/** @var UserInterface|null $user */
|
||||
$user = Grav::instance()['user'] ?? null;
|
||||
if (null !== $user && $user->exists()) {
|
||||
// TODO: Modify uniqueid so we can detect if flash is user or session based.
|
||||
$mediaFolder = $user->getMediaFolder();
|
||||
} else {
|
||||
// TODO: Implement session based flash.
|
||||
throw new \RuntimeException('Not implemented');
|
||||
}
|
||||
|
||||
$folder = "{$mediaFolder}/tmp/api/flex-{$type}";
|
||||
|
||||
$config = [
|
||||
'unique_id' => $uniqueId,
|
||||
'folder' => $folder
|
||||
];
|
||||
|
||||
return new FlexFormFlash($config);
|
||||
}
|
||||
|
||||
protected function getFlexObject(string $type, string $key): ?FlexObjectInterface
|
||||
{
|
||||
/** @var Flex $flex */
|
||||
$flex = Grav::instance()['flex'];
|
||||
|
||||
return $flex->getObject($key, $type);
|
||||
}
|
||||
}
|
||||
210
system/src/Grav/Framework/Media/MediaObject.php
Normal file
210
system/src/Grav/Framework/Media/MediaObject.php
Normal file
@@ -0,0 +1,210 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Grav\Framework\Media;
|
||||
|
||||
use Grav\Common\Media\Interfaces\MediaObjectInterface as GravMediaObjectInterface;
|
||||
use Grav\Common\Page\Medium\ImageMedium;
|
||||
use Grav\Framework\Contracts\Media\MediaObjectInterface;
|
||||
use Grav\Framework\Flex\Interfaces\FlexObjectInterface;
|
||||
use Grav\Framework\Psr7\Response;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* Class MediaObject
|
||||
*/
|
||||
class MediaObject implements MediaObjectInterface
|
||||
{
|
||||
// FIXME:
|
||||
static public string $placeholderImage = 'theme://img/revkit-temp.svg';
|
||||
|
||||
public FlexObjectInterface $object;
|
||||
public ?GravMediaObjectInterface $media;
|
||||
|
||||
private ?string $field;
|
||||
private string $filename;
|
||||
|
||||
/**
|
||||
* MediaObject constructor.
|
||||
* @param string|null $field
|
||||
* @param string $filename
|
||||
* @param GravMediaObjectInterface|null $media
|
||||
* @param FlexObjectInterface $object
|
||||
*/
|
||||
public function __construct(?string $field, string $filename, ?GravMediaObjectInterface $media, FlexObjectInterface $object)
|
||||
{
|
||||
$this->field = $field;
|
||||
$this->filename = $filename;
|
||||
$this->media = $media;
|
||||
$this->object = $object;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getType(): string
|
||||
{
|
||||
return 'media';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getId(): string
|
||||
{
|
||||
$field = $this->field;
|
||||
$object = $this->object;
|
||||
$path = $field ? "/{$field}/" : '/media/';
|
||||
|
||||
return $object->getType() . '/' . $object->getKey() . $path . basename($this->filename);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function exists(): bool
|
||||
{
|
||||
return $this->media !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getMeta(): array
|
||||
{
|
||||
if (!isset($this->media)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return $this->media->getMeta();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $field
|
||||
* @return mixed|null
|
||||
*/
|
||||
public function get(string $field)
|
||||
{
|
||||
if (!isset($this->media)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->media->get($field);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getUrl(): string
|
||||
{
|
||||
if (!isset($this->media)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return $this->media->url();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create media response.
|
||||
*
|
||||
* @param array $actions
|
||||
* @return Response
|
||||
*/
|
||||
public function createResponse(array $actions): Response
|
||||
{
|
||||
if (!isset($this->media)) {
|
||||
return $this->create404Response($actions);
|
||||
}
|
||||
|
||||
$media = $this->media;
|
||||
|
||||
if ($actions) {
|
||||
$media = $this->processMediaActions($media, $actions);
|
||||
}
|
||||
|
||||
// FIXME: This only works for images
|
||||
if (!$media instanceof ImageMedium) {
|
||||
throw new \RuntimeException('Not Implemented', 500);
|
||||
}
|
||||
|
||||
$filename = $media->path(false);
|
||||
$time = filemtime($filename);
|
||||
$size = filesize($filename);
|
||||
$body = fopen($filename, 'rb');
|
||||
$headers = [
|
||||
'Content-Type' => $media->get('mime'),
|
||||
'Last-Modified' => gmdate('D, d M Y H:i:s', $time) . ' GMT',
|
||||
'ETag' => sprintf('%x-%x', $size, $time)
|
||||
];
|
||||
|
||||
return new Response(200, $headers, $body);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process media actions
|
||||
*
|
||||
* @param GravMediaObjectInterface $medium
|
||||
* @param array $actions
|
||||
* @return GravMediaObjectInterface
|
||||
*/
|
||||
protected function processMediaActions(GravMediaObjectInterface $medium, array $actions): GravMediaObjectInterface
|
||||
{
|
||||
// loop through actions for the image and call them
|
||||
foreach ($actions as $method => $params) {
|
||||
$matches = [];
|
||||
|
||||
if (preg_match('/\[(.*)]/', $params, $matches)) {
|
||||
$args = [explode(',', $matches[1])];
|
||||
} else {
|
||||
$args = explode(',', $params);
|
||||
}
|
||||
|
||||
try {
|
||||
$medium->{$method}(...$args);
|
||||
} catch (Throwable $e) {
|
||||
// Ignore all errors for now and just skip the action.
|
||||
}
|
||||
}
|
||||
|
||||
return $medium;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $actions
|
||||
* @return Response
|
||||
*/
|
||||
protected function create404Response(array $actions): Response
|
||||
{
|
||||
// Display placeholder image.
|
||||
$filename = static::$placeholderImage;
|
||||
|
||||
$time = filemtime($filename);
|
||||
$size = filesize($filename);
|
||||
$body = fopen($filename, 'rb');
|
||||
$headers = [
|
||||
'Content-Type' => 'image/svg',
|
||||
'Last-Modified' => gmdate('D, d M Y H:i:s', $time) . ' GMT',
|
||||
'ETag' => sprintf('%x-%x', $size, $time)
|
||||
];
|
||||
|
||||
return new Response(404, $headers, $body);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function jsonSerialize(): array
|
||||
{
|
||||
return [
|
||||
'type' => $this->getType(),
|
||||
'id' => $this->getId()
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function __debugInfo(): array
|
||||
{
|
||||
return $this->jsonSerialize();
|
||||
}
|
||||
}
|
||||
158
system/src/Grav/Framework/Media/UploadedMediaObject.php
Normal file
158
system/src/Grav/Framework/Media/UploadedMediaObject.php
Normal file
@@ -0,0 +1,158 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Grav\Framework\Media;
|
||||
|
||||
use Grav\Framework\Contracts\Media\MediaObjectInterface;
|
||||
use Grav\Framework\Flex\FlexFormFlash;
|
||||
use Grav\Framework\Form\Interfaces\FormFlashInterface;
|
||||
use Grav\Framework\Psr7\Response;
|
||||
use Psr\Http\Message\UploadedFileInterface;
|
||||
|
||||
/**
|
||||
* Class UploadedMediaObject
|
||||
*/
|
||||
class UploadedMediaObject implements MediaObjectInterface
|
||||
{
|
||||
// FIXME:
|
||||
static public string $placeholderImage = 'theme://img/revkit-temp.svg';
|
||||
|
||||
public FormFlashInterface $object;
|
||||
|
||||
private ?string $field;
|
||||
private string $filename;
|
||||
private array $meta;
|
||||
private ?UploadedFileInterface $uploadedFile;
|
||||
|
||||
/**
|
||||
* UploadedMediaObject constructor.
|
||||
* @param string|null $field
|
||||
* @param string $filename
|
||||
* @param FormFlashInterface $object
|
||||
* @param UploadedFileInterface|null $uploadedFile
|
||||
*/
|
||||
public function __construct(?string $field, string $filename, FormFlashInterface $object, ?UploadedFileInterface $uploadedFile = null)
|
||||
{
|
||||
$this->field = $field;
|
||||
$this->filename = $filename;
|
||||
$this->object = $object;
|
||||
$this->uploadedFile = $uploadedFile;
|
||||
if ($uploadedFile) {
|
||||
$this->meta = [
|
||||
'filename' => $uploadedFile->getClientFilename(),
|
||||
'mime' => $uploadedFile->getClientMediaType(),
|
||||
'size' => $uploadedFile->getSize()
|
||||
];
|
||||
} else {
|
||||
$this->meta = [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getType(): string
|
||||
{
|
||||
return 'media';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getId(): string
|
||||
{
|
||||
$field = $this->field;
|
||||
$object = $this->object;
|
||||
if ($object instanceof FlexFormFlash) {
|
||||
$type = $object->getObject()->getFlexType();
|
||||
} else {
|
||||
$type = 'undefined';
|
||||
}
|
||||
|
||||
$id = $type . '/' . $object->getUniqueId();
|
||||
$path = $field ? "/{$field}/" : '';
|
||||
|
||||
return 'uploads/' . $id . $path . basename($this->filename);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function exists(): bool
|
||||
{
|
||||
//return $this->uploadedFile !== null;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getMeta(): array
|
||||
{
|
||||
return $this->meta;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $field
|
||||
* @return mixed|null
|
||||
*/
|
||||
public function get(string $field)
|
||||
{
|
||||
return $this->meta[$field] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getUrl(): string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return UploadedFileInterface|null
|
||||
*/
|
||||
public function getUploadedFile(): ?UploadedFileInterface
|
||||
{
|
||||
return $this->uploadedFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $actions
|
||||
* @return Response
|
||||
*/
|
||||
public function createResponse(array $actions): Response
|
||||
{
|
||||
// Display placeholder image.
|
||||
$filename = static::$placeholderImage;
|
||||
|
||||
$time = filemtime($filename);
|
||||
$size = filesize($filename);
|
||||
$body = fopen($filename, 'rb');
|
||||
$headers = [
|
||||
'Content-Type' => 'image/svg',
|
||||
'Last-Modified' => gmdate('D, d M Y H:i:s', $time) . ' GMT',
|
||||
'ETag' => sprintf('%x-%x', $size, $time)
|
||||
];
|
||||
|
||||
return new Response(404, $headers, $body);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function jsonSerialize(): array
|
||||
{
|
||||
return [
|
||||
'type' => $this->getType(),
|
||||
'id' => $this->getId()
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function __debugInfo(): array
|
||||
{
|
||||
return $this->jsonSerialize();
|
||||
}
|
||||
}
|
||||
64
system/src/Grav/Framework/Object/Identifiers/Identifier.php
Normal file
64
system/src/Grav/Framework/Object/Identifiers/Identifier.php
Normal file
@@ -0,0 +1,64 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Grav\Framework\Object\Identifiers;
|
||||
|
||||
use Grav\Framework\Contracts\Object\IdentifierInterface;
|
||||
|
||||
/**
|
||||
* Interface IdentifierInterface
|
||||
*
|
||||
* @template T of object
|
||||
*/
|
||||
class Identifier implements IdentifierInterface
|
||||
{
|
||||
private string $id;
|
||||
private string $type;
|
||||
|
||||
/**
|
||||
* IdentifierInterface constructor.
|
||||
* @param string $id
|
||||
* @param string $type
|
||||
*/
|
||||
public function __construct(string $id, string $type)
|
||||
{
|
||||
$this->id = $id;
|
||||
$this->type = $type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
* @phpstan-pure
|
||||
*/
|
||||
public function getId(): string
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
* @phpstan-pure
|
||||
*/
|
||||
public function getType(): string
|
||||
{
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function jsonSerialize(): array
|
||||
{
|
||||
return [
|
||||
'type' => $this->type,
|
||||
'id' => $this->id
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function __debugInfo(): array
|
||||
{
|
||||
return $this->jsonSerialize();
|
||||
}
|
||||
}
|
||||
211
system/src/Grav/Framework/Relationships/Relationships.php
Normal file
211
system/src/Grav/Framework/Relationships/Relationships.php
Normal file
@@ -0,0 +1,211 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Grav\Framework\Relationships;
|
||||
|
||||
use Grav\Framework\Contracts\Object\IdentifierInterface;
|
||||
use Grav\Framework\Contracts\Relationships\RelationshipInterface;
|
||||
use Grav\Framework\Contracts\Relationships\RelationshipsInterface;
|
||||
use Grav\Framework\Flex\FlexIdentifier;
|
||||
use RuntimeException;
|
||||
use function count;
|
||||
|
||||
/**
|
||||
* Class Relationships
|
||||
*/
|
||||
class Relationships implements RelationshipsInterface
|
||||
{
|
||||
protected IdentifierInterface $parent;
|
||||
protected array $options;
|
||||
|
||||
/** @var RelationshipInterface[] */
|
||||
protected array $relationships;
|
||||
|
||||
/**
|
||||
* Relationships constructor.
|
||||
* @param IdentifierInterface $parent
|
||||
* @param array $options
|
||||
*/
|
||||
public function __construct(IdentifierInterface $parent, array $options)
|
||||
{
|
||||
$this->parent = $parent;
|
||||
$this->options = $options;
|
||||
$this->relationships = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
* @phpstan-pure
|
||||
*/
|
||||
public function isModified(): bool
|
||||
{
|
||||
return !empty($this->getModified());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return RelationshipInterface[]
|
||||
* @phpstan-pure
|
||||
*/
|
||||
public function getModified(): array
|
||||
{
|
||||
$list = [];
|
||||
foreach ($this->relationships as $name => $relationship) {
|
||||
if ($relationship->isModified()) {
|
||||
$list[$name] = $relationship;
|
||||
}
|
||||
}
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
* @phpstan-pure
|
||||
*/
|
||||
public function count(): int
|
||||
{
|
||||
return count($this->options);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $offset
|
||||
* @return bool
|
||||
* @phpstan-pure
|
||||
*/
|
||||
public function offsetExists($offset): bool
|
||||
{
|
||||
return isset($this->options[$offset]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $offset
|
||||
* @return RelationshipInterface|null
|
||||
*/
|
||||
public function offsetGet($offset): ?RelationshipInterface
|
||||
{
|
||||
if (!isset($this->relationships[$offset])) {
|
||||
$options = $this->options[$offset] ?? null;
|
||||
if (null === $options) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$this->relationships[$offset] = $this->createRelationship($offset, $options);
|
||||
}
|
||||
|
||||
return $this->relationships[$offset];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $offset
|
||||
* @param mixed $value
|
||||
* @return never-return
|
||||
*/
|
||||
public function offsetSet($offset, $value)
|
||||
{
|
||||
throw new RuntimeException('Setting relationship is not supported', 500);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $offset
|
||||
* @return never-return
|
||||
*/
|
||||
public function offsetUnset($offset)
|
||||
{
|
||||
throw new RuntimeException('Removing relationship is not allowed', 500);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return RelationshipInterface|null
|
||||
*/
|
||||
public function current(): ?RelationshipInterface
|
||||
{
|
||||
$name = key($this->options);
|
||||
if ($name === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->offsetGet($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
* @phpstan-pure
|
||||
*/
|
||||
public function key(): string
|
||||
{
|
||||
return key($this->options);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
* @phpstan-pure
|
||||
*/
|
||||
public function next(): void
|
||||
{
|
||||
next($this->options);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
* @phpstan-pure
|
||||
*/
|
||||
public function rewind(): void
|
||||
{
|
||||
reset($this->options);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
* @phpstan-pure
|
||||
*/
|
||||
public function valid(): bool
|
||||
{
|
||||
return key($this->options) !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function jsonSerialize(): array
|
||||
{
|
||||
$list = [];
|
||||
foreach ($this as $name => $relationship) {
|
||||
$list[$name] = $relationship->jsonSerialize();
|
||||
}
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param array $options
|
||||
* @return RelationshipInterface
|
||||
*/
|
||||
private function createRelationship(string $name, array $options): RelationshipInterface
|
||||
{
|
||||
$data = null;
|
||||
|
||||
$parent = $this->parent;
|
||||
if ($parent instanceof FlexIdentifier) {
|
||||
$object = $parent->getObject();
|
||||
if (!method_exists($object, 'initRelationship')) {
|
||||
throw new RuntimeException(sprintf('Bad relationship %s', $name), 500);
|
||||
}
|
||||
|
||||
$data = $object->initRelationship($name);
|
||||
}
|
||||
|
||||
$cardinality = $options['cardinality'] ?? '';
|
||||
switch ($cardinality) {
|
||||
case 'to-one':
|
||||
$relationship = new ToOneRelationship($parent, $name, $options, $data);
|
||||
break;
|
||||
case 'to-many':
|
||||
$relationship = new ToManyRelationship($parent, $name, $options, $data ?? []);
|
||||
break;
|
||||
default:
|
||||
throw new RuntimeException(sprintf('Bad relationship cardinality %s', $cardinality), 500);
|
||||
}
|
||||
|
||||
return $relationship;
|
||||
}
|
||||
}
|
||||
244
system/src/Grav/Framework/Relationships/ToManyRelationship.php
Normal file
244
system/src/Grav/Framework/Relationships/ToManyRelationship.php
Normal file
@@ -0,0 +1,244 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Grav\Framework\Relationships;
|
||||
|
||||
use ArrayIterator;
|
||||
use Grav\Framework\Compat\Serializable;
|
||||
use Grav\Framework\Contracts\Object\IdentifierInterface;
|
||||
use Grav\Framework\Contracts\Relationships\ToManyRelationshipInterface;
|
||||
use Grav\Framework\Relationships\Traits\RelationshipTrait;
|
||||
use function count;
|
||||
use function is_callable;
|
||||
|
||||
/**
|
||||
* Class ToManyRelationship
|
||||
*
|
||||
* @template T of object
|
||||
* @template P of object
|
||||
* @template-implements ToManyRelationshipInterface<IdentifierInterface,IdentifierInterface>
|
||||
*/
|
||||
class ToManyRelationship implements ToManyRelationshipInterface
|
||||
{
|
||||
/** @template-use RelationshipTrait<T> */
|
||||
use RelationshipTrait;
|
||||
use Serializable;
|
||||
|
||||
/** @var IdentifierInterface[] */
|
||||
protected array $identifiers = [];
|
||||
|
||||
/**
|
||||
* ToManyRelationship constructor.
|
||||
* @param string $name
|
||||
* @param IdentifierInterface $parent
|
||||
* @param iterable<IdentifierInterface> $identifiers
|
||||
*/
|
||||
public function __construct(IdentifierInterface $parent, string $name, array $options, iterable $identifiers = [])
|
||||
{
|
||||
$this->parent = $parent;
|
||||
$this->name = $name;
|
||||
|
||||
$this->parseOptions($options);
|
||||
$this->addIdentifiers($identifiers);
|
||||
|
||||
$this->modified = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
* @phpstan-pure
|
||||
*/
|
||||
public function getCardinality(): string
|
||||
{
|
||||
return 'to-many';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
* @phpstan-pure
|
||||
*/
|
||||
public function count(): int
|
||||
{
|
||||
return count($this->identifiers);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function fetch(): array
|
||||
{
|
||||
$list = [];
|
||||
foreach ($this->identifiers as $identifier) {
|
||||
if (is_callable([$identifier, 'getObject'])) {
|
||||
$identifier = $identifier->getObject();
|
||||
}
|
||||
$list[] = $identifier;
|
||||
}
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $id
|
||||
* @param string|null $type
|
||||
* @return bool
|
||||
* @phpstan-pure
|
||||
*/
|
||||
public function has(string $id, string $type = null): bool
|
||||
{
|
||||
return $this->getIdentifier($id, $type) !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $id
|
||||
* @param string|null $type
|
||||
* @return IdentifierInterface|null
|
||||
* @phpstan-pure
|
||||
*/
|
||||
public function getIdentifier(string $id, string $type = null): ?IdentifierInterface
|
||||
{
|
||||
if (null === $type) {
|
||||
$type = $this->getType();
|
||||
}
|
||||
|
||||
if ($type === 'media' && !str_contains($id, '/')) {
|
||||
$name = $this->name;
|
||||
$id = $this->parent->getType() . '/' . $this->parent->getId() . '/'. $name . '/' . $id;
|
||||
}
|
||||
|
||||
$key = "{$type}/{$id}";
|
||||
|
||||
return $this->identifiers[$key] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $id
|
||||
* @param string|null $type
|
||||
* @return T|null
|
||||
*/
|
||||
public function getObject(string $id, string $type = null): ?object
|
||||
{
|
||||
$identifier = $this->getIdentifier($id, $type);
|
||||
if ($identifier && is_callable([$identifier, 'getObject'])) {
|
||||
$identifier = $identifier->getObject();
|
||||
}
|
||||
|
||||
return $identifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param IdentifierInterface $identifier
|
||||
* @return bool
|
||||
*/
|
||||
public function addIdentifier(IdentifierInterface $identifier): bool
|
||||
{
|
||||
return $this->addIdentifiers([$identifier]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param IdentifierInterface|null $identifier
|
||||
* @return bool
|
||||
*/
|
||||
public function removeIdentifier(IdentifierInterface $identifier = null): bool
|
||||
{
|
||||
return !$identifier || $this->removeIdentifiers([$identifier]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param iterable<IdentifierInterface> $identifiers
|
||||
* @return bool
|
||||
*/
|
||||
public function addIdentifiers(iterable $identifiers): bool
|
||||
{
|
||||
foreach ($identifiers as $identifier) {
|
||||
$type = $identifier->getType();
|
||||
$id = $identifier->getId();
|
||||
$key = "{$type}/{$id}";
|
||||
|
||||
$this->identifiers[$key] = $this->checkIdentifier($identifier);
|
||||
$this->modified = true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param iterable<IdentifierInterface> $identifiers
|
||||
* @return bool
|
||||
*/
|
||||
public function replaceIdentifiers(iterable $identifiers): bool
|
||||
{
|
||||
$this->identifiers = [];
|
||||
$this->modified = true;
|
||||
|
||||
return $this->addIdentifiers($identifiers);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param iterable<IdentifierInterface> $identifiers
|
||||
* @return bool
|
||||
*/
|
||||
public function removeIdentifiers(iterable $identifiers): bool
|
||||
{
|
||||
foreach ($identifiers as $identifier) {
|
||||
$type = $identifier->getType();
|
||||
$id = $identifier->getId();
|
||||
$key = "{$type}/{$id}";
|
||||
|
||||
unset($this->identifiers[$key]);
|
||||
$this->modified = true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return iterable<IdentifierInterface>
|
||||
* @phpstan-pure
|
||||
*/
|
||||
public function getIterator(): iterable
|
||||
{
|
||||
return new ArrayIterator($this->identifiers);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function jsonSerialize(): array
|
||||
{
|
||||
$list = [];
|
||||
foreach ($this->getIterator() as $item) {
|
||||
$list[] = $item->jsonSerialize();
|
||||
}
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function __serialize(): array
|
||||
{
|
||||
return [
|
||||
'parent' => $this->parent,
|
||||
'name' => $this->name,
|
||||
'type' => $this->type,
|
||||
'options' => $this->options,
|
||||
'modified' => $this->modified,
|
||||
'identifiers' => $this->identifiers,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @return void
|
||||
*/
|
||||
public function __unserialize(array $data): void
|
||||
{
|
||||
$this->parent = $data['parent'];
|
||||
$this->name = $data['name'];
|
||||
$this->type = $data['type'];
|
||||
$this->options = $data['options'];
|
||||
$this->modified = $data['modified'];
|
||||
$this->identifiers = $data['identifiers'];
|
||||
}
|
||||
}
|
||||
205
system/src/Grav/Framework/Relationships/ToOneRelationship.php
Normal file
205
system/src/Grav/Framework/Relationships/ToOneRelationship.php
Normal file
@@ -0,0 +1,205 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Grav\Framework\Relationships;
|
||||
|
||||
use ArrayIterator;
|
||||
use Grav\Framework\Compat\Serializable;
|
||||
use Grav\Framework\Contracts\Object\IdentifierInterface;
|
||||
use Grav\Framework\Contracts\Relationships\ToOneRelationshipInterface;
|
||||
use Grav\Framework\Relationships\Traits\RelationshipTrait;
|
||||
use function is_callable;
|
||||
|
||||
/**
|
||||
* Class ToOneRelationship
|
||||
*
|
||||
* @template T of object
|
||||
* @template-implements ToOneRelationshipInterface<IdentifierInterface,IdentifierInterface>
|
||||
*/
|
||||
class ToOneRelationship implements ToOneRelationshipInterface
|
||||
{
|
||||
/** @template-use RelationshipTrait<T> */
|
||||
use RelationshipTrait;
|
||||
use Serializable;
|
||||
|
||||
protected ?IdentifierInterface $identifier = null;
|
||||
|
||||
public function __construct(IdentifierInterface $parent, string $name, array $options, IdentifierInterface $identifier = null)
|
||||
{
|
||||
$this->parent = $parent;
|
||||
$this->name = $name;
|
||||
|
||||
$this->parseOptions($options);
|
||||
$this->replaceIdentifier($identifier);
|
||||
|
||||
$this->modified = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
* @phpstan-pure
|
||||
*/
|
||||
public function getCardinality(): string
|
||||
{
|
||||
return 'to-one';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
* @phpstan-pure
|
||||
*/
|
||||
public function count(): int
|
||||
{
|
||||
return $this->identifier ? 1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return object|null
|
||||
*/
|
||||
public function fetch(): ?object
|
||||
{
|
||||
$identifier = $this->identifier;
|
||||
if (is_callable([$identifier, 'getObject'])) {
|
||||
$identifier = $identifier->getObject();
|
||||
}
|
||||
|
||||
return $identifier;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string|null $id
|
||||
* @param string|null $type
|
||||
* @return bool
|
||||
* @phpstan-pure
|
||||
*/
|
||||
public function has(string $id = null, string $type = null): bool
|
||||
{
|
||||
return $this->getIdentifier($id, $type) !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|null $id
|
||||
* @param string|null $type
|
||||
* @return IdentifierInterface|null
|
||||
* @phpstan-pure
|
||||
*/
|
||||
public function getIdentifier(string $id = null, string $type = null): ?IdentifierInterface
|
||||
{
|
||||
if ($id && $this->getType() === 'media' && !str_contains($id, '/')) {
|
||||
$name = $this->name;
|
||||
$id = $this->parent->getType() . '/' . $this->parent->getId() . '/'. $name . '/' . $id;
|
||||
}
|
||||
|
||||
$identifier = $this->identifier ?? null;
|
||||
if (null === $identifier || ($type && $type !== $identifier->getType()) || ($id && $id !== $identifier->getId())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $identifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|null $id
|
||||
* @param string|null $type
|
||||
* @return T|null
|
||||
*/
|
||||
public function getObject(string $id = null, string $type = null): ?object
|
||||
{
|
||||
$identifier = $this->getIdentifier($id, $type);
|
||||
if ($identifier && is_callable([$identifier, 'getObject'])) {
|
||||
$identifier = $identifier->getObject();
|
||||
}
|
||||
|
||||
return $identifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param IdentifierInterface $identifier
|
||||
* @return bool
|
||||
*/
|
||||
public function addIdentifier(IdentifierInterface $identifier): bool
|
||||
{
|
||||
$this->identifier = $this->checkIdentifier($identifier);
|
||||
$this->modified = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param IdentifierInterface|null $identifier
|
||||
* @return bool
|
||||
*/
|
||||
public function replaceIdentifier(IdentifierInterface $identifier = null): bool
|
||||
{
|
||||
if ($identifier === null) {
|
||||
$this->identifier = null;
|
||||
$this->modified = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return $this->addIdentifier($identifier);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param IdentifierInterface|null $identifier
|
||||
* @return bool
|
||||
*/
|
||||
public function removeIdentifier(IdentifierInterface $identifier = null): bool
|
||||
{
|
||||
if (null === $identifier || $this->has($identifier->getId(), $identifier->getType())) {
|
||||
$this->identifier = null;
|
||||
$this->modified = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return iterable<IdentifierInterface>
|
||||
* @phpstan-pure
|
||||
*/
|
||||
public function getIterator(): iterable
|
||||
{
|
||||
return new ArrayIterator((array)$this->identifier);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array|null
|
||||
*/
|
||||
public function jsonSerialize(): ?array
|
||||
{
|
||||
return $this->identifier ? $this->identifier->jsonSerialize() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function __serialize(): array
|
||||
{
|
||||
return [
|
||||
'parent' => $this->parent,
|
||||
'name' => $this->name,
|
||||
'type' => $this->type,
|
||||
'options' => $this->options,
|
||||
'modified' => $this->modified,
|
||||
'identifier' => $this->identifier,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @return void
|
||||
*/
|
||||
public function __unserialize(array $data): void
|
||||
{
|
||||
$this->parent = $data['parent'];
|
||||
$this->name = $data['name'];
|
||||
$this->type = $data['type'];
|
||||
$this->options = $data['options'];
|
||||
$this->modified = $data['modified'];
|
||||
$this->identifier = $data['identifier'];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Grav\Framework\Relationships\Traits;
|
||||
|
||||
use Grav\Framework\Contracts\Object\IdentifierInterface;
|
||||
use Grav\Framework\Flex\FlexIdentifier;
|
||||
use Grav\Framework\Media\MediaIdentifier;
|
||||
use Grav\Framework\Object\Identifiers\Identifier;
|
||||
use function get_class;
|
||||
|
||||
/**
|
||||
* Trait RelationshipTrait
|
||||
*
|
||||
* @template T of object
|
||||
*/
|
||||
trait RelationshipTrait
|
||||
{
|
||||
protected IdentifierInterface $parent;
|
||||
protected string $name;
|
||||
protected string $type;
|
||||
protected array $options;
|
||||
protected bool $modified = false;
|
||||
|
||||
/**
|
||||
* @return string
|
||||
* @phpstan-pure
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
* @phpstan-pure
|
||||
*/
|
||||
public function getType(): string
|
||||
{
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
* @phpstan-pure
|
||||
*/
|
||||
public function isModified(): bool
|
||||
{
|
||||
return $this->modified;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return IdentifierInterface
|
||||
* @phpstan-pure
|
||||
*/
|
||||
public function getParent(): IdentifierInterface
|
||||
{
|
||||
return $this->parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param IdentifierInterface $identifier
|
||||
* @return bool
|
||||
* @phpstan-pure
|
||||
*/
|
||||
public function hasIdentifier(IdentifierInterface $identifier): bool
|
||||
{
|
||||
return $this->getIdentifier($identifier->getId(), $identifier->getType()) !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
* @phpstan-pure
|
||||
*/
|
||||
abstract public function count(): int;
|
||||
|
||||
/**
|
||||
* @return void
|
||||
* @phpstan-pure
|
||||
*/
|
||||
public function check(): void
|
||||
{
|
||||
$min = $this->options['min'] ?? 0;
|
||||
$max = $this->options['max'] ?? 0;
|
||||
|
||||
if ($min || $max) {
|
||||
$count = $this->count();
|
||||
if ($min && $count < $min) {
|
||||
throw new \RuntimeException(sprintf('%s relationship has too few objects in it', $this->name));
|
||||
}
|
||||
if ($max && $count > $max) {
|
||||
throw new \RuntimeException(sprintf('%s relationship has too many objects in it', $this->name));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param IdentifierInterface $identifier
|
||||
* @return IdentifierInterface
|
||||
*/
|
||||
private function checkIdentifier(IdentifierInterface $identifier): IdentifierInterface
|
||||
{
|
||||
if ($this->type !== $identifier->getType()) {
|
||||
throw new \RuntimeException(sprintf('Bad identifier type %s', $identifier->getType()));
|
||||
}
|
||||
|
||||
if (get_class($identifier) !== Identifier::class) {
|
||||
return $identifier;
|
||||
}
|
||||
|
||||
if ($this->type === 'media') {
|
||||
return new MediaIdentifier($identifier->getId());
|
||||
}
|
||||
|
||||
return new FlexIdentifier($identifier->getId(), $identifier->getType());
|
||||
}
|
||||
|
||||
private function parseOptions(array $options): void
|
||||
{
|
||||
$this->type = $options['type'];
|
||||
$this->options = $options;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user