parent
f83d16acb2
commit
f383ddd00a
|
@ -3,6 +3,7 @@
|
|||
|
||||
namespace Icinga\Repository;
|
||||
|
||||
use Icinga\Application\Logger;
|
||||
use Icinga\Data\Selectable;
|
||||
use Icinga\Exception\ProgrammingError;
|
||||
use Icinga\Exception\QueryException;
|
||||
|
@ -95,6 +96,21 @@ abstract class Repository implements Selectable
|
|||
*/
|
||||
protected $sortRules;
|
||||
|
||||
/**
|
||||
* The value conversion rules to apply on a query
|
||||
*
|
||||
* 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
|
||||
* is the type identifier, the repository attempts to find a conversion method for the alias/column first and,
|
||||
* if none is found, then for the type. If an entry only provides a value, which is the alias/column, the
|
||||
* repository only attempts to find a conversion method for the alias/column. The name of a conversion method
|
||||
* is expected to be declared using lowerCamelCase. (e.g. user_name will be translated to persistUserName and
|
||||
* groupname will be translated to retrieveGroupname)
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $conversionRules;
|
||||
|
||||
/**
|
||||
* An array to map table names to aliases
|
||||
*
|
||||
|
@ -268,6 +284,32 @@ abstract class Repository implements Selectable
|
|||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the value conversion rules to apply on a query
|
||||
*
|
||||
* Calls $this->initializeConversionRules() in case $this->conversionRules is null.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getConversionRules()
|
||||
{
|
||||
if ($this->conversionRules === null) {
|
||||
$this->conversionRules = $this->initializeConversionRules();
|
||||
}
|
||||
|
||||
return $this->conversionRules;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overwrite this in your repository implementation in case you need to initialize the conversion rules lazily
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function initializeConversionRules()
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array to map table names to aliases
|
||||
*
|
||||
|
@ -335,6 +377,100 @@ abstract class Repository implements Selectable
|
|||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether this repository is capable of converting values
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function providesValueConversion()
|
||||
{
|
||||
$conversionRules = $this->getConversionRules();
|
||||
return !empty($conversionRules);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a value supposed to be transmitted to the data source
|
||||
*
|
||||
* @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)
|
||||
{
|
||||
$converter = $this->getConverter($name, 'persist');
|
||||
if ($converter !== null) {
|
||||
$value = $this->$converter($value);
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a value which was fetched from the data source
|
||||
*
|
||||
* @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)
|
||||
{
|
||||
$converter = $this->getConverter($name, 'retrieve');
|
||||
if ($converter !== null) {
|
||||
$value = $this->$converter($value);
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the name of the conversion method for the given alias or column name and context
|
||||
*
|
||||
* @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($name, $context)
|
||||
{
|
||||
$conversionRules = $this->getConversionRules();
|
||||
|
||||
// Check for a conversion method for the alias/column first
|
||||
if (array_key_exists($name, $conversionRules) || in_array($name, $conversionRules)) {
|
||||
$methodName = $context . join('', array_map('ucfirst', explode('_', $name)));
|
||||
if (method_exists($this, $methodName)) {
|
||||
return $methodName;
|
||||
}
|
||||
}
|
||||
|
||||
// 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 (! 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]
|
||||
);
|
||||
}
|
||||
|
||||
Logger::debug(
|
||||
'Conversion method "%s" for type definition "%s" does not exist in repository "%s".',
|
||||
$context . $identifier,
|
||||
$conversionRules[$name],
|
||||
$this->getName()
|
||||
);
|
||||
} else {
|
||||
return $context . $identifier;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return this repository's query columns mapped to their respective aliases
|
||||
*
|
||||
|
|
|
@ -132,7 +132,10 @@ class RepositoryQuery implements QueryInterface
|
|||
*/
|
||||
public function where($column, $value = null)
|
||||
{
|
||||
$this->query->where($this->repository->requireFilterColumn($column), $value);
|
||||
$this->query->where(
|
||||
$this->repository->requireFilterColumn($column),
|
||||
$this->repository->persistColumn($column, $value)
|
||||
);
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
@ -182,13 +185,15 @@ class RepositoryQuery implements QueryInterface
|
|||
return $this;
|
||||
}
|
||||
|
||||
/*+
|
||||
/**
|
||||
* Recurse the given filter and notify the repository about each required filter column
|
||||
*/
|
||||
protected function requireFilterColumns(Filter $filter)
|
||||
{
|
||||
if ($filter->isExpression()) {
|
||||
$filter->setColumn($this->repository->requireFilterColumn($filter->getColumn()));
|
||||
$column = $filter->getColumn();
|
||||
$filter->setColumn($this->repository->requireFilterColumn($column));
|
||||
$filter->setExpression($this->repository->persistColumn($column, $filter->getExpression()));
|
||||
} elseif ($filter->isChain()) {
|
||||
foreach ($filter->filters() as $chainOrExpression) {
|
||||
$this->requireFilterColumns($chainOrExpression);
|
||||
|
@ -392,7 +397,14 @@ class RepositoryQuery implements QueryInterface
|
|||
$this->order();
|
||||
}
|
||||
|
||||
return $this->query->fetchOne();
|
||||
$result = $this->query->fetchOne();
|
||||
if ($this->repository->providesValueConversion()) {
|
||||
$columns = $this->getColumns();
|
||||
$column = isset($columns[0]) ? $columns[0] : key($columns);
|
||||
return $this->repository->retrieveColumn($column, $result);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -406,7 +418,18 @@ class RepositoryQuery implements QueryInterface
|
|||
$this->order();
|
||||
}
|
||||
|
||||
return $this->query->fetchRow();
|
||||
$result = $this->query->fetchRow();
|
||||
if ($this->repository->providesValueConversion()) {
|
||||
foreach ($this->getColumns() as $alias => $column) {
|
||||
if (! is_string($alias)) {
|
||||
$alias = $column;
|
||||
}
|
||||
|
||||
$result->$alias = $this->repository->retrieveColumn($alias, $result->$alias);
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -422,11 +445,23 @@ class RepositoryQuery implements QueryInterface
|
|||
$this->order();
|
||||
}
|
||||
|
||||
return $this->query->fetchColumn($columnIndex);
|
||||
$results = $this->query->fetchColumn($columnIndex);
|
||||
if ($this->repository->providesValueConversion()) {
|
||||
$columns = $this->getColumns();
|
||||
$aliases = array_keys($columns);
|
||||
$column = is_int($aliases[$columnIndex]) ? $columns[$columnIndex] : $aliases[$columnIndex];
|
||||
foreach ($results as & $value) {
|
||||
$value = $this->repository->retrieveColumn($column, $value);
|
||||
}
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch and return all rows of this query's result as a flattened key/value based array
|
||||
* Fetch and return all rows of this query's result set as an array of key-value pairs
|
||||
*
|
||||
* The first column is the key, the second column is the value.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
|
@ -436,7 +471,22 @@ class RepositoryQuery implements QueryInterface
|
|||
$this->order();
|
||||
}
|
||||
|
||||
return $this->query->fetchPairs();
|
||||
$results = $this->query->fetchPairs();
|
||||
if ($this->repository->providesValueConversion()) {
|
||||
$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);
|
||||
}
|
||||
|
||||
$results = $newResults;
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -450,7 +500,21 @@ class RepositoryQuery implements QueryInterface
|
|||
$this->order();
|
||||
}
|
||||
|
||||
return $this->query->fetchAll();
|
||||
$results = $this->query->fetchAll();
|
||||
if ($this->repository->providesValueConversion()) {
|
||||
$columns = $this->getColumns();
|
||||
foreach ($results as $row) {
|
||||
foreach ($columns as $alias => $column) {
|
||||
if (! is_string($alias)) {
|
||||
$alias = $column;
|
||||
}
|
||||
|
||||
$row->$alias = $this->repository->retrieveColumn($alias, $row->$alias);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in New Issue