vendor/pimcore/pimcore/bundles/AdminBundle/Controller/Admin/Asset/AssetHelperController.php line 736

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\Bundle\AdminBundle\Controller\Admin\Asset;
  15. use PhpOffice\PhpSpreadsheet\Reader\Csv;
  16. use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
  17. use Pimcore\Bundle\AdminBundle\Controller\AdminController;
  18. use Pimcore\Bundle\AdminBundle\Helper\GridHelperService;
  19. use Pimcore\Db;
  20. use Pimcore\Event\AdminEvents;
  21. use Pimcore\Loader\ImplementationLoader\Exception\UnsupportedException;
  22. use Pimcore\Localization\LocaleServiceInterface;
  23. use Pimcore\Logger;
  24. use Pimcore\Model\Asset;
  25. use Pimcore\Model\Element;
  26. use Pimcore\Model\GridConfig;
  27. use Pimcore\Model\GridConfigFavourite;
  28. use Pimcore\Model\GridConfigShare;
  29. use Pimcore\Model\Metadata;
  30. use Pimcore\Model\User;
  31. use Pimcore\Tool;
  32. use Pimcore\Version;
  33. use Symfony\Component\EventDispatcher\GenericEvent;
  34. use Symfony\Component\HttpFoundation\BinaryFileResponse;
  35. use Symfony\Component\HttpFoundation\JsonResponse;
  36. use Symfony\Component\HttpFoundation\Request;
  37. use Symfony\Component\HttpFoundation\ResponseHeaderBag;
  38. use Symfony\Component\HttpFoundation\Session\Attribute\AttributeBagInterface;
  39. use Symfony\Component\Routing\Annotation\Route;
  40. use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
  41. /**
  42.  * @Route("/asset-helper")
  43.  *
  44.  * @internal
  45.  */
  46. class AssetHelperController extends AdminController
  47. {
  48.     /**
  49.      * @param int $userId
  50.      * @param string $classId
  51.      * @param string $searchType
  52.      *
  53.      * @return array
  54.      */
  55.     public function getMyOwnGridColumnConfigs($userId$classId$searchType)
  56.     {
  57.         $db Db::get();
  58.         $configListingConditionParts = [];
  59.         $configListingConditionParts[] = 'ownerId = ' $userId;
  60.         $configListingConditionParts[] = 'classId = ' $db->quote($classId);
  61.         if ($searchType) {
  62.             $configListingConditionParts[] = 'searchType = ' $db->quote($searchType);
  63.         }
  64.         $configCondition implode(' AND '$configListingConditionParts);
  65.         $configListing = new GridConfig\Listing();
  66.         $configListing->setOrderKey('name');
  67.         $configListing->setOrder('ASC');
  68.         $configListing->setCondition($configCondition);
  69.         $configListing $configListing->load();
  70.         $configData = [];
  71.         if (is_array($configListing)) {
  72.             foreach ($configListing as $config) {
  73.                 $configData[] = $config->getObjectVars();
  74.             }
  75.         }
  76.         return $configData;
  77.     }
  78.     /**
  79.      * @param User $user
  80.      * @param string $classId
  81.      * @param string $searchType
  82.      *
  83.      * @return array
  84.      */
  85.     public function getSharedGridColumnConfigs($user$classId$searchType null)
  86.     {
  87.         $db Db::get();
  88.         $configListing = [];
  89.         $userIds = [$user->getId()];
  90.         // collect all roles
  91.         $userIds array_merge($userIds$user->getRoles());
  92.         $userIds implode(','$userIds);
  93.         $query 'select distinct c1.id from gridconfigs c1, gridconfig_shares s
  94.                     where (c1.searchType = ' $db->quote($searchType) . ' and ((c1.id = s.gridConfigId and s.sharedWithUserId IN (' $userIds '))) and c1.classId = ' $db->quote($classId) . ')
  95.                             UNION distinct select c2.id from gridconfigs c2 where shareGlobally = 1 and c2.classId = '$db->quote($classId) . '  and c2.ownerId != ' $db->quote($user->getId());
  96.         $ids $db->fetchCol($query);
  97.         if ($ids) {
  98.             $ids implode(','$ids);
  99.             $configListing = new GridConfig\Listing();
  100.             $configListing->setOrderKey('name');
  101.             $configListing->setOrder('ASC');
  102.             $configListing->setCondition('id in (' $ids ')');
  103.             $configListing $configListing->load();
  104.         }
  105.         $configData = [];
  106.         if (is_array($configListing)) {
  107.             foreach ($configListing as $config) {
  108.                 $configData[] = $config->getObjectVars();
  109.             }
  110.         }
  111.         return $configData;
  112.     }
  113.     /**
  114.      * @Route("/grid-delete-column-config", name="pimcore_admin_asset_assethelper_griddeletecolumnconfig", methods={"DELETE"})
  115.      *
  116.      * @param Request $request
  117.      *
  118.      * @return JsonResponse
  119.      */
  120.     public function gridDeleteColumnConfigAction(Request $request)
  121.     {
  122.         $gridConfigId $request->get('gridConfigId');
  123.         $gridConfig GridConfig::getById($gridConfigId);
  124.         $success false;
  125.         if ($gridConfig) {
  126.             if ($gridConfig->getOwnerId() != $this->getAdminUser()->getId()) {
  127.                 throw new \Exception("don't mess with someone elses grid config");
  128.             }
  129.             $gridConfig->delete();
  130.             $success true;
  131.         }
  132.         $newGridConfig $this->doGetGridColumnConfig($requesttrue);
  133.         $newGridConfig['deleteSuccess'] = $success;
  134.         return $this->adminJson($newGridConfig);
  135.     }
  136.     /**
  137.      * @Route("/grid-get-column-config", name="pimcore_admin_asset_assethelper_gridgetcolumnconfig", methods={"GET"})
  138.      *
  139.      * @param Request $request
  140.      *
  141.      * @return JsonResponse
  142.      */
  143.     public function gridGetColumnConfigAction(Request $request)
  144.     {
  145.         $result $this->doGetGridColumnConfig($request);
  146.         return $this->adminJson($result);
  147.     }
  148.     /**
  149.      * @param Request $request
  150.      * @param bool $isDelete
  151.      *
  152.      * @return array
  153.      */
  154.     public function doGetGridColumnConfig(Request $request$isDelete false)
  155.     {
  156.         $gridConfigId null;
  157.         $classId $request->get('id');
  158.         $type $request->get('type');
  159.         $context = ['purpose' => 'gridconfig'];
  160.         $types = [];
  161.         if ($request->get('types')) {
  162.             $types explode(','$request->get('types'));
  163.         }
  164.         $userId $this->getAdminUser()->getId();
  165.         $requestedGridConfigId $isDelete null $request->get('gridConfigId');
  166.         // grid config
  167.         $gridConfig = [];
  168.         $searchType $request->get('searchType');
  169.         if (strlen($requestedGridConfigId) == 0) {
  170.             // check if there is a favourite view
  171.             $favourite GridConfigFavourite::getByOwnerAndClassAndObjectId($userId$classId0$searchType);
  172.             if ($favourite) {
  173.                 $requestedGridConfigId $favourite->getGridConfigId();
  174.             }
  175.         }
  176.         if (is_numeric($requestedGridConfigId) && $requestedGridConfigId 0) {
  177.             $db Db::get();
  178.             $savedGridConfig GridConfig::getById((int) $requestedGridConfigId);
  179.             if ($savedGridConfig) {
  180.                 $shared null;
  181.                 try {
  182.                     $userIds = [$this->getAdminUser()->getId()];
  183.                     if ($this->getAdminUser()->getRoles()) {
  184.                         $userIds array_merge($userIds$this->getAdminUser()->getRoles());
  185.                     }
  186.                     $userIds implode(','$userIds);
  187.                     $shared = ($savedGridConfig->getOwnerId() != $userId && $savedGridConfig->isShareGlobally()) || $db->fetchOne('select * from gridconfig_shares where sharedWithUserId IN (' $userIds ') and gridConfigId = ' $savedGridConfig->getId());
  188.                 } catch (\Exception $e) {
  189.                 }
  190.                 if (!$shared && $savedGridConfig->getOwnerId() != $this->getAdminUser()->getId()) {
  191.                     throw new \Exception('You are neither the owner of this config nor it is shared with you');
  192.                 }
  193.                 $gridConfigId $savedGridConfig->getId();
  194.                 $gridConfig $savedGridConfig->getConfig();
  195.                 $gridConfig json_decode($gridConfigtrue);
  196.                 $gridConfigName $savedGridConfig->getName();
  197.                 $gridConfigDescription $savedGridConfig->getDescription();
  198.                 $sharedGlobally $savedGridConfig->isShareGlobally();
  199.                 $setAsFavourite $savedGridConfig->isSetAsFavourite();
  200.             }
  201.         }
  202.         $availableFields = [];
  203.         $language '';
  204.         if (empty($gridConfig)) {
  205.             $availableFields $this->getDefaultGridFields(
  206.                 $request->get('no_system_columns'),
  207.                 [], //maybe required for types other than metadata
  208.                 $context,
  209.                 $types);
  210.         } else {
  211.             $savedColumns $gridConfig['columns'];
  212.             foreach ($savedColumns as $key => $sc) {
  213.                 if (!$sc['hidden']) {
  214.                     $colConfig $this->getFieldGridConfig($sc$languagenull);
  215.                     if ($colConfig) {
  216.                         $availableFields[] = $colConfig;
  217.                     }
  218.                 }
  219.             }
  220.         }
  221.         usort($availableFields, function ($a$b) {
  222.             if ($a['position'] == $b['position']) {
  223.                 return 0;
  224.             }
  225.             return ($a['position'] < $b['position']) ? -1;
  226.         });
  227.         $availableConfigs $classId $this->getMyOwnGridColumnConfigs($userId$classId$searchType) : [];
  228.         $sharedConfigs $classId $this->getSharedGridColumnConfigs($this->getAdminUser(), $classId$searchType) : [];
  229.         $settings $this->getShareSettings((int)$gridConfigId);
  230.         $settings['gridConfigId'] = (int)$gridConfigId;
  231.         $settings['gridConfigName'] = $gridConfigName ?? null;
  232.         $settings['gridConfigDescription'] = $gridConfigDescription ?? null;
  233.         $settings['shareGlobally'] = $sharedGlobally ?? null;
  234.         $settings['setAsFavourite'] = $setAsFavourite ?? null;
  235.         $settings['isShared'] = !$gridConfigId || ($shared ?? null);
  236.         $context $gridConfig['context'] ?? null;
  237.         if ($context) {
  238.             $context json_decode($contexttrue);
  239.         }
  240.         return [
  241.             'sortinfo' => isset($gridConfig['sortinfo']) ? $gridConfig['sortinfo'] : false,
  242.             'availableFields' => $availableFields,
  243.             'settings' => $settings,
  244.             'onlyDirectChildren' => isset($gridConfig['onlyDirectChildren']) ? $gridConfig['onlyDirectChildren'] : false,
  245.             'onlyUnreferenced' => isset($gridConfig['onlyUnreferenced']) ? $gridConfig['onlyUnreferenced'] : false,
  246.             'pageSize' => isset($gridConfig['pageSize']) ? $gridConfig['pageSize'] : false,
  247.             'availableConfigs' => $availableConfigs,
  248.             'sharedConfigs' => $sharedConfigs,
  249.             'context' => $context,
  250.         ];
  251.     }
  252.     /**
  253.      * @param array $field
  254.      * @param string $language
  255.      * @param string|null $keyPrefix
  256.      *
  257.      * @return array|null
  258.      */
  259.     protected function getFieldGridConfig($field$language ''$keyPrefix null)
  260.     {
  261.         $defaulMetadataFields = ['copyright''alt''title'];
  262.         $predefined null;
  263.         if (isset($field['fieldConfig']['layout']['name'])) {
  264.             $predefined Metadata\Predefined::getByName($field['fieldConfig']['layout']['name']);
  265.         }
  266.         $key $field['name'];
  267.         if ($keyPrefix) {
  268.             $key $keyPrefix $key;
  269.         }
  270.         $fieldDef explode('~'$field['name']);
  271.         $field['name'] = $fieldDef[0];
  272.         if (isset($fieldDef[1]) && $fieldDef[1] === 'system') {
  273.             $type 'system';
  274.         } elseif (in_array($fieldDef[0], $defaulMetadataFields)) {
  275.             $type 'input';
  276.         } else {
  277.             $type $field['fieldConfig']['type'];
  278.             if (isset($fieldDef[1])) {
  279.                 $field['fieldConfig']['label'] = $field['fieldConfig']['layout']['title'] = $fieldDef[0] . ' (' $fieldDef[1] . ')';
  280.                 $field['fieldConfig']['layout']['icon'] = Tool::getLanguageFlagFile($fieldDef[1], true);
  281.             }
  282.         }
  283.         $result = [
  284.             'key' => $key,
  285.             'type' => $type,
  286.             'label' => $field['fieldConfig']['label'] ?? $key,
  287.             'width' => $field['width'],
  288.             'position' => $field['position'],
  289.             'language' => $field['fieldConfig']['language'] ?? null,
  290.             'layout' => $field['fieldConfig']['layout'] ?? null,
  291.         ];
  292.         if (isset($field['locked'])) {
  293.             $result['locked'] = $field['locked'];
  294.         }
  295.         if ($type === 'select' && $predefined) {
  296.             $field['fieldConfig']['layout']['config'] = $predefined->getConfig();
  297.             $result['layout'] = $field['fieldConfig']['layout'];
  298.         } elseif ($type === 'document' || $type === 'asset' || $type === 'object') {
  299.             $result['layout']['fieldtype'] = 'manyToOneRelation';
  300.             $result['layout']['subtype'] = $type;
  301.         }
  302.         return $result;
  303.     }
  304.     /**
  305.      * @param bool $noSystemColumns
  306.      * @param array $fields
  307.      * @param array $context
  308.      * @param array $types
  309.      *
  310.      * @return array
  311.      */
  312.     public function getDefaultGridFields($noSystemColumns$fields$context$types = [])
  313.     {
  314.         $count 0;
  315.         $availableFields = [];
  316.         if (!$noSystemColumns) {
  317.             foreach (Asset\Service::GRID_SYSTEM_COLUMNS as $sc) {
  318.                 if (empty($types)) {
  319.                     $availableFields[] = [
  320.                         'key' => $sc '~system',
  321.                         'type' => 'system',
  322.                         'label' => $sc,
  323.                         'position' => $count, ];
  324.                     $count++;
  325.                 }
  326.             }
  327.         }
  328.         return $availableFields;
  329.     }
  330.     /**
  331.      * @Route("/prepare-helper-column-configs", name="pimcore_admin_asset_assethelper_preparehelpercolumnconfigs", methods={"POST"})
  332.      *
  333.      * @param Request $request
  334.      *
  335.      * @return JsonResponse
  336.      */
  337.     public function prepareHelperColumnConfigs(Request $request)
  338.     {
  339.         $helperColumns = [];
  340.         $newData = [];
  341.         $data json_decode($request->get('columns'));
  342.         /** @var \stdClass $item */
  343.         foreach ($data as $item) {
  344.             if (!empty($item->isOperator)) {
  345.                 $itemKey '#' uniqid();
  346.                 $item->key $itemKey;
  347.                 $newData[] = $item;
  348.                 $helperColumns[$itemKey] = $item;
  349.             } else {
  350.                 $newData[] = $item;
  351.             }
  352.         }
  353.         Tool\Session::useSession(function (AttributeBagInterface $session) use ($helperColumns) {
  354.             $existingColumns $session->get('helpercolumns', []);
  355.             $helperColumns array_merge($helperColumns$existingColumns);
  356.             $session->set('helpercolumns'$helperColumns);
  357.         }, 'pimcore_gridconfig');
  358.         return $this->adminJson(['success' => true'columns' => $newData]);
  359.     }
  360.     /**
  361.      * @Route("/grid-mark-favourite-column-config", name="pimcore_admin_asset_assethelper_gridmarkfavouritecolumnconfig", methods={"POST"})
  362.      *
  363.      * @param Request $request
  364.      *
  365.      * @return JsonResponse
  366.      */
  367.     public function gridMarkFavouriteColumnConfigAction(Request $request)
  368.     {
  369.         $classId $request->get('classId');
  370.         $asset Asset::getById($classId);
  371.         if ($asset->isAllowed('list')) {
  372.             $gridConfigId $request->get('gridConfigId');
  373.             $searchType $request->get('searchType');
  374.             $type $request->get('type');
  375.             $user $this->getAdminUser();
  376.             $favourite = new GridConfigFavourite();
  377.             $favourite->setOwnerId($user->getId());
  378.             $favourite->setClassId($classId);
  379.             $favourite->setSearchType($searchType);
  380.             $favourite->setType($type);
  381.             $specializedConfigs false;
  382.             try {
  383.                 if ($gridConfigId != 0) {
  384.                     $gridConfig GridConfig::getById($gridConfigId);
  385.                     $favourite->setGridConfigId($gridConfig->getId());
  386.                 }
  387.                 $favourite->setObjectId(0);
  388.                 $favourite->save();
  389.             } catch (\Exception $e) {
  390.                 $favourite->delete();
  391.             }
  392.             return $this->adminJson(['success' => true'spezializedConfigs' => $specializedConfigs]);
  393.         }
  394.         throw $this->createAccessDeniedHttpException();
  395.     }
  396.     /**
  397.      * @param int $gridConfigId
  398.      *
  399.      * @return array
  400.      */
  401.     protected function getShareSettings($gridConfigId)
  402.     {
  403.         $result = [
  404.             'sharedUserIds' => [],
  405.             'sharedRoleIds' => [],
  406.         ];
  407.         $db Db::get();
  408.         $allShares $db->fetchAll('select s.sharedWithUserId, u.type from gridconfig_shares s, users u
  409.                       where s.sharedWithUserId = u.id and s.gridConfigId = ' $gridConfigId);
  410.         if ($allShares) {
  411.             foreach ($allShares as $share) {
  412.                 $type $share['type'];
  413.                 $key 'shared' ucfirst($type) . 'Ids';
  414.                 $result[$key][] = $share['sharedWithUserId'];
  415.             }
  416.         }
  417.         foreach ($result as $idx => $value) {
  418.             $value $value implode(','$value) : '';
  419.             $result[$idx] = $value;
  420.         }
  421.         return $result;
  422.     }
  423.     /**
  424.      * @Route("/grid-save-column-config", name="pimcore_admin_asset_assethelper_gridsavecolumnconfig", methods={"POST"})
  425.      *
  426.      * @param Request $request
  427.      *
  428.      * @return JsonResponse
  429.      */
  430.     public function gridSaveColumnConfigAction(Request $request)
  431.     {
  432.         $asset Asset::getById((int) $request->get('id'));
  433.         if (!$asset) {
  434.             throw $this->createNotFoundException();
  435.         }
  436.         if ($asset->isAllowed('list')) {
  437.             try {
  438.                 $classId $request->get('class_id');
  439.                 $context $request->get('context');
  440.                 $searchType $request->get('searchType');
  441.                 $type $request->get('type');
  442.                 // grid config
  443.                 $gridConfigData $this->decodeJson($request->get('gridconfig'));
  444.                 $gridConfigData['pimcore_version'] = Version::getVersion();
  445.                 $gridConfigData['pimcore_revision'] = Version::getRevision();
  446.                 $gridConfigData['context'] = $context;
  447.                 unset($gridConfigData['settings']['isShared']);
  448.                 $metadata $request->get('settings');
  449.                 $metadata json_decode($metadatatrue);
  450.                 $gridConfigId $metadata['gridConfigId'];
  451.                 $gridConfig GridConfig::getById($gridConfigId);
  452.                 if ($gridConfig && $gridConfig->getOwnerId() != $this->getAdminUser()->getId()) {
  453.                     throw new \Exception("don't mess around with somebody else's configuration");
  454.                 }
  455.                 $this->updateGridConfigShares($gridConfig$metadata);
  456.                 if ($metadata['setAsFavourite'] && $this->getAdminUser()->isAdmin()) {
  457.                     $this->updateGridConfigFavourites($gridConfig$metadata);
  458.                 }
  459.                 if (!$gridConfig) {
  460.                     $gridConfig = new GridConfig();
  461.                     $gridConfig->setName(date('c'));
  462.                     $gridConfig->setClassId($classId);
  463.                     $gridConfig->setSearchType($searchType);
  464.                     $gridConfig->setType($type);
  465.                     $gridConfig->setOwnerId($this->getAdminUser()->getId());
  466.                 }
  467.                 if ($metadata) {
  468.                     $gridConfig->setName($metadata['gridConfigName']);
  469.                     $gridConfig->setDescription($metadata['gridConfigDescription']);
  470.                     $gridConfig->setShareGlobally($metadata['shareGlobally'] && $this->getAdminUser()->isAdmin());
  471.                     $gridConfig->setSetAsFavourite($metadata['setAsFavourite'] && $this->getAdminUser()->isAdmin());
  472.                 }
  473.                 $gridConfigData json_encode($gridConfigData);
  474.                 $gridConfig->setConfig($gridConfigData);
  475.                 $gridConfig->save();
  476.                 $userId $this->getAdminUser()->getId();
  477.                 $availableConfigs $this->getMyOwnGridColumnConfigs($userId$classId$searchType);
  478.                 $sharedConfigs $this->getSharedGridColumnConfigs($this->getAdminUser(), $classId$searchType);
  479.                 $settings $this->getShareSettings($gridConfig->getId());
  480.                 $settings['gridConfigId'] = (int)$gridConfig->getId();
  481.                 $settings['gridConfigName'] = $gridConfig->getName();
  482.                 $settings['gridConfigDescription'] = $gridConfig->getDescription();
  483.                 $settings['shareGlobally'] = $gridConfig->isShareGlobally();
  484.                 $settings['setAsFavourite'] = $gridConfig->isSetAsFavourite();
  485.                 $settings['isShared'] = $gridConfig->getOwnerId() != $this->getAdminUser()->getId();
  486.                 return $this->adminJson([
  487.                     'success' => true,
  488.                     'settings' => $settings,
  489.                     'availableConfigs' => $availableConfigs,
  490.                     'sharedConfigs' => $sharedConfigs,
  491.                 ]);
  492.             } catch (\Exception $e) {
  493.                 return $this->adminJson(['success' => false'message' => $e->getMessage()]);
  494.             }
  495.         }
  496.         throw $this->createAccessDeniedHttpException();
  497.     }
  498.     /**
  499.      * @param GridConfig|null $gridConfig
  500.      * @param array $metadata
  501.      *
  502.      * @throws \Exception
  503.      */
  504.     protected function updateGridConfigShares($gridConfig$metadata)
  505.     {
  506.         $user $this->getAdminUser();
  507.         if (!$gridConfig || !$user->isAllowed('share_configurations')) {
  508.             // nothing to do
  509.             return;
  510.         }
  511.         if ($gridConfig->getOwnerId() != $this->getAdminUser()->getId()) {
  512.             throw new \Exception("don't mess with someone elses grid config");
  513.         }
  514.         $combinedShares = [];
  515.         $sharedUserIds $metadata['sharedUserIds'];
  516.         $sharedRoleIds $metadata['sharedRoleIds'];
  517.         if ($sharedUserIds) {
  518.             $combinedShares explode(','$sharedUserIds);
  519.         }
  520.         if ($sharedRoleIds) {
  521.             $sharedRoleIds explode(','$sharedRoleIds);
  522.             $combinedShares array_merge($combinedShares$sharedRoleIds);
  523.         }
  524.         $db Db::get();
  525.         $db->delete('gridconfig_shares', ['gridConfigId' => $gridConfig->getId()]);
  526.         foreach ($combinedShares as $id) {
  527.             $share = new GridConfigShare();
  528.             $share->setGridConfigId($gridConfig->getId());
  529.             $share->setSharedWithUserId((int) $id);
  530.             $share->save();
  531.         }
  532.     }
  533.     /**
  534.      * @param GridConfig|null $gridConfig
  535.      * @param array $metadata
  536.      *
  537.      * @throws \Exception
  538.      */
  539.     protected function updateGridConfigFavourites($gridConfig$metadata)
  540.     {
  541.         $currentUser $this->getAdminUser();
  542.         if (!$gridConfig || $currentUser === null || !$currentUser->isAllowed('share_configurations')) {
  543.             // nothing to do
  544.             return;
  545.         }
  546.         if (!$currentUser->isAdmin() && (int) $gridConfig->getOwnerId() !== $currentUser->getId()) {
  547.             throw new \Exception("don't mess with someone elses grid config");
  548.         }
  549.         $sharedUsers = [];
  550.         if ($metadata['shareGlobally'] === false) {
  551.             $sharedUserIds $metadata['sharedUserIds'];
  552.             if ($sharedUserIds) {
  553.                 $sharedUsers explode(','$sharedUserIds);
  554.             }
  555.         }
  556.         if ($metadata['shareGlobally'] === true) {
  557.             $users = new User\Listing();
  558.             $users->setCondition('id = ?'$currentUser->getId());
  559.             foreach ($users as $user) {
  560.                 $sharedUsers[] = $user->getId();
  561.             }
  562.         }
  563.         foreach ($sharedUsers as $id) {
  564.             // Check if the user has already a favourite
  565.             $favourite GridConfigFavourite::getByOwnerAndClassAndObjectId(
  566.                 (int) $id,
  567.                 $gridConfig->getClassId(),
  568.                 0,
  569.                 $gridConfig->getSearchType()
  570.             );
  571.             if ($favourite instanceof GridConfigFavourite) {
  572.                 $favouriteGridConfig GridConfig::getById($favourite->getGridConfigId());
  573.                 if ($favouriteGridConfig instanceof GridConfig) {
  574.                     // Check if the grid config was shared globally if that is *not* the case we also not update
  575.                     if ((bool) $favouriteGridConfig->isShareGlobally() === false) {
  576.                         continue;
  577.                     }
  578.                     // Check if the user is the owner. If that is the case we do not update the favourite
  579.                     if ((int) $favouriteGridConfig->getOwnerId() === (int) $id) {
  580.                         continue;
  581.                     }
  582.                 }
  583.             }
  584.             $favourite = new GridConfigFavourite();
  585.             $favourite->setGridConfigId($gridConfig->getId());
  586.             $favourite->setClassId($gridConfig->getClassId());
  587.             $favourite->setObjectId(0);
  588.             $favourite->setOwnerId($id);
  589.             $favourite->setType($gridConfig->getType());
  590.             $favourite->setSearchType($gridConfig->getSearchType());
  591.             $favourite->save();
  592.         }
  593.     }
  594.     /**
  595.      * @Route("/get-export-jobs", name="pimcore_admin_asset_assethelper_getexportjobs", methods={"GET"})
  596.      *
  597.      * @param Request $request
  598.      * @param GridHelperService $gridHelperService
  599.      *
  600.      * @return JsonResponse
  601.      */
  602.     public function getExportJobsAction(Request $requestGridHelperService $gridHelperService)
  603.     {
  604.         $allParams array_merge($request->request->all(), $request->query->all());
  605.         $list $gridHelperService->prepareAssetListingForGrid($allParams$this->getAdminUser());
  606.         if (empty($ids $allParams['ids'] ?? '')) {
  607.             $ids $list->loadIdList();
  608.         }
  609.         $jobs array_chunk($ids20);
  610.         $fileHandle uniqid('asset-export-');
  611.         file_put_contents($this->getCsvFile($fileHandle), '');
  612.         return $this->adminJson(['success' => true'jobs' => $jobs'fileHandle' => $fileHandle]);
  613.     }
  614.     /**
  615.      * @Route("/do-export", name="pimcore_admin_asset_assethelper_doexport", methods={"POST"})
  616.      *
  617.      * @param Request $request
  618.      * @param LocaleServiceInterface $localeService
  619.      *
  620.      * @return JsonResponse
  621.      */
  622.     public function doExportAction(Request $requestLocaleServiceInterface $localeService)
  623.     {
  624.         $fileHandle \Pimcore\File::getValidFilename($request->get('fileHandle'));
  625.         $ids $request->get('ids');
  626.         $settings $request->get('settings');
  627.         $settings json_decode($settingstrue);
  628.         $delimiter $settings['delimiter'] ?? ';';
  629.         $language str_replace('default'''$request->get('language'));
  630.         $list = new Asset\Listing();
  631.         $quotedIds = [];
  632.         foreach ($ids as $id) {
  633.             $quotedIds[] = $list->quote($id);
  634.         }
  635.         $list->setCondition('id IN (' implode(','$quotedIds) . ')');
  636.         $list->setOrderKey(' FIELD(id, ' implode(','$quotedIds) . ')'false);
  637.         $fields $request->get('fields');
  638.         $addTitles $request->get('initial');
  639.         $csv $this->getCsvData($request$language$list$fields$addTitles);
  640.         $fp fopen($this->getCsvFile($fileHandle), 'a');
  641.         $firstLine true;
  642.         foreach ($csv as $line) {
  643.             if ($addTitles && $firstLine) {
  644.                 $firstLine false;
  645.                 $line implode($delimiter$line) . "\r\n";
  646.                 fwrite($fp$line);
  647.             } else {
  648.                 fwrite($fpimplode($delimiterarray_map([$this'encodeFunc'], $line)) . "\r\n");
  649.             }
  650.         }
  651.         fclose($fp);
  652.         return $this->adminJson(['success' => true]);
  653.     }
  654.     public function encodeFunc($value)
  655.     {
  656.         $value str_replace('"''""'$value);
  657.         //force wrap value in quotes and return
  658.         return '"' $value '"';
  659.     }
  660.     /**
  661.      * @param Request $request
  662.      * @param string $language
  663.      * @param Asset\Listing $list
  664.      * @param array $fields
  665.      * @param bool $addTitles
  666.      *
  667.      * @return array
  668.      */
  669.     protected function getCsvData(Request $request$language$list$fields$addTitles true)
  670.     {
  671.         //create csv
  672.         $csv = [];
  673.         $unsupportedFields = ['preview~system''size~system'];
  674.         $fields array_diff($fields$unsupportedFields);
  675.         if ($addTitles) {
  676.             $columns $fields;
  677.             foreach ($columns as $columnIdx => $columnKey) {
  678.                 $columns[$columnIdx] = '"' $columnKey '"';
  679.             }
  680.             $csv[] = $columns;
  681.         }
  682.         foreach ($list->load() as $asset) {
  683.             if ($fields) {
  684.                 $dataRows = [];
  685.                 foreach ($fields as $field) {
  686.                     $fieldDef explode('~'$field);
  687.                     $getter 'get' ucfirst($fieldDef[0]);
  688.                     if (isset($fieldDef[1])) {
  689.                         if ($fieldDef[1] == 'system' && method_exists($asset$getter)) {
  690.                             $data $asset->$getter($language);
  691.                             if(is_numeric($data) && $data 1000000000){
  692.                               $data date("Y-m-d H:i:s"$data);
  693.                             }
  694.                         } else {
  695.                             $fieldDef[1] = str_replace('none'''$fieldDef[1]);
  696.                             $data $asset->getMetadata($fieldDef[0], $fieldDef[1], true);
  697.                         }
  698.                     } else {
  699.                         $data $asset->getMetadata($field$languagetrue);
  700.                     }
  701.                     if ($data instanceof Element\ElementInterface) {
  702.                         $data $data->getRealFullPath();
  703.                     }
  704.                     $dataRows[] = $data;
  705.                 }
  706.                 $dataRows Element\Service::escapeCsvRecord($dataRows);
  707.                 $csv[] = $dataRows;
  708.             }
  709.         }
  710.         return $csv;
  711.     }
  712.     /**
  713.      * @param Request $request
  714.      *
  715.      * @return mixed|string
  716.      */
  717.     protected function extractLanguage(Request $request)
  718.     {
  719.         $requestedLanguage $request->get('language');
  720.         if ($requestedLanguage) {
  721.             if ($requestedLanguage != 'default') {
  722.                 $request->setLocale($requestedLanguage);
  723.             }
  724.         } else {
  725.             $requestedLanguage $request->getLocale();
  726.         }
  727.         return $requestedLanguage;
  728.     }
  729.     /**
  730.      * @param string $fileHandle
  731.      *
  732.      * @return string
  733.      */
  734.     protected function getCsvFile($fileHandle)
  735.     {
  736.         return PIMCORE_SYSTEM_TEMP_DIRECTORY '/' $fileHandle '.csv';
  737.     }
  738.     /**
  739.      * @Route("/download-csv-file", name="pimcore_admin_asset_assethelper_downloadcsvfile", methods={"GET"})
  740.      *
  741.      * @param Request $request
  742.      *
  743.      * @return BinaryFileResponse
  744.      */
  745.     public function downloadCsvFileAction(Request $request)
  746.     {
  747.         $fileHandle \Pimcore\File::getValidFilename($request->get('fileHandle'));
  748.         $csvFile $this->getCsvFile($fileHandle);
  749.         if (file_exists($csvFile)) {
  750.             $response = new BinaryFileResponse($csvFile);
  751.             $response->headers->set('Content-Type''application/csv');
  752.             $response->setContentDisposition(ResponseHeaderBag::DISPOSITION_ATTACHMENT'export.csv');
  753.             $response->deleteFileAfterSend(true);
  754.             return $response;
  755.         }
  756.         throw $this->createNotFoundException('CSV file not found');
  757.     }
  758.     /**
  759.      * @Route("/download-xlsx-file", name="pimcore_admin_asset_assethelper_downloadxlsxfile", methods={"GET"})
  760.      *
  761.      * @param Request $request
  762.      *
  763.      * @return BinaryFileResponse
  764.      */
  765.     public function downloadXlsxFileAction(Request $request)
  766.     {
  767.         $fileHandle \Pimcore\File::getValidFilename($request->get('fileHandle'));
  768.         $csvFile $this->getCsvFile($fileHandle);
  769.         if (file_exists($csvFile)) {
  770.             $csvReader = new Csv();
  771.             $csvReader->setDelimiter(';');
  772.             $csvReader->setSheetIndex(0);
  773.             $spreadsheet $csvReader->load($csvFile);
  774.             $writer = new Xlsx($spreadsheet);
  775.             $xlsxFilename PIMCORE_SYSTEM_TEMP_DIRECTORY'/' .$fileHandle'.xlsx';
  776.             $writer->save($xlsxFilename);
  777.             $response = new BinaryFileResponse($xlsxFilename);
  778.             $response->headers->set('Content-Type''application/xlsx');
  779.             $response->setContentDisposition(ResponseHeaderBag::DISPOSITION_ATTACHMENT'export.xlsx');
  780.             $response->deleteFileAfterSend(true);
  781.             return $response;
  782.         }
  783.         throw $this->createNotFoundException('XLSX file not found');
  784.     }
  785.     /**
  786.      * @Route("/get-metadata-for-column-config", name="pimcore_admin_asset_assethelper_getmetadataforcolumnconfig", methods={"GET"})
  787.      *
  788.      * @param Request $request
  789.      *
  790.      * @return JsonResponse
  791.      */
  792.     public function getMetadataForColumnConfigAction(Request $request)
  793.     {
  794.         $result = [];
  795.         //default metadata
  796.         $defaultMetadataNames = ['copyright''alt''title'];
  797.         foreach ($defaultMetadataNames as $defaultMetadata) {
  798.             $defaultColumns[] = ['title' => $defaultMetadata'name' => $defaultMetadata'datatype' => 'data''fieldtype' => 'input'];
  799.         }
  800.         $result['defaultColumns']['nodeLabel'] = 'default_metadata';
  801.         $result['defaultColumns']['nodeType'] = 'image';
  802.         $result['defaultColumns']['children'] = $defaultColumns;
  803.         //predefined metadata
  804.         $list Metadata\Predefined\Listing::getByTargetType('asset');
  805.         $metadataItems = [];
  806.         $tmp = [];
  807.         foreach ($list as $item) {
  808.             //only allow unique metadata columns with subtypes
  809.             $uniqueKey $item->getName().'_'.$item->getTargetSubtype();
  810.             if (!in_array($uniqueKey$tmp) && !in_array($item->getName(), $defaultMetadataNames)) {
  811.                 $tmp[] = $uniqueKey;
  812.                 $item->expand();
  813.                 $metadataItems[] = [
  814.                     'title' => $item->getName(),
  815.                     'name' => $item->getName(),
  816.                     'subtype' => $item->getTargetSubtype(),
  817.                     'datatype' => 'data',
  818.                     'fieldtype' => $item->getType(),
  819.                     'config' => $item->getConfig(),
  820.                 ];
  821.             }
  822.         }
  823.         $result['metadataColumns']['children'] = $metadataItems;
  824.         $result['metadataColumns']['nodeLabel'] = 'predefined_metadata';
  825.         $result['metadataColumns']['nodeType'] = 'metadata';
  826.         //system columns
  827.         $systemColumnNames Asset\Service::GRID_SYSTEM_COLUMNS;
  828.         $systemColumns = [];
  829.         foreach ($systemColumnNames as $systemColumn) {
  830.             $systemColumns[] = ['title' => $systemColumn'name' => $systemColumn'datatype' => 'data''fieldtype' => 'system'];
  831.         }
  832.         $result['systemColumns']['nodeLabel'] = 'system_columns';
  833.         $result['systemColumns']['nodeType'] = 'system';
  834.         $result['systemColumns']['children'] = $systemColumns;
  835.         return $this->adminJson($result);
  836.     }
  837.     /**
  838.      * @Route("/get-batch-jobs", name="pimcore_admin_asset_assethelper_getbatchjobs", methods={"GET"})
  839.      *
  840.      * @param Request $request
  841.      *
  842.      * @return JsonResponse
  843.      */
  844.     public function getBatchJobsAction(Request $requestGridHelperService $gridHelperService)
  845.     {
  846.         if ($request->get('language')) {
  847.             $request->setLocale($request->get('language'));
  848.         }
  849.         $allParams array_merge($request->request->all(), $request->query->all());
  850.         $list $gridHelperService->prepareAssetListingForGrid($allParams$this->getAdminUser());
  851.         $jobs $list->loadIdList();
  852.         return $this->adminJson(['success' => true'jobs' => $jobs]);
  853.     }
  854.     /**
  855.      * @Route("/batch", name="pimcore_admin_asset_assethelper_batch", methods={"PUT"})
  856.      *
  857.      * @param Request $request
  858.      * @param EventDispatcherInterface $eventDispatcher
  859.      *
  860.      * @return JsonResponse
  861.      */
  862.     public function batchAction(Request $requestEventDispatcherInterface $eventDispatcher)
  863.     {
  864.         try {
  865.             if ($request->get('data')) {
  866.                 $loader \Pimcore::getContainer()->get('pimcore.implementation_loader.asset.metadata.data');
  867.                 $data $this->decodeJson($request->get('data'), true);
  868.                 $updateEvent = new GenericEvent($this, [
  869.                     'data' => $data,
  870.                     'processed' => false,
  871.                 ]);
  872.                 $eventDispatcher->dispatch($updateEventAdminEvents::ASSET_LIST_BEFORE_BATCH_UPDATE);
  873.                 $processed $updateEvent->getArgument('processed');
  874.                 if ($processed) {
  875.                     return $this->adminJson(['success' => true]);
  876.                 }
  877.                 $language null;
  878.                 if (isset($data['language'])) {
  879.                     $language $data['language'] != 'default' $data['language'] : null;
  880.                 }
  881.                 $asset Asset::getById($data['job']);
  882.                 if ($asset) {
  883.                     if (!$asset->isAllowed('publish')) {
  884.                         throw new \Exception("Permission denied. You don't have the rights to save this asset.");
  885.                     }
  886.                     $metadata $asset->getMetadata(nullnullfalsetrue);
  887.                     $dirty false;
  888.                     $name $data['name'];
  889.                     $value $data['value'];
  890.                     if ($data['valueType'] == 'object') {
  891.                         $value $this->decodeJson($value);
  892.                     }
  893.                     $fieldDef explode('~'$name);
  894.                     $name $fieldDef[0];
  895.                     if (count($fieldDef) > 1) {
  896.                         $language = ($fieldDef[1] == 'none' '' $fieldDef[1]);
  897.                     }
  898.                     foreach ($metadata as $idx => &$em) {
  899.                         if ($em['name'] == $name && $em['language'] == $language) {
  900.                             try {
  901.                                 $dataImpl $loader->build($em['type']);
  902.                                 $value $dataImpl->getDataFromListfolderGrid($value$em);
  903.                             } catch (UnsupportedException $le) {
  904.                                 Logger::error('could not resolve metadata implementation for ' $em['type']);
  905.                             }
  906.                             $em['data'] = $value;
  907.                             $dirty true;
  908.                             break;
  909.                         }
  910.                     }
  911.                     if (!$dirty) {
  912.                         $defaulMetadata = ['title''alt''copyright'];
  913.                         if (in_array($name$defaulMetadata)) {
  914.                             $newEm = [
  915.                                 'name' => $name,
  916.                                 'language' => $language,
  917.                                 'type' => 'input',
  918.                                 'data' => $value,
  919.                             ];
  920.                             try {
  921.                                 $dataImpl $loader->build($newEm['type']);
  922.                                 $newEm['data'] = $dataImpl->getDataFromListfolderGrid($value$newEm);
  923.                             } catch (UnsupportedException $le) {
  924.                                 Logger::error('could not resolve metadata implementation for ' $newEm['type']);
  925.                             }
  926.                             $metadata[] = $newEm;
  927.                             $dirty true;
  928.                         } else {
  929.                             $predefined Metadata\Predefined::getByName($name);
  930.                             if ($predefined && (empty($predefined->getTargetSubtype())
  931.                                     || $predefined->getTargetSubtype() == $asset->getType())) {
  932.                                 $newEm = [
  933.                                     'name' => $name,
  934.                                     'language' => $language,
  935.                                     'type' => $predefined->getType(),
  936.                                     'data' => $value,
  937.                                 ];
  938.                                 try {
  939.                                     $dataImpl $loader->build($newEm['type']);
  940.                                     $newEm['data'] = $dataImpl->getDataFromListfolderGrid($value$newEm);
  941.                                 } catch (UnsupportedException $le) {
  942.                                     Logger::error('could not resolve metadata implementation for ' $newEm['type']);
  943.                                 }
  944.                                 $metadata[] = $newEm;
  945.                                 $dirty true;
  946.                             }
  947.                         }
  948.                     }
  949.                     try {
  950.                         if ($dirty) {
  951.                             // $metadata = Asset\Service::minimizeMetadata($metadata, "grid");
  952.                             $asset->setMetadataRaw($metadata);
  953.                             $asset->save();
  954.                             return $this->adminJson(['success' => true]);
  955.                         }
  956.                     } catch (\Exception $e) {
  957.                         return $this->adminJson(['success' => false'message' => $e->getMessage()]);
  958.                     }
  959.                 } else {
  960.                     Logger::debug('AssetHelperController::batchAction => There is no asset left to update.');
  961.                     return $this->adminJson(['success' => false'message' => 'AssetHelperController::batchAction => There is no asset left to update.']);
  962.                 }
  963.             }
  964.         } catch (\Exception $e) {
  965.             Logger::err($e);
  966.             return $this->adminJson(['success' => false'message' => $e->getMessage()]);
  967.         }
  968.         return $this->adminJson(['success' => false'message' => 'something went wrong.']);
  969.     }
  970. }