Repository: Ensure that we'll internally only work with virtual table names

refs #10367
This commit is contained in:
Johannes Meyer 2015-10-16 14:46:44 +02:00
parent f88bd525f1
commit 36340aafa6
4 changed files with 74 additions and 123 deletions

View File

@ -102,15 +102,13 @@ class LdapUserBackend extends LdapRepository implements UserBackendInterface, In
/**
* Set the objectClass where to look for users
*
* Sets also the base table name for the underlying repository.
*
* @param string $userClass
*
* @return $this
*/
public function setUserClass($userClass)
{
$this->baseTable = $this->userClass = $this->getNormedAttribute($userClass);
$this->userClass = $this->getNormedAttribute($userClass);
return $this;
}
@ -216,13 +214,10 @@ class LdapUserBackend extends LdapRepository implements UserBackendInterface, In
*
* @return array
*
* @throws ProgrammingError In case either $this->userNameAttribute or $this->userClass has not been set yet
* @throws ProgrammingError In case $this->userNameAttribute has not been set yet
*/
protected function initializeQueryColumns()
{
if ($this->userClass === null) {
throw new ProgrammingError('It is required to set the objectClass where to look for users first');
}
if ($this->userNameAttribute === null) {
throw new ProgrammingError('It is required to set a attribute name where to find a user\'s name first');
}
@ -240,7 +235,7 @@ class LdapUserBackend extends LdapRepository implements UserBackendInterface, In
}
return array(
$this->userClass => array(
'user' => array(
'user' => $this->userNameAttribute,
'user_name' => $this->userNameAttribute,
'is_active' => $isActiveAttribute,
@ -269,15 +264,9 @@ class LdapUserBackend extends LdapRepository implements UserBackendInterface, In
* Initialize this repository's conversion rules
*
* @return array
*
* @throws ProgrammingError In case $this->userClass has not been set yet
*/
protected function initializeConversionRules()
{
if ($this->userClass === null) {
throw new ProgrammingError('It is required to set the objectClass where to look for users first');
}
if ($this->ds->getCapabilities()->isActiveDirectory()) {
$stateConverter = 'user_account_control';
} else {
@ -285,7 +274,7 @@ class LdapUserBackend extends LdapRepository implements UserBackendInterface, In
}
return array(
$this->userClass => array(
'user' => array(
'is_active' => $stateConverter,
'created_at' => 'generalized_time',
'last_modified' => 'generalized_time'
@ -330,14 +319,26 @@ class LdapUserBackend extends LdapRepository implements UserBackendInterface, In
}
/**
* @param Inspection $info Optional inspection to fill with diagnostic info
* Validate that the requested table exists
*
* @throws AuthenticationException When authentication is not possible
* This will return $this->userClass in case $table equals "user".
*
* @param string $table The table to validate
* @param RepositoryQuery $query An optional query to pass as context
* (unused by the base implementation)
*
* @return string
*
* @throws ProgrammingError In case the given table does not exist
*/
public function assertAuthenticationPossible(Inspection $insp = null)
public function requireTable($table, RepositoryQuery $query = null)
{
$table = parent::requireTable($table, $query);
if ($table === 'user') {
$table = $this->userClass;
}
return $table;
}
/**
@ -359,17 +360,16 @@ class LdapUserBackend extends LdapRepository implements UserBackendInterface, In
->getQuery()
->setUsePagedResults(false)
->fetchDn();
if ($userDn === null) {
return false;
}
$testCredentialsResult = $this->ds->testCredentials($userDn, $password);
if ($testCredentialsResult) {
$validCredentials = $this->ds->testCredentials($userDn, $password);
if ($validCredentials) {
$user->setAdditional('ldap_dn', $userDn);
}
return $testCredentialsResult;
return $validCredentials;
} catch (LdapException $e) {
throw new AuthenticationException(
'Failed to authenticate user "%s" against backend "%s". An exception was thrown:',

View File

@ -211,15 +211,13 @@ class LdapUserGroupBackend extends LdapRepository implements UserGroupBackendInt
/**
* Set the objectClass where to look for groups
*
* Sets also the base table name for the underlying repository.
*
* @param string $groupClass
*
* @return $this
*/
public function setGroupClass($groupClass)
{
$this->baseTable = $this->groupClass = $this->getNormedAttribute($groupClass);
$this->groupClass = $this->getNormedAttribute($groupClass);
return $this;
}
@ -382,16 +380,17 @@ class LdapUserGroupBackend extends LdapRepository implements UserGroupBackendInt
*
* @return array
*
* @throws ProgrammingError In case either $this->groupNameAttribute or $this->groupClass has not been set yet
* @throws ProgrammingError In case either $this->groupNameAttribute or
* $this->groupMemberAttribute has not been set yet
*/
protected function initializeQueryColumns()
{
if ($this->groupClass === null) {
throw new ProgrammingError('It is required to set the objectClass where to look for groups first');
}
if ($this->groupNameAttribute === null) {
throw new ProgrammingError('It is required to set a attribute name where to find a group\'s name first');
}
if ($this->groupMemberAttribute === null) {
throw new ProgrammingError('It is required to set a attribute name where to find a group\'s members first');
}
if ($this->ds->getCapabilities()->isActiveDirectory()) {
$createdAtAttribute = 'whenCreated';
@ -409,7 +408,7 @@ class LdapUserGroupBackend extends LdapRepository implements UserGroupBackendInt
'created_at' => $createdAtAttribute,
'last_modified' => $lastModifiedAttribute
);
return array($this->groupClass => $columns, $this->groupClass => $columns);
return array('group' => $columns, 'group_membership' => $columns);
}
/**
@ -432,7 +431,8 @@ class LdapUserGroupBackend extends LdapRepository implements UserGroupBackendInt
*
* @return array
*
* @throws ProgrammingError In case $this->groupClass has not been set yet
* @throws ProgrammingError In case either $this->groupClass or $this->groupMemberAttribute
* has not been set yet
*/
protected function initializeConversionRules()
{
@ -444,13 +444,17 @@ class LdapUserGroupBackend extends LdapRepository implements UserGroupBackendInt
}
$rules = array(
$this->groupClass => array(
'group' => array(
'created_at' => 'generalized_time',
'last_modified' => 'generalized_time'
),
'group_membership' => array(
'created_at' => 'generalized_time',
'last_modified' => 'generalized_time'
)
);
if (! $this->isAmbiguous($this->groupClass, $this->groupMemberAttribute)) {
$rules[$this->groupClass][] = 'user_name';
$rules['group']['user_name'] = 'user_name';
}
return $rules;

View File

@ -468,7 +468,7 @@ abstract class DbRepository extends Repository implements Extensible, Updatable,
* This does not check whether any conversion for the given table is available if $column is not given, as it
* may be possible that columns from another table where joined in which would otherwise not being converted.
*
* @param array|string $table
* @param string $table
* @param string $column
*
* @return bool
@ -477,10 +477,7 @@ abstract class DbRepository extends Repository implements Extensible, Updatable,
{
if ($column !== null) {
if ($this->validateQueryColumnAssociation($table, $column)) {
return parent::providesValueConversion(
$this->removeTablePrefix($this->clearTableAlias($table)),
$column
);
return parent::providesValueConversion($table, $column);
}
if (($tableName = $this->findTableName($column))) {
@ -513,11 +510,9 @@ abstract class DbRepository extends Repository implements Extensible, Updatable,
protected function getConverter($table, $name, $context, RepositoryQuery $query = null)
{
if (
($query !== null && $this->validateQueryColumnAssociation($table, $name))
|| ($query === null && $this->validateStatementColumnAssociation($table, $name))
! ($query !== null && $this->validateQueryColumnAssociation($table, $name))
&& !($query === null && $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?');
@ -584,44 +579,17 @@ abstract class DbRepository extends Repository implements Extensible, Updatable,
return $filter;
}
/**
* Return this repository's query columns of the given table mapped to their respective aliases
*
* @param array|string $table
*
* @return array
*
* @throws ProgrammingError In case $table does not exist
*/
public function requireAllQueryColumns($table)
{
return parent::requireAllQueryColumns($this->removeTablePrefix($this->clearTableAlias($table)));
}
/**
* Return the query column name for the given alias or null in case the alias does not exist
*
* @param array|string $table
* @param string $alias
*
* @return string|null
*/
public function resolveQueryColumnAlias($table, $alias)
{
return parent::resolveQueryColumnAlias($this->removeTablePrefix($this->clearTableAlias($table)), $alias);
}
/**
* Return the alias for the given query column name or null in case the query column name does not exist
*
* @param array|string $table
* @param string $table
* @param string $column
*
* @return string|null
*/
public function reassembleQueryColumnAlias($table, $column)
{
$alias = parent::reassembleQueryColumnAlias($this->removeTablePrefix($this->clearTableAlias($table)), $column);
$alias = parent::reassembleQueryColumnAlias($table, $column);
if (
$alias === null
&& !$this->validateQueryColumnAssociation($table, $column)
@ -633,29 +601,13 @@ abstract class DbRepository extends Repository implements Extensible, Updatable,
return $alias;
}
/**
* Return whether the given query column name or alias is available in the given table
*
* @param array|string $table
* @param string $column
*
* @return bool
*/
public function validateQueryColumnAssociation($table, $column)
{
return parent::validateQueryColumnAssociation(
$this->removeTablePrefix($this->clearTableAlias($table)),
$column
);
}
/**
* Validate that the given column is a valid query target and return it or the actual name if it's an alias
*
* Attempts to join the given column from a different table if its association to the given table cannot be
* verified.
*
* @param array|string $table The table where to look for the column or alias
* @param string $table The table where to look for the column or alias
* @param string $name The name or alias of the column to validate
* @param RepositoryQuery $query An optional query to pass as context,
* if not given no join will be attempted
@ -667,7 +619,7 @@ abstract class DbRepository extends Repository implements Extensible, Updatable,
public function requireQueryColumn($table, $name, RepositoryQuery $query = null)
{
if ($query === null || $this->validateQueryColumnAssociation($table, $name)) {
return parent::requireQueryColumn($this->removeTablePrefix($this->clearTableAlias($table)), $name, $query);
return parent::requireQueryColumn($table, $name, $query);
}
return $this->joinColumn($name, $table, $query);
@ -679,7 +631,7 @@ abstract class DbRepository extends Repository implements Extensible, Updatable,
* Attempts to join the given column from a different table if its association to the given table cannot be
* verified.
*
* @param array|string $table The table where to look for the column or alias
* @param string $table The table where to look for the column or alias
* @param string $name The name or alias of the column to validate
* @param RepositoryQuery $query An optional query to pass as context,
* if not given the column is considered being used for a statement filter
@ -695,7 +647,7 @@ abstract class DbRepository extends Repository implements Extensible, Updatable,
}
if ($this->validateQueryColumnAssociation($table, $name)) {
return parent::requireFilterColumn($this->removeTablePrefix($this->clearTableAlias($table)), $name, $query);
return parent::requireFilterColumn($table, $name, $query);
}
return $this->joinColumn($name, $table, $query);
@ -704,7 +656,7 @@ abstract class DbRepository extends Repository implements Extensible, Updatable,
/**
* Return the statement column name for the given alias or null in case the alias does not exist
*
* @param array|string $table
* @param string $table
* @param string $alias
*
* @return string|null
@ -716,7 +668,7 @@ abstract class DbRepository extends Repository implements Extensible, Updatable,
return $statementAliasColumnMap[$alias];
}
$prefixedAlias = $this->removeTablePrefix($this->clearTableAlias($table)) . '.' . $alias;
$prefixedAlias = $table . '.' . $alias;
if (isset($statementAliasColumnMap[$prefixedAlias])) {
return $statementAliasColumnMap[$prefixedAlias];
}
@ -725,7 +677,7 @@ abstract class DbRepository extends Repository implements Extensible, Updatable,
/**
* Return the alias for the given statement column name or null in case the statement column does not exist
*
* @param array|string $table
* @param string $table
* @param string $column
*
* @return string|null
@ -737,7 +689,7 @@ abstract class DbRepository extends Repository implements Extensible, Updatable,
return $statementColumnAliasMap[$column];
}
$prefixedColumn = $this->removeTablePrefix($this->clearTableAlias($table)) . '.' . $column;
$prefixedColumn = $table . '.' . $column;
if (isset($statementColumnAliasMap[$prefixedColumn])) {
return $statementColumnAliasMap[$prefixedColumn];
}
@ -746,33 +698,31 @@ abstract class DbRepository extends Repository implements Extensible, Updatable,
/**
* Return whether the given alias or statement column name is available in the given table
*
* @param array|string $table
* @param string $table
* @param string $alias
*
* @return bool
*/
public function validateStatementColumnAssociation($table, $alias)
{
$tableName = $this->removeTablePrefix($this->clearTableAlias($table));
$statementAliasTableMap = $this->getStatementAliasTableMap();
if (isset($statementAliasTableMap[$alias])) {
return $statementAliasTableMap[$alias] === $tableName;
return $statementAliasTableMap[$alias] === $table;
}
$statementColumnTableMap = $this->getStatementColumnTableMap();
if (isset($statementColumnTableMap[$alias])) {
return $statementColumnTableMap[$alias] === $tableName;
return $statementColumnTableMap[$alias] === $table;
}
$prefixedAlias = $tableName . '.' . $alias;
$prefixedAlias = $table . '.' . $alias;
return isset($statementAliasTableMap[$prefixedAlias]) || isset($statementColumnTableMap[$prefixedAlias]);
}
/**
* Return whether the given column name or alias of the given table is a valid statement column
*
* @param array|string $table The table where to look for the column or alias
* @param string $table The table where to look for the column or alias
* @param string $name The column name or alias to check
*
* @return bool
@ -784,7 +734,7 @@ abstract class DbRepository extends Repository implements Extensible, Updatable,
&& $this->reassembleStatementColumnAlias($table, $name) === null)
|| !$this->validateStatementColumnAssociation($table, $name)
) {
return parent::hasStatementColumn($this->removeTablePrefix($this->clearTableAlias($table)), $name);
return parent::hasStatementColumn($table, $name);
}
return true;
@ -793,7 +743,7 @@ abstract class DbRepository extends Repository implements Extensible, Updatable,
/**
* Validate that the given column is a valid statement column and return it or the actual name if it's an alias
*
* @param array|string $table The table for which to require the column
* @param string $table The table for which to require the column
* @param string $name The name or alias of the column to validate
*
* @return string The given column's name
@ -807,15 +757,11 @@ abstract class DbRepository extends Repository implements Extensible, Updatable,
} elseif (($alias = $this->reassembleStatementColumnAlias($table, $name)) !== null) {
$column = $name;
} else {
return parent::requireStatementColumn($this->removeTablePrefix($this->clearTableAlias($table)), $name);
return parent::requireStatementColumn($table, $name);
}
if (! $this->validateStatementColumnAssociation($table, $alias)) {
throw new StatementException(
'Statement column "%s" not found in table "%s"',
$name,
$this->removeTablePrefix($this->clearTableAlias($table))
);
throw new StatementException('Statement column "%s" not found in table "%s"', $name, $table);
}
return $column;
@ -829,7 +775,7 @@ abstract class DbRepository extends Repository implements Extensible, Updatable,
* The method is called with the same parameters but in reversed order.
*
* @param string $name The alias or column name to join into $target
* @param array|string $target The table to join $name into
* @param string $target The table to join $name into
* @param RepositoryQUery $query The query to apply the JOIN-clause on
*
* @return string The resolved alias or $name
@ -843,7 +789,7 @@ abstract class DbRepository extends Repository implements Extensible, Updatable,
throw new ProgrammingError(
'Unable to find a valid table for column "%s" to join into "%s"',
$name,
$this->removeTablePrefix($this->clearTableAlias($target))
$target
);
}
@ -861,7 +807,7 @@ abstract class DbRepository extends Repository implements Extensible, Updatable,
throw new ProgrammingError(
'Unable to join table "%s" into "%s". Method "%s" not found',
$tableName,
$this->removeTablePrefix($this->clearTableAlias($target)),
$target,
$joinMethod
);
}

View File

@ -79,8 +79,9 @@ class RepositoryQuery implements QueryInterface, SortRules, FilterColumns, Itera
*/
public function from($target, array $columns = null)
{
$target = $this->repository->requireTable($target, $this);
$this->query = $this->repository->getDataSource()->select()->from($target);
$this->query = $this->repository->getDataSource()->select()->from(
$this->repository->requireTable($target, $this)
);
$this->query->columns($this->prepareQueryColumns($target, $columns));
$this->target = $target;
return $this;