mirror of
				https://github.com/Icinga/icingaweb2.git
				synced 2025-10-31 11:24:51 +01:00 
			
		
		
		
	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 |      * @var array | ||||||
|      */ |      */ | ||||||
|     protected $conversionRules = array('password'); |     protected $conversionRules = array( | ||||||
|  |         'user' => array( | ||||||
|  |             'password' | ||||||
|  |         ) | ||||||
|  |     ); | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * Initialize this database user backend |      * Initialize this database user backend | ||||||
|  | |||||||
| @ -35,14 +35,16 @@ class IniUserGroupBackend extends IniRepository implements UserGroupBackendInter | |||||||
|     protected $filterColumns = array('group'); |     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 |      * @var array | ||||||
|      */ |      */ | ||||||
|     protected $conversionRules = array( |     protected $conversionRules = array( | ||||||
|  |         'groups' => array( | ||||||
|             'created_at'    => 'date_time', |             'created_at'    => 'date_time', | ||||||
|             'last_modified' => 'date_time', |             'last_modified' => 'date_time', | ||||||
|             'users'         => 'comma_separated_string' |             '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 |      * Validate that the requested table exists | ||||||
|      * |      * | ||||||
| @ -692,6 +732,8 @@ abstract class DbRepository extends Repository implements Extensible, Updatable, | |||||||
|             return $aliasTableMap[$column]; |             return $aliasTableMap[$column]; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         // TODO(jom): Elaborate whether it makes sense to throw ProgrammingError
 | ||||||
|  |         //            instead (duplicate aliases in different tables?)
 | ||||||
|         foreach ($aliasTableMap as $alias => $table) { |         foreach ($aliasTableMap as $alias => $table) { | ||||||
|             if (strpos($alias, '.') !== false) { |             if (strpos($alias, '.') !== false) { | ||||||
|                 list($_, $alias) = split('.', $column, 2); |                 list($_, $alias) = split('.', $column, 2); | ||||||
|  | |||||||
| @ -106,7 +106,7 @@ abstract class Repository implements Selectable | |||||||
|     protected $sortRules; |     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 |      * 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 |      * 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 |      * @return  bool | ||||||
|      */ |      */ | ||||||
|     public function providesValueConversion() |     public function providesValueConversion($table) | ||||||
|     { |     { | ||||||
|         $conversionRules = $this->getConversionRules(); |         $conversionRules = $this->getConversionRules(); | ||||||
|         return !empty($conversionRules); |         return !empty($conversionRules) && isset($conversionRules[$table]); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * Convert a value supposed to be transmitted to the data source |      * 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   string  $name       The alias or column name | ||||||
|      * @param   mixed   $value      The value to convert |      * @param   mixed   $value      The value to convert | ||||||
|      * |      * | ||||||
|      * @return  mixed               If conversion was possible, the converted value, otherwise the unchanged value |      * @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) { |         if ($converter !== null) { | ||||||
|             $value = $this->$converter($value); |             $value = $this->$converter($value); | ||||||
|         } |         } | ||||||
| @ -434,14 +437,15 @@ abstract class Repository implements Selectable | |||||||
|     /** |     /** | ||||||
|      * Convert a value which was fetched from the data source |      * 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   string  $name       The alias or column name | ||||||
|      * @param   mixed   $value      The value to convert |      * @param   mixed   $value      The value to convert | ||||||
|      * |      * | ||||||
|      * @return  mixed               If conversion was possible, the converted value, otherwise the unchanged value |      * @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) { |         if ($converter !== null) { | ||||||
|             $value = $this->$converter($value); |             $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 |      * 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  $name       The alias or column name for which to return a conversion method | ||||||
|      * @param   string  $context    The context of the conversion: persist or retrieve |      * @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 |      * @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(); |         $conversionRules = $this->getConversionRules(); | ||||||
|  |         $tableRules = $conversionRules[$table]; | ||||||
| 
 | 
 | ||||||
|         // Check for a conversion method for the alias/column first
 |         // 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))); |             $methodName = $context . join('', array_map('ucfirst', explode('_', $name))); | ||||||
|             if (method_exists($this, $methodName)) { |             if (method_exists($this, $methodName)) { | ||||||
|                 return $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
 |         // The conversion method for the type is just a fallback, but it is required to exist if defined
 | ||||||
|         if (isset($conversionRules[$name])) { |         if (isset($tableRules[$name])) { | ||||||
|             $identifier = join('', array_map('ucfirst', explode('_', $conversionRules[$name]))); |             $identifier = join('', array_map('ucfirst', explode('_', $tableRules[$name]))); | ||||||
|             if (! method_exists($this, $context . $identifier)) { |             if (! method_exists($this, $context . $identifier)) { | ||||||
|                 // Do not throw an error in case at least one conversion method exists
 |                 // Do not throw an error in case at least one conversion method exists
 | ||||||
|                 if (! method_exists($this, ($context === 'persist' ? 'retrieve' : 'persist') . $identifier)) { |                 if (! method_exists($this, ($context === 'persist' ? 'retrieve' : 'persist') . $identifier)) { | ||||||
|                     throw new ProgrammingError( |                     throw new ProgrammingError( | ||||||
|                         'Cannot find any conversion method for type "%s"' |                         'Cannot find any conversion method for type "%s"' | ||||||
|                         . '. Add a proper conversion method or remove the type definition', |                         . '. Add a proper conversion method or remove the type definition', | ||||||
|                         $conversionRules[$name] |                         $tableRules[$name] | ||||||
|                     ); |                     ); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 Logger::debug( |                 Logger::debug( | ||||||
|                     'Conversion method "%s" for type definition "%s" does not exist in repository "%s".', |                     'Conversion method "%s" for type definition "%s" does not exist in repository "%s".', | ||||||
|                     $context . $identifier, |                     $context . $identifier, | ||||||
|                     $conversionRules[$name], |                     $tableRules[$name], | ||||||
|                     $this->getName() |                     $this->getName() | ||||||
|                 ); |                 ); | ||||||
|             } else { |             } else { | ||||||
| @ -623,7 +629,7 @@ abstract class Repository implements Selectable | |||||||
|         if ($filter->isExpression()) { |         if ($filter->isExpression()) { | ||||||
|             $column = $filter->getColumn(); |             $column = $filter->getColumn(); | ||||||
|             $filter->setColumn($this->requireFilterColumn($table, $column, $query)); |             $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()) { |         } elseif ($filter->isChain()) { | ||||||
|             foreach ($filter->filters() as $chainOrExpression) { |             foreach ($filter->filters() as $chainOrExpression) { | ||||||
|                 $this->requireFilter($table, $chainOrExpression, $query); |                 $this->requireFilter($table, $chainOrExpression, $query); | ||||||
| @ -826,7 +832,7 @@ abstract class Repository implements Selectable | |||||||
|     { |     { | ||||||
|         $resolved = array(); |         $resolved = array(); | ||||||
|         foreach ($data as $alias => $value) { |         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; |         return $resolved; | ||||||
|  | |||||||
| @ -153,7 +153,7 @@ class RepositoryQuery implements QueryInterface, Iterator | |||||||
|     { |     { | ||||||
|         $this->query->where( |         $this->query->where( | ||||||
|             $this->repository->requireFilterColumn($this->target, $column, $this), |             $this->repository->requireFilterColumn($this->target, $column, $this), | ||||||
|             $this->repository->persistColumn($column, $value) |             $this->repository->persistColumn($this->target, $column, $value) | ||||||
|         ); |         ); | ||||||
|         return $this; |         return $this; | ||||||
|     } |     } | ||||||
| @ -388,10 +388,10 @@ class RepositoryQuery implements QueryInterface, Iterator | |||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         $result = $this->query->fetchOne(); |         $result = $this->query->fetchOne(); | ||||||
|         if ($result !== false && $this->repository->providesValueConversion()) { |         if ($result !== false && $this->repository->providesValueConversion($this->target)) { | ||||||
|             $columns = $this->getColumns(); |             $columns = $this->getColumns(); | ||||||
|             $column = isset($columns[0]) ? $columns[0] : key($columns); |             $column = isset($columns[0]) ? $columns[0] : key($columns); | ||||||
|             return $this->repository->retrieveColumn($column, $result); |             return $this->repository->retrieveColumn($this->target, $column, $result); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         return $result; |         return $result; | ||||||
| @ -409,13 +409,13 @@ class RepositoryQuery implements QueryInterface, Iterator | |||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         $result = $this->query->fetchRow(); |         $result = $this->query->fetchRow(); | ||||||
|         if ($result !== false && $this->repository->providesValueConversion()) { |         if ($result !== false && $this->repository->providesValueConversion($this->target)) { | ||||||
|             foreach ($this->getColumns() as $alias => $column) { |             foreach ($this->getColumns() as $alias => $column) { | ||||||
|                 if (! is_string($alias)) { |                 if (! is_string($alias)) { | ||||||
|                     $alias = $column; |                     $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(); |         $results = $this->query->fetchColumn(); | ||||||
|         if (! empty($results) && $this->repository->providesValueConversion()) { |         if (! empty($results) && $this->repository->providesValueConversion($this->target)) { | ||||||
|             $columns = $this->getColumns(); |             $columns = $this->getColumns(); | ||||||
|             $aliases = array_keys($columns); |             $aliases = array_keys($columns); | ||||||
|             $column = is_int($aliases[0]) ? $columns[0] : $aliases[0]; |             $column = is_int($aliases[0]) ? $columns[0] : $aliases[0]; | ||||||
|             foreach ($results as & $value) { |             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(); |         $results = $this->query->fetchPairs(); | ||||||
|         if (! empty($results) && $this->repository->providesValueConversion()) { |         if (! empty($results) && $this->repository->providesValueConversion($this->target)) { | ||||||
|             $columns = $this->getColumns(); |             $columns = $this->getColumns(); | ||||||
|             $aliases = array_keys($columns); |             $aliases = array_keys($columns); | ||||||
|             $newResults = array(); |             $newResults = array(); | ||||||
|             foreach ($results as $colOneValue => $colTwoValue) { |             foreach ($results as $colOneValue => $colTwoValue) { | ||||||
|                 $colOne = $aliases[0] !== 0 ? $aliases[0] : $columns[0]; |                 $colOne = $aliases[0] !== 0 ? $aliases[0] : $columns[0]; | ||||||
|                 $colTwo = count($aliases) < 2 ? $colOne : ($aliases[1] !== 1 ? $aliases[1] : $columns[1]); |                 $colTwo = count($aliases) < 2 ? $colOne : ($aliases[1] !== 1 ? $aliases[1] : $columns[1]); | ||||||
|                 $colOneValue = $this->repository->retrieveColumn($colOne, $colOneValue); |                 $colOneValue = $this->repository->retrieveColumn($this->target, $colOne, $colOneValue); | ||||||
|                 $newResults[$colOneValue] = $this->repository->retrieveColumn($colTwo, $colTwoValue); |                 $newResults[$colOneValue] = $this->repository->retrieveColumn($this->target, $colTwo, $colTwoValue); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             $results = $newResults; |             $results = $newResults; | ||||||
| @ -489,7 +489,7 @@ class RepositoryQuery implements QueryInterface, Iterator | |||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         $results = $this->query->fetchAll(); |         $results = $this->query->fetchAll(); | ||||||
|         if (! empty($results) && $this->repository->providesValueConversion()) { |         if (! empty($results) && $this->repository->providesValueConversion($this->target)) { | ||||||
|             $columns = $this->getColumns(); |             $columns = $this->getColumns(); | ||||||
|             foreach ($results as $row) { |             foreach ($results as $row) { | ||||||
|                 foreach ($columns as $alias => $column) { |                 foreach ($columns as $alias => $column) { | ||||||
| @ -497,7 +497,7 @@ class RepositoryQuery implements QueryInterface, Iterator | |||||||
|                         $alias = $column; |                         $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() |     public function current() | ||||||
|     { |     { | ||||||
|         $row = $this->iterator->current(); |         $row = $this->iterator->current(); | ||||||
|         if ($this->repository->providesValueConversion()) { |         if ($this->repository->providesValueConversion($this->target)) { | ||||||
|             foreach ($this->getColumns() as $alias => $column) { |             foreach ($this->getColumns() as $alias => $column) { | ||||||
|                 if (! is_string($alias)) { |                 if (! is_string($alias)) { | ||||||
|                     $alias = $column; |                     $alias = $column; | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 $row->$alias = $this->repository->retrieveColumn($alias, $row->$alias); |                 $row->$alias = $this->repository->retrieveColumn($this->target, $alias, $row->$alias); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user