silverstripe-framework/model/queries/SQLAssignmentRow.php
Damian Mooyman d8e9af8af8 API New Database abstraction layer. Ticket #7429
Database abstraction broken up into controller, connector, query builder, and schema manager, each independently configurable via YAML / Injector
Creation of new DBQueryGenerator for database specific generation of SQL
Support for parameterised queries, move of code base to use these over escaped conditions
Refactor of SQLQuery into separate query classes for each of INSERT UPDATE DELETE and SELECT
Support for PDO
Installation process upgraded to use new ORM
SS_DatabaseException created to handle database errors, maintaining details of raw sql and parameter details for user code designed interested in that data.
Renamed DB static methods to conform correctly to naming conventions (e.g. DB::getConn -> DB::get_conn)
3.2 upgrade docs
Performance Optimisation and simplification of code to use more concise API
API Ability for database adapters to register extensions to ConfigureFromEnv.php
2014-07-09 18:04:05 +12:00

221 lines
6.3 KiB
PHP

<?php
/**
* Represents a list of updates / inserts made to a single row in a table
*
* @package framework
* @subpackage model
*/
class SQLAssignmentRow {
/**
* List of field values to store for this query
*
* Each item in this array will be in the form of a single-length array
* in the format array('sql' => array($parameters)).
* The field name is stored as the key
*
* E.g.
*
* <code>$assignments['ID'] = array('?' => array(1));</code>
*
* This allows for complex, parameterised updates, or explict field values set
* without any prameters
*
* @var array
*/
protected $assignments = array();
/**
* Instantiate a new SQLAssignmentRow object with the given values
*
* @param array $values
*/
function __construct(array $values = array()) {
$this->setAssignments($values);
}
/**
* Given a key / value pair, extract the predicate and any potential paramaters
* in a format suitable for storing internally as a list of paramaterised conditions.
*
* @param mixed $value Either a literal field value, or an array with
* placeholder => parameter(s) as a pair
* @return array A single item array in the format array($sql => array($parameters))
*/
protected function parseAssignment($value) {
// Assume string values (or values saved as customised array objects)
// represent simple assignment
if(!is_array($value) || isset($value['type'])) {
return array('?' => array($value));
}
// If given as array then extract and check both the SQL as well as the parameter(s)
// Note that there could be multiple parameters, e.g.
// array('MAX(?,?)' => array(1,2)) although the container should
// have a single item
if(count($value) == 1) {
foreach($value as $sql => $parameters) {
if(!is_string($sql)) continue;
if(!is_array($parameters)) $parameters = array($parameters);
// @todo Some input sanitisation checking the key contains the
// correct number of ? placeholders as the number of parameters
return array($sql => $parameters);
}
}
user_error("Nested field assignments should be given as a single parameterised item array in "
. "array('?' => array('value')) format)", E_USER_ERROR);
}
/**
* Given a list of assignments in any user-acceptible format, normalise the
* value to a common array('SQL' => array(parameters)) format
*
* @param array $predicates List of assignments.
* The key of this array should be the field name, and the value the assigned
* literal value, or an array with parameterised information.
* @return array List of normalised assignments
*/
protected function normaliseAssignments(array $assignments) {
$normalised = array();
foreach($assignments as $field => $value) {
$normalised[$field] = $this->parseAssignment($value);
}
return $normalised;
}
/**
* Adds assignments for a list of several fields
*
* Note that field values must not be escaped, as these will be internally
* parameterised by the database engine.
*
* <code>
*
* // Basic assignments
* $query->addAssignments(array(
* '"Object"."Title"' => 'Bob',
* '"Object"."Description"' => 'Bob was here'
* ))
*
* // Parameterised assignments
* $query->addAssignments(array(
* '"Object"."Title"' => array('?' => 'Bob')),
* '"Object"."Description"' => array('?' => null))
* ))
*
* // Complex parameters
* $query->addAssignments(array(
* '"Object"."Score"' => array('MAX(?,?)' => array(1, 3))
* ));
*
* // Assigment of literal SQL for a field. The empty array is
* // important to denote the zero-number paramater list
* $query->addAssignments(array(
* '"Object"."Score"' => array('NOW()' => array())
* ));
*
* </code>
*
* @param array $assignments The list of fields to assign
* @return self The self reference to this row
*/
public function addAssignments(array $assignments) {
$assignments = $this->normaliseAssignments($assignments);
$this->assignments = array_merge($this->assignments, $assignments);
return $this;
}
/**
* Sets the list of assignments to the given list
*
* @see SQLWriteExpression::addAssignments() for syntax examples
*
* @param array $assignments
* @return self The self reference to this row
*/
public function setAssignments(array $assignments) {
return $this->clear()->addAssignments($assignments);
}
/**
* Retrieves the list of assignments in parameterised format
*
* @return array List of assigments. The key of this array will be the
* column to assign, and the value a parameterised array in the format
* array('SQL' => array(parameters));
*/
public function getAssignments() {
return $this->assignments;
}
/**
* Set the value for a single field
*
* E.g.
* <code>
*
* // Literal assignment
* $query->assign('"Object"."Description"', 'lorum ipsum');
*
* // Single parameter
* $query->assign('"Object"."Title"', array('?' => 'Bob'));
*
* // Complex parameters
* $query->assign('"Object"."Score"', array('MAX(?,?)' => array(1, 3));
* </code>
*
* @param string $field The field name to update
* @param mixed $value The value to assign to this field. This could be an
* array containing a parameterised SQL query of any number of parameters,
* or a single literal value.
* @return self The self reference to this row
*/
public function assign($field, $value) {
return $this->addAssignments(array($field => $value));
}
/**
* Assigns a value to a field using the literal SQL expression, rather than
* a value to be escaped
*
* @param string $field The field name to update
* @param string $sql The SQL to use for this update. E.g. "NOW()"
* @return self The self reference to this row
*/
public function assignSQL($field, $sql) {
return $this->assign($field, array($sql => array()));
}
/**
* Determine if this assignment is empty
*
* @return boolean Flag indicating that this assignment is empty
*/
public function isEmpty() {
return empty($this->assignments);
}
/**
* Retrieves the list of columns updated
*
* @return array
*/
public function getColumns() {
return array_keys($this->assignments);
}
/**
* Clears all assignment values
*
* @return self The self reference to this row
*/
public function clear() {
$this->assignments = array();
return $this;
}
}