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