PageRenderTime 39ms CodeModel.GetById 13ms RepoModel.GetById 1ms app.codeStats 0ms

/Taxonomy/Model/Term.php

https://github.com/kareypowell/croogo
PHP | 286 lines | 166 code | 23 blank | 97 comment | 20 complexity | c999436e8be6a8d9c9031ad27deed4e3 MD5 | raw file
  1. <?php
  2. App::uses('TaxonomyAppModel', 'Taxonomy.Model');
  3. /**
  4. * Term
  5. *
  6. * @category Taxonomy.Model
  7. * @package Croogo.Taxonomy.Model
  8. * @version 1.0
  9. * @author Fahad Ibnay Heylaal <contact@fahad19.com>
  10. * @license http://www.opensource.org/licenses/mit-license.php The MIT License
  11. * @link http://www.croogo.org
  12. */
  13. class Term extends TaxonomyAppModel {
  14. /**
  15. * Model name
  16. *
  17. * @var string
  18. * @access public
  19. */
  20. public $name = 'Term';
  21. public $findMethods = array(
  22. 'byVocabulary' => true,
  23. );
  24. /**
  25. * Behaviors used by the Model
  26. *
  27. * @var array
  28. * @access public
  29. */
  30. public $actsAs = array(
  31. 'Croogo.Cached' => array(
  32. 'groups' => array(
  33. 'taxonomy',
  34. 'nodes',
  35. ),
  36. ),
  37. 'Croogo.Trackable',
  38. );
  39. /**
  40. * Validation
  41. *
  42. * @var array
  43. * @access public
  44. */
  45. public $validate = array(
  46. 'slug' => array(
  47. 'isUnique' => array(
  48. 'rule' => 'isUnique',
  49. 'message' => 'This slug has already been taken.',
  50. ),
  51. 'minLength' => array(
  52. 'rule' => array('minLength', 1),
  53. 'message' => 'Slug cannot be empty.',
  54. ),
  55. ),
  56. );
  57. /**
  58. * Model associations: hasAndBelongsToMany
  59. *
  60. * @var array
  61. * @access public
  62. */
  63. public $hasAndBelongsToMany = array(
  64. 'Vocabulary' => array(
  65. 'className' => 'Taxonomy.Vocabulary',
  66. 'with' => 'Taxonomy',
  67. 'joinTable' => 'taxonomy',
  68. 'foreignKey' => 'term_id',
  69. 'associationForeignKey' => 'vocabulary_id',
  70. 'unique' => true,
  71. ),
  72. );
  73. /**
  74. * Save Term and return ID.
  75. * If another Term with same slug exists, return ID of that Term without saving.
  76. *
  77. * @param array $data
  78. * @return integer
  79. */
  80. public function saveAndGetId($data) {
  81. $dataToPersist = $data;
  82. if (!array_key_exists($this->alias, $data)) {
  83. $dataToPersist = array($this->alias => $data);
  84. }
  85. $term = $this->find('first', array(
  86. 'conditions' => array(
  87. $this->escapeField('slug') => $dataToPersist[$this->alias]['slug'],
  88. ),
  89. ));
  90. if (isset($term[$this->alias][$this->primaryKey])) {
  91. $id = $term[$this->alias][$this->primaryKey];
  92. $update = $dataToPersist[$this->alias];
  93. if ($id && isset($update['description'])) {
  94. $this->id = $id;
  95. $this->saveField('description', $update['description']);
  96. }
  97. return $id;
  98. }
  99. $this->id = false;
  100. if ($this->save($dataToPersist)) {
  101. return $this->id;
  102. }
  103. return false;
  104. }
  105. /**
  106. * Allow delete on whether given Term has any association left with Taxonomy
  107. *
  108. * @return bool
  109. */
  110. public function beforeDelete($cascade = true) {
  111. $Taxonomy = ClassRegistry::init('Taxonomy.Taxonomy');
  112. $count = $Taxonomy->find('count', array(
  113. 'recursive' => -1,
  114. 'conditions' => array(
  115. $Taxonomy->escapeField('term_id') => $this->id,
  116. ),
  117. ));
  118. return $count === 0;
  119. }
  120. /**
  121. * Convenience method to check whether term exists within a vocabulary
  122. *
  123. * @param integer $id Term Id
  124. * @param integer $vocabularyId Vocabulary Id
  125. * @param integer $taxonomyId Taxonomy Id
  126. * @return bool True if Term exists in Vocabulary
  127. */
  128. public function isInVocabulary($id, $vocabularyId, $taxonomyId = null) {
  129. $conditions = array('term_id' => $id, 'vocabulary_id' => $vocabularyId);
  130. if (!is_null($taxonomyId)) {
  131. $conditions['Taxonomy.id !='] = $taxonomyId;
  132. }
  133. return $this->Vocabulary->Taxonomy->hasAny($conditions);
  134. }
  135. /**
  136. * Save term
  137. *
  138. * @see Term::_save()
  139. * @return array|bool Array of saved term or boolean false
  140. */
  141. public function add($data, $vocabularyId) {
  142. return $this->_save($data, $vocabularyId);
  143. }
  144. /**
  145. * Edit term
  146. *
  147. * @see Term::_save()
  148. * @return array|bool Array of saved term or boolean false
  149. */
  150. public function edit($data, $vocabularyId) {
  151. $id = $data[$this->alias][$this->primaryKey];
  152. $slug = $data[$this->alias]['slug'];
  153. if ($this->hasSlugChanged($id, $slug) && $this->slugExists($slug)) {
  154. $edited = false;
  155. } else {
  156. $taxonomyId = !empty($data['Taxonomy']['id']) ? $data['Taxonomy']['id'] : null;
  157. $edited = $this->_save($data, $vocabularyId, $taxonomyId);
  158. }
  159. return $edited;
  160. }
  161. /**
  162. * Checks wether slug has changed for given Term id
  163. *
  164. * @param int $id Term Id
  165. * @param string $slug Slug
  166. * @return bool True if slug has changed
  167. * @throws NotFoundException
  168. */
  169. public function hasSlugChanged($id, $slug) {
  170. if (!is_numeric($id) || !$this->exists($id)) {
  171. throw new NotFoundException(__d('croogo', 'Invalid Term Id'));
  172. }
  173. return $this->field('slug', array($this->escapeField() => $id)) != $slug;
  174. }
  175. /**
  176. * Convenience check for slug
  177. *
  178. * @return bool
  179. */
  180. public function slugExists($slug) {
  181. return $this->hasAny(compact('slug'));
  182. }
  183. /**
  184. * Remove term
  185. *
  186. * @param integer $id Term Id
  187. * @param integer $vocabularyId Vocabulary Id
  188. */
  189. public function remove($id, $vocabularyId) {
  190. $taxonomyId = $this->Vocabulary->Taxonomy->field('id', array(
  191. 'term_id' => $id, 'vocabulary_id' => $vocabularyId
  192. ));
  193. $this->setScopeForTaxonomy($vocabularyId);
  194. return $this->Taxonomy->delete($taxonomyId) && $this->delete($id);
  195. }
  196. /**
  197. * Save new/updated term data
  198. *
  199. * @param array $data Term data
  200. * @param integer $vocabularyId Vocabulary Id
  201. * @param integer $taxonomyId Taxonomy Id
  202. */
  203. protected function _save($data, $vocabularyId, $taxonomyId = null) {
  204. $added = false;
  205. $termId = $this->saveAndGetId($data);
  206. if (!$this->isInVocabulary($termId, $vocabularyId, $taxonomyId)) {
  207. $this->setScopeForTaxonomy($vocabularyId);
  208. $dataToPersist = array(
  209. 'parent_id' => $data['Taxonomy']['parent_id'],
  210. 'term_id' => $termId,
  211. 'vocabulary_id' => $vocabularyId,
  212. );
  213. if (!is_null($taxonomyId)) {
  214. $dataToPersist['id'] = $taxonomyId;
  215. }
  216. $added = $this->Taxonomy->save($dataToPersist);
  217. }
  218. return $added;
  219. }
  220. protected function _findByVocabulary($state, $query, $results = array()) {
  221. static $termsId = null;
  222. if (empty($query['vocabulary_id'])) {
  223. trigger_error(__d('croogo', '"vocabulary_id" key not found'));
  224. }
  225. if ($state == 'before') {
  226. $vocabularyAlias = $this->Vocabulary->field('alias', array('id' => $query['vocabulary_id']));
  227. $termsId = $this->Vocabulary->Taxonomy->getTree($vocabularyAlias, array('key' => 'id', 'value' => 'title'));
  228. $defaultQuery = array(
  229. 'conditions' => array(
  230. $this->escapeField() => array_keys($termsId)
  231. )
  232. );
  233. return array_merge_recursive($defaultQuery, (array)$query);
  234. }
  235. $ordered = array_keys($termsId);
  236. $terms = array();
  237. foreach ($results as $tempTerm) {
  238. $term = $tempTerm;
  239. $id = $term[$this->alias][$this->primaryKey];
  240. $term[$this->alias]['indent'] = substr_count($termsId[$id], '_');
  241. $position = array_search($id, $ordered);
  242. $terms[$position] = $term;
  243. }
  244. ksort($terms);
  245. $termsId = null;
  246. return $terms;
  247. }
  248. /**
  249. * Set Scope
  250. *
  251. * @param integer $vocabularyId Vocabulary Id
  252. */
  253. public function setScopeForTaxonomy($vocabularyId) {
  254. $scopeSettings = array('scope' => array(
  255. 'Taxonomy.vocabulary_id' => $vocabularyId,
  256. ));
  257. if ($this->Vocabulary->Taxonomy->Behaviors->loaded('Tree')) {
  258. $this->Vocabulary->Taxonomy->Behaviors->Tree->setup($this->Vocabulary->Taxonomy, $scopeSettings);
  259. } else {
  260. $this->Vocabulary->Taxonomy->Behaviors->load('Tree', $scopeSettings);
  261. }
  262. }
  263. }