PageRenderTime 53ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/dmCorePlugin/lib/doctrine/table/dmDoctrineTable.php

https://github.com/leszek/diem
PHP | 606 lines | 434 code | 96 blank | 76 comment | 49 complexity | 6c5dde0e5aaf981c941e9d281079359a MD5 | raw file
Possible License(s): MIT
  1. <?php
  2. abstract class dmDoctrineTable extends Doctrine_Table
  3. {
  4. protected static
  5. $eventDispatcher, // mandatory
  6. $moduleManager, // mandatory
  7. $serviceContainer; // optional
  8. protected
  9. $hasI18n; // cache
  10. public function construct()
  11. {
  12. $this->hasI18n = $this->hasRelation('Translation');
  13. }
  14. /**
  15. * @return DmMediaFolder the DmMediaFolder used to store this table's record's medias
  16. */
  17. public function getDmMediaFolder()
  18. {
  19. if ($this->hasCache('dm_media_folder'))
  20. {
  21. return $this->getCache('dm_media_folder');
  22. }
  23. return $this->setCache('dm_media_folder', dmDb::table('DmMediaFolder')->findOneByRelPathOrCreate($this->getDmModule()->getUnderscore()));
  24. }
  25. /**
  26. * @return bool if this table's records interact with page tree
  27. * so if a record is saved or deleted, page tree must be updated
  28. */
  29. public function interactsWithPageTree()
  30. {
  31. if($this->hasCache('interacts_with_page_tree'))
  32. {
  33. return $this->getCache('interacts_with_page_tree');
  34. }
  35. /*
  36. * If table belongs to a project module,
  37. * it may interact with tree
  38. */
  39. if ($module = $this->getDmModule())
  40. {
  41. $interacts = $module->interactsWithPageTree();
  42. }
  43. /*
  44. * If table owns project records,
  45. * it may interact with tree
  46. */
  47. else
  48. {
  49. $interacts = false;
  50. foreach($this->getRelationHolder()->getLocals() as $localRelation)
  51. {
  52. if ($localModule = $this->getModuleManager()->getModuleByModel($localRelation['class']))
  53. {
  54. if ($localModule->interactsWithPageTree())
  55. {
  56. $interacts = true;
  57. break;
  58. }
  59. }
  60. }
  61. }
  62. return $this->setCache('interacts_with_page_tree', $interacts);
  63. }
  64. /**
  65. * @return myDoctrineRecord the first record in the table
  66. */
  67. public function findOne()
  68. {
  69. return $this->createQuery()->fetchRecord();
  70. }
  71. /**
  72. * Will join all record available medias
  73. * @return myDoctrineQuery
  74. */
  75. public function joinDmMedias(myDoctrineQuery $query)
  76. {
  77. foreach($this->getRelationHolder()->getLocalMedias() as $relation)
  78. {
  79. $query->withDmMedia($relation->getAlias());
  80. }
  81. return $query;
  82. }
  83. /**
  84. * Will join all localKey relations
  85. * @return myDoctrineQuery
  86. */
  87. public function joinLocals(myDoctrineQuery $query)
  88. {
  89. $rootAlias = $query->getRootAlias();
  90. foreach($this->getRelationHolder()->getLocals() as $relation)
  91. {
  92. $query->leftJoin(sprintf('%s.%s %s', $rootAlias, $relation->getAlias(), dmString::lcfirst($relation->getAlias())));
  93. }
  94. return $query;
  95. }
  96. public function fetchJoinAll($params = array(), $hydrationMode = Doctrine_Core::HYDRATE_RECORD)
  97. {
  98. return $this->joinAll()->execute($params, $hydrationMode);
  99. }
  100. /**
  101. * Will join all relations
  102. * @return myDoctrineQuery
  103. */
  104. public function joinAll(dmDoctrineQuery $query = null)
  105. {
  106. if ($query instanceof dmDoctrineQuery)
  107. {
  108. $rootAlias = $query->getRootAlias();
  109. }
  110. else
  111. {
  112. $query = $this->createQuery($rootAlias = 'q');
  113. }
  114. foreach($this->getRelationHolder()->getAll() as $relation)
  115. {
  116. if($relation->getAlias() === 'Version' && $this->isVersionable())
  117. {
  118. continue;
  119. }
  120. elseif ($relation->getAlias() === 'Translation')
  121. {
  122. $query->withI18n();
  123. }
  124. elseif ($relation->getClass() === 'DmMedia')
  125. {
  126. if ($relation instanceof Doctrine_Relation_Association && $this->hasTemplate('DmGallery'))
  127. {
  128. continue;
  129. }
  130. $query->withDmMedia($relation->getAlias());
  131. }
  132. else
  133. {
  134. if ($relation instanceof Doctrine_Relation_ForeignKey)
  135. {
  136. if ($this->getRelationHolder()->getAssociationByRefClass($relation->getClass()))
  137. {
  138. continue;
  139. }
  140. }
  141. $joinAlias = dmString::lcfirst($relation->getAlias());
  142. $query->leftJoin(sprintf('%s.%s %s', $rootAlias, $relation->getAlias(), $joinAlias));
  143. if($relation->getTable()->hasRelation('Translation'))
  144. {
  145. $joinI18nAlias = $joinAlias.'Translation';
  146. $query->leftJoin(sprintf('%s.%s %s WITH %s.lang = ?', $joinAlias, 'Translation', $joinI18nAlias, $joinI18nAlias), dmDoctrineRecord::getDefaultCulture());
  147. }
  148. }
  149. }
  150. return $query;
  151. }
  152. /**
  153. * Will join named relations
  154. */
  155. public function joinRelations(array $aliases)
  156. {
  157. $rootAlias = $query->getRootAlias();
  158. foreach($aliases as $alias)
  159. {
  160. if (!$relation = $this->getRelationHolder()->get($alias))
  161. {
  162. throw new dmException(sprintf('%s is not a valid alias for the table %s', $alias, $this->getComponentName()));
  163. }
  164. if ($relation->getAlias() === 'Translation')
  165. {
  166. $query->withI18n();
  167. }
  168. elseif ($relation->getClass() === 'DmMedia')
  169. {
  170. $mediaJoinAlias = dmString::lcfirst($relation->getAlias());
  171. $query->leftJoin(sprintf('%s.%s %s', $rootAlias, $relation->getAlias(), $mediaJoinAlias))
  172. ->leftJoin(sprintf('%s.%s %s', $mediaJoinAlias, 'Folder', $mediaJoinAlias.'Folder'));
  173. }
  174. else
  175. {
  176. $joinAlias = dmString::lcfirst($relation->getAlias());
  177. $query->leftJoin(sprintf('%s.%s %s', $rootAlias, $relation->getAlias(), $joinAlias));
  178. }
  179. }
  180. return $query;
  181. }
  182. /**
  183. * @return dmDoctrineQuery the default admin list query
  184. */
  185. public function getAdminListQuery(dmDoctrineQuery $query)
  186. {
  187. return $this->joinAll($query);
  188. }
  189. /**
  190. * add i18n columns if needed
  191. */
  192. public function getAllColumns()
  193. {
  194. $columns = $this->getColumns();
  195. if($this->hasI18n())
  196. {
  197. $columns = array_merge($columns, $this->getI18nTable()->getColumns());
  198. }
  199. return $columns;
  200. }
  201. public function hasField($fieldName)
  202. {
  203. if (isset($this->_columnNames[$fieldName]))
  204. {
  205. return true;
  206. }
  207. if ($this->hasI18n() && $this->getI18nTable()->hasField($fieldName))
  208. {
  209. return true;
  210. }
  211. return false;
  212. }
  213. /**
  214. * Return columns that a human can fill
  215. * Will exclude primary key, timestampable fields
  216. */
  217. public function getHumanColumns()
  218. {
  219. if ($this->hasCache('human_columns'))
  220. {
  221. return $this->getCache('human_columns');
  222. }
  223. $columns = $this->getAllColumns();
  224. if ($this->isVersionable())
  225. {
  226. unset($columns['version']);
  227. }
  228. foreach($columns as $columnName => $column)
  229. {
  230. if (!empty($column['autoincrement']) || in_array($columnName, array('created_at', 'updated_at', 'id')))
  231. {
  232. unset($columns[$columnName]);
  233. }
  234. }
  235. return $this->setCache('human_columns', $columns);
  236. }
  237. public function getSeoColumns()
  238. {
  239. $columns = array_keys($this->getHumanColumns());
  240. $columns = array();
  241. foreach($this->getHumanColumns() as $columnName => $column)
  242. {
  243. if (in_array($column['type'], array('string', 'blob', 'clob', 'enum')))
  244. {
  245. $columns[] = $columnName;
  246. }
  247. }
  248. if ($pk = $this->getPrimaryKey())
  249. {
  250. $columns[] = $pk;
  251. }
  252. $columns = $this->getEventDispatcher()->filter(
  253. new sfEvent($this, 'dm.table.filter_seo_columns'),
  254. $columns
  255. )->getReturnValue();
  256. return array_unique(array_filter($columns));
  257. }
  258. public function getIndexableColumns()
  259. {
  260. $columns = $this->getHumanColumns();
  261. foreach($columns as $columnName => $column)
  262. {
  263. if(in_array($column['type'], array('time', 'timestamp', 'boolean')))
  264. {
  265. unset($columns[$columnName]);
  266. }
  267. }
  268. return $columns;
  269. }
  270. public function getAllColumnNames()
  271. {
  272. return array_keys($this->getAllColumns());
  273. }
  274. public function getHumanColumnNames()
  275. {
  276. return array_key($this->getHumanColumns());
  277. }
  278. public function getColumn($columnName)
  279. {
  280. return dmArray::get($this->getAllColumns(), $columnName);
  281. }
  282. public function isSortable()
  283. {
  284. return ($this->hasTemplate('DmSortable') || $this->hasTemplate('Sortable')) && 'id' === $this->getPrimaryKey();
  285. }
  286. public function isVersionable()
  287. {
  288. return $this->hasTemplate('DmVersionable') || ($this->hasI18n() && $this->getI18nTable()->hasTemplate('DmVersionable'));
  289. }
  290. public function hasI18n()
  291. {
  292. return $this->hasI18n;
  293. }
  294. public function getI18nTable()
  295. {
  296. if ($this->hasCache('i18n_table'))
  297. {
  298. return $this->getCache('i18n_table');
  299. }
  300. return $this->setCache('i18n_table', $this->hasI18n()
  301. ? $this->getRelationHolder()->get('Translation')->getTable()
  302. : false
  303. );
  304. }
  305. /**
  306. * Retrieves a column definition from this table schema.
  307. *
  308. * @param string $columnName
  309. * @return array column definition; @see $_columns
  310. */
  311. public function getColumnDefinition($columnName)
  312. {
  313. $columnDefinition = parent::getColumnDefinition($columnName);
  314. if (!$columnDefinition && $this->hasI18n())
  315. {
  316. $columnDefinition = $this->getI18nTable()->getColumnDefinition($columnName);
  317. }
  318. return $columnDefinition;
  319. }
  320. public function isMarkdownColumn($columnName)
  321. {
  322. return strpos(dmArray::get($this->getColumnDefinition($columnName), 'extra', ''), 'markdown') !== false;
  323. }
  324. public function isBooleanColumn($columnName)
  325. {
  326. return 'boolean' === dmArray::get($this->getColumnDefinition($columnName), 'type');
  327. }
  328. public function isI18nColumn($columnName)
  329. {
  330. return !isset($this->_columnNames[$columnName]) && $this->hasI18n() && $this->getI18nTable()->hasField($columnName);
  331. }
  332. public function isLinkColumn($columnName)
  333. {
  334. return false !== strpos(dmArray::get($this->getColumnDefinition($columnName), 'extra', ''), 'link');
  335. }
  336. /**
  337. * Tries to find a column name that could be used to represent a record of this table
  338. */
  339. public function getIdentifierColumnName()
  340. {
  341. if ($this->hasCache('dm_identifier_column_name'))
  342. {
  343. return $this->getCache('dm_identifier_column_name');
  344. }
  345. if (!$columnName = dmArray::first(array_intersect(sfConfig::get('dm_orm_identifier_fields'), $this->getAllColumnNames())))
  346. {
  347. if (!$columnName = dmArray::first($this->getIdentifierColumnNames()))
  348. {
  349. $columnName = dmArray::first($this->getColumnNames());
  350. }
  351. }
  352. return $this->setCache('dm_identifier_column_name', $columnName);
  353. }
  354. public function getPrimaryKeys()
  355. {
  356. if ($this->hasCache('dm_primary_keys'))
  357. {
  358. return $this->getCache('dm_primary_keys');
  359. }
  360. $primaryKeys = array();
  361. foreach($this->getColumns() as $columnName => $column)
  362. {
  363. if (!empty($column['primary']))
  364. {
  365. $primaryKeys[] = $columnName;
  366. }
  367. }
  368. return $this->setCache('dm_primary_keys', $primaryKeys);
  369. }
  370. /**
  371. * Will return pk column name if table has only one pk, or null
  372. */
  373. public function getPrimaryKey()
  374. {
  375. if (count($this->getPrimaryKeys()) === 1)
  376. {
  377. return dmArray::first($this->getPrimaryKeys());
  378. }
  379. return null;
  380. }
  381. /**
  382. * @return dmTableRelationHolder the table relation holder
  383. */
  384. public function getRelationHolder()
  385. {
  386. if ($this->hasCache('dm_relation_holder'))
  387. {
  388. return $this->getCache('dm_relation_holder');
  389. }
  390. return $this->setCache('dm_relation_holder', new dmTableRelationHolder($this));
  391. }
  392. /**
  393. * Reorders a set of sortable objects based on a list of id/position
  394. * Beware that there is no check made on the positions passed
  395. * So incoherent positions will result in an incoherent list
  396. *
  397. * @param array id/position pairs
  398. *
  399. * @return Boolean true if the reordering took place, false if a database problem prevented it
  400. **/
  401. public function doSort(array $order)
  402. {
  403. if (!$this->hasField('position'))
  404. {
  405. throw new dmException(sprintf('%s table has no position field', $this->getComponentName()));
  406. }
  407. $records = $this->createQuery('q INDEXBY q.id')->whereIn('q.id', array_keys($order))->fetchRecords();
  408. $modifiedRecords = new Doctrine_Collection($this);
  409. foreach ($order as $id => $position)
  410. {
  411. if ($position != $records[$id]->get('position'))
  412. {
  413. $records[$id]->set('position', $position);
  414. $modifiedRecords[] = $records[$id];
  415. }
  416. }
  417. $modifiedRecords->save();
  418. unset($records, $modifiedRecords);
  419. }
  420. /**
  421. * return dmModule this record module
  422. */
  423. public function getDmModule()
  424. {
  425. if($this->hasCache('dm_module'))
  426. {
  427. return $this->getCache('dm_module');
  428. }
  429. return $this->setCache('dm_module', $this->getModuleManager()->getModuleByModel($this->getComponentName()));
  430. }
  431. /**
  432. * Usefull for generators ( admin, form, filter )
  433. */
  434. public function getSfDoctrineColumns()
  435. {
  436. $columns = array();
  437. foreach ($this->getAllColumnNames() as $name)
  438. {
  439. $columns[$name] = new sfDoctrineColumn($name, $this);
  440. }
  441. return $columns;
  442. }
  443. /**
  444. * dmMicroCache
  445. */
  446. protected
  447. $cache;
  448. protected function getCache($cacheKey)
  449. {
  450. if(isset($this->cache[$cacheKey]))
  451. {
  452. return $this->cache[$cacheKey];
  453. }
  454. return null;
  455. }
  456. protected function hasCache($cacheKey)
  457. {
  458. return isset($this->cache[$cacheKey]);
  459. }
  460. protected function setCache($cacheKey, $cacheValue)
  461. {
  462. return $this->cache[$cacheKey] = $cacheValue;
  463. }
  464. public function clearCache($cacheKey = null)
  465. {
  466. if (null === $cacheKey)
  467. {
  468. $this->cache = array();
  469. }
  470. elseif(isset($this->cache[$cacheKey]))
  471. {
  472. unset($this->cache[$cacheKey]);
  473. }
  474. return $this;
  475. }
  476. public static function setEventDispatcher(sfEventDispatcher $eventDispatcher)
  477. {
  478. self::$eventDispatcher = $eventDispatcher;
  479. }
  480. public static function setServiceContainer(dmBaseServiceContainer $serviceContainer)
  481. {
  482. self::$serviceContainer = $serviceContainer;
  483. self::setModuleManager($serviceContainer->getService('module_manager'));
  484. self::setEventDispatcher($serviceContainer->getService('dispatcher'));
  485. }
  486. public static function setModuleManager(dmModuleManager $moduleManager)
  487. {
  488. self::$moduleManager = $moduleManager;
  489. }
  490. public function getEventDispatcher()
  491. {
  492. return self::$eventDispatcher;
  493. }
  494. public function getServiceContainer()
  495. {
  496. return self::$serviceContainer;
  497. }
  498. public function getService($name, $class = null)
  499. {
  500. if($sc = $this->getServiceContainer())
  501. {
  502. return $sc->getService($name, $class);
  503. }
  504. return null;
  505. }
  506. public function getModuleManager()
  507. {
  508. return self::$moduleManager;
  509. }
  510. }