| 
									
										
										
										
											2010-08-16 14:02:31 -07:00
										 |  |  | <?php | 
					
						
							|  |  |  | /* | 
					
						
							|  |  |  |  * StatusNet - the distributed open-source microblogging tool | 
					
						
							|  |  |  |  * Copyright (C) 2010, StatusNet, Inc. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This program is free software: you can redistribute it and/or modify | 
					
						
							|  |  |  |  * it under the terms of the GNU Affero General Public License as published by | 
					
						
							|  |  |  |  * the Free Software Foundation, either version 3 of the License, or | 
					
						
							|  |  |  |  * (at your option) any later version. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This program is distributed in the hope that it will be useful, | 
					
						
							|  |  |  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
					
						
							|  |  |  |  * GNU Affero General Public License for more details. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * You should have received a copy of the GNU Affero General Public License | 
					
						
							|  |  |  |  * along with this program.  If not, see <http://www.gnu.org/licenses/>. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * Wrapper for Memcached_DataObject which knows its own schema definition. | 
					
						
							|  |  |  |  * Builds its own damn settings from a schema definition. | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2010-08-16 15:14:16 -07:00
										 |  |  |  * @author Brion Vibber <brion@status.net> | 
					
						
							| 
									
										
										
										
											2010-08-16 14:02:31 -07:00
										 |  |  |  */ | 
					
						
							| 
									
										
										
										
											2010-08-16 15:14:16 -07:00
										 |  |  | abstract class Managed_DataObject extends Memcached_DataObject | 
					
						
							| 
									
										
										
										
											2010-08-16 14:02:31 -07:00
										 |  |  | { | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * The One True Thingy that must be defined and declared. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public static abstract function schemaDef(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * get/set an associative array of table columns | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @access public | 
					
						
							|  |  |  |      * @return array (associative) | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     function table() | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2010-10-07 14:21:06 -07:00
										 |  |  |         // Hack for PHP 5.2 not supporting late static binding
 | 
					
						
							|  |  |  |         //$table = static::schemaDef();
 | 
					
						
							|  |  |  |         $table = call_user_func(array(get_class($this), 'schemaDef')); | 
					
						
							| 
									
										
										
										
											2010-08-16 14:02:31 -07:00
										 |  |  |         return array_map(array($this, 'columnBitmap'), $table['fields']); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * get/set an  array of table primary keys | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * Key info is pulled from the table definition array. | 
					
						
							|  |  |  |      *  | 
					
						
							|  |  |  |      * @access private | 
					
						
							|  |  |  |      * @return array | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     function keys() | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         return array_keys($this->keyTypes()); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Get a sequence key | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * Returns the first serial column defined in the table, if any. | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @access private | 
					
						
							|  |  |  |      * @return array (column,use_native,sequence_name) | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     function sequenceKey() | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2010-11-01 14:31:32 -07:00
										 |  |  |         $table = call_user_func(array(get_class($this), 'schemaDef')); | 
					
						
							| 
									
										
										
										
											2010-08-16 14:02:31 -07:00
										 |  |  |         foreach ($table['fields'] as $name => $column) { | 
					
						
							|  |  |  |             if ($column['type'] == 'serial') { | 
					
						
							|  |  |  |                 // We have a serial/autoincrement column.
 | 
					
						
							|  |  |  |                 // Declare it to be a native sequence!
 | 
					
						
							|  |  |  |                 return array($name, true, false); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // No sequence key on this table.
 | 
					
						
							|  |  |  |         return array(false, false, false); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Return key definitions for DB_DataObject and Memcache_DataObject. | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * DB_DataObject needs to know about keys that the table has; this function
 | 
					
						
							|  |  |  |      * defines them. | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @return array key definitions | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     function keyTypes() | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2010-11-01 14:31:32 -07:00
										 |  |  |         $table = call_user_func(array(get_class($this), 'schemaDef')); | 
					
						
							| 
									
										
										
										
											2011-03-21 15:04:32 -07:00
										 |  |  |         $keys = array(); | 
					
						
							| 
									
										
										
										
											2010-08-16 14:02:31 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |         if (!empty($table['unique keys'])) { | 
					
						
							|  |  |  |             foreach ($table['unique keys'] as $idx => $fields) { | 
					
						
							|  |  |  |                 foreach ($fields as $name) { | 
					
						
							|  |  |  |                     $keys[$name] = 'U'; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (!empty($table['primary key'])) { | 
					
						
							|  |  |  |             foreach ($table['primary key'] as $name) { | 
					
						
							|  |  |  |                 $keys[$name] = 'K'; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return $keys; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Build the appropriate DB_DataObject bitfield map for this field. | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @param array $column | 
					
						
							|  |  |  |      * @return int | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     function columnBitmap($column) | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2010-08-16 15:28:00 -07:00
										 |  |  |         $type = $column['type']; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // For quoting style...
 | 
					
						
							|  |  |  |         $intTypes = array('int', | 
					
						
							|  |  |  |                           'integer', | 
					
						
							|  |  |  |                           'float', | 
					
						
							|  |  |  |                           'serial', | 
					
						
							|  |  |  |                           'numeric'); | 
					
						
							|  |  |  |         if (in_array($type, $intTypes)) { | 
					
						
							|  |  |  |             $style = DB_DATAOBJECT_INT; | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             $style = DB_DATAOBJECT_STR; | 
					
						
							| 
									
										
										
										
											2010-08-16 14:02:31 -07:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-08-16 15:28:00 -07:00
										 |  |  |         // Data type formatting style...
 | 
					
						
							|  |  |  |         $formatStyles = array('blob' => DB_DATAOBJECT_BLOB, | 
					
						
							|  |  |  |                               'text' => DB_DATAOBJECT_TXT, | 
					
						
							|  |  |  |                               'date' => DB_DATAOBJECT_DATE, | 
					
						
							|  |  |  |                               'time' => DB_DATAOBJECT_TIME, | 
					
						
							|  |  |  |                               'datetime' => DB_DATAOBJECT_DATE | DB_DATAOBJECT_TIME, | 
					
						
							|  |  |  |                               'timestamp' => DB_DATAOBJECT_MYSQLTIMESTAMP); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (isset($formatStyles[$type])) { | 
					
						
							|  |  |  |             $style |= $formatStyles[$type]; | 
					
						
							| 
									
										
										
										
											2010-08-16 14:02:31 -07:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-08-16 15:28:00 -07:00
										 |  |  |         // Nullable?
 | 
					
						
							| 
									
										
										
										
											2010-08-16 14:02:31 -07:00
										 |  |  |         if (!empty($column['not null'])) { | 
					
						
							| 
									
										
										
										
											2010-08-16 15:28:00 -07:00
										 |  |  |             $style |= DB_DATAOBJECT_NOTNULL; | 
					
						
							| 
									
										
										
										
											2010-08-16 14:02:31 -07:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-08-16 15:28:00 -07:00
										 |  |  |         return $style; | 
					
						
							| 
									
										
										
										
											2010-08-16 14:02:31 -07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2011-08-26 11:37:45 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |     function links() | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $links = array(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         $table = call_user_func(array(get_class($this), 'schemaDef')); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         foreach ($table['foreign keys'] as $keyname => $keydef) { | 
					
						
							|  |  |  |             if (count($keydef) == 2 && is_string($keydef[0]) && is_array($keydef[1]) && count($keydef[1]) == 1) { | 
					
						
							| 
									
										
										
										
											2011-09-07 21:45:49 -07:00
										 |  |  |                 if (isset($keydef[1][0])) { | 
					
						
							|  |  |  |                     $links[$keydef[1][0]] = $keydef[0].':'.$keydef[1][1]; | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2011-08-26 11:37:45 -04:00
										 |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return $links; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2011-09-28 18:32:43 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Return a list of all primary/unique keys / vals that will be used for | 
					
						
							|  |  |  |      * caching. This will understand compound unique keys, which | 
					
						
							|  |  |  |      * Memcached_DataObject doesn't have enough info to handle properly. | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @return array of strings | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     function _allCacheKeys() | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $table = call_user_func(array(get_class($this), 'schemaDef')); | 
					
						
							|  |  |  |         $ckeys = array(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (!empty($table['unique keys'])) { | 
					
						
							| 
									
										
											  
											
												Further fixes to Managed_DataObject::_allCacheKeys(): now uses self::multicacheKey() to generate the (possibly compound) keys, which makes it match the order of the keys used when calling pkeyGet().
This should resolve the issues darkip was reporting with user_im_prefs entries returning null immediately after insertion (seen with memcached off, so it was happening even with the built-in in-process cache in the Cache base class).
What was happening was that the initial pkeyGet() would end up saving a negative cache entry under the form with the fields sorted in the key, as via multicacheKey():
    'statusnet:blaguette:user_im_prefs:screenname,transport:brionv,sms' => 'N;'
then we'd do an insert() on the new entry, saving cache entries for the non-sorted key names returned by _allCacheKeys():
    'statusnet:blaguette:user_im_prefs:transport,screenname:sms,brionv' => 'O...'
    'statusnet:blaguette:user_im_prefs:user_id,transport:1234,sms' => 'O...'
but the next query via pkeyGet() still saw the negative lookup cache from before, and came back with null.
Now, _allCacheKeys() sorts the fields in the keys by using the same key-builder function, and queries pick up the same thing you just inserted. :)
											
										 
											2011-09-29 15:21:52 -07:00
										 |  |  |             $keyNames = $table['unique keys']; | 
					
						
							|  |  |  |             foreach ($keyNames as $idx => $fields) { | 
					
						
							| 
									
										
										
										
											2011-09-28 18:32:43 -07:00
										 |  |  |                 $val = array(); | 
					
						
							|  |  |  |                 foreach ($fields as $name) { | 
					
						
							| 
									
										
											  
											
												Further fixes to Managed_DataObject::_allCacheKeys(): now uses self::multicacheKey() to generate the (possibly compound) keys, which makes it match the order of the keys used when calling pkeyGet().
This should resolve the issues darkip was reporting with user_im_prefs entries returning null immediately after insertion (seen with memcached off, so it was happening even with the built-in in-process cache in the Cache base class).
What was happening was that the initial pkeyGet() would end up saving a negative cache entry under the form with the fields sorted in the key, as via multicacheKey():
    'statusnet:blaguette:user_im_prefs:screenname,transport:brionv,sms' => 'N;'
then we'd do an insert() on the new entry, saving cache entries for the non-sorted key names returned by _allCacheKeys():
    'statusnet:blaguette:user_im_prefs:transport,screenname:sms,brionv' => 'O...'
    'statusnet:blaguette:user_im_prefs:user_id,transport:1234,sms' => 'O...'
but the next query via pkeyGet() still saw the negative lookup cache from before, and came back with null.
Now, _allCacheKeys() sorts the fields in the keys by using the same key-builder function, and queries pick up the same thing you just inserted. :)
											
										 
											2011-09-29 15:21:52 -07:00
										 |  |  |                     $val[$name] = self::valueString($this->$name); | 
					
						
							| 
									
										
										
										
											2011-09-28 18:32:43 -07:00
										 |  |  |                 } | 
					
						
							| 
									
										
											  
											
												Further fixes to Managed_DataObject::_allCacheKeys(): now uses self::multicacheKey() to generate the (possibly compound) keys, which makes it match the order of the keys used when calling pkeyGet().
This should resolve the issues darkip was reporting with user_im_prefs entries returning null immediately after insertion (seen with memcached off, so it was happening even with the built-in in-process cache in the Cache base class).
What was happening was that the initial pkeyGet() would end up saving a negative cache entry under the form with the fields sorted in the key, as via multicacheKey():
    'statusnet:blaguette:user_im_prefs:screenname,transport:brionv,sms' => 'N;'
then we'd do an insert() on the new entry, saving cache entries for the non-sorted key names returned by _allCacheKeys():
    'statusnet:blaguette:user_im_prefs:transport,screenname:sms,brionv' => 'O...'
    'statusnet:blaguette:user_im_prefs:user_id,transport:1234,sms' => 'O...'
but the next query via pkeyGet() still saw the negative lookup cache from before, and came back with null.
Now, _allCacheKeys() sorts the fields in the keys by using the same key-builder function, and queries pick up the same thing you just inserted. :)
											
										 
											2011-09-29 15:21:52 -07:00
										 |  |  |                 $ckeys[] = self::multicacheKey($this->tableName(), $val); | 
					
						
							| 
									
										
										
										
											2011-09-28 18:32:43 -07:00
										 |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (!empty($table['primary key'])) { | 
					
						
							|  |  |  |             $fields = $table['primary key']; | 
					
						
							|  |  |  |             $val = array(); | 
					
						
							|  |  |  |             foreach ($fields as $name) { | 
					
						
							| 
									
										
											  
											
												Further fixes to Managed_DataObject::_allCacheKeys(): now uses self::multicacheKey() to generate the (possibly compound) keys, which makes it match the order of the keys used when calling pkeyGet().
This should resolve the issues darkip was reporting with user_im_prefs entries returning null immediately after insertion (seen with memcached off, so it was happening even with the built-in in-process cache in the Cache base class).
What was happening was that the initial pkeyGet() would end up saving a negative cache entry under the form with the fields sorted in the key, as via multicacheKey():
    'statusnet:blaguette:user_im_prefs:screenname,transport:brionv,sms' => 'N;'
then we'd do an insert() on the new entry, saving cache entries for the non-sorted key names returned by _allCacheKeys():
    'statusnet:blaguette:user_im_prefs:transport,screenname:sms,brionv' => 'O...'
    'statusnet:blaguette:user_im_prefs:user_id,transport:1234,sms' => 'O...'
but the next query via pkeyGet() still saw the negative lookup cache from before, and came back with null.
Now, _allCacheKeys() sorts the fields in the keys by using the same key-builder function, and queries pick up the same thing you just inserted. :)
											
										 
											2011-09-29 15:21:52 -07:00
										 |  |  |                 $val[$name] = self::valueString($this->$name); | 
					
						
							| 
									
										
										
										
											2011-09-28 18:32:43 -07:00
										 |  |  |             } | 
					
						
							| 
									
										
											  
											
												Further fixes to Managed_DataObject::_allCacheKeys(): now uses self::multicacheKey() to generate the (possibly compound) keys, which makes it match the order of the keys used when calling pkeyGet().
This should resolve the issues darkip was reporting with user_im_prefs entries returning null immediately after insertion (seen with memcached off, so it was happening even with the built-in in-process cache in the Cache base class).
What was happening was that the initial pkeyGet() would end up saving a negative cache entry under the form with the fields sorted in the key, as via multicacheKey():
    'statusnet:blaguette:user_im_prefs:screenname,transport:brionv,sms' => 'N;'
then we'd do an insert() on the new entry, saving cache entries for the non-sorted key names returned by _allCacheKeys():
    'statusnet:blaguette:user_im_prefs:transport,screenname:sms,brionv' => 'O...'
    'statusnet:blaguette:user_im_prefs:user_id,transport:1234,sms' => 'O...'
but the next query via pkeyGet() still saw the negative lookup cache from before, and came back with null.
Now, _allCacheKeys() sorts the fields in the keys by using the same key-builder function, and queries pick up the same thing you just inserted. :)
											
										 
											2011-09-29 15:21:52 -07:00
										 |  |  |             $ckeys[] = self::multicacheKey($this->tableName(), $val); | 
					
						
							| 
									
										
										
										
											2011-09-28 18:32:43 -07:00
										 |  |  |         } | 
					
						
							|  |  |  |         return $ckeys; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2010-08-16 14:02:31 -07:00
										 |  |  | } |