1<?php
2
3/*
4 * This  is the root class for use by plugins to extend the Zenphoto database
5 * table fields. The administrative tabs for the objects will have input items
6 * for these new fields. They will be placed in the proximate location of the
7 * "custom data" field on the page.
8 *
9 * Fields added to searchable objects will be included in the list of selectable search
10 * fields. They will be enabled in the list by default. The standard search
11 * form allows a visitor to choose to disable the field for a particular search.
12 *
13 * Since the Zenphoto objects are not directly aware of these new fields, themes
14 * must use the "get()" methods to retrieve the content for display. E.g.
15 * <code>echo $_zp_current_album->get('new_field');</code>
16 *
17 * Fields are defined in the child class and passed as the <var>fields</var> array
18 * parameter which consists of a multi-dimensional array, one row per object/field.
19 * The elements of each row are:
20 *
21 * "table" is the database table name (without prefix) of the object to which the field is to be added.
22 * "name" is the MySQL field name for the new field
23 * "desc" is the "display name" of the field
24 * "type" is the database field type: int, varchar, tinytext, text, mediumtext, and longtext.
25 * "size" is the byte size of the varchar or int field (it is not needed for other types)
26 *
27 * Database fields names must conform to
28 * {@link http://dev.mysql.com/doc/refman/5.0/en/identifiers.html MySQL field naming rules}.
29 *
30 * The <var>constructor($fields)</var> method establishes the fields in the database.
31 * It is recommended that the plugin invoke this method from its class <var>__constructor<var>
32 * method and that the the class be instantiated when the plugin is loaded from
33 * the <em>setup</em> plugin options processing (e.g. when <var>OFFSET_PATH</var>==2.
34 * The <var>constructor</var> method will check if the plugin is enabled. If so
35 * it adds the fields, if not it removes any previously added fields.
36 *
37 * @author Stephen Billard (sbillard)
38 * @package plugins
39 * @subpackage fieldextender
40 *
41 */
42
43class fieldExtender {
44
45	/**
46	 *
47	 * This method establishes the current set of database fields. It will add the
48	 * fields to the database if they are not already present. Fields from previous
49	 * constructor calls that are no longer in the list will be removed from the
50	 * database (along with any data associated with them.)
51	 *
52	 * @param array $newfields
53	 */
54	function constructor($me, $newfields) {
55		$previous = getSerializedArray(getOption(get_class($this) . '_addedFields'));
56		$current = $fields = array();
57		if (extensionEnabled($me)) { //need to update the database tables.
58			foreach ($newfields as $newfield) {
59				$current[$newfield['table']][$newfield['name']] = true;
60				unset($previous[$newfield['table']][$newfield['name']]);
61				switch (strtolower($newfield['type'])) {
62					default:
63						$dbType = strtoupper($newfield['type']);
64						break;
65					case 'int':
66					case 'varchar':
67						$dbType = strtoupper($newfield['type']) . '(' . min(255, $newfield['size']) . ')';
68						break;
69				}
70				$sql = 'ALTER TABLE ' . prefix($newfield['table']) . ' ADD COLUMN `' . $newfield['name'] . '` ' . $dbType;
71				if (query($sql, false) && in_array($newfield['table'], array('albums', 'images', 'news', 'news_categories', 'pages')))
72					$fields[] = strtolower($newfield['name']);
73			}
74			setOption(get_class($this) . '_addedFields', serialize($current));
75		} else {
76			purgeOption(get_class($this) . '_addedFields');
77		}
78
79		$set_fields = array_flip(explode(',', getOption('search_fields')));
80		foreach ($previous as $table => $orpahed) { //drop fields no longer defined
81			foreach ($orpahed as $field => $v) {
82				unset($set_fields[$field]);
83				$sql = 'ALTER TABLE ' . prefix($table) . ' DROP `' . $field . '`';
84				query($sql, false);
85			}
86		}
87		$set_fields = array_unique(array_merge($fields, array_flip($set_fields)));
88		setOption('search_fields', implode(',', $set_fields));
89	}
90
91	/**
92	 * Updates the list of search fields to include the new fields
93	 * @param array $list the list of fields as known to the search engine
94	 * @return array
95	 */
96	static function _addToSearch($list, $fields) {
97		foreach ($fields as $newfield) {
98			if (in_array($newfield['table'], array('albums', 'images', 'news', 'news_categories', 'pages'))) {
99				$list[strtolower($newfield['name'])] = $newfield['desc'];
100			}
101		}
102		return $list;
103	}
104
105	/**
106	 * Process the save of user object type elements
107	 *
108	 * @param boolean $updated
109	 * @param object $userobj
110	 * @param int $i
111	 * @param boolean $alter
112	 * @return boolean
113	 */
114	static function _adminSave($updated, $userobj, $i, $alter, $fields) {
115		if ($userobj->getValid()) {
116			foreach ($fields as $field) {
117				if (isset($_POST[$field['name'] . '_' . $i])) {
118					if ($field['table'] == 'administrators') {
119						$olddata = $userobj->get($field['name']);
120						$userobj->set($field['name'], $newdata = $_POST[$field['name'] . '_' . $i]);
121						if ($olddata != $newdata) {
122							$updated = true;
123						}
124					}
125				}
126			}
127		}
128		return $updated;
129	}
130
131	/**
132	 * Displays the edit fields for user type objects
133	 *
134	 * @param string $html
135	 * @param object $userobj
136	 * @param int $i
137	 * @param string $background
138	 * @param boolean $current
139	 * @return string
140	 */
141	static function _adminEdit($html, $userobj, $i, $background, $current, $fields) {
142		$list = array();
143		foreach ($fields as $field) {
144			if ($field['table'] == 'administrators') {
145				$input = '<fieldset>' .
146								'<legend>' . $field['desc'] . '</legend>';
147				if (in_array(strtolower($field['type']), array('varchar', 'int', 'tinytext'))) {
148					$input .= '<input name = "' . $field['name'] . '_' . $i . '" type = "text" size = "' . TEXT_INPUT_SIZE . '" value = "' . html_encode($userobj->get($field['name'])) . '" />';
149				} else {
150					$input .= '<textarea name = "' . $field['name'] . '_' . $i . '" cols = "' . TEXTAREA_COLUMNS . '"rows = "1">' . html_encode($userobj->get($field['name'])) . '</textarea>';
151				}
152
153				$input .='</fieldset>';
154				$list[] = $input;
155			}
156		}
157		if (($count = count($list)) % 2) {
158			$list[] = '';
159		}
160
161		if (!empty($list)) {
162			for ($key = 0; $key < $count; $key = $key + 2) {
163				$html .=
164								'<tr' . ((!$current) ? ' style = "display:none;"' : '') . ' class = "userextrainfo">' .
165								'<td width = "20%"' . ((!empty($background)) ? ' style = "' . $background . '"' : '') . ' valign = "top">' .
166								$list[$key] .
167								'</td>' .
168								'<td ' . ((!empty($background)) ? ' style = "' . $background . '"' : '') . ' valign = "top">' .
169								$list[$key + 1] .
170								'</td>' .
171								'</tr>';
172			}
173		}
174		return $html;
175	}
176
177	/**
178	 * Processes the save of image and album objects
179	 * @param object $object
180	 * @param int $i
181	 */
182	static function _mediaItemSave($object, $i, $fields) {
183		foreach ($fields as $field) {
184			if ($field['table'] == $object->table) {
185				$olddata = $object->get($field['name']);
186				$object->set($field['name'], $newdata = $_POST[$field['name'] . '_' . $i]);
187				if ($olddata != $newdata) {
188					$updated = true;
189				}
190			}
191		}
192	}
193
194	/**
195	 * Displays the edit fields for image and album objects
196	 *
197	 * @param string $html
198	 * @param object $object
199	 * @param int $i
200	 * @return string
201	 */
202	static function _mediaItemEdit($html, $object, $i, $fields) {
203		foreach ($fields as $field) {
204			if ($field['table'] == $object->table) {
205				$html .= '<tr><td>' . $field['desc'] . '</td><td>';
206				if (in_array(strtolower($field['type']), array('varchar', 'int', 'tinytext'))) {
207					$html .= '<input name = "' . $field['name'] . '_' . $i . '" type = "text" style = "width:100%;" value = "' . html_encode($object->get($field['name'])) . '" />';
208				} else {
209					$html .= '<textarea name = "' . $field['name'] . '_' . $i . '" style = "width:100%;" rows = "6">' . html_encode($object->get($field['name'])) . '</textarea>';
210				}
211
212				$html .='</td></tr>';
213			}
214		}
215		return $html;
216	}
217
218	/**
219	 * Processes the save of zenpage objects
220	 *
221	 * @param string $custom
222	 * @param object $object
223	 * @return string
224	 */
225	static function _zenpageItemSave($custom, $object, $fields) {
226		foreach ($fields as $field) {
227			if ($field['table'] == $object->table) {
228				$olddata = $object->get($field['name']);
229				$object->set($field['name'], $newdata = $_POST[$field['name']]);
230				if ($olddata != $newdata) {
231					$updated = true;
232				}
233			}
234		}
235		return $custom;
236	}
237
238	/**
239	 * Displays the edit fields for zenpage objects
240	 *
241	 * @param string $html
242	 * @param object $object
243	 * @return string
244	 */
245	static function _zenpageItemEdit($html, $object, $fields) {
246		foreach ($fields as $field) {
247			if ($field['table'] == $object->table) {
248				$html .= '<tr><td>' . $field['desc'] . '</td><td>';
249				if (in_array(strtolower($field['type']), array('varchar', 'int', 'tinytext'))) {
250					$html .= '<input name="' . $field['name'] . '" type="text" style = "width:97%;"
251value="' . html_encode($object->get($field['name'])) . '" />';
252				} else {
253					$html .= '<textarea name = "' . $field['name'] . '" style = "width:97%;" "rows="6">' . html_encode($object->get($field['name'])) . '</textarea>';
254				}
255			}
256		}
257		return $html;
258	}
259
260	/**
261	 * registers filters for handling display and edit of objects as appropriate
262	 */
263	static function _register($me, $fields) {
264		zp_register_filter('searchable_fields', "$me::addToSearch");
265		$items = array();
266		foreach ($fields as $field) {
267			$items[$field['table']] = true;
268		}
269		if (isset($items['albums'])) {
270			zp_register_filter("save_album_utilities_data", "$me::mediaItemSave");
271			zp_register_filter("edit_album_custom_data", "$me::mediaItemEdit");
272		}
273		if (isset($items['images'])) {
274			zp_register_filter("save_image_utilities_data", "$me::mediaItemSave");
275			zp_register_filter("edit_image_custom_data", "$me::mediaItemEdit");
276		}
277		if (isset($items['administrators'])) {
278			zp_register_filter("save_admin_custom_data", "$me::adminSave");
279			zp_register_filter("edit_admin_custom_data", "$me::adminEdit");
280		}
281		if (isset($items['news'])) {
282			zp_register_filter("save_article_custom_data", "$me::zenpageItemSave");
283			zp_register_filter("edit_article_custom_data", "$me::zenpageItemEdit");
284		}
285		if (isset($items['news_categories'])) {
286			zp_register_filter("save_category_custom_data", "$me::zenpageItemSave");
287			zp_register_filter("edit_category_custom_data", "$me::zenpageItemEdit");
288		}
289		if (isset($items['pages'])) {
290			zp_register_filter("save_page_custom_data", "$me::zenpageItemSave");
291			zp_register_filter("edit_page_custom_data", "$me::zenpageItemEdit");
292		}
293		if (OFFSET_PATH && !getOption($me . "_addedFields")) {
294			zp_register_filter('admin_note', "$me::adminNotice");
295		}
296	}
297
298	/**
299	 * Notification of need to run setup
300	 * @param type $tab
301	 * @param type $subtab
302	 * @param type $me
303	 * @return type
304	 */
305	static function _adminNotice($tab, $subtab, $me) {
306		echo '<p class="notebox">' . sprintf(gettext('You will need to run <a href="%1$s">setup</a> to update the database with the custom fields defined by the <em>%2$s</em> plugin.'), FULLWEBPATH . '/' . ZENFOLDER . '/setup.php', $me) . '</p>';
307		return $tab;
308	}
309
310	/**
311	 * Returns an array with the content of the custom fields for the object
312	 * @param object $obj
313	 * @param array $fields
314	 * @return array
315	 */
316	static function _getCustomData($obj, $fields) {
317		$result = array();
318		foreach ($fields as $element) {
319			if ($element['table'] == $obj->table) {
320				$result[$element['name']] = $obj->get($element['name']);
321			}
322		}
323		return $result;
324	}
325
326	static function _setCustomData($obj, $values) {
327		foreach ($values as $field => $value) {
328			$obj->set($field, $value);
329		}
330	}
331
332}
333
334?>
335