vendor/pimcore/pimcore/models/Element/Dao.php line 34

Open in your IDE?
  1. <?php
  2. /**
  3.  * Pimcore
  4.  *
  5.  * This source file is available under two different licenses:
  6.  * - GNU General Public License version 3 (GPLv3)
  7.  * - Pimcore Commercial License (PCL)
  8.  * Full copyright and license information is available in
  9.  * LICENSE.md which is distributed with this source code.
  10.  *
  11.  *  @copyright  Copyright (c) Pimcore GmbH (http://www.pimcore.org)
  12.  *  @license    http://www.pimcore.org/license     GPLv3 and PCL
  13.  */
  14. namespace Pimcore\Model\Element;
  15. use Pimcore\Db\Helper;
  16. use Pimcore\Model;
  17. use Pimcore\Model\User;
  18. /**
  19.  * @internal
  20.  *
  21.  * @property Model\Document|Model\Asset|Model\DataObject\AbstractObject $model
  22.  */
  23. abstract class Dao extends Model\Dao\AbstractDao
  24. {
  25.     /**
  26.      * @return int[]
  27.      *
  28.      * @throws \Exception
  29.      */
  30.     public function getParentIds()
  31.     {
  32.         // collect properties via parent - ids
  33.         $parentIds = [1];
  34.         $obj $this->model->getParent();
  35.         if ($obj) {
  36.             while ($obj) {
  37.                 if ($obj->getId() == 1) {
  38.                     break;
  39.                 }
  40.                 if (in_array($obj->getId(), $parentIds)) {
  41.                     throw new \Exception('detected infinite loop while resolving all parents from ' $this->model->getId() . ' on ' $obj->getId());
  42.                 }
  43.                 $parentIds[] = $obj->getId();
  44.                 $obj $obj->getParent();
  45.             }
  46.         }
  47.         return $parentIds;
  48.     }
  49.     /**
  50.      * @param string $fullpath
  51.      *
  52.      * @return array
  53.      */
  54.     protected function extractKeyAndPath($fullpath)
  55.     {
  56.         $key '';
  57.         $path $fullpath;
  58.         if ($fullpath !== '/') {
  59.             $lastPart strrpos($fullpath'/') + 1;
  60.             $key substr($fullpath$lastPart);
  61.             $path substr($fullpath0$lastPart);
  62.         }
  63.         return [
  64.             'key' => $key,
  65.             'path' => $path,
  66.         ];
  67.     }
  68.     /**
  69.      * @return int
  70.      */
  71.     abstract public function getVersionCountForUpdate(): int;
  72.     /**
  73.      * @param string $type
  74.      * @param array $userIds
  75.      * @param string $tableSuffix
  76.      *
  77.      * @return int
  78.      *
  79.      * @throws \Doctrine\DBAL\Exception
  80.      */
  81.     public function InheritingPermission(string $type, array $userIdsstring $tableSuffix): int
  82.     {
  83.         $current $this->model;
  84.         if (!$current->getId()) {
  85.             return 0;
  86.         }
  87.         $fullPath $current->getPath() . $current->getKey();
  88.         $sql 'SELECT ' $this->db->quoteIdentifier($type) . ' FROM users_workspaces_' $tableSuffix ' WHERE LOCATE(cpath, ?)=1 AND
  89.         userId IN (' implode(','$userIds) . ')
  90.         ORDER BY LENGTH(cpath) DESC, FIELD(userId, ' end($userIds) . ') DESC, ' $this->db->quoteIdentifier($type) . ' DESC LIMIT 1';
  91.         return (int)$this->db->fetchOne($sql, [$fullPath]);
  92.     }
  93.     /**
  94.      * @param array $columns
  95.      * @param User $user
  96.      * @param string $tableSuffix
  97.      *
  98.      * @return array<string, int>
  99.      *
  100.      * @internal
  101.      */
  102.     protected function permissionByTypes(array $columnsUser $userstring $tableSuffix)
  103.     {
  104.         $permissions = [];
  105.         foreach ($columns as $type) {
  106.             $permissions[$type] = 0;
  107.         }
  108.         $parentIds $this->getParentIds();
  109.         if ($id $this->model->getId()) {
  110.             $parentIds[] = $id;
  111.         }
  112.         $currentUserId $user->getId();
  113.         $userIds $user->getRoles();
  114.         $userIds[] = $currentUserId;
  115.         $highestWorkspaceQuery '
  116.             SELECT userId,cid,`'implode('`,`'$columns) .'` FROM users_workspaces_'.$tableSuffix.'
  117.             WHERE cid IN (' implode(','$parentIds) . ') AND userId IN (' implode(','$userIds) . ')
  118.             ORDER BY LENGTH(cpath) DESC, FIELD(userId, ' $currentUserId ') DESC LIMIT 1
  119.         ';
  120.         $highestWorkspace $this->db->fetchAssociative($highestWorkspaceQuery);
  121.         if ($highestWorkspace) {
  122.             //if it's the current user, this is the permission that rules them all, no need to check others
  123.             if ($highestWorkspace['userId'] == $currentUserId) {
  124.                 foreach ($columns as $type) {
  125.                     $permissions[$type] = (int) $highestWorkspace[$type];
  126.                 }
  127.                 if ($permissions['list'] == 0) {
  128.                     $permissions['list'] = $this->checkChildrenForPathTraversal($tableSuffix$userIds);
  129.                 }
  130.                 return $permissions;
  131.             }
  132.             //if not found, having already the longest cpath from first query,
  133.             //we either have role permission for the same object, or it could be any of its parents permission.
  134.             $roleWorkspaceSql '
  135.              SELECT userId,`'implode('`,`'$columns) .'` FROM users_workspaces_'.$tableSuffix.'
  136.              WHERE cid = ' $highestWorkspace['cid'] . ' AND userId IN (' implode(','$userIds) . ')
  137.              ORDER BY FIELD(userId, ' $currentUserId ') DESC
  138.              ';
  139.             $objectPermissions $this->db->fetchAllAssociative($roleWorkspaceSql);
  140.             //this performs the additive rule when conflicting rules with multiple roles,
  141.             //breaks the loop when permission=1 is found and move on to check next permission type.
  142.             foreach ($columns as $type) {
  143.                 foreach ($objectPermissions as $workspace) {
  144.                     if ($workspace[$type] == 1) {
  145.                         $permissions[$type] = 1;
  146.                         break;
  147.                     }
  148.                 }
  149.             }
  150.         }
  151.         //when list=0, we look for any allowed children, so that can make possible to list the path of the folder in between
  152.         //to reach that children by "exceptionally" turning list=0 to list=1
  153.         if ($permissions['list']==0) {
  154.             $permissions['list'] = $this->checkChildrenForPathTraversal($tableSuffix$userIds);
  155.         }
  156.         return $permissions;
  157.     }
  158.     /**
  159.      * for "path traversal" intending the list=1 on parent folder (with list=0) when there are nested children allowed
  160.      *
  161.      * @param string $tableSuffix
  162.      * @param array $userIds
  163.      *
  164.      * @return int
  165.      *
  166.      * @internal
  167.      */
  168.     private function checkChildrenForPathTraversal(string $tableSuffix, array $userIds)
  169.     {
  170.         $path $this->model->getId() == '/' $this->model->getRealFullPath() . '/';
  171.         $permissionsChildren $this->db->fetchOne('
  172.             SELECT list FROM users_workspaces_'.$tableSuffix.' as uw
  173.             WHERE cpath LIKE ? AND userId IN (' implode(','$userIds) . ') AND list = 1
  174.             AND NOT EXISTS( SELECT list FROM users_workspaces_'.$tableSuffix.' WHERE cid = uw.cid AND list = 0 AND userId ='.end($userIds).')
  175.             LIMIT 1',
  176.             [Helper::escapeLike($path) . '%']);
  177.         return (int)$permissionsChildren;
  178.     }
  179. }