1<?php 2/** 3 * Copyright 2008-2017 Horde LLC (http://www.horde.org/) 4 * 5 * @author Chuck Hagenbuch <chuck@horde.org> 6 * @author Michael Rubinsky <mrubinsk@horde.org> 7 * @license http://www.horde.org/licenses/bsd BSD 8 * @category Horde 9 * @package Horde_Content 10 */ 11 12/** 13 * @author Chuck Hagenbuch <chuck@horde.org> 14 * @author Michael Rubinsky <mrubinsk@horde.org> 15 * @license http://www.horde.org/licenses/bsd BSD 16 * @category Horde 17 * @package Horde_Content 18 */ 19class Content_Objects_Manager 20{ 21 /** 22 * Database adapter 23 * 24 * @var Horde_Db_Adapter 25 */ 26 protected $_db; 27 28 /** 29 * Tables 30 * 31 * @TODO: this should probably be populated by the responsible manager... 32 * @var array 33 */ 34 protected $_tables = array( 35 'objects' => 'rampage_objects', 36 ); 37 38 /** 39 * Type manager 40 * 41 * @var Content_Types_Manager 42 */ 43 protected $_typeManager; 44 45 /** 46 * Constructor 47 * 48 * @param Horde_Db_Adapter $db The db adapter 49 * @param Content_Types_Manager $typeManager A content type manager 50 * 51 * @return Content_Objects_Manager 52 */ 53 public function __construct(Horde_Db_Adapter $db, Content_Types_Manager $typeManager) 54 { 55 $this->_db = $db; 56 $this->_typeManager = $typeManager; 57 } 58 59 /** 60 * Check for object existence without causing the objects to be created. 61 * Helps save queries for things like tags when we already know the object 62 * doesn't yet exist in rampage tables. 63 * 64 * @param mixed string|array $objects Either an object identifier or an 65 * array of them. 66 * @param mixed $type A type identifier. Either a string 67 * type name or the integer type_id. 68 * 69 * @return mixed Either a hash of object_id => object_names or false if 70 * the object(s) do not exist. 71 * @throws InvalidArgumentException, Content_Exception 72 */ 73 public function exists($objects, $type) 74 { 75 $type = current($this->_typeManager->ensureTypes($type)); 76 if (!is_array($objects)) { 77 $objects = array($objects); 78 } 79 if (!count($objects)) { 80 return array(); 81 } 82 // Ensure we take the object as a string indentifier. 83 foreach ($objects as &$object) { 84 $object = strval($object); 85 } 86 $params = $objects; 87 $params[] = $type; 88 89 try { 90 $ids = $this->_db->selectAssoc( 91 'SELECT object_id, object_name FROM ' . $this->_t('objects') 92 . ' WHERE object_name IN (' 93 . str_repeat('?,', count($objects) - 1) . '?)' 94 . ' AND type_id = ?', $params); 95 if ($ids) { 96 return $ids; 97 } 98 } catch (Horde_Db_Exception $e) { 99 throw new Content_Exception($e); 100 } 101 102 return false; 103 } 104 105 /** 106 * Remove the object. 107 * NOTE: This does not ensure any references to this object were removed. 108 * E.g., does not remove any tags etc... That is client code's 109 * responsibility. 110 * 111 * @param array $objects An array of object identifiers to delete. 112 * @param string $type The type of the objects. All objects must be of 113 * the same type. 114 * 115 * @throws Content_Exception 116 */ 117 public function delete(array $objects, $type) 118 { 119 $type = current($this->_typeManager->ensureTypes($type)); 120 121 // Ensure we take the object as a string indentifier. 122 foreach ($objects as &$object) { 123 $object = strval($object); 124 } 125 $params = $objects; 126 $params[] = $type; 127 128 try { 129 $this->_db->delete( 130 'DELETE FROM ' . $this->_t('objects') . ' WHERE object_name IN (' 131 . str_repeat('?,', count($objects) - 1) . '?)' 132 . ' AND type_id = ?', 133 $params 134 ); 135 } catch (Horde_Db_Exception $e) { 136 throw new Content_Exception($e); 137 } 138 } 139 140 /** 141 * Ensure that an array of objects exist in storage. Create any that don't, 142 * return object_ids for all. All objects in the $objects array must be 143 * of the same content type. 144 * 145 * @param mixed $objects An array of objects (or single obejct value). 146 * Values typed as an integer are assumed to already 147 * be an object_id. 148 * @param mixed $type Either a string type_name or integer type_id 149 * 150 * @return array An array of object_ids. 151 */ 152 public function ensureObjects($objects, $type) 153 { 154 if (!is_array($objects)) { 155 $objects = array($objects); 156 } 157 158 $objectIds = array(); 159 $objectName = array(); 160 161 $type = current($this->_typeManager->ensureTypes($type)); 162 163 // Anything already typed as an integer is assumed to be an object id. 164 foreach ($objects as $objectIndex => $object) { 165 if (is_int($object)) { 166 $objectIds[$objectIndex] = $object; 167 } else { 168 $objectName[$object] = $objectIndex; 169 } 170 } 171 172 // Get the ids for any objects that already exist. 173 try { 174 if (count($objectName)) { 175 $rows = $this->_db->selectAll( 176 'SELECT object_id, object_name FROM ' . $this->_t('objects') 177 . ' WHERE object_name IN (' 178 . implode(',', array_map(array($this->_db, 'quoteString'), array_keys($objectName))) 179 . ') AND type_id = ' . $type); 180 foreach ($rows as $row) { 181 $objectIndex = $objectName[$row['object_name']]; 182 unset($objectName[$row['object_name']]); 183 $objectIds[$objectIndex] = $row['object_id']; 184 } 185 } 186 187 // Create any objects that didn't already exist 188 foreach ($objectName as $object => $objectIndex) { 189 $objectIds[$objectIndex] = $this->_db->insert('INSERT INTO ' 190 . $this->_t('objects') . ' (object_name, type_id) VALUES (' 191 . $this->_db->quoteString($object) . ', ' . $type . ')'); 192 } 193 } catch (Horde_Db_Exception $e) { 194 throw new Content_Exception($e); 195 } 196 197 return $objectIds; 198 } 199 200 /** 201 * Shortcut for getting a table name. 202 * 203 * @param string $tableType 204 * 205 * @return string Configured table name. 206 */ 207 protected function _t($tableType) 208 { 209 return $this->_db->quoteTableName($this->_tables[$tableType]); 210 } 211} 212