Differentiate the source or destination of a column when converting values
refs #8826
This commit is contained in:
parent
60ce78c958
commit
bb285db05b
|
@ -76,11 +76,15 @@ class DbUserBackend extends DbRepository implements UserBackendInterface
|
|||
);
|
||||
|
||||
/**
|
||||
* The value conversion rules to apply on a query/statement
|
||||
* The value conversion rules to apply on a query or statement
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $conversionRules = array('password');
|
||||
protected $conversionRules = array(
|
||||
'user' => array(
|
||||
'password'
|
||||
)
|
||||
);
|
||||
|
||||
/**
|
||||
* Initialize this database user backend
|
||||
|
|
|
@ -35,14 +35,16 @@ class IniUserGroupBackend extends IniRepository implements UserGroupBackendInter
|
|||
protected $filterColumns = array('group');
|
||||
|
||||
/**
|
||||
* The value conversion rules to apply on a query
|
||||
* The value conversion rules to apply on a query or statement
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $conversionRules = array(
|
||||
'created_at' => 'date_time',
|
||||
'last_modified' => 'date_time',
|
||||
'users' => 'comma_separated_string'
|
||||
'groups' => array(
|
||||
'created_at' => 'date_time',
|
||||
'last_modified' => 'date_time',
|
||||
'users' => 'comma_separated_string'
|
||||
)
|
||||
);
|
||||
|
||||
/**
|
||||
|
|
|
@ -401,6 +401,46 @@ abstract class DbRepository extends Repository implements Extensible, Updatable,
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether this repository is capable of converting values for the given table
|
||||
*
|
||||
* @param array|string $table
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function providesValueConversion($table)
|
||||
{
|
||||
return parent::providesValueConversion($this->removeTablePrefix($this->clearTableAlias($table)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the name of the conversion method for the given alias or column name and context
|
||||
*
|
||||
* @param array|string $table The datasource's table
|
||||
* @param string $name The alias or column name for which to return a conversion method
|
||||
* @param string $context The context of the conversion: persist or retrieve
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @throws ProgrammingError In case a conversion rule is found but not any conversion method
|
||||
*/
|
||||
protected function getConverter($table, $name, $context)
|
||||
{
|
||||
if (
|
||||
$this->validateQueryColumnAssociation($table, $name)
|
||||
|| $this->validateStatementColumnAssociation($table, $name)
|
||||
) {
|
||||
$table = $this->removeTablePrefix($this->clearTableAlias($table));
|
||||
} else {
|
||||
$table = $this->findTableName($name);
|
||||
if (! $table) {
|
||||
throw new ProgrammingError('Column name validation seems to have failed. Did you require the column?');
|
||||
}
|
||||
}
|
||||
|
||||
return parent::getConverter($table, $name, $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that the requested table exists
|
||||
*
|
||||
|
@ -692,6 +732,8 @@ abstract class DbRepository extends Repository implements Extensible, Updatable,
|
|||
return $aliasTableMap[$column];
|
||||
}
|
||||
|
||||
// TODO(jom): Elaborate whether it makes sense to throw ProgrammingError
|
||||
// instead (duplicate aliases in different tables?)
|
||||
foreach ($aliasTableMap as $alias => $table) {
|
||||
if (strpos($alias, '.') !== false) {
|
||||
list($_, $alias) = split('.', $column, 2);
|
||||
|
|
|
@ -106,7 +106,7 @@ abstract class Repository implements Selectable
|
|||
protected $sortRules;
|
||||
|
||||
/**
|
||||
* The value conversion rules to apply on a query
|
||||
* The value conversion rules to apply on a query or statement
|
||||
*
|
||||
* This may be initialized by concrete repository implementations and describes for which aliases or column
|
||||
* names what type of conversion is available. For entries, where the key is the alias/column and the value
|
||||
|
@ -403,27 +403,30 @@ abstract class Repository implements Selectable
|
|||
}
|
||||
|
||||
/**
|
||||
* Return whether this repository is capable of converting values
|
||||
* Return whether this repository is capable of converting values for the given table
|
||||
*
|
||||
* @param string $table
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function providesValueConversion()
|
||||
public function providesValueConversion($table)
|
||||
{
|
||||
$conversionRules = $this->getConversionRules();
|
||||
return !empty($conversionRules);
|
||||
return !empty($conversionRules) && isset($conversionRules[$table]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a value supposed to be transmitted to the data source
|
||||
*
|
||||
* @param string $table The table where to persist the value
|
||||
* @param string $name The alias or column name
|
||||
* @param mixed $value The value to convert
|
||||
*
|
||||
* @return mixed If conversion was possible, the converted value, otherwise the unchanged value
|
||||
*/
|
||||
public function persistColumn($name, $value)
|
||||
public function persistColumn($table, $name, $value)
|
||||
{
|
||||
$converter = $this->getConverter($name, 'persist');
|
||||
$converter = $this->getConverter($table, $name, 'persist');
|
||||
if ($converter !== null) {
|
||||
$value = $this->$converter($value);
|
||||
}
|
||||
|
@ -434,14 +437,15 @@ abstract class Repository implements Selectable
|
|||
/**
|
||||
* Convert a value which was fetched from the data source
|
||||
*
|
||||
* @param string $table The table the value has been fetched from
|
||||
* @param string $name The alias or column name
|
||||
* @param mixed $value The value to convert
|
||||
*
|
||||
* @return mixed If conversion was possible, the converted value, otherwise the unchanged value
|
||||
*/
|
||||
public function retrieveColumn($name, $value)
|
||||
public function retrieveColumn($table, $name, $value)
|
||||
{
|
||||
$converter = $this->getConverter($name, 'retrieve');
|
||||
$converter = $this->getConverter($table, $name, 'retrieve');
|
||||
if ($converter !== null) {
|
||||
$value = $this->$converter($value);
|
||||
}
|
||||
|
@ -452,6 +456,7 @@ abstract class Repository implements Selectable
|
|||
/**
|
||||
* Return the name of the conversion method for the given alias or column name and context
|
||||
*
|
||||
* @param string $table The datasource's table
|
||||
* @param string $name The alias or column name for which to return a conversion method
|
||||
* @param string $context The context of the conversion: persist or retrieve
|
||||
*
|
||||
|
@ -459,12 +464,13 @@ abstract class Repository implements Selectable
|
|||
*
|
||||
* @throws ProgrammingError In case a conversion rule is found but not any conversion method
|
||||
*/
|
||||
protected function getConverter($name, $context)
|
||||
protected function getConverter($table, $name, $context)
|
||||
{
|
||||
$conversionRules = $this->getConversionRules();
|
||||
$tableRules = $conversionRules[$table];
|
||||
|
||||
// Check for a conversion method for the alias/column first
|
||||
if (array_key_exists($name, $conversionRules) || in_array($name, $conversionRules)) {
|
||||
if (array_key_exists($name, $tableRules) || in_array($name, $tableRules)) {
|
||||
$methodName = $context . join('', array_map('ucfirst', explode('_', $name)));
|
||||
if (method_exists($this, $methodName)) {
|
||||
return $methodName;
|
||||
|
@ -472,22 +478,22 @@ abstract class Repository implements Selectable
|
|||
}
|
||||
|
||||
// The conversion method for the type is just a fallback, but it is required to exist if defined
|
||||
if (isset($conversionRules[$name])) {
|
||||
$identifier = join('', array_map('ucfirst', explode('_', $conversionRules[$name])));
|
||||
if (isset($tableRules[$name])) {
|
||||
$identifier = join('', array_map('ucfirst', explode('_', $tableRules[$name])));
|
||||
if (! method_exists($this, $context . $identifier)) {
|
||||
// Do not throw an error in case at least one conversion method exists
|
||||
if (! method_exists($this, ($context === 'persist' ? 'retrieve' : 'persist') . $identifier)) {
|
||||
throw new ProgrammingError(
|
||||
'Cannot find any conversion method for type "%s"'
|
||||
. '. Add a proper conversion method or remove the type definition',
|
||||
$conversionRules[$name]
|
||||
$tableRules[$name]
|
||||
);
|
||||
}
|
||||
|
||||
Logger::debug(
|
||||
'Conversion method "%s" for type definition "%s" does not exist in repository "%s".',
|
||||
$context . $identifier,
|
||||
$conversionRules[$name],
|
||||
$tableRules[$name],
|
||||
$this->getName()
|
||||
);
|
||||
} else {
|
||||
|
@ -623,7 +629,7 @@ abstract class Repository implements Selectable
|
|||
if ($filter->isExpression()) {
|
||||
$column = $filter->getColumn();
|
||||
$filter->setColumn($this->requireFilterColumn($table, $column, $query));
|
||||
$filter->setExpression($this->persistColumn($column, $filter->getExpression()));
|
||||
$filter->setExpression($this->persistColumn($table, $column, $filter->getExpression()));
|
||||
} elseif ($filter->isChain()) {
|
||||
foreach ($filter->filters() as $chainOrExpression) {
|
||||
$this->requireFilter($table, $chainOrExpression, $query);
|
||||
|
@ -826,7 +832,7 @@ abstract class Repository implements Selectable
|
|||
{
|
||||
$resolved = array();
|
||||
foreach ($data as $alias => $value) {
|
||||
$resolved[$this->requireStatementColumn($table, $alias)] = $this->persistColumn($alias, $value);
|
||||
$resolved[$this->requireStatementColumn($table, $alias)] = $this->persistColumn($table, $alias, $value);
|
||||
}
|
||||
|
||||
return $resolved;
|
||||
|
|
|
@ -153,7 +153,7 @@ class RepositoryQuery implements QueryInterface, Iterator
|
|||
{
|
||||
$this->query->where(
|
||||
$this->repository->requireFilterColumn($this->target, $column, $this),
|
||||
$this->repository->persistColumn($column, $value)
|
||||
$this->repository->persistColumn($this->target, $column, $value)
|
||||
);
|
||||
return $this;
|
||||
}
|
||||
|
@ -388,10 +388,10 @@ class RepositoryQuery implements QueryInterface, Iterator
|
|||
}
|
||||
|
||||
$result = $this->query->fetchOne();
|
||||
if ($result !== false && $this->repository->providesValueConversion()) {
|
||||
if ($result !== false && $this->repository->providesValueConversion($this->target)) {
|
||||
$columns = $this->getColumns();
|
||||
$column = isset($columns[0]) ? $columns[0] : key($columns);
|
||||
return $this->repository->retrieveColumn($column, $result);
|
||||
return $this->repository->retrieveColumn($this->target, $column, $result);
|
||||
}
|
||||
|
||||
return $result;
|
||||
|
@ -409,13 +409,13 @@ class RepositoryQuery implements QueryInterface, Iterator
|
|||
}
|
||||
|
||||
$result = $this->query->fetchRow();
|
||||
if ($result !== false && $this->repository->providesValueConversion()) {
|
||||
if ($result !== false && $this->repository->providesValueConversion($this->target)) {
|
||||
foreach ($this->getColumns() as $alias => $column) {
|
||||
if (! is_string($alias)) {
|
||||
$alias = $column;
|
||||
}
|
||||
|
||||
$result->$alias = $this->repository->retrieveColumn($alias, $result->$alias);
|
||||
$result->$alias = $this->repository->retrieveColumn($this->target, $alias, $result->$alias);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -434,12 +434,12 @@ class RepositoryQuery implements QueryInterface, Iterator
|
|||
}
|
||||
|
||||
$results = $this->query->fetchColumn();
|
||||
if (! empty($results) && $this->repository->providesValueConversion()) {
|
||||
if (! empty($results) && $this->repository->providesValueConversion($this->target)) {
|
||||
$columns = $this->getColumns();
|
||||
$aliases = array_keys($columns);
|
||||
$column = is_int($aliases[0]) ? $columns[0] : $aliases[0];
|
||||
foreach ($results as & $value) {
|
||||
$value = $this->repository->retrieveColumn($column, $value);
|
||||
$value = $this->repository->retrieveColumn($this->target, $column, $value);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -460,15 +460,15 @@ class RepositoryQuery implements QueryInterface, Iterator
|
|||
}
|
||||
|
||||
$results = $this->query->fetchPairs();
|
||||
if (! empty($results) && $this->repository->providesValueConversion()) {
|
||||
if (! empty($results) && $this->repository->providesValueConversion($this->target)) {
|
||||
$columns = $this->getColumns();
|
||||
$aliases = array_keys($columns);
|
||||
$newResults = array();
|
||||
foreach ($results as $colOneValue => $colTwoValue) {
|
||||
$colOne = $aliases[0] !== 0 ? $aliases[0] : $columns[0];
|
||||
$colTwo = count($aliases) < 2 ? $colOne : ($aliases[1] !== 1 ? $aliases[1] : $columns[1]);
|
||||
$colOneValue = $this->repository->retrieveColumn($colOne, $colOneValue);
|
||||
$newResults[$colOneValue] = $this->repository->retrieveColumn($colTwo, $colTwoValue);
|
||||
$colOneValue = $this->repository->retrieveColumn($this->target, $colOne, $colOneValue);
|
||||
$newResults[$colOneValue] = $this->repository->retrieveColumn($this->target, $colTwo, $colTwoValue);
|
||||
}
|
||||
|
||||
$results = $newResults;
|
||||
|
@ -489,7 +489,7 @@ class RepositoryQuery implements QueryInterface, Iterator
|
|||
}
|
||||
|
||||
$results = $this->query->fetchAll();
|
||||
if (! empty($results) && $this->repository->providesValueConversion()) {
|
||||
if (! empty($results) && $this->repository->providesValueConversion($this->target)) {
|
||||
$columns = $this->getColumns();
|
||||
foreach ($results as $row) {
|
||||
foreach ($columns as $alias => $column) {
|
||||
|
@ -497,7 +497,7 @@ class RepositoryQuery implements QueryInterface, Iterator
|
|||
$alias = $column;
|
||||
}
|
||||
|
||||
$row->$alias = $this->repository->retrieveColumn($alias, $row->$alias);
|
||||
$row->$alias = $this->repository->retrieveColumn($this->target, $alias, $row->$alias);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -545,13 +545,13 @@ class RepositoryQuery implements QueryInterface, Iterator
|
|||
public function current()
|
||||
{
|
||||
$row = $this->iterator->current();
|
||||
if ($this->repository->providesValueConversion()) {
|
||||
if ($this->repository->providesValueConversion($this->target)) {
|
||||
foreach ($this->getColumns() as $alias => $column) {
|
||||
if (! is_string($alias)) {
|
||||
$alias = $column;
|
||||
}
|
||||
|
||||
$row->$alias = $this->repository->retrieveColumn($alias, $row->$alias);
|
||||
$row->$alias = $this->repository->retrieveColumn($this->target, $alias, $row->$alias);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue