PageRenderTime 1270ms CodeModel.GetById 2ms RepoModel.GetById 0ms app.codeStats 0ms

/src/IndexedModel.php

https://gitlab.com/pomirleanu.florentin/Elodex
PHP | 260 lines | 118 code | 42 blank | 100 comment | 8 complexity | d4fc464fddd47c0dcc69ae2be4c2c46e MD5 | raw file
  1. <?php
  2. namespace Elodex;
  3. use Elodex\Contracts\IndexedDocument;
  4. use Illuminate\Support\Str;
  5. use Illuminate\Contracts\Support\Arrayable;
  6. trait IndexedModel
  7. {
  8. use IndexManagement,
  9. IndexRepositoryAccess;
  10. /**
  11. * The relationships that should be added to the index document.
  12. *
  13. * @var array
  14. */
  15. protected $indexRelations = [];
  16. /**
  17. * The version of the model's document in the index.
  18. *
  19. * @var int|null
  20. */
  21. protected $indexVersion;
  22. /**
  23. * The index score of the model as a result of an index search.
  24. *
  25. * @var float|null
  26. */
  27. protected $indexScore;
  28. /**
  29. * {@inheritdoc}
  30. */
  31. public function getIndexTypeName()
  32. {
  33. return $this->getTable();
  34. }
  35. /**
  36. * {@inheritdoc}
  37. */
  38. public function getIndexKey()
  39. {
  40. return $this->getKey();
  41. }
  42. /**
  43. * {@inheritdoc}
  44. */
  45. public function getIndexRelations()
  46. {
  47. return $this->indexRelations;
  48. }
  49. /**
  50. * {@inheritdoc}
  51. */
  52. public function toIndexDocument()
  53. {
  54. // Temporarily disable all whitelisting and blacklisting for relations.
  55. $visible = $this->getVisible();
  56. $hidden = $this->getHidden();
  57. $this->hideNonIndexRelations();
  58. // Load all needed relations for the index document.
  59. $this->loadIndexRelations();
  60. // Convert the model to a document representation.
  61. $document = array_merge($this->attributesToArray(), $this->indexRelationsDocuments());
  62. // Restore whitelist and blacklist properties.
  63. $this->setHidden($hidden);
  64. $this->setVisible($visible);
  65. return $document;
  66. }
  67. /**
  68. * Get an array of documents for the index relations.
  69. *
  70. * @return array
  71. */
  72. public function indexRelationsDocuments()
  73. {
  74. $documents = [];
  75. foreach ($this->indexRelations as $relation) {
  76. $related = $this->relations[$relation];
  77. // Check if the related instance implements the indexed document
  78. // interface to create a document representation.
  79. if ($related instanceof IndexedDocument) {
  80. $document = $related->toIndexDocument();
  81. }
  82. // Fallback to the Arrayable interface and its toArray method.
  83. elseif ($related instanceof Arrayable) {
  84. $document = $related->toArray();
  85. }
  86. // If the value is null, we'll still go ahead and set it in this list of
  87. // attributes since null is used to represent empty relationships if
  88. // if it a has one or belongs to type relationships on the models.
  89. elseif (is_null($related)) {
  90. $document = $related;
  91. }
  92. // Make sure the relation name is snake-cased if needed.
  93. if (static::$snakeAttributes) {
  94. $relation = Str::snake($relation);
  95. }
  96. if (isset($relation) || is_null($related)) {
  97. $documents[$relation] = $document;
  98. }
  99. unset($document);
  100. }
  101. return $documents;
  102. }
  103. /**
  104. * {@inheritdoc}
  105. */
  106. public function getChangedIndexDocument()
  107. {
  108. // Note that indexed relations are only loaded for complete documents,
  109. // there's no reliable way to know which relations might have changed.
  110. // Check which attributes are marked as 'dirty'.
  111. $dirtyAttributes = array_keys($this->getDirty());
  112. if (empty($dirtyAttributes)) {
  113. return [];
  114. }
  115. // Use temporary whitelisting to exclude all attributes that have not changed.
  116. $visible = $this->getVisible();
  117. $this->setVisible($dirtyAttributes);
  118. // Convert the dirty attributes to an array.
  119. // Note that no relationships are being included here since there's no
  120. // tight binding between related models and their parents.
  121. $document = $this->attributesToArray();
  122. // Restore the visible attributes on the model.
  123. $this->setVisible($visible);
  124. return $document;
  125. }
  126. /**
  127. * Set the index document version.
  128. *
  129. * @param int $version
  130. * @return $this
  131. */
  132. public function setIndexVersion($version)
  133. {
  134. $this->indexVersion = $version;
  135. return $this;
  136. }
  137. /**
  138. * Get the index document version.
  139. *
  140. * @return int|null
  141. */
  142. public function getIndexVersion()
  143. {
  144. return $this->indexVersion;
  145. }
  146. /**
  147. * Set the index score of the model.
  148. *
  149. * @param float $score
  150. * @return $this
  151. */
  152. public function setIndexScore($score)
  153. {
  154. $this->indexScore = $score;
  155. return $this;
  156. }
  157. /**
  158. * Get the index score of the model.
  159. *
  160. * @return float|null
  161. */
  162. public function getIndexScore()
  163. {
  164. return $this->indexScore;
  165. }
  166. /**
  167. * {@inheritdoc}
  168. */
  169. public function canAddToIndex()
  170. {
  171. return $this->exists;
  172. }
  173. /**
  174. * Hides all relations which are not meant to be part of the indexed document.
  175. *
  176. * @return void
  177. */
  178. protected function hideNonIndexRelations()
  179. {
  180. // Make sure all relations which may have been loaded and which
  181. // shouldn't be added to the document are being hidden.
  182. $loadedRelations = array_keys($this->relations);
  183. $hiddenRelations = array_diff($loadedRelations, $this->indexRelations);
  184. if (empty($hiddenRelations)) {
  185. return;
  186. }
  187. // Remove all visible non-indexed relations from the whitelist.
  188. $visible = $this->getVisible();
  189. if (count($visible) > 0) {
  190. $this->setVisible(array_diff($visible, $hiddenRelations));
  191. return;
  192. }
  193. // Add the non-indexed relations to the blacklist.
  194. $this->addHidden($hiddenRelations);
  195. }
  196. /**
  197. * Load all relations relevant for the indexed document.
  198. *
  199. * @return void
  200. */
  201. protected function loadIndexRelations()
  202. {
  203. // Do not load any index relations if the indicating property is null on
  204. // the model instance. This does give subclasses the opportunity to disable
  205. // this functionality without having to override the method.
  206. if (! empty($this->indexRelations)) {
  207. // Don't load already loaded relations
  208. $this->load(array_diff($this->indexRelations, array_keys($this->relations)));
  209. }
  210. }
  211. /**
  212. * {@inheritdoc}
  213. */
  214. public function newCollection(array $models = [])
  215. {
  216. return new Collection($models);
  217. }
  218. }