1 <?php
2
3 /*
4 * This file is part of the Icybee package.
5 *
6 * (c) Olivier Laviale <olivier.laviale@gmail.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12 namespace Icybee\Modules\Taxonomy\Terms;
13
14 /**
15 * A term of a vocabulary.
16 *
17 * @property-read array $nodes_keys
18 */
19 class Term extends \ICanBoogie\ActiveRecord implements \IteratorAggregate, \Brickrouge\CSSClassNames
20 {
21 use \Brickrouge\CSSClassNamesProperty;
22
23 const VTID = 'vtid';
24 const VID = 'vid';
25 const TERM = 'term';
26 const TERMSLUG = 'termslug';
27 const WEIGHT = 'weight';
28
29 /**
30 * Identifier of the vocabulary term.
31 *
32 * @var int
33 */
34 public $vtid;
35
36 /**
37 * Identifier of the vocabulary the term belongs to.
38 *
39 * @var int
40 */
41 public $vid;
42
43 /**
44 * Name of the term.
45 *
46 * @var string
47 */
48 public $term;
49
50 /**
51 * Normalized name of the term.
52 *
53 * @var string
54 */
55 public $termslug;
56
57 /**
58 * Weight of the term relative to other terms in the same vocabulary.
59 *
60 * @var int
61 */
62 public $weight;
63
64 /**
65 * The `$model` property defaults to "taxonomy.terms".
66 *
67 * @param string $model
68 */
69 public function __construct($model='taxonomy.terms')
70 {
71 parent::__construct($model);
72 }
73
74 /**
75 * Returns the {@link $term} property.
76 *
77 * @return string
78 */
79 public function __toString()
80 {
81 return $this->term;
82 }
83
84 /**
85 * Returns the iterator for the IteratorAggregate interface.
86 */
87 public function getIterator()
88 {
89 return new \ArrayIterator($this->nodes);
90 }
91
92 /**
93 * Returns the vocabulary the term belongs to.
94 *
95 * @return \Icybee\Modules\Taxonomy\Vocabulary\Vocabulary
96 */
97 protected function lazy_get_vocabulary()
98 {
99 global $core;
100
101 return $this->vid ? $core->models['taxonomy.vocabulary'][$this->vid] : null;
102 }
103
104 static private $nodes_keys_by_vid_and_vtid = array();
105
106 /**
107 * Returns the nodes keys associated with the term.
108 *
109 * Note: In order to reduce the number of database requests, the nodes keys of _all_ the terms
110 * in the same vocabulary are gathered.
111 *
112 * @return array
113 */
114 protected function lazy_get_nodes_keys()
115 {
116 global $core;
117
118 $vid = $this->vid;
119
120 if (!isset(self::$nodes_keys_by_vid_and_vtid[$vid]))
121 {
122 $groups = $core->models['taxonomy.terms/nodes']
123 ->select('vtid, nid')
124 ->filter_by_vid($this->vid)
125 ->order('term_node.weight')
126 ->all(\PDO::FETCH_COLUMN | \PDO::FETCH_GROUP);
127
128 foreach ($groups as &$keys)
129 {
130 if (empty($keys)) continue;
131
132 $keys = array_combine($keys, $keys);
133 }
134
135 unset($keys);
136
137 self::$nodes_keys_by_vid_and_vtid[$vid] = $groups;
138 }
139
140 $vtid = $this->vtid;
141
142 if (!isset(self::$nodes_keys_by_vid_and_vtid[$vid][$vtid]))
143 {
144 return array();
145 }
146
147 return self::$nodes_keys_by_vid_and_vtid[$vid][$vtid];
148 }
149
150 /**
151 * Returns the nodes associated with the term.
152 *
153 * @return array The nodes associated with the term, or an empty array if there is none.
154 */
155 protected function lazy_get_nodes()
156 {
157 global $core;
158
159 $ids = $this->model
160 ->select('nid')
161 ->joins('INNER JOIN {prefix}taxonomy_terms__nodes ttnode USING(vtid)') // FIXME-20110614 Query should be cleverer then that
162 ->joins(':nodes')
163 ->filter_by_vtid($this->vtid)
164 ->where('is_online = 1')
165 ->order('ttnode.weight')
166 ->all(PDO::FETCH_COLUMN);
167
168 if (!$ids)
169 {
170 return array();
171 }
172
173 $constructors = $core->models['nodes']->select('constructor, nid')->where(array('nid' => $ids))
174 ->all(PDO::FETCH_GROUP | PDO::FETCH_COLUMN);
175
176 $rc = array_flip($ids);
177
178 foreach ($constructors as $constructor => $constructor_ids)
179 {
180 $records = $core->models[$constructor]->find($constructor_ids);
181
182 foreach ($records as $id => $record)
183 {
184 $rc[$id] = $record;
185 }
186 }
187
188 return array_values($rc);
189 }
190
191 /**
192 * Returns the CSS class names of the term.
193 *
194 * @return array[string]mixed
195 */
196 protected function get_css_class_names()
197 {
198 $vocabulary_slug = '';
199
200 if (isset($this->vocabularyslug))
201 {
202 $vocabulary_slug = $this->vocabularyslug;
203 }
204 else if ($this->vid && $this->vocabulary)
205 {
206 $vocabulary_slug = $this->vocabulary->vocabularyslug;
207 }
208
209 return array
210 (
211 'type' => 'term',
212 'id' => 'term-' . $this->vtid,
213 'slug' => 'term-slug--' . $this->termslug,
214 'vid' => $this->vid ? 'vocabulary-' . $this->vid : null,
215 'vslug' => $vocabulary_slug ? "vocabulary-slug--{$vocabulary_slug}" : null
216 );
217 }
218 }