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

/Taxonomy/Model/Behavior/TaxonomizableBehavior.php

https://github.com/kareypowell/croogo
PHP | 265 lines | 182 code | 24 blank | 59 comment | 19 complexity | deddf3d67b0b91bc0ee34c19e33f2bb5 MD5 | raw file
  1. <?php
  2. App::uses('ModelBehavior', 'Model/Behavior');
  3. /**
  4. * TaxonomizableBehavior
  5. *
  6. * @category Taxonomy.Model.Behavior
  7. * @package Croogo.Taxonomy.Model.Behavior
  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 TaxonomizableBehavior extends ModelBehavior {
  14. /**
  15. * Taxonomy instance
  16. */
  17. protected $_Taxonomy = null;
  18. /**
  19. * Setup behavior
  20. *
  21. * @return void
  22. */
  23. public function setup(Model $model, $config = array()) {
  24. $this->settings[$model->alias] = $config;
  25. $this->_setupRelationships($model);
  26. $this->_setupEvents($model);
  27. $this->_Taxonomy = $model->Taxonomy;
  28. }
  29. /**
  30. * Setup relationships
  31. *
  32. * @return void
  33. */
  34. protected function _setupRelationships(Model $model) {
  35. $model->bindModel(array(
  36. 'hasAndBelongsToMany' => array(
  37. 'Taxonomy' => array(
  38. 'className' => 'Taxonomy.Taxonomy',
  39. 'with' => 'Taxonomy.ModelTaxonomy',
  40. 'foreignKey' => 'foreign_key',
  41. 'associationForeignKey' => 'taxonomy_id',
  42. 'unique' => true,
  43. 'conditions' => array(
  44. 'model' => $model->alias,
  45. ),
  46. ),
  47. ),
  48. ), false);
  49. $model->Taxonomy->bindModel(array(
  50. 'hasAndBelongsToMany' => array(
  51. $model->alias => array(
  52. 'className' => $model->plugin . '.' . $model->alias,
  53. 'with' => 'Taxonomy.ModelTaxonomy',
  54. 'foreignKey' => 'foreign_key',
  55. 'associationForeignKey' => 'taxonomy_id',
  56. 'unique' => true,
  57. 'conditions' => array(
  58. 'model' => $model->alias,
  59. ),
  60. ),
  61. ),
  62. ), false);
  63. }
  64. /**
  65. * Setup Event handlers
  66. *
  67. * @return void
  68. */
  69. protected function _setupEvents($model) {
  70. $callback = array($this, 'onBeforeSaveNode');
  71. $eventManager = $model->getEventManager();
  72. $eventManager->attach($callback, 'Model.Node.beforeSaveNode');
  73. }
  74. /**
  75. * Get selected terms from data
  76. */
  77. protected function _getSelectedTerms($data) {
  78. if (isset($data['Taxonomy']['Taxonomy'])) {
  79. return array_filter($data['Taxonomy']['Taxonomy']);
  80. } elseif (isset($data['Taxonomy'])) {
  81. return Hash::extract($data['Taxonomy'], '{n}.taxonomy_id');
  82. } else {
  83. return array();
  84. }
  85. }
  86. /**
  87. * Validate Taxonomy data
  88. */
  89. public function validateTaxonomyData(Model $model) {
  90. $typeField = 'type';
  91. $data =& $model->data;
  92. if (isset($data[$model->alias][$typeField])) {
  93. $typeAlias = $data[$model->alias][$typeField];
  94. } elseif (isset($model->type)) {
  95. $typeAlias = $model->type;
  96. } else {
  97. $this->log('Unable to determine type for model ' . $model->alias);
  98. return false;
  99. }
  100. $type = $this->_Taxonomy->Vocabulary->Type->find('first', array(
  101. 'fields' => array('id', 'title', 'alias'),
  102. 'contain' => array(
  103. 'Vocabulary' => array(
  104. 'fields' => array('id', 'title', 'alias', 'required', 'multiple'),
  105. ),
  106. ),
  107. 'conditions' => array(
  108. 'alias' => $typeAlias,
  109. ),
  110. ));
  111. if (empty($type)) {
  112. $this->log('Type ' . $typeAlias . ' cannot be found');
  113. return true;
  114. }
  115. $selectedTerms = $this->_getSelectedTerms($data);
  116. $result = true;
  117. $requiredError = __d('croogo', 'Please select at least 1 value');
  118. $multipleError = __d('croogo', 'Please select at most 1 value');
  119. foreach ($type['Vocabulary'] as $vocabulary) {
  120. $fieldName = 'TaxonomyData.' . $vocabulary['id'];
  121. $terms = $this->_Taxonomy->find('all', array(
  122. 'recursive' => -1,
  123. 'fields' => 'term_id',
  124. 'conditions' => array(
  125. 'vocabulary_id' => $vocabulary['id'],
  126. ),
  127. ));
  128. $terms = Hash::extract($terms, '{n}.Taxonomy.term_id');
  129. $selected = count(array_intersect($selectedTerms, $terms));
  130. if ($vocabulary['required']) {
  131. if ($selected == 0) {
  132. $model->invalidate($fieldName, $requiredError);
  133. $result = false;
  134. }
  135. }
  136. if (!$vocabulary['multiple']) {
  137. if ($selected > 1) {
  138. $model->invalidate($fieldName, $multipleError);
  139. $result = false;
  140. }
  141. }
  142. }
  143. return $result;
  144. }
  145. /**
  146. * Transform TaxonomyData array to a format that can be used for save operation
  147. *
  148. * @param array $data Array containing relevant Taxonomy data
  149. * @param string $typeAlias string Node type alias
  150. * @return array Formatted data
  151. * @throws InvalidArgumentException
  152. */
  153. public function formatTaxonomyData(Model $model, &$data, $typeAlias) {
  154. $type = $model->Taxonomy->Vocabulary->Type->findByAlias($typeAlias);
  155. if (empty($type)) {
  156. throw new InvalidArgumentException(__d('croogo', 'Invalid Content Type'));
  157. }
  158. if (empty($data[$model->alias]['type'])) {
  159. $data[$model->alias]['type'] = $typeAlias;
  160. }
  161. $model->type = $type['Type']['alias'];
  162. if (!$model->Behaviors->enabled('Tree')) {
  163. $model->Behaviors->attach('Tree', array(
  164. 'scope' => array(
  165. $model->escapeField('type') => $model->type,
  166. ),
  167. ));
  168. }
  169. if (array_key_exists('TaxonomyData', $data)) {
  170. $foreignKey = $model->id;
  171. if (isset($data[$model->alias][$model->primaryKey])) {
  172. $foreignKey = $data[$model->alias][$model->primaryKey];
  173. }
  174. $data['Taxonomy'] = array();
  175. foreach ($data['TaxonomyData'] as $vocabularyId => $taxonomyIds) {
  176. if (empty($taxonomyIds)) {
  177. continue;
  178. }
  179. foreach ((array)$taxonomyIds as $taxonomyId) {
  180. $join = array(
  181. 'model' => $model->alias,
  182. 'foreign_key' => $foreignKey,
  183. 'taxonomy_id' => $taxonomyId,
  184. );
  185. $data['Taxonomy'][] = $join;
  186. }
  187. }
  188. unset($data['TaxonomyData']);
  189. }
  190. $this->cacheTerms($model, $data);
  191. }
  192. /**
  193. * Handle Model.Node.beforeSaveNode event
  194. *
  195. * @param CakeEvent $event Event containing `data` and `typeAlias`
  196. */
  197. public function onBeforeSaveNode($event) {
  198. $data = $event->data['data'];
  199. $typeAlias = $event->data['typeAlias'];
  200. $this->formatTaxonomyData($event->subject, $data, $typeAlias);
  201. $event->data['data'] = $data;
  202. }
  203. /**
  204. * beforeSave
  205. *
  206. * @return bool
  207. */
  208. public function beforeSave(Model $model, $options = array()) {
  209. if (!empty($options['fieldList'])) {
  210. return true;
  211. }
  212. $result = $this->validateTaxonomyData($model);
  213. if ($result !== true) {
  214. return $result;
  215. }
  216. return true;
  217. }
  218. /**
  219. * Caches Term in `terms` field
  220. *
  221. * @param Model model
  222. * @param array $data
  223. * @return void
  224. */
  225. public function cacheTerms(Model $model, &$data = null) {
  226. if ($data === null) {
  227. $data =& $model->data;
  228. }
  229. $taxonomyIds = $this->_getSelectedTerms($data);
  230. $taxonomies = $model->Taxonomy->find('all', array(
  231. 'conditions' => array(
  232. 'Taxonomy.id' => $taxonomyIds,
  233. ),
  234. ));
  235. $terms = Hash::combine($taxonomies, '{n}.Term.id', '{n}.Term.slug');
  236. $data[$model->alias]['terms'] = $model->encodeData($terms, array(
  237. 'trim' => false,
  238. 'json' => true,
  239. ));
  240. }
  241. }