ToOneRelationship.php 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. <?php declare(strict_types=1);
  2. namespace Grav\Framework\Relationships;
  3. use ArrayIterator;
  4. use Grav\Framework\Compat\Serializable;
  5. use Grav\Framework\Contracts\Object\IdentifierInterface;
  6. use Grav\Framework\Contracts\Relationships\ToOneRelationshipInterface;
  7. use Grav\Framework\Relationships\Traits\RelationshipTrait;
  8. use function is_callable;
  9. /**
  10. * Class ToOneRelationship
  11. *
  12. * @template T of IdentifierInterface
  13. * @template P of IdentifierInterface
  14. * @template-implements ToOneRelationshipInterface<T,P>
  15. */
  16. class ToOneRelationship implements ToOneRelationshipInterface
  17. {
  18. /** @template-use RelationshipTrait<T> */
  19. use RelationshipTrait;
  20. use Serializable;
  21. /** @var IdentifierInterface|null */
  22. protected $identifier = null;
  23. public function __construct(IdentifierInterface $parent, string $name, array $options, IdentifierInterface $identifier = null)
  24. {
  25. $this->parent = $parent;
  26. $this->name = $name;
  27. $this->parseOptions($options);
  28. $this->replaceIdentifier($identifier);
  29. $this->modified = false;
  30. }
  31. /**
  32. * @return string
  33. * @phpstan-pure
  34. */
  35. public function getCardinality(): string
  36. {
  37. return 'to-one';
  38. }
  39. /**
  40. * @return int
  41. * @phpstan-pure
  42. */
  43. public function count(): int
  44. {
  45. return $this->identifier ? 1 : 0;
  46. }
  47. /**
  48. * @return object|null
  49. */
  50. public function fetch(): ?object
  51. {
  52. $identifier = $this->identifier;
  53. if (is_callable([$identifier, 'getObject'])) {
  54. $identifier = $identifier->getObject();
  55. }
  56. return $identifier;
  57. }
  58. /**
  59. * @param string|null $id
  60. * @param string|null $type
  61. * @return bool
  62. * @phpstan-pure
  63. */
  64. public function has(string $id = null, string $type = null): bool
  65. {
  66. return $this->getIdentifier($id, $type) !== null;
  67. }
  68. /**
  69. * @param string|null $id
  70. * @param string|null $type
  71. * @return IdentifierInterface|null
  72. * @phpstan-pure
  73. */
  74. public function getIdentifier(string $id = null, string $type = null): ?IdentifierInterface
  75. {
  76. if ($id && $this->getType() === 'media' && !str_contains($id, '/')) {
  77. $name = $this->name;
  78. $id = $this->parent->getType() . '/' . $this->parent->getId() . '/'. $name . '/' . $id;
  79. }
  80. $identifier = $this->identifier ?? null;
  81. if (null === $identifier || ($type && $type !== $identifier->getType()) || ($id && $id !== $identifier->getId())) {
  82. return null;
  83. }
  84. return $identifier;
  85. }
  86. /**
  87. * @param string|null $id
  88. * @param string|null $type
  89. * @return T|null
  90. */
  91. public function getObject(string $id = null, string $type = null): ?object
  92. {
  93. $identifier = $this->getIdentifier($id, $type);
  94. if ($identifier && is_callable([$identifier, 'getObject'])) {
  95. $identifier = $identifier->getObject();
  96. }
  97. return $identifier;
  98. }
  99. /**
  100. * @param IdentifierInterface $identifier
  101. * @return bool
  102. */
  103. public function addIdentifier(IdentifierInterface $identifier): bool
  104. {
  105. $this->identifier = $this->checkIdentifier($identifier);
  106. $this->modified = true;
  107. return true;
  108. }
  109. /**
  110. * @param IdentifierInterface|null $identifier
  111. * @return bool
  112. */
  113. public function replaceIdentifier(IdentifierInterface $identifier = null): bool
  114. {
  115. if ($identifier === null) {
  116. $this->identifier = null;
  117. $this->modified = true;
  118. return true;
  119. }
  120. return $this->addIdentifier($identifier);
  121. }
  122. /**
  123. * @param IdentifierInterface|null $identifier
  124. * @return bool
  125. */
  126. public function removeIdentifier(IdentifierInterface $identifier = null): bool
  127. {
  128. if (null === $identifier || $this->has($identifier->getId(), $identifier->getType())) {
  129. $this->identifier = null;
  130. $this->modified = true;
  131. return true;
  132. }
  133. return false;
  134. }
  135. /**
  136. * @return iterable<IdentifierInterface>
  137. * @phpstan-pure
  138. */
  139. public function getIterator(): iterable
  140. {
  141. return new ArrayIterator((array)$this->identifier);
  142. }
  143. /**
  144. * @return array|null
  145. */
  146. public function jsonSerialize(): ?array
  147. {
  148. return $this->identifier ? $this->identifier->jsonSerialize() : null;
  149. }
  150. /**
  151. * @return array
  152. */
  153. public function __serialize(): array
  154. {
  155. return [
  156. 'parent' => $this->parent,
  157. 'name' => $this->name,
  158. 'type' => $this->type,
  159. 'options' => $this->options,
  160. 'modified' => $this->modified,
  161. 'identifier' => $this->identifier,
  162. ];
  163. }
  164. /**
  165. * @param array $data
  166. * @return void
  167. */
  168. public function __unserialize(array $data): void
  169. {
  170. $this->parent = $data['parent'];
  171. $this->name = $data['name'];
  172. $this->type = $data['type'];
  173. $this->options = $data['options'];
  174. $this->modified = $data['modified'];
  175. $this->identifier = $data['identifier'];
  176. }
  177. }