⚝
One Hat Cyber Team
⚝
Your IP:
216.73.216.89
Server IP:
41.128.143.86
Server:
Linux host.raqmix.cloud 6.8.0-1025-azure #30~22.04.1-Ubuntu SMP Wed Mar 12 15:28:20 UTC 2025 x86_64
Server Software:
Apache
PHP Version:
8.3.23
Buat File
|
Buat Folder
Eksekusi
Dir :
~
/
usr
/
share
/
psa-pear
/
pear
/
php
/
Horde
/
Rdo
/
Edit File: Mapper.php
<?php /** * @category Horde * @package Rdo */ /** * Rdo Mapper class. * * Controls mapping of entity obects (instances of Horde_Rdo_Base) from and to * Horde_Db_Adapters. * * Public properties: * $adapter - Horde_Db_Adapter that stores this Mapper's objects. * * $inflector - The Horde_Support_Inflector this mapper uses to singularize * and pluralize PHP class, database table, and database field/key names. * * $table - The Horde_Db_Adapter_Base_TableDefinition object describing * the main table of this entity. * * @category Horde * @package Rdo */ abstract class Horde_Rdo_Mapper implements Countable { /** * If this is true and fields named created_at and updated_at are present, * Rdo will automatically set creation and last updated timestamps. * Timestamps are always GMT for portability. * * @var boolean */ protected $_setTimestamps = true; /** * What class should this Mapper create for objects? Defaults to the Mapper * subclass' name minus "Mapper". So if the Rdo_Mapper subclass is * UserMapper, it will default to trying to create User objects. * * @var string */ protected $_classname; /** * The definition of the database table (or view, etc.) that holds this * Mapper's objects. * * @var Horde_Db_Adapter_Base_TableDefinition */ protected $_tableDefinition; /** * Fields that should only be read from the database when they are * accessed. * * @var array */ protected $_lazyFields = array(); /** * Relationships for this entity. * * @var array */ protected $_relationships = array(); /** * Relationships that should only be read from the database when * they are accessed. * * @var array */ protected $_lazyRelationships = array(); /** * Default sorting rule to use for all queries made with this mapper. This * is a SQL ORDER BY fragment (without 'ORDER BY'). * * @var string */ protected $_defaultSort; /** * The caching factory, if used * * @var Horde_Rdo_Factory */ protected $_factory = null; public function __construct(Horde_Db_Adapter $adapter) { $this->adapter = $adapter; } /** * Attach a Horde_Rdo_Factory to the mapper. * If called without arguments, detaches the mapper from factory * * @param Horde_Rdo_Factory $factory A Factory instance or null * @return Horde_Rdo_Mapper this mapper */ public function setFactory(Horde_Rdo_Factory $factory = null) { $this->_factory = $factory; return $this; } /** * Provide read-only, on-demand access to several properties. This * method will only be called for properties that aren't already * present; once a property is fetched once it is cached and * returned directly on any subsequent access. * * These properties are available: * * adapter: The Horde_Db_Adapter this mapper is using to talk to * the database. * * factory: The Horde_Rdo_Factory instance, if present * * inflector: The Horde_Support_Inflector this Mapper uses to singularize * and pluralize PHP class, database table, and database field/key names. * * table: The database table or view that this Mapper manages. * * tableDefinition: The Horde_Db_Adapter_Base_TableDefinition object describing * the table or view this Mapper manages. * * fields: Array of all field names that are loaded up front * (eager loading) from the table. * * lazyFields: Array of fields that are only loaded when accessed. * * relationships: Array of relationships to other Mappers. * * lazyRelationships: Array of relationships to other Mappers which * are only loaded when accessed. * * @param string $key Property name to fetch * * @return mixed Value of $key */ public function __get($key) { switch ($key) { case 'inflector': $this->inflector = new Horde_Support_Inflector(); return $this->inflector; case 'primaryKey': $this->primaryKey = (string)$this->tableDefinition->getPrimaryKey(); return $this->primaryKey; case 'table': $this->table = !empty($this->_table) ? $this->_table : $this->mapperToTable(); return $this->table; case 'tableDefinition': $this->tableDefinition = $this->adapter->table($this->table); return $this->tableDefinition; case 'fields': $this->fields = array_diff($this->tableDefinition->getColumnNames(), $this->_lazyFields); return $this->fields; case 'lazyFields': case 'relationships': case 'lazyRelationships': case 'factory': case 'defaultSort': return $this->{'_' . $key}; } return null; } /** * Create an instance of $this->_classname from a set of data. * * @param array $fields Field names/default values for the new object. * * @see $_classname * * @return Horde_Rdo_Base An instance of $this->_classname with $fields * as initial data. */ public function map($fields = array()) { // Guess a classname if one isn't explicitly set. if (!$this->_classname) { $this->_classname = $this->mapperToEntity(); if (!$this->_classname) { throw new Horde_Rdo_Exception('Unable to find an entity class (extending Horde_Rdo_Base) for ' . get_class($this)); } } $o = new $this->_classname(); $o->setMapper($this); $this->mapFields($o, $fields); if (is_callable(array($o, 'afterMap'))) { $o->afterMap(); } return $o; } /** * Update an instance of $this->_classname from a set of data. * * @param Horde_Rdo_Base $object The object to update * @param array $fields Field names/default values for the object */ public function mapFields($object, $fields = array()) { $relationships = array(); foreach ($fields as $fieldName => &$fieldValue) { if (strpos($fieldName, '@') !== false) { list($rel, $field) = explode('@', $fieldName, 2); $relationships[$rel][$field] = $fieldValue; unset($fields[$fieldName]); } if (isset($this->fields[$fieldName])) { $fieldName = $this->fields[$fieldName]; } $column = $this->tableDefinition->getColumn($fieldName); if ($column) { $fieldValue = $column->typeCast($fieldValue); } } $object->setFields($fields); if (count($relationships)) { foreach ($this->relationships as $relationship => $rel) { if (isset($rel['mapper'])) { if ($this->_factory) { $m = $this->_factory->create($rel['mapper']); } // @TODO - should be getting this instance from somewhere // else external, and not passing the adapter along // automatically. else { $m = new $rel['mapper']($this->adapter); } } else { $m = $this->tableToMapper($relationship); if (is_null($m)) { // @TODO Throw an exception? continue; } } // Don't check the table only. If there was a match for LEFT // JOINs, there may be a "empty" result if (isset($relationships[$m->table], $relationships[$m->table][$m->primaryKey])) { $object->$relationship = $m->map($relationships[$m->table]); } } } } /** * Transform a table name to a mapper class name. * * @param string $table The database table name to look up. * * @return Horde_Rdo_Mapper A new Mapper instance if it exists, else null. */ public function tableToMapper($table) { if (class_exists(($class = Horde_String::ucwords($table) . 'Mapper'))) { return new $class; } return null; } /** * Transform this mapper's class name to a database table name. * * @return string The database table name. */ public function mapperToTable() { return $this->inflector->pluralize(Horde_String::lower(str_replace('Mapper', '', get_class($this)))); } /** * Transform this mapper's class name to an entity class name. * * @return string A Horde_Rdo_Base concrete class name if the class exists, else null. */ public function mapperToEntity() { $class = str_replace('Mapper', '', get_class($this)); if (class_exists($class)) { return $class; } return null; } /** * Count objects that match $query. * * @param mixed $query The query to count matches of. * * @return integer All objects matching $query. */ public function count($query = null) { $query = Horde_Rdo_Query::create($query, $this); $query->setFields('COUNT(*)') ->clearSort(); list($sql, $bindParams) = $query->getQuery(); return $this->adapter->selectValue($sql, $bindParams); } /** * Check if at least one object matches $query. * * @param mixed $query Either a primary key, an array of keys * => values, or a Horde_Rdo_Query object. * * @return boolean True or false. */ public function exists($query) { $query = Horde_Rdo_Query::create($query, $this); $query->setFields(1) ->clearSort(); list($sql, $bindParams) = $query->getQuery(); return (bool)$this->adapter->selectValue($sql, $bindParams); } /** * Create a new object in the backend with $fields as initial values. * * @param array $fields Array of field names => initial values. * * @return Horde_Rdo_Base The newly created object. */ public function create($fields) { // If configured to record creation and update times, set them // here. We set updated_at to the initial creation time so it's // always set. if ($this->_setTimestamps) { $time = time(); $fields['created_at'] = $time; $fields['updated_at'] = $time; } // Filter out any extra fields. $fields = array_intersect_key($fields, array_flip($this->tableDefinition->getColumnNames())); if (!$fields) { throw new Horde_Rdo_Exception('create() requires at least one field value.'); } $sql = 'INSERT INTO ' . $this->adapter->quoteTableName($this->table); $keys = array(); $placeholders = array(); $bindParams = array(); foreach ($fields as $field => $value) { $keys[] = $this->adapter->quoteColumnName($field); $placeholders[] = '?'; $bindParams[] = $value; } $sql .= ' (' . implode(', ', $keys) . ') VALUES (' . implode(', ', $placeholders) . ')'; $id = $this->adapter->insert($sql, $bindParams); return $this->map(array_merge($fields, array($this->primaryKey => $id))); } /** * Updates a record in the backend. $object can be either a * primary key or an Rdo object. If $object is an Rdo instance * then $fields will be ignored as values will be pulled from the * object. * * @param string|Rdo $object The Rdo instance or unique id to update. * @param array $fields If passing a unique id, the array of field properties * to set for $object. * * @return integer Number of objects updated. */ public function update($object, $fields = null) { if ($object instanceof Horde_Rdo_Base) { $key = $this->primaryKey; $id = $object->$key; $fields = iterator_to_array($object); if (!$id) { // Object doesn't exist yet; create it instead. $o = $this->create($fields); $this->mapFields($object, iterator_to_array($o)); return 1; } } else { $id = $object; } // If configured to record update time, set it here. if ($this->_setTimestamps) { $fields['updated_at'] = time(); } // Filter out any extra fields. $fields = array_intersect_key($fields, array_flip($this->tableDefinition->getColumnNames())); if (!$fields) { // Nothing to change. return 0; } $sql = 'UPDATE ' . $this->adapter->quoteTableName($this->table) . ' SET'; $bindParams = array(); foreach ($fields as $field => $value) { $sql .= ' ' . $this->adapter->quoteColumnName($field) . ' = ?,'; $bindParams[] = $value; } $sql = substr($sql, 0, -1) . ' WHERE ' . $this->primaryKey . ' = ?'; $bindParams[] = $id; return $this->adapter->update($sql, $bindParams); } /** * Deletes a record from the backend. $object can be either a * primary key, an Rdo_Query object, or an Rdo object. * * @param string|Horde_Rdo_Base|Horde_Rdo_Query $object The Rdo object, * Horde_Rdo_Query, or unique id to delete. * * @return integer Number of objects deleted. */ public function delete($object) { if ($object instanceof Horde_Rdo_Base) { $key = $this->primaryKey; $id = $object->$key; $query = array($key => $id); } elseif ($object instanceof Horde_Rdo_Query) { $query = $object; } else { $key = $this->primaryKey; $query = array($key => $object); } $query = Horde_Rdo_Query::create($query, $this); $clauses = array(); $bindParams = array(); foreach ($query->tests as $test) { $clauses[] = $this->adapter->quoteColumnName($test['field']) . ' ' . $test['test'] . ' ?'; $bindParams[] = $test['value']; } if (!$clauses) { throw new Horde_Rdo_Exception('Refusing to delete the entire table.'); } $sql = 'DELETE FROM ' . $this->adapter->quoteTableName($this->table) . ' WHERE ' . implode(' ' . $query->conjunction . ' ', $clauses); return $this->adapter->delete($sql, $bindParams); } /** * find() can be called in several ways. * * Primary key mode: pass find() a numerically indexed array of primary * keys, and it will return a list of the objects that correspond to those * keys. * * If you pass find() no arguments, all objects of this type will be * returned. * * If you pass find() an associative array, it will be turned into a * Horde_Rdo_Query object. * * If you pass find() a Horde_Rdo_Query, it will return a list of all * objects matching that query. */ public function find($arg = null) { if (is_null($arg)) { $query = null; } elseif (is_array($arg)) { if (!count($arg)) { throw new Horde_Rdo_Exception('No criteria found'); } if (is_numeric(key($arg))) { // Numerically indexed arrays are assumed to be an array of // primary keys. $query = new Horde_Rdo_Query(); $query->combineWith('OR'); foreach ($argv[0] as $id) { $query->addTest($this->primaryKey, '=', $id); } } else { $query = $arg; } } else { $query = $arg; } // Build a full Query object. $query = Horde_Rdo_Query::create($query, $this); return new Horde_Rdo_List($query); } /** * Adds a relation. * * - For one-to-one relations, simply updates the relation field. * - For one-to-many relations, updates the related object's relation field. * - For many-to-many relations, adds an entry in the "through" table. * - Performs a no-op if the peer is already related. * * @param string $relationship The relationship key in the mapper. * @param Horde_Rdo_Base $ours The object from this mapper to add the * relation. * @param Horde_Rdo_Base $theirs The other object from any mapper to add * the relation. * * @throws Horde_Rdo_Exception */ public function addRelation($relationship, Horde_Rdo_Base $ours, Horde_Rdo_Base $theirs) { if ($ours->hasRelation($relationship, $theirs)) { return; } $ourKey = $this->primaryKey; $theirKey = $theirs->mapper->primaryKey; if (isset($this->relationships[$relationship])) { $rel = $this->relationships[$relationship]; } elseif (isset($this->lazyRelationships[$relationship])) { $rel = $this->lazyRelationships[$relationship]; } else { throw new Horde_Rdo_Exception('The requested relation is not defined in the mapper'); } switch ($rel['type']) { case Horde_Rdo::ONE_TO_ONE: case Horde_Rdo::MANY_TO_ONE: $ours->{$rel['foreignKey']} = $theirs->$theirKey; $ours->save(); break; case Horde_Rdo::ONE_TO_MANY: $theirs->{$rel['foreignKey']} = $ours->$ourKey; $theirs->save(); break; case Horde_Rdo::MANY_TO_MANY: $sql = sprintf('INSERT INTO %s (%s, %s) VALUES (?, ?)', $this->adapter->quoteTableName($rel['through']), $this->adapter->quoteColumnName($ourKey), $this->adapter->quoteColumnName($theirKey)); try { $this->adapter->insert($sql, array($ours->$ourKey, $theirs->$theirKey)); } catch (Horde_Db_Exception $e) { throw new Horde_Rdo_Exception($e); } break; } } /** * Removes a relation to one of the relationships defined in the mapper. * * - For one-to-one and one-to-many relations, simply sets the relation * field to 0. * - For many-to-many, either deletes all relations to this object or just * the relation to a given peer object. * - Performs a no-op if the peer is already unrelated. * * This is a proxy to the mapper's removeRelation method. * * @param string $relationship The relationship key in the mapper. * @param Horde_Rdo_Base $ours The object from this mapper. * @param Horde_Rdo_Base $theirs The object to remove from the relation. * @return integer the number of affected relations * * @throws Horde_Rdo_Exception */ public function removeRelation($relationship, Horde_Rdo_Base $ours, Horde_Rdo_Base $theirs = null) { if (!$ours->hasRelation($relationship, $theirs)) { return; } $ourKey = $this->primaryKey; if (isset($this->relationships[$relationship])) { $rel = $this->relationships[$relationship]; } elseif (isset($this->lazyRelationships[$relationship])) { $rel = $this->lazyRelationships[$relationship]; } else { throw new Horde_Rdo_Exception('The requested relation is not defined in the mapper'); } switch ($rel['type']) { case Horde_Rdo::ONE_TO_ONE: case Horde_Rdo::MANY_TO_ONE: $ours->{$rel['foreignKey']} = null; $ours->save(); return 1; break; case Horde_Rdo::ONE_TO_MANY: $theirs->{$rel['foreignKey']} = null; $theirs->save(); return 1; break; case Horde_Rdo::MANY_TO_MANY: $sql = sprintf('DELETE FROM %s WHERE %s = ? ', $this->adapter->quoteTableName($rel['through']), $this->adapter->quoteColumnName($ourKey)); $values = array($ours->$ourKey); if (!empty($theirs)) { $theirKey = $theirs->mapper->primaryKey; $sql .= sprintf(' AND %s = ?', $this->adapter->quoteColumnName($theirKey)); $values[] = $theirs->$theirKey; } try { return $this->adapter->delete($sql, $values); } catch (Horde_Db_Exception $e) { throw new Horde_Rdo_Exception($e); } break; } } /** * findOne can be called in several ways. * * Primary key mode: pass find() a single primary key, and it will return a * single object matching that primary key. * * If you pass findOne() no arguments, the first object of this type will be * returned. * * If you pass findOne() an associative array, it will be turned into a * Horde_Rdo_Query object. * * If you pass findOne() a Horde_Rdo_Query, it will return the first object * matching that query. */ public function findOne($arg = null) { if (is_null($arg)) { $query = null; } elseif (is_scalar($arg)) { $query = array($this->primaryKey => $arg); } else { $query = $arg; } // Build a full Query object, and limit it to one result. $query = Horde_Rdo_Query::create($query, $this); $query->limit(1); $list = new Horde_Rdo_List($query); return $list->current(); } /** * Set a default sort rule for all queries done with this Mapper. * * @param string $sort SQL sort fragment, such as 'updated DESC' */ public function sortBy($sort) { $this->_defaultSort = $sort; return $this; } }
Simpan