1 | <?php |
||
2 | |||
3 | /** |
||
4 | * @package toolkit |
||
5 | */ |
||
6 | /** |
||
7 | * An entry is a combination of data that is stored in several Fields |
||
8 | * typically contained in one Section. Entries are created by the |
||
9 | * Authors of Symphony and hold all the content for the website. |
||
10 | * Entries are typically created from the Symphony backend, but |
||
11 | * can also be created using Events from the Frontend. |
||
12 | */ |
||
13 | |||
14 | class Entry |
||
15 | { |
||
16 | /** |
||
17 | * The constant for when an Entry is ok, that is, no errors have |
||
18 | * been raised by any of it's Fields. |
||
19 | * @var integer |
||
20 | */ |
||
21 | const __ENTRY_OK__ = 0; |
||
22 | |||
23 | /** |
||
24 | * The constant for an Entry if there is an error is raised by any of |
||
25 | * it's Fields. |
||
26 | * @var integer |
||
27 | */ |
||
28 | const __ENTRY_FIELD_ERROR__ = 100; |
||
29 | |||
30 | /** |
||
31 | * An associative array of basic metadata/settings for this Entry |
||
32 | * @var array |
||
33 | */ |
||
34 | protected $_fields = array(); |
||
35 | |||
36 | /** |
||
37 | * An associative array of the data for each of the Fields that make up |
||
38 | * this Entry. The key is the Field ID, and the value is typically an array |
||
39 | * @var array |
||
40 | */ |
||
41 | protected $_data = array(); |
||
42 | |||
43 | /** |
||
44 | * An ISO 8601 representation of when this Entry was created |
||
45 | * eg. `2004-02-12T15:19:21+00:00` |
||
46 | * @deprecated Since Symphony 2.3.1, use $entry->get('creation_date') instead. This |
||
47 | * variable will be removed in Symphony 3.0 |
||
48 | * @var string |
||
49 | */ |
||
50 | public $creationDate = null; |
||
51 | |||
52 | /** |
||
53 | * Entries have some basic metadata settings such as the Entry ID, the Author ID |
||
54 | * who created it and the Section that the Entry sits in. This function will set a |
||
55 | * setting to a value overwriting any existing value for this setting |
||
56 | * |
||
57 | * @param string $setting |
||
58 | * the setting key. |
||
59 | * @param mixed $value |
||
60 | * the value of the setting. |
||
61 | */ |
||
62 | public function set($setting, $value) |
||
63 | { |
||
64 | $this->_fields[$setting] = $value; |
||
65 | } |
||
66 | |||
67 | /** |
||
68 | * Accessor to the a setting by name. If no setting is provided all the |
||
69 | * settings of this Entry instance are returned. |
||
70 | * |
||
71 | * @param string $setting (optional) |
||
72 | * the name of the setting to access the value for. This is optional and |
||
73 | * defaults to null in which case all settings are returned. |
||
74 | * @return null|mixed|array |
||
75 | * the value of the setting if there is one, all settings if the input setting |
||
76 | * was omitted or null if the setting was supplied but there is no value |
||
77 | * for that setting. |
||
78 | */ |
||
79 | public function get($setting = null) |
||
0 ignored issues
–
show
Coding Style
introduced
by
![]() |
|||
80 | { |
||
81 | if (is_null($setting)) { |
||
82 | return $this->_fields; |
||
83 | } |
||
84 | |||
85 | if (!isset($this->_fields[$setting])) { |
||
86 | return null; |
||
87 | } |
||
88 | |||
89 | return $this->_fields[$setting]; |
||
90 | } |
||
91 | |||
92 | /** |
||
93 | * Creates the initial entry row in tbl_entries and returns the resulting |
||
94 | * Entry ID using `getInsertID()`. |
||
95 | * |
||
96 | * @see toolkit.MySQL#getInsertID() |
||
97 | * @throws DatabaseException |
||
98 | * @return integer |
||
99 | */ |
||
100 | public function assignEntryId() |
||
101 | { |
||
102 | $fields = $this->get(); |
||
103 | $fields['creation_date'] = $fields['modification_date'] = DateTimeObj::get('Y-m-d H:i:s'); |
||
104 | $fields['creation_date_gmt'] = $fields['modification_date_gmt'] = DateTimeObj::getGMT('Y-m-d H:i:s'); |
||
105 | $fields['author_id'] = is_null($this->get('author_id')) ? 1 : (int)$this->get('author_id'); // Author_id cannot be null |
||
106 | $fields['modification_author_id'] = is_null($this->get('modification_author_id')) ? $fields['author_id'] : (int)$this->get('modification_author_id'); |
||
107 | |||
108 | Symphony::Database()->insert($fields, 'tbl_entries'); |
||
109 | |||
110 | if (!$entry_id = Symphony::Database()->getInsertID()) { |
||
111 | return null; |
||
112 | } |
||
113 | |||
114 | $this->set('id', $entry_id); |
||
115 | |||
116 | return $entry_id; |
||
117 | } |
||
118 | |||
119 | /** |
||
120 | * Set the data for a Field in this Entry, given the Field ID and it's data |
||
121 | * |
||
122 | * @param integer $field_id |
||
123 | * The ID of the Field this data is for |
||
124 | * @param mixed $data |
||
125 | * Often an array |
||
126 | */ |
||
127 | public function setData($field_id, $data) |
||
128 | { |
||
129 | $this->_data[$field_id] = $data; |
||
130 | } |
||
131 | |||
132 | /** |
||
133 | * When an entry is saved from a form (either Frontend/Backend) this |
||
134 | * function will find all the fields in this set and loop over them, setting |
||
135 | * the data to each of the fields for processing. If any errors occur during |
||
136 | * this, `_ENTRY_FIELD_ERROR_` is returned, and an array is available with |
||
137 | * the errors. |
||
138 | * |
||
139 | * @param array $data |
||
140 | * An associative array of the data for this entry where they key is the |
||
141 | * Field's handle for this Section and the value is the data from the form |
||
142 | * @param array $errors |
||
143 | * An associative array of errors, by reference. The key is the `field_id`, the value |
||
144 | * is the message text. Defaults to an empty array |
||
145 | * @param boolean $simulate |
||
146 | * If $simulate is given as true, a dry run of this function will occur, where |
||
147 | * regardless of errors, an Entry will not be saved in the database. Defaults to |
||
148 | * false |
||
149 | * @param boolean $ignore_missing_fields |
||
150 | * This parameter allows Entries to be updated, rather than replaced. This is |
||
151 | * useful if the input form only contains a couple of the fields for this Entry. |
||
152 | * Defaults to false, which will set Fields to their default values if they are not |
||
153 | * provided in the $data |
||
154 | * @throws DatabaseException |
||
155 | * @throws Exception |
||
156 | * @return integer |
||
157 | * Either `Entry::__ENTRY_OK__` or `Entry::__ENTRY_FIELD_ERROR__` |
||
158 | */ |
||
159 | public function setDataFromPost($data, &$errors = null, $simulate = false, $ignore_missing_fields = false) |
||
0 ignored issues
–
show
|
|||
160 | { |
||
161 | $status = Entry::__ENTRY_OK__; |
||
162 | |||
163 | // Entry has no ID, create it: |
||
164 | if (!$this->get('id') && $simulate === false) { |
||
165 | $entry_id = $this->assignEntryId(); |
||
166 | |||
167 | if (is_null($entry_id)) { |
||
0 ignored issues
–
show
|
|||
168 | return Entry::__ENTRY_FIELD_ERROR__; |
||
169 | } |
||
170 | } |
||
171 | |||
172 | $section = SectionManager::fetch($this->get('section_id')); |
||
173 | $schema = $section->fetchFieldsSchema(); |
||
174 | |||
175 | foreach ($schema as $info) { |
||
176 | $message = null; |
||
177 | $field = FieldManager::fetch($info['id']); |
||
178 | |||
179 | if ($ignore_missing_fields && !isset($data[$field->get('element_name')])) { |
||
180 | continue; |
||
181 | } |
||
182 | |||
183 | $result = $field->processRawFieldData((isset($data[$info['element_name']]) ? $data[$info['element_name']] : null), $s, $message, $simulate, $this->get('id')); |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||
184 | |||
185 | if ($s !== Field::__OK__) { |
||
186 | $status = Entry::__ENTRY_FIELD_ERROR__; |
||
187 | $errors[$info['id']] = $message; |
||
188 | } |
||
189 | |||
190 | $this->setData($info['id'], $result); |
||
191 | } |
||
192 | |||
193 | // Failed to create entry, cleanup |
||
194 | if ($status !== Entry::__ENTRY_OK__ && !is_null($entry_id)) { |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||
195 | Symphony::Database()->delete('tbl_entries', sprintf(" `id` = %d ", $entry_id)); |
||
0 ignored issues
–
show
Coding Style
Comprehensibility
introduced
by
The string literal
`id` = %d does not require double quotes, as per coding-style, please use single quotes.
PHP provides two ways to mark string literals. Either with single quotes String literals in single quotes on the other hand are evaluated very literally and the only two
characters that needs escaping in the literal are the single quote itself ( Double quoted string literals may contain other variables or more complex escape sequences. <?php
$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";
print $doubleQuoted;
will print an indented: If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear. For more information on PHP string literals and available escape sequences see the PHP core documentation. ![]() |
|||
196 | } |
||
197 | |||
198 | return $status; |
||
199 | } |
||
200 | |||
201 | /** |
||
202 | * Accessor function to return data from this Entry for a particular |
||
203 | * field. Optional parameter to return this data as an object instead |
||
204 | * of an array. If a Field is not provided, an associative array of all data |
||
205 | * assigned to this Entry will be returned. |
||
206 | * |
||
207 | * @param integer $field_id |
||
208 | * The ID of the Field whose data you want |
||
209 | * @param boolean $asObject |
||
210 | * If true, the data will be returned as an object instead of an |
||
211 | * array. Defaults to false. Note that if a `$field_id` is not provided |
||
212 | * the result will always be an array. |
||
213 | * @return array|object |
||
214 | * Depending on the value of `$asObject`, return the field's data |
||
215 | * as either an array or an object. If no data exists, null will be |
||
216 | * returned. |
||
217 | */ |
||
218 | public function getData($field_id = null, $asObject = false) |
||
0 ignored issues
–
show
|
|||
219 | { |
||
220 | $fieldData = isset($this->_data[$field_id]) |
||
221 | ? $this->_data[$field_id] |
||
0 ignored issues
–
show
|
|||
222 | : array(); |
||
223 | |||
224 | if (!$field_id) { |
||
0 ignored issues
–
show
The expression
$field_id of type integer|null is loosely compared to false ; this is ambiguous if the integer can be 0. You might want to explicitly use === null instead.
In PHP, under loose comparison (like For 0 == false // true
0 == null // true
123 == false // false
123 == null // false
// It is often better to use strict comparison
0 === false // false
0 === null // false
![]() |
|||
225 | return $this->_data; |
||
226 | } |
||
227 | |||
228 | return ($asObject ? (object)$fieldData : $fieldData); |
||
0 ignored issues
–
show
|
|||
229 | } |
||
230 | |||
231 | /** |
||
232 | * Given a array of data from a form, this function will iterate over all the fields |
||
233 | * in this Entry's Section and call their `checkPostFieldData()` function. |
||
234 | * |
||
235 | * @param array $data |
||
236 | * An associative array of the data for this entry where they key is the |
||
237 | * Field's handle for this Section and the value is the data from the form |
||
238 | * @param null|array $errors |
||
239 | * An array of errors, by reference. Defaults to empty* An array of errors, by reference. |
||
240 | * Defaults to empty |
||
241 | * @param boolean $ignore_missing_fields |
||
242 | * This parameter allows Entries to be updated, rather than replaced. This is |
||
243 | * useful if the input form only contains a couple of the fields for this Entry. |
||
244 | * Defaults to false, which will check all Fields even if they are not |
||
245 | * provided in the $data |
||
246 | * @throws Exception |
||
247 | * @return integer |
||
248 | * Either `Entry::__ENTRY_OK__` or `Entry::__ENTRY_FIELD_ERROR__` |
||
249 | */ |
||
250 | public function checkPostData($data, &$errors = null, $ignore_missing_fields = false) |
||
0 ignored issues
–
show
|
|||
251 | { |
||
252 | $status = Entry::__ENTRY_OK__; |
||
253 | $section = SectionManager::fetch($this->get('section_id')); |
||
254 | $schema = $section->fetchFieldsSchema(); |
||
255 | |||
256 | foreach ($schema as $info) { |
||
257 | $message = null; |
||
258 | $field = FieldManager::fetch($info['id']); |
||
259 | |||
260 | /** |
||
261 | * Prior to checking a field's post data. |
||
262 | * |
||
263 | * @delegate EntryPreCheckPostFieldData |
||
264 | * @since Symphony 2.7.0 |
||
265 | * @param string $context |
||
266 | * '/backend/' resp. '/frontend/' |
||
267 | * @param object $section |
||
268 | * The section of the field |
||
269 | * @param object $field |
||
270 | * The field, passed by reference |
||
271 | * @param array $post_data |
||
272 | * All post data, passed by reference |
||
273 | * @param array $errors |
||
274 | * The errors (of fields already checked), passed by reference |
||
275 | */ |
||
276 | Symphony::ExtensionManager()->notifyMembers( |
||
277 | 'EntryPreCheckPostFieldData', |
||
278 | class_exists('Administration', false) ? '/backend/' : '/frontend/', |
||
279 | array( |
||
280 | 'section' => $section, |
||
281 | 'field' => &$field, |
||
282 | 'post_data' => &$data, |
||
283 | 'errors' => &$errors |
||
284 | ) |
||
285 | ); |
||
286 | |||
287 | if ($ignore_missing_fields && !isset($data[$field->get('element_name')])) { |
||
288 | continue; |
||
289 | } |
||
290 | |||
291 | if (Field::__OK__ !== $field->checkPostFieldData((isset($data[$info['element_name']]) ? $data[$info['element_name']] : null), $message, $this->get('id'))) { |
||
292 | $status = Entry::__ENTRY_FIELD_ERROR__; |
||
293 | $errors[$info['id']] = $message; |
||
294 | } |
||
295 | } |
||
296 | |||
297 | return $status; |
||
298 | } |
||
299 | |||
300 | /** |
||
301 | * Iterates over all the Fields in this Entry calling their |
||
302 | * `processRawFieldData()` function to set default values for this Entry. |
||
303 | * |
||
304 | * @see toolkit.Field#processRawFieldData() |
||
305 | */ |
||
306 | public function findDefaultData() |
||
307 | { |
||
308 | $section = SectionManager::fetch($this->get('section_id')); |
||
309 | $schema = $section->fetchFields(); |
||
310 | |||
311 | foreach ($schema as $field) { |
||
312 | $field_id = $field->get('field_id'); |
||
313 | if (empty($field_id) || isset($this->_data[$field_id])) { |
||
314 | continue; |
||
315 | } |
||
316 | |||
317 | $result = $field->processRawFieldData(null, $status, $message, false, $this->get('id')); |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
Comprehensibility
Best Practice
introduced
by
|
|||
318 | $this->setData($field_id, $result); |
||
319 | } |
||
320 | |||
321 | $this->set('modification_date', DateTimeObj::get('Y-m-d H:i:s')); |
||
322 | $this->set('modification_date_gmt', DateTimeObj::getGMT('Y-m-d H:i:s')); |
||
323 | |||
324 | if (!$this->get('creation_date')) { |
||
325 | $this->set('creation_date', $this->get('modification_date')); |
||
326 | } |
||
327 | |||
328 | if (!$this->get('creation_date_gmt')) { |
||
329 | $this->set('creation_date_gmt', $this->get('modification_date_gmt')); |
||
330 | } |
||
331 | |||
332 | if (!$this->get('author_id')) { |
||
333 | $this->set('author_id', 1); |
||
334 | } |
||
335 | |||
336 | if (!$this->get('modification_author_id')) { |
||
337 | $this->set('modification_author_id', $this->get('author_id')); |
||
338 | } |
||
339 | } |
||
340 | |||
341 | /** |
||
342 | * Commits this Entry's data to the database, by first finding the default |
||
343 | * data for this `Entry` and then utilising the `EntryManager`'s |
||
344 | * add or edit function. The `EntryManager::edit` function is used if |
||
345 | * the current `Entry` object has an ID, otherwise `EntryManager::add` |
||
346 | * is used. |
||
347 | * |
||
348 | * @see toolkit.Entry#findDefaultData() |
||
349 | * @throws Exception |
||
350 | * @return boolean |
||
351 | * true if the commit was successful, false otherwise. |
||
352 | */ |
||
353 | public function commit() |
||
354 | { |
||
355 | $this->findDefaultData(); |
||
356 | |||
357 | return ($this->get('id') ? EntryManager::edit($this) : EntryManager::add($this)); |
||
358 | } |
||
359 | |||
360 | /** |
||
361 | * Entries may link to other Entries through fields. This function will return the |
||
362 | * number of entries that are associated with the current entry as an associative |
||
363 | * array. If there are no associated entries, null will be returned. |
||
364 | * |
||
365 | * @param array $associated_sections |
||
366 | * An associative array of sections to return the Entry counts from. Defaults to |
||
367 | * null, which will fetch all the associations of this Entry. |
||
368 | * @throws Exception |
||
369 | * @return array |
||
370 | * An associative array with the key being the associated Section's ID and the |
||
371 | * value being the number of entries associated with this Entry. |
||
372 | */ |
||
373 | public function fetchAllAssociatedEntryCounts($associated_sections = null) |
||
0 ignored issues
–
show
|
|||
374 | { |
||
375 | if (is_null($this->get('section_id'))) { |
||
376 | return null; |
||
377 | } |
||
378 | |||
379 | if (is_null($associated_sections)) { |
||
380 | $section = SectionManager::fetch($this->get('section_id')); |
||
381 | $associated_sections = $section->fetchChildAssociations(); |
||
382 | } |
||
383 | |||
384 | if (!is_array($associated_sections) || empty($associated_sections)) { |
||
0 ignored issues
–
show
|
|||
385 | return null; |
||
386 | } |
||
387 | |||
388 | $counts = array(); |
||
389 | |||
390 | foreach ($associated_sections as $as) { |
||
391 | $field = FieldManager::fetch($as['child_section_field_id']); |
||
392 | $parent_section_field_id = $as['parent_section_field_id']; |
||
393 | |||
394 | if (!is_null($parent_section_field_id)) { |
||
395 | $search_value = $field->fetchAssociatedEntrySearchValue( |
||
396 | $this->getData($as['parent_section_field_id']), |
||
397 | $as['parent_section_field_id'], |
||
398 | $this->get('id') |
||
399 | ); |
||
400 | } else { |
||
401 | $search_value = $this->get('id'); |
||
402 | } |
||
403 | |||
404 | $counts[$as['child_section_id']][$as['child_section_field_id']] = $field->fetchAssociatedEntryCount($search_value); |
||
405 | } |
||
406 | |||
407 | return $counts; |
||
408 | } |
||
409 | } |
||
410 |