vendor/pimcore/advanced-object-search/src/Controller/AdminController.php line 42

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 AdvancedObjectSearchBundle\Controller;
  15. use AdvancedObjectSearchBundle\Event\AdvancedObjectSearchEvents;
  16. use AdvancedObjectSearchBundle\Event\FilterListingEvent;
  17. use AdvancedObjectSearchBundle\Model\SavedSearch;
  18. use AdvancedObjectSearchBundle\Service;
  19. use Pimcore\Bundle\AdminBundle\Helper\QueryParams;
  20. use Pimcore\Controller\Traits\JsonHelperTrait;
  21. use Pimcore\Controller\UserAwareController;
  22. use Pimcore\Db;
  23. use Pimcore\Model\DataObject;
  24. use Pimcore\Model\DataObject\Listing;
  25. use Pimcore\Model\DataObject\Service as DataObjectService;
  26. use Pimcore\Tool;
  27. use Symfony\Component\EventDispatcher\EventDispatcherInterface;
  28. use Symfony\Component\HttpFoundation\JsonResponse;
  29. use Symfony\Component\HttpFoundation\Request;
  30. use Symfony\Component\HttpFoundation\Response;
  31. use Symfony\Component\HttpFoundation\Session\Attribute\AttributeBagInterface;
  32. use Symfony\Component\Routing\Annotation\Route;
  33. /**
  34.  * Class AdminController
  35.  *
  36.  * @Route("/admin")
  37.  */
  38. class AdminController extends UserAwareController
  39. {
  40.     use JsonHelperTrait;
  41.     /**
  42.      * @Route("/get-fields")
  43.      */
  44.     public function getFieldsAction(Request $requestService $service): JsonResponse
  45.     {
  46.         $type strip_tags($request->get('type'));
  47.         $allowInheritance false;
  48.         switch ($type) {
  49.             case 'class':
  50.                 $classId strip_tags($request->get('class_id'));
  51.                 $definition DataObject\ClassDefinition::getById($classId);
  52.                 $allowInheritance $definition->getAllowInherit();
  53.                 break;
  54.             case 'fieldcollection':
  55.                 $key strip_tags($request->get('key'));
  56.                 $definition DataObject\Fieldcollection\Definition::getByKey($key);
  57.                 break;
  58.             case 'objectbrick':
  59.                 $key strip_tags($request->get('key'));
  60.                 $definition DataObject\Objectbrick\Definition::getByKey($key);
  61.                 $classId strip_tags($request->get('class_id'));
  62.                 $classDefinition DataObject\ClassDefinition::getById($classId);
  63.                 $allowInheritance $classDefinition->getAllowInherit();
  64.                 break;
  65.             default:
  66.                 throw new \Exception("Invalid type '$type''");
  67.         }
  68.         $fieldSelectionInformationEntries $service->getFieldSelectionInformationForClassDefinition($definition$allowInheritance);
  69.         $fields = [];
  70.         foreach ($fieldSelectionInformationEntries as $entry) {
  71.             $fields[] = $entry->toArray();
  72.         }
  73.         return $this->jsonResponse(['data' => $fields]);
  74.     }
  75.     /**
  76.      * @Route("/grid-proxy")
  77.      */
  78.     public function gridProxyAction(Request $requestService $serviceEventDispatcherInterface $eventDispatcher): JsonResponse Response
  79.     {
  80.         $requestedLanguage $request->get('language');
  81.         if ($requestedLanguage) {
  82.             if ($requestedLanguage != 'default') {
  83.                 $request->setLocale($requestedLanguage);
  84.             }
  85.         } else {
  86.             $requestedLanguage $request->getLocale();
  87.         }
  88.         if ($request->get('data')) {
  89.             return $this->forward('Pimcore\Bundle\AdminBundle\Controller\Admin\DataObject\DataObjectController:gridProxyAction', [], $request->query->all());
  90.         } else {
  91.             // get list of objects
  92.             $class DataObject\ClassDefinition::getById($request->get('classId'));
  93.             $className $class->getName();
  94.             $fields = [];
  95.             if ($request->get('fields')) {
  96.                 $fields $request->get('fields');
  97.             }
  98.             $start 0;
  99.             $limit 20;
  100.             if ($request->get('limit')) {
  101.                 $limit $request->get('limit');
  102.             }
  103.             if ($request->get('start')) {
  104.                 $start $request->get('start');
  105.             }
  106.             $listClass '\\Pimcore\\Model\\DataObject\\' ucfirst($className) . '\\Listing';
  107.             //get ID list from ES Service
  108.             $data json_decode($request->get('filter'), true);
  109.             $results $service->doFilter($data['classId'], $data['conditions']['filters'], $data['conditions']['fulltextSearchTerm'], $start$limit);
  110.             $total $service->extractTotalCountFromResult($results);
  111.             $ids $service->extractIdsFromResult($results);
  112.             /**
  113.              * @var Listing $list
  114.              */
  115.             $list = new $listClass();
  116.             $list->setObjectTypes(['object''folder''variant']);
  117.             $conditionFilters = [];
  118.             $idField DataObjectService::getVersionDependentDatabaseColumnName('id');
  119.             $keyColumn DataObjectService::getVersionDependentDatabaseColumnName('key');
  120.             $pathColumn DataObjectService::getVersionDependentDatabaseColumnName('path');
  121.             if (!$this->getPimcoreUser()->isAdmin()) {
  122.                 $userIds $this->getPimcoreUser()->getRoles();
  123.                 $userIds[] = $this->getPimcoreUser()->getId();
  124.                 $conditionFilters[] = ' (
  125.                                                     (select list from users_workspaces_object where userId in (' implode(','$userIds) . ') and LOCATE(CONCAT('$pathColumn .', ' $keyColumn '),cpath)=1  ORDER BY LENGTH(cpath) DESC LIMIT 1)=1
  126.                                                     OR
  127.                                                     (select list from users_workspaces_object where userId in (' implode(','$userIds) . ') and LOCATE(cpath,CONCAT('$pathColumn .', ' $keyColumn '))=1  ORDER BY LENGTH(cpath) DESC LIMIT 1)=1
  128.                                                  )';
  129.             }
  130.             if (!empty($ids)) {
  131.                 $conditionFilters[] = $idField ' IN (' implode(','$ids) . ')';
  132.                 //$list->setCondition($idField . " IN (" . implode(",", $ids) . ")");
  133.                 $list->setOrderKey(' FIELD(' $idField ', ' implode(','$ids) . ')'false);
  134.             } else {
  135.                 $conditionFilters[] = '1=2';
  136.                 //$list->setCondition("1=2");
  137.             }
  138.             $list->setCondition(implode(' AND '$conditionFilters));
  139.             /* @phpstan-ignore-next-line */
  140.             $eventDispatcher->dispatch(new FilterListingEvent($list), AdvancedObjectSearchEvents::LISTING_FILER);
  141.             $list->load();
  142.             $objects = [];
  143.             foreach ($list->getObjects() as $object) {
  144.                 $o DataObject\Service::gridObjectData($object$fields$requestedLanguage);
  145.                 $objects[] = $o;
  146.             }
  147.             return $this->jsonResponse(['data' => $objects'success' => true'total' => $total]);
  148.         }
  149.     }
  150.     /**
  151.      * @Route("/get-batch-jobs")
  152.      */
  153.     public function getBatchJobsAction(Request $requestService $service): JsonResponse
  154.     {
  155.         if ($request->get('language')) {
  156.             $request->setLocale($request->get('language'));
  157.         }
  158.         $class DataObject\ClassDefinition::getById($request->get('classId'));
  159.         //get ID list from ES Service
  160.         $data json_decode($request->get('filter'), true);
  161.         $results $service->doFilter($data['classId'], $data['conditions']['filters'] ?? [], $data['conditions']['fulltextSearchTerm'] ?? [], null9999);
  162.         $ids $service->extractIdsFromResult($results);
  163.         $className $class->getName();
  164.         $listClass '\\Pimcore\\Model\\DataObject\\' ucfirst($className) . '\\Listing';
  165.         $list = new $listClass();
  166.         $list->setObjectTypes(['object''folder''variant']);
  167.         $idField DataObjectService::getVersionDependentDatabaseColumnName('id');
  168.         $list->setCondition($idField ' IN (' implode(','$ids) . ')');
  169.         $list->setOrderKey(' FIELD('$idField .', ' implode(','$ids) . ')'false);
  170.         if ($request->get('objecttype')) {
  171.             $list->setObjectTypes([$request->get('objecttype')]);
  172.         }
  173.         $jobs $list->loadIdList();
  174.         return $this->jsonResponse(['success' => true'jobs' => $jobs]);
  175.     }
  176.     protected function getCsvFile(string $fileHandle): string
  177.     {
  178.         return PIMCORE_SYSTEM_TEMP_DIRECTORY '/' $fileHandle '.csv';
  179.     }
  180.     /**
  181.      * @Route("/get-export-jobs")
  182.      */
  183.     public function getExportJobsAction(Request $requestService $service): JsonResponse
  184.     {
  185.         if ($request->get('language')) {
  186.             $request->setLocale($request->get('language'));
  187.         }
  188.         $data json_decode($request->get('filter'), true);
  189.         if (empty($ids $request->get('ids'false))) {
  190.             $results $service->doFilter(
  191.                 $data['classId'],
  192.                 $data['conditions']['filters'],
  193.                 $data['conditions']['fulltextSearchTerm'],
  194.                 0,
  195.                 9999 // elastic search cannot export more results than 9999 in one request
  196.             );
  197.             //get ID list from ES Service
  198.             $ids $service->extractIdsFromResult($results);
  199.         }
  200.         $jobs array_chunk($ids20);
  201.         $fileHandle uniqid('export-');
  202.         file_put_contents($this->getCsvFile($fileHandle), '');
  203.         return $this->jsonResponse(['success' => true'jobs' => $jobs'fileHandle' => $fileHandle]);
  204.     }
  205.     /**
  206.      * @Route("/save")
  207.      */
  208.     public function saveAction(Request $request): JsonResponse
  209.     {
  210.         $data $request->get('data');
  211.         $data json_decode($data);
  212.         $id = (intval($request->get('id')));
  213.         if ($id) {
  214.             $savedSearch SavedSearch::getById($id);
  215.         } else {
  216.             $savedSearch = new SavedSearch();
  217.             $savedSearch->setOwner($this->getPimcoreUser());
  218.         }
  219.         $savedSearch->setName($data->settings->name);
  220.         $savedSearch->setDescription($data->settings->description);
  221.         $savedSearch->setCategory($data->settings->category);
  222.         $savedSearch->setSharedUserIds(array_merge($data->settings->shared_users$data->settings->shared_roles));
  223.         $savedSearch->setShareGlobally($this->getPimcoreUser()->isAdmin() && $data->settings->share_globally);
  224.         $config = ['classId' => $data->classId'gridConfig' => $data->gridConfig'conditions' => $data->conditions];
  225.         $savedSearch->setConfig(json_encode($config));
  226.         $savedSearch->save();
  227.         return $this->jsonResponse(['success' => true'id' => $savedSearch->getId()]);
  228.     }
  229.     /**
  230.      * @Route("/delete")
  231.      */
  232.     public function deleteAction(Request $request): JsonResponse
  233.     {
  234.         $id intval($request->get('id'));
  235.         $savedSearch SavedSearch::getById($id);
  236.         if ($savedSearch) {
  237.             $savedSearch->delete();
  238.             return $this->jsonResponse(['success' => true'id' => $savedSearch->getId()]);
  239.         }
  240.         return $this->jsonResponse(['success' => false'message' => "Saved Search with $id not found."]);
  241.     }
  242.     /**
  243.      * @Route("/find")
  244.      */
  245.     public function findAction(Request $request): JsonResponse
  246.     {
  247.         $user $this->getPimcoreUser();
  248.         $query $request->get('query');
  249.         if ($query == '*') {
  250.             $query '';
  251.         }
  252.         $query str_replace('%''*'$query);
  253.         $offset intval($request->get('start'));
  254.         $limit intval($request->get('limit'));
  255.         $offset $offset $offset 0;
  256.         $limit $limit $limit 50;
  257.         $db Db::get();
  258.         $searcherList = new SavedSearch\Listing();
  259.         $conditionParts = [];
  260.         $conditionParams = [];
  261.         //filter for current user
  262.         $userIds = [$user->getId()];
  263.         $userIds array_merge($userIds$user->getRoles());
  264.         $userIds implode('|'$userIds);
  265.         $conditionParts[] = '(shareGlobally = 1 OR ownerId = ? OR sharedUserIds REGEXP ?)';
  266.         $conditionParams[] = $user->getId();
  267.         $conditionParams[] = ',(' $userIds '),';
  268.         //filter for query
  269.         if (!empty($query)) {
  270.             $conditionParts[] = sprintf('(%s LIKE ? OR %s LIKE ? OR %s LIKE ?)',
  271.                 $db->quoteIdentifier('name'),
  272.                 $db->quoteIdentifier('description'),
  273.                 $db->quoteIdentifier('category')
  274.             );
  275.             $conditionParams[] = '%' $query '%';
  276.             $conditionParams[] = '%' $query '%';
  277.             $conditionParams[] = '%' $query '%';
  278.         }
  279.         $condition implode(' AND '$conditionParts);
  280.         $searcherList->setCondition($condition$conditionParams);
  281.         $searcherList->setOffset($offset);
  282.         $searcherList->setLimit($limit);
  283.         $sortingSettings = [];
  284.         if (class_exists(QueryParams::class)) {
  285.             $sortingSettings QueryParams::extractSortingSettings(array_merge($request->request->all(), $request->query->all()));
  286.         }
  287.         if ($sortingSettings['orderKey'] ?? false) {
  288.             $searcherList->setOrderKey($sortingSettings['orderKey']);
  289.         }
  290.         if ($sortingSettings['order'] ?? false) {
  291.             $searcherList->setOrder($sortingSettings['order']);
  292.         }
  293.         $results = []; //$searcherList->load();
  294.         foreach ($searcherList->load() as $result) {
  295.             $results[] = [
  296.                 'id' => $result->getId(),
  297.                 'name' => $result->getName(),
  298.                 'description' => $result->getDescription(),
  299.                 'category' => $result->getCategory(),
  300.                 'owner' => $result->getOwner() ? $result->getOwner()->getUsername() . ' (' $result->getOwner()->getFirstname() . ' ' $result->getOwner()->getLastName() . ')' '',
  301.                 'ownerId' => $result->getOwnerId()
  302.             ];
  303.         }
  304.         // only get the real total-count when the limit parameter is given otherwise use the default limit
  305.         if ($request->get('limit')) {
  306.             $totalMatches $searcherList->getTotalCount();
  307.         } else {
  308.             $totalMatches count($results);
  309.         }
  310.         return $this->jsonResponse(['data' => $results'success' => true'total' => $totalMatches]);
  311.     }
  312.     /**
  313.      * @Route("/load-search")
  314.      */
  315.     public function loadSearchAction(Request $request): JsonResponse
  316.     {
  317.         $id intval($request->get('id'));
  318.         $savedSearch SavedSearch::getById($id);
  319.         if ($savedSearch) {
  320.             $config json_decode($savedSearch->getConfig(), true);
  321.             $classDefinition DataObject\ClassDefinition::getById($config['classId']);
  322.             if (!empty($config['gridConfig']['columns'])) {
  323.                 $helperColumns = [];
  324.                 foreach ($config['gridConfig']['columns'] as &$column) {
  325.                     if (!($column['isOperator'] ?? false)) {
  326.                         $fieldDefinition $classDefinition->getFieldDefinition($column['key']);
  327.                         if ($fieldDefinition) {
  328.                             $width $column['layout']['width'] ?? null;
  329.                             $column['layout'] = json_decode(json_encode($fieldDefinition), true);
  330.                             if ($width) {
  331.                                 $column['layout']['width'] = $width;
  332.                             }
  333.                         }
  334.                     }
  335.                     if (!DataObject\Service::isHelperGridColumnConfig($column['key'])) {
  336.                         continue;
  337.                     }
  338.                     // columnconfig has to be a stdclass
  339.                     $helperColumns[$column['key']] = json_decode(json_encode($column));
  340.                 }
  341.                 // store the saved search columns in the session, otherwise they won't work
  342.                 Tool\Session::useBag($request->getSession(), function (AttributeBagInterface $session) use ($helperColumns) {
  343.                     $existingColumns $session->get('helpercolumns', []);
  344.                     $helperColumns array_merge($existingColumns$helperColumns);
  345.                     $session->set('helpercolumns'$helperColumns);
  346.                 }, 'pimcore_gridconfig');
  347.             }
  348.             return $this->jsonResponse([
  349.                 'id' => $savedSearch->getId(),
  350.                 'classId' => $config['classId'],
  351.                 'settings' => [
  352.                     'name' => $savedSearch->getName(),
  353.                     'description' => $savedSearch->getDescription(),
  354.                     'category' => $savedSearch->getCategory(),
  355.                     'sharedUserIds' => $savedSearch->getSharedUserIds(),
  356.                     'shareGlobally' => $savedSearch->getShareGlobally(),
  357.                     'isOwner' => $savedSearch->getOwnerId() == $this->getPimcoreUser()->getId(),
  358.                     'hasShortCut' => $savedSearch->isInShortCutsForUser($this->getPimcoreUser())
  359.                 ],
  360.                 'conditions' => $config['conditions'],
  361.                 'gridConfig' => $config['gridConfig']
  362.             ]);
  363.         }
  364.         return $this->jsonResponse(['success' => false'message' => "Saved Search with $id not found."]);
  365.     }
  366.     /**
  367.      * @Route("/load-short-cuts")
  368.      */
  369.     public function loadShortCutsAction(Request $request): JsonResponse
  370.     {
  371.         $list = new SavedSearch\Listing();
  372.         $list->setCondition(
  373.             '(shareGlobally = ? OR ownerId = ? OR sharedUserIds LIKE ?) AND shortCutUserIds LIKE ?',
  374.             [
  375.                 true,
  376.                 $this->getPimcoreUser()->getId(),
  377.                 '%,' $this->getPimcoreUser()->getId() . ',%',
  378.                 '%,' $this->getPimcoreUser()->getId() . ',%'
  379.             ]
  380.         );
  381.         $list->load();
  382.         $entries = [];
  383.         foreach ($list->getSavedSearches() as $entry) {
  384.             $entries[] = [
  385.                 'id' => $entry->getId(),
  386.                 'name' => $entry->getName()
  387.             ];
  388.         }
  389.         return $this->jsonResponse(['entries' => $entries]);
  390.     }
  391.     /**
  392.      * @Route("/toggle-short-cut")
  393.      */
  394.     public function toggleShortCutAction(Request $request): JsonResponse
  395.     {
  396.         $id intval($request->get('id'));
  397.         $savedSearch SavedSearch::getById($id);
  398.         if ($savedSearch) {
  399.             $user $this->getPimcoreUser();
  400.             if ($savedSearch->isInShortCutsForUser($user)) {
  401.                 $savedSearch->removeShortCutForUser($user);
  402.             } else {
  403.                 $savedSearch->addShortCutForUser($user);
  404.             }
  405.             $savedSearch->save();
  406.             return $this->jsonResponse(['success' => 'true''hasShortCut' => $savedSearch->isInShortCutsForUser($user)]);
  407.         }
  408.         return $this->jsonResponse(['success' => 'false']);
  409.     }
  410.     /**
  411.      * @Route("/get-users")
  412.      */
  413.     public function getUsersAction(Request $request): JsonResponse
  414.     {
  415.         $users = [];
  416.         // condition for users with groups having DAM permission
  417.         $condition = [];
  418.         $rolesList = new \Pimcore\Model\User\Role\Listing();
  419.         $rolesList->addConditionParam("CONCAT(',', permissions, ',') LIKE ?"'%,bundle_advancedsearch_search,%');
  420.         $rolesList->load();
  421.         $roles $rolesList->getRoles();
  422.         foreach ($roles as $role) {
  423.             $condition[] = "CONCAT(',', roles, ',') LIKE '%," $role->getId() . ",%'";
  424.         }
  425.         // get available user
  426.         $list = new \Pimcore\Model\User\Listing();
  427.         $condition[] = 'admin = 1';
  428.         $list->addConditionParam("((CONCAT(',', permissions, ',') LIKE ? ) OR " implode(' OR '$condition) . ')''%,bundle_advancedsearch_search,%');
  429.         $list->addConditionParam('id != ?'$this->getPimcoreUser()->getId());
  430.         $list->load();
  431.         $userList $list->getUsers();
  432.         foreach ($userList as $user) {
  433.             $users[] = [
  434.                 'id' => $user->getId(),
  435.                 'label' => $user->getName()
  436.             ];
  437.         }
  438.         return $this->jsonResponse(['success' => true'total' => count($users), 'data' => $users]);
  439.     }
  440.     /**
  441.      * @Route("/get-roles")
  442.      */
  443.     public function getRolesAction(): JsonResponse
  444.     {
  445.         $roles = [];
  446.         $rolesList = new \Pimcore\Model\User\Role\Listing();
  447.         $rolesList->setCondition('type = "role"');
  448.         $rolesList->addConditionParam("CONCAT(',', permissions, ',') LIKE ?"'%,bundle_advancedsearch_search,%');
  449.         $rolesList->load();
  450.         foreach ($rolesList->getRoles() as $role) {
  451.             $roles[] = [
  452.                 'id' => $role->getId(),
  453.                 'label' => $role->getName()
  454.             ];
  455.         }
  456.         return $this->jsonResponse(['success' => true'total' => count($roles), 'data' => $roles]);
  457.     }
  458.     /**
  459.      * @Route("/check-index-status")
  460.      */
  461.     public function checkIndexStatusAction(Request $requestService $service): JsonResponse
  462.     {
  463.         return $this->jsonResponse(['indexUptodate' => $service->updateQueueEmpty()]);
  464.     }
  465. }