PageRenderTime 22ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/concrete/src/Attribute/Category/AbstractCategory.php

http://github.com/concrete5/concrete5
PHP | 468 lines | 252 code | 58 blank | 158 comment | 20 complexity | 7fe5ba911739706558020ad29427a417 MD5 | raw file
Possible License(s): MIT, LGPL-2.1, MPL-2.0-no-copyleft-exception, BSD-3-Clause
  1. <?php
  2. namespace Concrete\Core\Attribute\Category;
  3. use Concrete\Core\Application\Application;
  4. use Concrete\Core\Attribute\AttributeValueInterface;
  5. use Concrete\Core\Attribute\Category\SearchIndexer\StandardSearchIndexer;
  6. use Concrete\Core\Attribute\Category\SearchIndexer\StandardSearchIndexerInterface;
  7. use Concrete\Core\Attribute\Key\ImportLoader\StandardImportLoader;
  8. use Concrete\Core\Attribute\Key\RequestLoader\StandardRequestLoader;
  9. use Concrete\Core\Attribute\SetFactory;
  10. use Concrete\Core\Attribute\TypeFactory;
  11. use Concrete\Core\Entity\Attribute\Key\Key;
  12. use Concrete\Core\Entity\Attribute\Type as AttributeType;
  13. use Concrete\Core\Entity\Package;
  14. use Doctrine\ORM\EntityManager;
  15. use SimpleXMLElement;
  16. use Symfony\Component\HttpFoundation\Request;
  17. /**
  18. * Abstract class to be used by attribute category classes.
  19. */
  20. abstract class AbstractCategory implements CategoryInterface, StandardSearchIndexerInterface
  21. {
  22. /**
  23. * The EntityManager instance.
  24. *
  25. * @var EntityManager
  26. */
  27. protected $entityManager;
  28. /**
  29. * @ignore It seems that this is not used.
  30. */
  31. protected $entity;
  32. /**
  33. * The Application instance.
  34. *
  35. * @var Application
  36. */
  37. protected $application;
  38. /**
  39. * The instance of the SetManagerInterface (if set).
  40. *
  41. * @var \Concrete\Core\Attribute\SetManagerInterface|null
  42. */
  43. protected $setManager;
  44. /**
  45. * Initialize the instance.
  46. *
  47. * @param Application $application the Application instance
  48. * @param EntityManager $entityManager the EntityManager instance
  49. */
  50. public function __construct(Application $application, EntityManager $entityManager)
  51. {
  52. $this->application = $application;
  53. $this->entityManager = $entityManager;
  54. }
  55. /**
  56. * Get the repository for the attribute keys.
  57. *
  58. * @return \Doctrine\ORM\EntityRepository
  59. */
  60. abstract public function getAttributeKeyRepository();
  61. /**
  62. * Get the repository for the attribute values.
  63. *
  64. * @return \Doctrine\ORM\EntityRepository
  65. */
  66. abstract public function getAttributeValueRepository();
  67. /**
  68. * Create a new attribute key.
  69. *
  70. * @return \Concrete\Core\Entity\Attribute\Key\Key
  71. */
  72. abstract public function createAttributeKey();
  73. /**
  74. * {@inheritdoc}
  75. *
  76. * @see \Concrete\Core\Attribute\Category\CategoryInterface::getSearchIndexer()
  77. */
  78. public function getSearchIndexer()
  79. {
  80. $indexer = $this->application->make(StandardSearchIndexer::class);
  81. return $indexer;
  82. }
  83. /**
  84. * {@inheritdoc}
  85. *
  86. * @see \Concrete\Core\Attribute\Category\CategoryInterface::getList()
  87. *
  88. * @return \Concrete\Core\Entity\Attribute\Key\Key[]
  89. */
  90. public function getList()
  91. {
  92. return $this->getAttributeKeyRepository()->findBy([
  93. 'akIsInternal' => false,
  94. ]);
  95. }
  96. /**
  97. * Get the list of attribute keys that are searchable.
  98. *
  99. * @return \Concrete\Core\Entity\Attribute\Key\Key[]
  100. */
  101. public function getSearchableList()
  102. {
  103. return $this->getAttributeKeyRepository()->findBy([
  104. 'akIsSearchable' => true,
  105. ]);
  106. }
  107. /**
  108. * Get the list of attribute keys that are searchable and indexed.
  109. *
  110. * @return \Concrete\Core\Entity\Attribute\Key\Key[]
  111. */
  112. public function getSearchableIndexedList()
  113. {
  114. return $this->getAttributeKeyRepository()->findBy([
  115. 'akIsSearchableIndexed' => true,
  116. ]);
  117. }
  118. /**
  119. * {@inheritdoc}
  120. *
  121. * @see \Concrete\Core\Attribute\Category\CategoryInterface::getAttributeKeyByHandle()
  122. *
  123. * @return \Concrete\Core\Entity\Attribute\Key\Key|null
  124. */
  125. public function getAttributeKeyByHandle($handle)
  126. {
  127. $cache = $this->application->make('cache/request');
  128. $class = substr(get_class($this), strrpos(get_class($this), '\\') + 1);
  129. $category = strtolower(substr($class, 0, strpos($class, 'Category')));
  130. $item = $cache->getItem(sprintf('/attribute/%s/handle/%s', $category, $handle));
  131. if (!$item->isMiss()) {
  132. $key = $item->get();
  133. } else {
  134. $key = $this->getAttributeKeyRepository()->findOneBy([
  135. 'akHandle' => $handle,
  136. ]);
  137. $cache->save($item->set($key));
  138. }
  139. return $key;
  140. }
  141. /**
  142. * {@inheritdoc}
  143. *
  144. * @see \Concrete\Core\Attribute\Category\CategoryInterface::getAttributeKeyByID()
  145. *
  146. * @return \Concrete\Core\Entity\Attribute\Key\Key|null
  147. */
  148. public function getAttributeKeyByID($akID)
  149. {
  150. $cache = $this->application->make('cache/request');
  151. $class = substr(get_class($this), strrpos(get_class($this), '\\') + 1);
  152. $category = strtolower(substr($class, 0, strpos($class, 'Category')));
  153. $item = $cache->getItem(sprintf('/attribute/%s/id/%s', $category, $akID));
  154. if (!$item->isMiss()) {
  155. $key = $item->get();
  156. } else {
  157. $key = $this->getAttributeKeyRepository()->findOneBy([
  158. 'akID' => $akID,
  159. ]);
  160. $cache->save($item->set($key));
  161. }
  162. return $key;
  163. }
  164. /**
  165. * {@inheritdoc}
  166. *
  167. * @see \Concrete\Core\Attribute\Category\CategoryInterface::delete()
  168. */
  169. public function delete()
  170. {
  171. $keys = $this->getList();
  172. foreach ($keys as $key) {
  173. $this->entityManager->remove($key);
  174. }
  175. $this->entityManager->flush();
  176. }
  177. /**
  178. * Add a new attribute key.
  179. *
  180. * @param \Concrete\Core\Entity\Attribute\Type|string $type the attribute type (or its handle)
  181. * @param \Concrete\Core\Entity\Attribute\Key\Key|array $key an empty attribute key, or an array with keys 'akHandle' (the attribute key handle), 'akName' (the attribute key name) and optionally 'asID' (the ID of the attribute set)
  182. * @param \Concrete\Core\Entity\Attribute\Key\Settings\Settings|null $settings the attribute key settings (if not specified, a new settings instance will be created)
  183. * @param \Concrete\Core\Entity\Package|null $pkg the entity of the package that's creating the attribute key
  184. *
  185. * @return \Concrete\Core\Entity\Attribute\Key\Key
  186. */
  187. public function add($type, $key, $settings = null, $pkg = null)
  188. {
  189. if (is_string($type)) {
  190. $typeFactory = $this->application->make(TypeFactory::class);
  191. /* @var TypeFactory $typeFactory */
  192. $type = $typeFactory->getByHandle($type);
  193. }
  194. // Legacy array support for $key
  195. $asID = false;
  196. if (is_array($key)) {
  197. $handle = $key['akHandle'];
  198. $name = $key['akName'];
  199. if (isset($key['asID'])) {
  200. $asID = $key['asID'];
  201. }
  202. $key = $this->createAttributeKey();
  203. $key->setAttributeKeyHandle($handle);
  204. $key->setAttributeKeyName($name);
  205. }
  206. // Legacy support for third parameter which used to be package
  207. if ($settings instanceof Package || $settings instanceof \Concrete\Core\Package\Package) {
  208. $pkg = $settings;
  209. $settings = null;
  210. }
  211. if (!$settings) {
  212. $settings = $type->getController()->getAttributeKeySettings();
  213. }
  214. $key->setAttributeType($type);
  215. $this->entityManager->persist($key);
  216. $this->entityManager->flush();
  217. $settings->setAttributeKey($key);
  218. $key->setAttributeKeySettings($settings);
  219. $this->entityManager->persist($settings);
  220. $this->entityManager->flush();
  221. if (is_object($pkg)) {
  222. $key->setPackage($pkg);
  223. }
  224. // Modify the category's search indexer.
  225. $indexer = $this->getSearchIndexer();
  226. if (is_object($indexer)) {
  227. $indexer->updateRepositoryColumns($this, $key);
  228. }
  229. $this->entityManager->persist($key);
  230. $this->entityManager->flush();
  231. /* legacy support, attribute set */
  232. if ($asID) {
  233. $manager = $this->getSetManager();
  234. $factory = new SetFactory($this->entityManager);
  235. $set = $factory->getByID($asID);
  236. if ($set !== null) {
  237. $manager->addKey($set, $key);
  238. }
  239. }
  240. return $key;
  241. }
  242. /**
  243. * {@inheritdoc}
  244. *
  245. * @see \Concrete\Core\Attribute\Category\CategoryInterface::addFromRequest()
  246. *
  247. * @return \Concrete\Core\Entity\Attribute\Key\Key
  248. */
  249. public function addFromRequest(AttributeType $type, Request $request)
  250. {
  251. $key = $this->createAttributeKey();
  252. $loader = $this->getRequestLoader();
  253. $loader->load($key, $request);
  254. $controller = $type->getController();
  255. $this->entityManager->persist($key);
  256. $this->entityManager->flush();
  257. $controller->setAttributeKey($key);
  258. $settings = $controller->saveKey($request->request->all());
  259. if (!is_object($settings)) {
  260. $settings = $controller->getAttributeKeySettings();
  261. }
  262. return $this->add($type, $key, $settings);
  263. }
  264. /**
  265. * Import a new attribute key from a SimpleXMLElement instance.
  266. *
  267. * @param AttributeType $type the type of the attribute key to be created
  268. * @param SimpleXMLElement $element the SimpleXMLElement instance containing the data of the attribute key to be created
  269. * @param Package|null $package the entity of the package that's creating the attribute key (if applicable)
  270. *
  271. * @return \Concrete\Core\Entity\Attribute\Key\Key
  272. */
  273. public function import(AttributeType $type, SimpleXMLElement $element, Package $package = null)
  274. {
  275. $key = $this->createAttributeKey();
  276. $loader = $this->getImportLoader();
  277. $loader->load($key, $element);
  278. $controller = $type->getController();
  279. $settings = $controller->importKey($element);
  280. if (!is_object($settings)) {
  281. $settings = $controller->getAttributeKeySettings();
  282. }
  283. return $this->add($type, $key, $settings, $package);
  284. }
  285. /**
  286. * {@inheritdoc}
  287. *
  288. * @see \Concrete\Core\Attribute\Category\CategoryInterface::updateFromRequest()
  289. */
  290. public function updateFromRequest(Key $key, Request $request)
  291. {
  292. $previousHandle = $key->getAttributeKeyHandle();
  293. $loader = $this->getRequestLoader();
  294. $loader->load($key, $request);
  295. $controller = $key->getController();
  296. $settings = $controller->saveKey($request->request->all());
  297. if (!is_object($settings)) {
  298. $settings = $controller->getAttributeKeySettings();
  299. }
  300. $settings->setAttributeKey($key);
  301. $this->entityManager->persist($settings);
  302. $this->entityManager->flush();
  303. // Modify the category's search indexer.
  304. $indexer = $this->getSearchIndexer();
  305. if (is_object($indexer)) {
  306. $indexer->updateRepositoryColumns($this, $key, $previousHandle);
  307. }
  308. $this->entityManager->persist($key);
  309. $this->entityManager->flush();
  310. return $key;
  311. }
  312. /**
  313. * @return EntityManager
  314. */
  315. public function getEntityManager()
  316. {
  317. return $this->entityManager;
  318. }
  319. /**
  320. * Get the EntityManager instance.
  321. *
  322. * @param EntityManager $entityManager
  323. */
  324. public function setEntityManager($entityManager)
  325. {
  326. $this->entityManager = $entityManager;
  327. }
  328. /**
  329. * {@inheritdoc}
  330. *
  331. * @see \Concrete\Core\Attribute\Category\CategoryInterface::deleteKey()
  332. */
  333. public function deleteKey(Key $key)
  334. {
  335. // Delete any attribute values found attached to this key
  336. $values = $this->getAttributeValueRepository()->findBy(['attribute_key' => $key]);
  337. foreach ($values as $attributeValue) {
  338. $this->deleteValue($attributeValue);
  339. }
  340. }
  341. /**
  342. * {@inheritdoc}
  343. *
  344. * @see \Concrete\Core\Attribute\Category\CategoryInterface::deleteValue()
  345. */
  346. public function deleteValue(AttributeValueInterface $attributeValue)
  347. {
  348. /* @var \Concrete\Core\Entity\Attribute\Value\AbstractValue $attributeValue */
  349. $genericValue = $attributeValue->getGenericValue();
  350. if ($genericValue !== null) {
  351. $genericValues = $this->getAttributeValueRepository()->findBy(['generic_value' => $genericValue]);
  352. if (count($genericValues) == 1) {
  353. // Handle legacy attributes with these three lines.
  354. $controller = $attributeValue->getAttributeKey()->getController();
  355. $controller->setAttributeValue($attributeValue);
  356. $controller->deleteValue();
  357. $value = $attributeValue->getValueObject();
  358. if (is_object($value)) {
  359. $this->entityManager->remove($value);
  360. $this->entityManager->flush();
  361. }
  362. $this->entityManager->remove($genericValue);
  363. }
  364. $this->entityManager->remove($attributeValue);
  365. }
  366. $this->entityManager->flush();
  367. }
  368. /**
  369. * Get the object to be used to update attribute keys with the data contained in a Symfony\Component\HttpFoundation\Request instance.
  370. *
  371. * @return \Concrete\Core\Attribute\Key\RequestLoader\RequestLoaderInterface
  372. */
  373. public function getRequestLoader()
  374. {
  375. return new StandardRequestLoader();
  376. }
  377. /**
  378. * Get the object to be used to update attribute keys with the data contained in a SimpleXMLElement instance.
  379. *
  380. * @return \Concrete\Core\Attribute\Key\ImportLoader\ImportLoaderInterface
  381. */
  382. public function getImportLoader()
  383. {
  384. return new StandardImportLoader();
  385. }
  386. /**
  387. * @param int $akID
  388. *
  389. * @return \Concrete\Core\Entity\Attribute\Key\Key|null
  390. *
  391. * @deprecated use the getAttributeKeyByID method
  392. */
  393. public function getByID($akID)
  394. {
  395. return $this->getAttributeKeyByID($akID);
  396. }
  397. /**
  398. * @param string $akHandle
  399. *
  400. * @return \Concrete\Core\Entity\Attribute\Key\Key|null
  401. *
  402. * @deprecated use the getAttributeKeyByHandle method
  403. */
  404. public function getByHandle($akHandle)
  405. {
  406. return $this->getAttributeKeyByHandle($akHandle);
  407. }
  408. }