/** * Adds a hint to a query object * * @param Query $query * @param string $name * @param mixed $value * * @return bool TRUE if the hint is added; otherwise, FALSE */ public function addHint(Query $query, $name, $value) { $result = false; if ($name === Query::HINT_CUSTOM_TREE_WALKERS) { $walkers = $query->getHint(Query::HINT_CUSTOM_TREE_WALKERS); if (false === $walkers) { $walkers = [$value]; $query->setHint(Query::HINT_CUSTOM_TREE_WALKERS, $walkers); $result = true; } elseif (!in_array($value, $walkers, true)) { $walkers[] = $value; $query->setHint(Query::HINT_CUSTOM_TREE_WALKERS, $walkers); $result = true; } } elseif ($name === Query::HINT_CUSTOM_OUTPUT_WALKER) { if ($query->getHint($name) !== $value) { $query->setHint($name, $value); $result = true; } } else { $query->setHint($name, $value); $result = true; } return $result; }
/** * Parses a query string. * * @return ParserResult */ public function parse() { $AST = $this->getAST(); if (($customWalkers = $this->_query->getHint(Query::HINT_CUSTOM_TREE_WALKERS)) !== false) { $this->_customTreeWalkers = $customWalkers; } if (($customOutputWalker = $this->_query->getHint(Query::HINT_CUSTOM_OUTPUT_WALKER)) !== false) { $this->_customOutputWalker = $customOutputWalker; } // Run any custom tree walkers over the AST if ($this->_customTreeWalkers) { $treeWalkerChain = new TreeWalkerChain($this->_query, $this->_parserResult, $this->_queryComponents); foreach ($this->_customTreeWalkers as $walker) { $treeWalkerChain->addTreeWalker($walker); } if ($AST instanceof AST\SelectStatement) { $treeWalkerChain->walkSelectStatement($AST); } else { if ($AST instanceof AST\UpdateStatement) { $treeWalkerChain->walkUpdateStatement($AST); } else { $treeWalkerChain->walkDeleteStatement($AST); } } } if ($this->_customOutputWalker) { $outputWalker = new $this->_customOutputWalker($this->_query, $this->_parserResult, $this->_queryComponents); } else { $outputWalker = new SqlWalker($this->_query, $this->_parserResult, $this->_queryComponents); } // Assign an SQL executor to the parser result $this->_parserResult->setSqlExecutor($outputWalker->getExecutor($AST)); return $this->_parserResult; }
/** * Appends a custom tree walker to the tree walkers hint. * * @param Query $query * @param string $walkerClass */ private function appendTreeWalker(Query $query, $walkerClass) { $hints = $query->getHint(Query::HINT_CUSTOM_TREE_WALKERS); if ($hints === false) { $hints = array(); } $hints[] = $walkerClass; $query->setHint(Query::HINT_CUSTOM_TREE_WALKERS, $hints); }
/** * Add a custom TreeWalker $walker class name to * be included in the CustomTreeWalker hint list * of the given $query * * @param Query $query * @param string $walker * @return void */ public static function addCustomTreeWalker(Query $query, $walker) { $customTreeWalkers = $query->getHint(Query::HINT_CUSTOM_TREE_WALKERS); if ($customTreeWalkers !== false && is_array($customTreeWalkers)) { $customTreeWalkers = array_merge($customTreeWalkers, array($walker)); } else { $customTreeWalkers = array($walker); } $query->setHint(Query::HINT_CUSTOM_TREE_WALKERS, $customTreeWalkers); }
/** * Parses a query string. * * @return ParserResult */ public function parse() { $AST = $this->getAST(); // Fix order of identification variables. // They have to appear in the select clause in the same order as the // declarations (from ... x join ... y join ... z ...) appear in the query // as the hydration process relies on that order for proper operation. if (count($this->_identVariableExpressions) > 1) { foreach ($this->_queryComponents as $dqlAlias => $qComp) { if (isset($this->_identVariableExpressions[$dqlAlias])) { $expr = $this->_identVariableExpressions[$dqlAlias]; $key = array_search($expr, $AST->selectClause->selectExpressions); unset($AST->selectClause->selectExpressions[$key]); $AST->selectClause->selectExpressions[] = $expr; } } } if (($customWalkers = $this->_query->getHint(Query::HINT_CUSTOM_TREE_WALKERS)) !== false) { $this->_customTreeWalkers = $customWalkers; } if (($customOutputWalker = $this->_query->getHint(Query::HINT_CUSTOM_OUTPUT_WALKER)) !== false) { $this->_customOutputWalker = $customOutputWalker; } // Run any custom tree walkers over the AST if ($this->_customTreeWalkers) { $treeWalkerChain = new TreeWalkerChain($this->_query, $this->_parserResult, $this->_queryComponents); foreach ($this->_customTreeWalkers as $walker) { $treeWalkerChain->addTreeWalker($walker); } if ($AST instanceof AST\SelectStatement) { $treeWalkerChain->walkSelectStatement($AST); } else { if ($AST instanceof AST\UpdateStatement) { $treeWalkerChain->walkUpdateStatement($AST); } else { $treeWalkerChain->walkDeleteStatement($AST); } } } if ($this->_customOutputWalker) { $outputWalker = new $this->_customOutputWalker($this->_query, $this->_parserResult, $this->_queryComponents); } else { $outputWalker = new SqlWalker($this->_query, $this->_parserResult, $this->_queryComponents); } // Assign an SQL executor to the parser result $this->_parserResult->setSqlExecutor($outputWalker->getExecutor($AST)); return $this->_parserResult; }
/** * SelectExpression ::= * IdentificationVariable | StateFieldPathExpression | * (AggregateExpression | "(" Subselect ")" | FunctionDeclaration) [["AS"] AliasResultVariable] * * @return \Doctrine\ORM\Query\AST\SelectExpression */ public function SelectExpression() { $expression = null; $fieldAliasIdentificationVariable = null; $peek = $this->_lexer->glimpse(); // First we recognize for an IdentificationVariable (DQL class alias) if ($peek['value'] != '.' && $peek['value'] != '(' && $this->_lexer->lookahead['type'] === Lexer::T_IDENTIFIER) { $expression = $this->IdentificationVariable(); } else { if (($isFunction = $this->_isFunction()) !== false || $this->_isSubselect()) { if ($isFunction) { if ($this->_isAggregateFunction($this->_lexer->lookahead['type'])) { $expression = $this->AggregateExpression(); } else { $expression = $this->FunctionDeclaration(); } } else { $this->match(Lexer::T_OPEN_PARENTHESIS); $expression = $this->Subselect(); $this->match(Lexer::T_CLOSE_PARENTHESIS); } if ($this->_lexer->isNextToken(Lexer::T_AS)) { $this->match(Lexer::T_AS); } if ($this->_lexer->isNextToken(Lexer::T_IDENTIFIER)) { $token = $this->_lexer->lookahead; $fieldAliasIdentificationVariable = $this->AliasResultVariable(); // Include AliasResultVariable in query components. $this->_queryComponents[$fieldAliasIdentificationVariable] = array('resultVariable' => $expression, 'nestingLevel' => $this->_nestingLevel, 'token' => $token); } } else { // Deny hydration of partial objects if doctrine.forcePartialLoad query hint not defined if ($this->_query->getHydrationMode() == Query::HYDRATE_OBJECT && !$this->_query->getHint(Query::HINT_FORCE_PARTIAL_LOAD)) { throw DoctrineException::partialObjectsAreDangerous(); } $expression = $this->StateFieldPathExpression(); } } return new AST\SelectExpression($expression, $fieldAliasIdentificationVariable); }
/** * Parses a query string. * * @return ParserResult */ public function parse() { $AST = $this->getAST(); if (($customWalkers = $this->query->getHint(Query::HINT_CUSTOM_TREE_WALKERS)) !== false) { $this->customTreeWalkers = $customWalkers; } if (($customOutputWalker = $this->query->getHint(Query::HINT_CUSTOM_OUTPUT_WALKER)) !== false) { $this->customOutputWalker = $customOutputWalker; } // Run any custom tree walkers over the AST if ($this->customTreeWalkers) { $treeWalkerChain = new TreeWalkerChain($this->query, $this->parserResult, $this->queryComponents); foreach ($this->customTreeWalkers as $walker) { $treeWalkerChain->addTreeWalker($walker); } switch (true) { case $AST instanceof AST\UpdateStatement: $treeWalkerChain->walkUpdateStatement($AST); break; case $AST instanceof AST\DeleteStatement: $treeWalkerChain->walkDeleteStatement($AST); break; case $AST instanceof AST\SelectStatement: default: $treeWalkerChain->walkSelectStatement($AST); } $this->queryComponents = $treeWalkerChain->getQueryComponents(); } $outputWalkerClass = $this->customOutputWalker ?: __NAMESPACE__ . '\\SqlWalker'; $outputWalker = new $outputWalkerClass($this->query, $this->parserResult, $this->queryComponents); // Assign an SQL executor to the parser result $this->parserResult->setSqlExecutor($outputWalker->getExecutor($AST)); return $this->parserResult; }
/** * This query works well with small offset, but if want to use it with large offsets please refer to the link on how to implement * http://www.scribd.com/doc/14683263/Efficient-Pagination-Using-MySQL * This will only check permissions on the first entity added in the from clause, it will not check permissions * By default the number of rows returned are 10 starting from 0 * * @param Query $query * * @return string */ private function getPermittedAclIdsSQLForUser(Query $query) { $aclConnection = $this->em->getConnection(); $databasePrefix = is_file($aclConnection->getDatabase()) ? '' : $aclConnection->getDatabase() . '.'; $mask = $query->getHint('acl.mask'); $rootEntity = '"' . str_replace('\\', '\\\\', $query->getHint('acl.root.entity')) . '"'; /* @var $token TokenInterface */ $token = $this->securityContext->getToken(); $userRoles = array(); $user = null; if (!is_null($token)) { $user = $token->getUser(); $userRoles = $this->roleHierarchy->getReachableRoles($token->getRoles()); } // Security context does not provide anonymous role automatically. $uR = array('"IS_AUTHENTICATED_ANONYMOUSLY"'); /* @var $role RoleInterface */ foreach ($userRoles as $role) { // The reason we ignore this is because by default FOSUserBundle adds ROLE_USER for every user if ($role->getRole() !== 'ROLE_USER') { $uR[] = '"' . $role->getRole() . '"'; } } $uR = array_unique($uR); $inString = implode(' OR s.identifier = ', $uR); if (is_object($user)) { $inString .= ' OR s.identifier = "' . str_replace('\\', '\\\\', get_class($user)) . '-' . $user->getUserName() . '"'; } $selectQuery = <<<SELECTQUERY SELECT DISTINCT o.object_identifier as id FROM {$databasePrefix}acl_object_identities as o INNER JOIN {$databasePrefix}acl_classes c ON c.id = o.class_id LEFT JOIN {$databasePrefix}acl_entries e ON ( e.class_id = o.class_id AND (e.object_identity_id = o.id OR {$aclConnection->getDatabasePlatform()->getIsNullExpression('e.object_identity_id')}) ) LEFT JOIN {$databasePrefix}acl_security_identities s ON ( s.id = e.security_identity_id ) WHERE c.class_type = {$rootEntity} AND (s.identifier = {$inString}) AND e.mask & {$mask} > 0 SELECTQUERY; return $selectQuery; }
/** * Determine whether to use an output walker for the query * * @param Query $query The query. * * @return bool */ private function useOutputWalker(Query $query) { if ($this->useOutputWalkers === null) { return (bool) $query->getHint(Query::HINT_CUSTOM_OUTPUT_WALKER) == false; } return $this->useOutputWalkers; }
/** * This query works well with small offset, but if want to use it with large offsets please refer to the link on how to implement * http://www.scribd.com/doc/14683263/Efficient-Pagination-Using-MySQL * This will only check permissions on first enity added in the from clause, it will not check permissions * By default the number of rows returned are 10 starting from 0 * * @param Query $query Query * @param QueryBuilder $queryBuilder QueryBuilder * @param UserInterface $user User * * @return string */ private function getPermittedIdsACLSQLForUser(Query $query, QueryBuilder $queryBuilder, UserInterface $user = null) { $database = $this->aclConnection->getDatabase(); $mask = $query->getHint('acl.mask'); $rootEntities = $query->getHint('acl.root.entities'); foreach ($rootEntities as $rootEntity) { $rE[] = '"' . str_replace('\\', '\\\\', $rootEntity) . '"'; // For now ACL will be checked for first root entity, it will not check for all other entities in join etc.., break; } $rootEntities = implode(',', $rE); if (!is_object($user)) { $token = $this->securityContext->getToken(); // for now lets imagine we will have token i.e user is logged in $user = $token->getUser(); } $identifier = "''"; if (is_object($user)) { $identifiers = array(); $userRoles = $user->getRoles(); foreach ($userRoles as $role) { // The reason we ignore this is because by default FOSUserBundle adds ROLE_USER for every user if ($role !== 'ROLE_USER') { $identifiers[] = $role; } } $identifiers[] = str_replace('\\', '\\\\', get_class($user)) . '-' . $user->getUserName(); $identifier = '"' . implode('","', $identifiers) . '"'; } $isNullExpression = $this->aclConnection->getDatabasePlatform()->getIsNullExpression('e.object_identity_id'); $selectQuery = <<<SELECTQUERY SELECT DISTINCT o.object_identifier as id FROM {$database}.acl_object_identities as o INNER JOIN {$database}.acl_classes c ON c.id = o.class_id LEFT JOIN {$database}.acl_entries e ON ( e.class_id = o.class_id AND (e.object_identity_id = o.id OR {$isNullExpression}) ) LEFT JOIN {$database}.acl_security_identities s ON ( s.id = e.security_identity_id ) WHERE c.class_type = {$rootEntities} AND s.identifier IN ({$identifier}) AND e.mask >= {$mask} SELECTQUERY; return $selectQuery; }