123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689 |
- <?php
- /**
- *
- * Cube Framework $Id$ nA+FcfJEqlljKnQskh69zN7RJom7AO+CWjAOWAIoYA4=
- *
- * @link http://codecu.be/framework
- * @copyright Copyright (c) 2017 CodeCube SRL
- * @license http://codecu.be/framework/license Commercial License
- *
- * @version 1.9 [rev.1.9.02]
- */
- namespace Cube\Db\Table\Row;
- use Cube\Db\Table\AbstractTable,
- Cube\Db\Select,
- Cube\Db\Expr,
- Cube\Controller\Front,
- Cube\Translate\Adapter\AbstractAdapter as TranslateAdapter,
- Cube\Translate;
- class AbstractRow implements \Countable, \ArrayAccess, \IteratorAggregate
- {
- const FQN_SEP = '\\';
- /**
- *
- * table row data (column_name => value)
- *
- *
- * @var array
- */
- protected $_data = array();
- /**
- *
- * table class the row belongs to
- *
- * @var \Cube\Db\Table\AbstractTable
- */
- protected $_table = null;
- /**
- *
- * primary key(s)
- *
- * @var array
- */
- protected $_primary;
- /**
- *
- * true if we do not have a deserialized object, false otherwise
- *
- * @var bool
- */
- protected $_connected = true;
- /**
- *
- * serializable fields
- *
- * @var array
- */
- protected $_serializable = array();
- /**
- *
- * translate adapter
- *
- * @var \Cube\Translate\Adapter\AbstractAdapter
- */
- protected $_translate;
- /**
- *
- * class constructor
- *
- * @param array $data
- */
- public function __construct($data = array())
- {
- if (isset($data['table']) && $data['table'] instanceof AbstractTable) {
- $this->_table = $data['table'];
- }
- else {
- throw new \InvalidArgumentException("The 'table' key must be set when creating a Row object");
- }
- if (isset($data['data'])) {
- if (!is_array($data['data'])) {
- throw new \InvalidArgumentException(
- sprintf('The "data" key must be an array, %s given.', gettype($data['data'])));
- }
- $this->setData($data['data']);
- }
- if (!$this->_primary) {
- $this->_primary = $this->_table->info('primary');
- }
- }
- /**
- *
- * set row data
- *
- * @param array $data
- *
- * @return $this
- */
- public function setData(array $data)
- {
- $this->_data = array();
- foreach ($data as $name => $value) {
- $this->addData($name, $value);
- }
- return $this;
- }
- /**
- *
- * set (update) the value of a column in the row.
- * also accepts serialized fields, if the column names are defined in the $_serialized array
- *
- * @param string $key
- * @param mixed $value
- *
- * @return $this
- */
- public function addData($key, $value)
- {
- $array = null;
- if (in_array($key, $this->_serializable)) {
- $array = @unserialize($value);
- }
- if (is_array($array)) {
- $this->_data[$key] = $array;
- foreach ($array as $k => $v) {
- if (is_string($k)) {
- $this->_data[$k] = $v;
- }
- }
- }
- else {
- $this->_data[$key] = $value;
- }
- return $this;
- }
- /**
- *
- * get row data
- *
- * @1.9 the $null value is only returned if the key doesn't exist
- *
- * @param string $name key name
- * @param mixed $null null value
- *
- * @return array|string|null
- */
- public function getData($name = null, $null = null)
- {
- if ($name !== null) {
- if (isset($this->_data[$name])) {
- return $this->_data[$name];
- }
- return $null;
- }
- return $this->_data;
- }
- /**
- *
- * set translate adapter
- *
- * @param \Cube\Translate\Adapter\AbstractAdapter $translate
- *
- * @return $this
- */
- public function setTranslate(TranslateAdapter $translate)
- {
- $this->_translate = $translate;
- return $this;
- }
- /**
- *
- * get translate adapter
- *
- * @return \Cube\Translate\Adapter\AbstractAdapter
- */
- public function getTranslate()
- {
- if (!$this->_translate instanceof TranslateAdapter) {
- $translate = Front::getInstance()->getBootstrap()->getResource('translate');
- if ($translate instanceof Translate) {
- $this->setTranslate(
- $translate->getAdapter());
- }
- }
- return $this->_translate;
- }
- /**
- *
- * save the updated row in the table
- * also update the data array from the object with the most recent values
- *
- * @param array $data partial data to be saved
- * the complete row is saved if this parameter is null
- *
- * @throws \RuntimeException
- * @return $this
- */
- public function save(array $data = null)
- {
- if ($data === null) {
- $data = $this->_data;
- }
- else {
- foreach ($data as $key => $value) {
- $this->_data[$key] = $value;
- }
- }
- if ($this->_connected === true) {
- $this->_table->update($data, $this->_getWhereQuery());
- }
- else {
- throw new \RuntimeException("Cannot save a row in unconnected state.");
- }
- return $this;
- }
- /**
- *
- * get table
- *
- * @return \Cube\Db\Table\AbstractTable
- */
- public function getTable()
- {
- return $this->_table;
- }
- /**
- *
- * find a dependent rowset
- *
- * @param string|\Cube\Db\Table\AbstractTable $dependentTable
- * @param string $ruleKey
- * @param \Cube\Db\Select $select
- *
- * @return \Cube\Db\Table\Rowset\AbstractRowset
- * @throws \RuntimeException
- */
- public function findDependentRowset($dependentTable, $ruleKey = null, Select $select = null)
- {
- if (is_string($dependentTable)) {
- $dependentTable = $this->_getTableFromString($dependentTable);
- }
- if (!$dependentTable instanceof AbstractTable) {
- throw new \RuntimeException(
- sprintf('The table must be an instance of \Cube\Db\Table\AbstractTable, %s given',
- gettype($dependentTable)));
- }
- if ($select === null) {
- $select = $dependentTable->select();
- }
- else {
- $select->reset(Select::COLUMNS);
- $select->reset(Select::FROM);
- $select->from($dependentTable->getName(), '*');
- }
- $map = $this->_prepareReference($dependentTable, $this->_table, $ruleKey);
- for ($i = 0; $i < count($map[AbstractTable::COLUMNS]); $i++) {
- $value = $this->_data[$map[AbstractTable::REF_COLUMNS][$i]];
- $column = $dependentTable->getAdapter()->quoteIdentifier(
- $map[AbstractTable::COLUMNS][$i]);
- $select->where("$column = ?", $value);
- }
- return $dependentTable->fetchAll($select);
- }
- /**
- *
- * count the rows in a dependent rowset
- *
- * @param string|\Cube\Db\Table\AbstractTable $dependentTable
- * @param string $ruleKey
- * @param \Cube\Db\Select $select
- *
- * @return int
- * @throws \RuntimeException
- */
- public function countDependentRowset($dependentTable, $ruleKey = null, Select $select = null)
- {
- if (is_string($dependentTable)) {
- $dependentTable = $this->_getTableFromString($dependentTable);
- }
- if (!$dependentTable instanceof AbstractTable) {
- throw new \RuntimeException(
- sprintf('The table must be an instance of \Cube\Db\Table\AbstractTable, %s given',
- gettype($dependentTable)));
- }
- if ($select === null) {
- $select = $dependentTable->select();
- }
- else {
- $select->reset(Select::FROM);
- $select->from($dependentTable->getName(), '*');
- }
- $select->reset(Select::COLUMNS)
- ->reset(Select::ORDER);
- $select->columns(array('nb_rows' => new Expr('count(*)')));
- $map = $this->_prepareReference($dependentTable, $this->_table, $ruleKey);
- for ($i = 0; $i < count($map[AbstractTable::COLUMNS]); $i++) {
- $value = $this->_data[$map[AbstractTable::REF_COLUMNS][$i]];
- $column = $dependentTable->getAdapter()->quoteIdentifier(
- $map[AbstractTable::COLUMNS][$i]);
- $select->where("$column = ?", $value);
- }
- $stmt = $select->query();
- return (integer)$stmt->fetchColumn('nb_rows');
- }
- /**
- *
- * find the matching parent row
- *
- * @param string|\Cube\Db\Table\AbstractTable $parentTable
- * @param string $ruleKey
- * @param \Cube\Db\Select $select
- *
- * @return \Cube\Db\Table\Row\AbstractRow
- * @throws \RuntimeException
- */
- public function findParentRow($parentTable, $ruleKey = null, Select $select = null)
- {
- if (is_string($parentTable)) {
- $parentTable = $this->_getTableFromString($parentTable);
- }
- if (!$parentTable instanceof AbstractTable) {
- throw new \RuntimeException(
- sprintf('The table must be an instance of \Cube\Db\Table\AbstractTable, %s given',
- gettype($parentTable)));
- }
- if ($select === null) {
- $select = $parentTable->select();
- }
- else {
- $select->reset(Select::COLUMNS);
- $select->reset(Select::FROM);
- $select->from($parentTable->getName(), '*');
- }
- $map = $this->_prepareReference($this->_table, $parentTable, $ruleKey);
- for ($i = 0; $i < count($map[AbstractTable::COLUMNS]); $i++) {
- $value = $this->_data[$map[AbstractTable::COLUMNS][$i]];
- $column = $parentTable->getAdapter()->quoteIdentifier(
- $map[AbstractTable::REF_COLUMNS][$i]);
- if ($value) {
- $select->where("$column = ?", $value);
- }
- else {
- $select->where("$column is null");
- }
- }
- return $parentTable->fetchRow($select);
- }
- /**
- *
- * delete the row from the table
- *
- * @return int
- */
- public function delete()
- {
- $result = $this->_table->delete($this->_getWhereQuery());
- $this->_data = array();
- return $result;
- }
- /**
- *
- * retrieve field value
- * proxy to getData($name) method
- *
- * @param string $name column name
- *
- * @return string|null return field value or null if field doesnt exist
- */
- public function __get($name)
- {
- return $this->getData($name);
- }
- /**
- *
- * proxy to addData($name, $value) method
- *
- * @param string $name
- * @param mixed $value
- *
- * @return $this
- */
- public function __set($name, $value)
- {
- return $this->addData($name, $value);
- }
- /**
- *
- * unset column from row
- *
- * @param string $name column name
- *
- * @throws \InvalidArgumentException
- * @return $this
- */
- public function __unset($name)
- {
- if (!array_key_exists($name, $this->_data)) {
- throw new \InvalidArgumentException(
- sprintf("Column name '%s' is not in the row.", $name));
- }
- unset($this->_data[$name]);
- return $this;
- }
- /**
- *
- * data to be added in the serialized object
- *
- * @return array
- */
- public function __sleep()
- {
- return array('_primary', '_data');
- }
- /**
- *
- * when deserializing an object, return it in unconnected state
- */
- public function __wakeup()
- {
- $this->_connected = false;
- }
- /**
- *
- * return data as an array
- *
- * @return array
- */
- public function toArray()
- {
- return (array)$this->_data;
- }
- /**
- *
- * check if column name exists in row
- *
- * @param string $name column name
- *
- * @return bool
- */
- public function __isset($name)
- {
- return array_key_exists($name, $this->_data);
- }
- /**
- *
- * retrieves an associative array of primary keys.
- *
- * @throws \RuntimeException
- * @return array
- */
- protected function _getPrimaryKey()
- {
- if (!is_array($this->_primary)) {
- throw new \RuntimeException("The primary key must be set as an array");
- }
- $primary = array_flip($this->_primary);
- $array = array_intersect_key($this->_data, $primary);
- if (count($primary) != count($array)) {
- throw new \RuntimeException(
- sprintf("Table '%s' does not have the same primary key as the row.", get_class($this->_table)));
- }
- return $array;
- }
- /**
- *
- * Constructs where statement for retrieving row(s).
- *
- * @return array
- */
- protected function _getWhereQuery()
- {
- $where = array();
- $db = $this->_table->getAdapter();
- $primaryKey = $this->_getPrimaryKey();
- $info = $this->_table->info();
- $metadata = $info[AbstractTable::METADATA];
- // retrieve recently updated row using primary keys
- foreach ($primaryKey as $column => $value) {
- $type = $metadata[$column]['DATA_TYPE'];
- $columnName = $db->quoteIdentifier($column, true);
- $where[] = $db->quoteInto("{$columnName} = ?", $value, $type);
- }
- return $where;
- }
- /**
- *
- * create a new table object
- *
- * @param string $tableName
- *
- * @return \Cube\Db\Table\AbstractTable
- * @throws \RuntimeException
- */
- protected function _getTableFromString($tableName)
- {
- if (class_exists($tableName)) {
- return new $tableName();
- }
- throw new \RuntimeException(
- sprintf("Table '%s' does not exist.", $tableName));
- }
- /**
- *
- * prepare table reference
- *
- * @param \Cube\Db\Table\AbstractTable $dependentTable
- * @param \Cube\Db\Table\AbstractTable $parentTable
- * @param string $ruleKey
- *
- * @return array
- */
- protected function _prepareReference(AbstractTable $dependentTable, AbstractTable $parentTable, $ruleKey)
- {
- $parentTableName = self::FQN_SEP . get_class($parentTable);
- $map = $dependentTable->getReference($parentTableName, $ruleKey);
- if (!isset($map[AbstractTable::REF_COLUMNS])) {
- $parentInfo = $parentTable->info();
- $map[AbstractTable::REF_COLUMNS] = array_values((array)$parentInfo['primary']);
- }
- $map[AbstractTable::COLUMNS] = (array)$map[AbstractTable::COLUMNS];
- $map[AbstractTable::REF_COLUMNS] = (array)$map[AbstractTable::REF_COLUMNS];
- return $map;
- }
- /*
- * methods needed to implement the ArrayAccess and IteratorAggregate interfaces
- */
- /**
- * check whether a offset exists
- *
- * @param mixed $offset
- *
- * @return bool
- */
- public function offsetExists($offset)
- {
- return $this->__isset($offset);
- }
- /**
- *
- * get offset
- *
- * @param mixed $offset
- *
- * @return mixed|null|string
- */
- public function offsetGet($offset)
- {
- return $this->__get($offset);
- }
- /**
- *
- * set offset
- *
- * @param mixed $offset
- * @param mixed $value
- */
- public function offsetSet($offset, $value)
- {
- $this->__set($offset, $value);
- }
- /**
- *
- * unset offset
- *
- * @param mixed $offset
- *
- * @return $this
- */
- public function offsetUnset($offset)
- {
- return $this->__unset($offset);
- }
- /**
- *
- * get iterator
- *
- * @return \ArrayIterator|\Traversable
- */
- public function getIterator()
- {
- return new \ArrayIterator((array)$this->_data);
- }
- /**
- *
- * count elements of an object
- *
- * @return int
- */
- public function count()
- {
- return count((array)$this->_data);
- }
- }
|