/** * Get the parameters needed in the template. This is common for the default link chooser and the cke link chooser. * * @return array */ private function getTemplateParameters() { /* @var EntityManager $em */ $em = $this->getDoctrine()->getManager(); $locale = $this->getRequest()->getLocale(); $qb = $em->getConnection()->createQueryBuilder(); $qb->select('n.id, n.parent_id, t.weight, t.title, t.online, t.url, n.ref_entity_name')->from('kuma_nodes', 'n')->leftJoin('n', 'kuma_node_translations', 't', "(t.node_id = n.id AND t.lang = ?)")->where('n.deleted = 0')->andWhere('t.online IN (0, 1)')->addOrderBy('parent_id', 'ASC')->addOrderBy('weight', 'ASC')->addOrderBy('title', 'ASC'); $permissionDef = new PermissionDefinition(array(PermissionMap::PERMISSION_VIEW)); $permissionDef->setEntity('Kunstmaan\\NodeBundle\\Entity\\Node'); $permissionDef->setAlias('n'); $qb = $this->get('kunstmaan_admin.acl.native.helper')->apply($qb, $permissionDef); $stmt = $em->getConnection()->prepare($qb->getSQL()); $stmt->bindValue(1, $locale); $stmt->execute(); $result = $stmt->fetchAll(); $simpleTreeView = new SimpleTreeView(); foreach ($result as $data) { if ($this->isStructureNode($data['ref_entity_name'])) { $data['online'] = true; } $simpleTreeView->addItem($data['parent_id'], $data); } // When the media bundle is available, we show a link in the header to the media chooser $allBundles = $this->container->getParameter('kernel.bundles'); if (array_key_exists('KunstmaanMediaBundle', $allBundles)) { $params = array('linkChooser' => 1); $cKEditorFuncNum = $this->getRequest()->get('CKEditorFuncNum'); if (!empty($cKEditorFuncNum)) { $params['CKEditorFuncNum'] = $cKEditorFuncNum; } $mediaChooserLink = $this->generateUrl('KunstmaanMediaBundle_chooser', $params); } return array('tree' => $simpleTreeView, 'mediaChooserLink' => $mediaChooserLink); }
/** * Apply the ACL constraints to the specified query builder, using the permission definition * * @param QueryBuilder $queryBuilder The query builder * @param PermissionDefinition $permissionDef The permission definition * * @return QueryBuilder */ public function apply(QueryBuilder $queryBuilder, PermissionDefinition $permissionDef) { $aclConnection = $this->em->getConnection(); $databasePrefix = is_file($aclConnection->getDatabase()) ? '' : $aclConnection->getDatabase() . '.'; $rootEntity = $permissionDef->getEntity(); $linkAlias = $permissionDef->getAlias(); // Only tables with a single ID PK are currently supported $linkField = $this->em->getClassMetadata($rootEntity)->getSingleIdentifierColumnName(); $rootEntity = '"' . str_replace('\\', '\\\\', $rootEntity) . '"'; $query = $queryBuilder; $builder = new MaskBuilder(); foreach ($permissionDef->getPermissions() as $permission) { $mask = constant(get_class($builder) . '::MASK_' . strtoupper($permission)); $builder->add($mask); } $mask = $builder->get(); /* @var $token TokenInterface */ $token = $this->tokenStorage->getToken(); $userRoles = array(); 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 = ', (array) $uR); if (is_object($user)) { $inString .= ' OR s.identifier = "' . str_replace('\\', '\\\\', get_class($user)) . '-' . $user->getUserName() . '"'; } $joinTableQuery = <<<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; $query->join($linkAlias, '(' . $joinTableQuery . ')', 'perms_', 'perms_.id = ' . $linkAlias . '.' . $linkField); return $query; }
/** * Returns valid IDs for a specific entity with ACL restrictions for current user applied * * @param PermissionDefinition $permissionDef * * @throws InvalidArgumentException * * @return array */ public function getAllowedEntityIds(PermissionDefinition $permissionDef) { $rootEntity = $permissionDef->getEntity(); if (empty($rootEntity)) { throw new InvalidArgumentException("You have to provide an entity class name!"); } $builder = new MaskBuilder(); foreach ($permissionDef->getPermissions() as $permission) { $mask = constant(get_class($builder) . '::MASK_' . strtoupper($permission)); $builder->add($mask); } $query = new Query($this->em); $query->setHint('acl.mask', $builder->get()); $query->setHint('acl.root.entity', $rootEntity); $sql = $this->getPermittedAclIdsSQLForUser($query); $rsm = new ResultSetMapping(); $rsm->addScalarResult('id', 'id'); $nativeQuery = $this->em->createNativeQuery($sql, $rsm); $transform = function ($item) { return $item['id']; }; $result = array_map($transform, $nativeQuery->getScalarResult()); return $result; }
/** * Get all the information needed to build a menu tree with one query. * We only fetch the fields we need, instead of fetching full objects to limit the memory usage. * * @param string $lang The locale * @param string $permission The permission (read, write, ...) * @param AclNativeHelper $aclNativeHelper The acl helper * @param bool $includeHiddenFromNav Include nodes hidden from navigation or not * * @return array */ public function getAllMenuNodes($lang, $permission, AclNativeHelper $aclNativeHelper, $includeHiddenFromNav = false) { $connection = $this->_em->getConnection(); $qb = $connection->createQueryBuilder(); $databasePlatformName = $connection->getDatabasePlatform()->getName(); $createIfStatement = function ($expression, $trueValue, $falseValue) use($databasePlatformName) { switch ($databasePlatformName) { case 'sqlite': $statement = 'CASE WHEN %s THEN %s ELSE %s END'; break; default: $statement = 'IF(%s, %s, %s)'; } return sprintf($statement, $expression, $trueValue, $falseValue); }; $sql = <<<SQL n.id, n.parent_id AS parent, t.url, {$createIfStatement('t.weight IS NULL', 'v.weight', 't.weight')} AS weight, {$createIfStatement('t.title IS NULL', 'v.title', 't.title')} AS title, {$createIfStatement('t.online IS NULL', '0', 't.online')} AS online, n.hidden_from_nav AS hidden, n.ref_entity_name AS ref_entity_name SQL; $qb->select($sql)->from('kuma_nodes', 'n')->leftJoin('n', 'kuma_node_translations', 't', '(t.node_id = n.id AND t.lang = ?)')->leftJoin('n', '(SELECT lang, title, weight, node_id, url FROM kuma_node_translations GROUP BY node_id ORDER BY id ASC)', 'v', '(v.node_id = n.id AND v.lang <> ?)')->where('n.deleted = 0')->addGroupBy('n.id')->addOrderBy('t.weight', 'ASC')->addOrderBy('t.title', 'ASC'); if (!$includeHiddenFromNav) { $qb->andWhere('n.hidden_from_nav <> 0'); } $permissionDef = new PermissionDefinition(array($permission)); $permissionDef->setEntity('Kunstmaan\\NodeBundle\\Entity\\Node'); $permissionDef->setAlias('n'); $qb = $aclNativeHelper->apply($qb, $permissionDef); $stmt = $this->_em->getConnection()->prepare($qb->getSQL()); $stmt->bindValue(1, $lang); $stmt->bindValue(2, $lang); $stmt->execute(); return $stmt->fetchAll(); }
/** * @covers Kunstmaan\AdminBundle\Helper\Security\Acl\Permission\PermissionDefinition::setPermissions * @expectedException \InvalidArgumentException */ public function testSetPermissionsWithInvalidData() { $this->object->setPermissions(array()); }