vendor/pimcore/pimcore/bundles/AdminBundle/Controller/Admin/SettingsController.php line 72

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;
  15. use Pimcore\Bundle\AdminBundle\Controller\AdminAbstractController;
  16. use Pimcore\Cache;
  17. use Pimcore\Cache\Core\CoreCacheHandler;
  18. use Pimcore\Cache\Symfony\CacheClearer;
  19. use Pimcore\Config;
  20. use Pimcore\Db;
  21. use Pimcore\Event\SystemEvents;
  22. use Pimcore\File;
  23. use Pimcore\Helper\StopMessengerWorkersTrait;
  24. use Pimcore\Localization\LocaleServiceInterface;
  25. use Pimcore\Logger;
  26. use Pimcore\Model;
  27. use Pimcore\Model\Asset;
  28. use Pimcore\Model\Document;
  29. use Pimcore\Model\Element;
  30. use Pimcore\Model\Exception\ConfigWriteException;
  31. use Pimcore\Model\Glossary;
  32. use Pimcore\Model\Metadata;
  33. use Pimcore\Model\Property;
  34. use Pimcore\Model\Staticroute;
  35. use Pimcore\Model\Tool\SettingsStore;
  36. use Pimcore\Model\WebsiteSetting;
  37. use Pimcore\Tool;
  38. use Symfony\Component\EventDispatcher\EventDispatcherInterface;
  39. use Symfony\Component\EventDispatcher\GenericEvent;
  40. use Symfony\Component\Filesystem\Filesystem;
  41. use Symfony\Component\HttpFoundation\File\UploadedFile;
  42. use Symfony\Component\HttpFoundation\JsonResponse;
  43. use Symfony\Component\HttpFoundation\Request;
  44. use Symfony\Component\HttpFoundation\Response;
  45. use Symfony\Component\HttpFoundation\StreamedResponse;
  46. use Symfony\Component\HttpKernel\Event\TerminateEvent;
  47. use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
  48. use Symfony\Component\HttpKernel\KernelEvents;
  49. use Symfony\Component\HttpKernel\KernelInterface;
  50. use Symfony\Component\Routing\Annotation\Route;
  51. use Symfony\Component\Yaml\Yaml;
  52. use Symfony\Contracts\Translation\TranslatorInterface;
  53. /**
  54.  * @Route("/settings")
  55.  *
  56.  * @internal
  57.  */
  58. class SettingsController extends AdminAbstractController
  59. {
  60.     use StopMessengerWorkersTrait;
  61.     private const CUSTOM_LOGO_PATH 'custom-logo.image';
  62.     public function __construct(protected TranslatorInterface $translator)
  63.     {
  64.     }
  65.     /**
  66.      * @Route("/display-custom-logo", name="pimcore_settings_display_custom_logo", methods={"GET"})
  67.      *
  68.      * @param Request $request
  69.      *
  70.      * @return StreamedResponse
  71.      */
  72.     public function displayCustomLogoAction(Request $request)
  73.     {
  74.         $mime 'image/svg+xml';
  75.         if ($request->get('white')) {
  76.             $logo PIMCORE_WEB_ROOT '/bundles/pimcoreadmin/img/logo-claim-white.svg';
  77.         } else {
  78.             $logo PIMCORE_WEB_ROOT '/bundles/pimcoreadmin/img/logo-claim-gray.svg';
  79.         }
  80.         $stream fopen($logo'rb');
  81.         $storage Tool\Storage::get('admin');
  82.         if ($storage->fileExists(self::CUSTOM_LOGO_PATH)) {
  83.             try {
  84.                 $mime $storage->mimeType(self::CUSTOM_LOGO_PATH);
  85.                 $stream $storage->readStream(self::CUSTOM_LOGO_PATH);
  86.             } catch (\Exception $e) {
  87.                 // do nothing
  88.             }
  89.         }
  90.         return new StreamedResponse(function () use ($stream) {
  91.             fpassthru($stream);
  92.         }, 200, [
  93.             'Content-Type' => $mime,
  94.             'Content-Security-Policy' => "script-src 'none'",
  95.         ]);
  96.     }
  97.     /**
  98.      * @Route("/upload-custom-logo", name="pimcore_admin_settings_uploadcustomlogo", methods={"POST"})
  99.      *
  100.      * @param Request $request
  101.      *
  102.      * @return JsonResponse
  103.      *
  104.      * @throws \Exception
  105.      */
  106.     public function uploadCustomLogoAction(Request $request)
  107.     {
  108.         $logoFile $request->files->get('Filedata');
  109.         if (!$logoFile instanceof UploadedFile
  110.             || !in_array($logoFile->guessExtension(), ['svg''png''jpg'])
  111.         ) {
  112.             throw new \Exception('Unsupported file format.');
  113.         }
  114.         $storage Tool\Storage::get('admin');
  115.         $storage->writeStream(self::CUSTOM_LOGO_PATHfopen($logoFile->getPathname(), 'rb'));
  116.         // set content-type to text/html, otherwise (when application/json is sent) chrome will complain in
  117.         // Ext.form.Action.Submit and mark the submission as failed
  118.         $response $this->adminJson(['success' => true]);
  119.         $response->headers->set('Content-Type''text/html');
  120.         return $response;
  121.     }
  122.     /**
  123.      * @Route("/delete-custom-logo", name="pimcore_admin_settings_deletecustomlogo", methods={"DELETE"})
  124.      *
  125.      * @param Request $request
  126.      *
  127.      * @return JsonResponse
  128.      */
  129.     public function deleteCustomLogoAction(Request $request)
  130.     {
  131.         if (Tool\Storage::get('admin')->fileExists(self::CUSTOM_LOGO_PATH)) {
  132.             Tool\Storage::get('admin')->delete(self::CUSTOM_LOGO_PATH);
  133.         }
  134.         return $this->adminJson(['success' => true]);
  135.     }
  136.     /**
  137.      * Used by the predefined metadata grid
  138.      *
  139.      * @Route("/predefined-metadata", name="pimcore_admin_settings_metadata", methods={"POST"})
  140.      *
  141.      * @param Request $request
  142.      *
  143.      * @return JsonResponse
  144.      */
  145.     public function metadataAction(Request $request)
  146.     {
  147.         $this->checkPermission('asset_metadata');
  148.         if ($request->get('data')) {
  149.             if ($request->get('xaction') == 'destroy') {
  150.                 $data $this->decodeJson($request->get('data'));
  151.                 $id $data['id'];
  152.                 $metadata Metadata\Predefined::getById($id);
  153.                 if (!$metadata->isWriteable()) {
  154.                     throw new ConfigWriteException();
  155.                 }
  156.                 $metadata->delete();
  157.                 return $this->adminJson(['success' => true'data' => []]);
  158.             } elseif ($request->get('xaction') == 'update') {
  159.                 $data $this->decodeJson($request->get('data'));
  160.                 // save type
  161.                 $metadata Metadata\Predefined::getById($data['id']);
  162.                 if (!$metadata->isWriteable()) {
  163.                     throw new ConfigWriteException();
  164.                 }
  165.                 $metadata->setValues($data);
  166.                 $existingItem Metadata\Predefined\Listing::getByKeyAndLanguage($metadata->getName(), $metadata->getLanguage(), $metadata->getTargetSubtype());
  167.                 if ($existingItem && $existingItem->getId() != $metadata->getId()) {
  168.                     return $this->adminJson(['message' => 'rule_violation''success' => false]);
  169.                 }
  170.                 $metadata->minimize();
  171.                 $metadata->save();
  172.                 $metadata->expand();
  173.                 $responseData $metadata->getObjectVars();
  174.                 $responseData['writeable'] = $metadata->isWriteable();
  175.                 return $this->adminJson(['data' => $responseData'success' => true]);
  176.             } elseif ($request->get('xaction') == 'create') {
  177.                 if (!(new Metadata\Predefined())->isWriteable()) {
  178.                     throw new ConfigWriteException();
  179.                 }
  180.                 $data $this->decodeJson($request->get('data'));
  181.                 unset($data['id']);
  182.                 // save type
  183.                 $metadata Metadata\Predefined::create();
  184.                 $metadata->setValues($data);
  185.                 $existingItem Metadata\Predefined\Listing::getByKeyAndLanguage($metadata->getName(), $metadata->getLanguage(), $metadata->getTargetSubtype());
  186.                 if ($existingItem) {
  187.                     return $this->adminJson(['message' => 'rule_violation''success' => false]);
  188.                 }
  189.                 $metadata->save();
  190.                 $responseData $metadata->getObjectVars();
  191.                 $responseData['writeable'] = $metadata->isWriteable();
  192.                 return $this->adminJson(['data' => $responseData'success' => true]);
  193.             }
  194.         } else {
  195.             // get list of types
  196.             $list = new Metadata\Predefined\Listing();
  197.             if ($filter $request->get('filter')) {
  198.                 $list->setFilter(function (Metadata\Predefined $predefined) use ($filter) {
  199.                     foreach ($predefined->getObjectVars() as $value) {
  200.                         if (stripos((string)$value$filter) !== false) {
  201.                             return true;
  202.                         }
  203.                     }
  204.                     return false;
  205.                 });
  206.             }
  207.             $properties = [];
  208.             foreach ($list->getDefinitions() as $metadata) {
  209.                 $metadata->expand();
  210.                 $data $metadata->getObjectVars();
  211.                 $data['writeable'] = $metadata->isWriteable();
  212.                 $properties[] = $data;
  213.             }
  214.             return $this->adminJson(['data' => $properties'success' => true'total' => $list->getTotalCount()]);
  215.         }
  216.         return $this->adminJson(['success' => false]);
  217.     }
  218.     /**
  219.      * @Route("/get-predefined-metadata", name="pimcore_admin_settings_getpredefinedmetadata", methods={"GET"})
  220.      *
  221.      * @param Request $request
  222.      *
  223.      * @return JsonResponse
  224.      */
  225.     public function getPredefinedMetadataAction(Request $request)
  226.     {
  227.         $type $request->get('type');
  228.         $subType $request->get('subType');
  229.         $group $request->get('group');
  230.         $list Metadata\Predefined\Listing::getByTargetType($type, [$subType]);
  231.         $result = [];
  232.         foreach ($list as $item) {
  233.             $itemGroup $item->getGroup() ?? '';
  234.             if ($group === 'default' || $group === $itemGroup) {
  235.                 $item->expand();
  236.                 $data $item->getObjectVars();
  237.                 $data['writeable'] = $item->isWriteable();
  238.                 $result[] = $data;
  239.             }
  240.         }
  241.         return $this->adminJson(['data' => $result'success' => true]);
  242.     }
  243.     /**
  244.      * @Route("/properties", name="pimcore_admin_settings_properties", methods={"POST"})
  245.      *
  246.      * @param Request $request
  247.      *
  248.      * @return JsonResponse
  249.      */
  250.     public function propertiesAction(Request $request)
  251.     {
  252.         if ($request->get('data')) {
  253.             $this->checkPermission('predefined_properties');
  254.             if ($request->get('xaction') == 'destroy') {
  255.                 $data $this->decodeJson($request->get('data'));
  256.                 $id $data['id'];
  257.                 $property Property\Predefined::getById($id);
  258.                 if (!$property->isWriteable()) {
  259.                     throw new ConfigWriteException();
  260.                 }
  261.                 $property->delete();
  262.                 return $this->adminJson(['success' => true'data' => []]);
  263.             } elseif ($request->get('xaction') == 'update') {
  264.                 $data $this->decodeJson($request->get('data'));
  265.                 // save type
  266.                 $property Property\Predefined::getById($data['id']);
  267.                 if (!$property->isWriteable()) {
  268.                     throw new ConfigWriteException();
  269.                 }
  270.                 if (is_array($data['ctype'])) {
  271.                     $data['ctype'] = implode(','$data['ctype']);
  272.                 }
  273.                 $property->setValues($data);
  274.                 $property->save();
  275.                 $responseData $property->getObjectVars();
  276.                 $responseData['writeable'] = $property->isWriteable();
  277.                 return $this->adminJson(['data' => $responseData'success' => true]);
  278.             } elseif ($request->get('xaction') == 'create') {
  279.                 if (!(new Property\Predefined())->isWriteable()) {
  280.                     throw new ConfigWriteException();
  281.                 }
  282.                 $data $this->decodeJson($request->get('data'));
  283.                 unset($data['id']);
  284.                 // save type
  285.                 $property Property\Predefined::create();
  286.                 $property->setValues($data);
  287.                 $property->save();
  288.                 $responseData $property->getObjectVars();
  289.                 $responseData['writeable'] = $property->isWriteable();
  290.                 return $this->adminJson(['data' => $responseData'success' => true]);
  291.             }
  292.         } else {
  293.             // get list of types
  294.             $list = new Property\Predefined\Listing();
  295.             if ($filter $request->get('filter')) {
  296.                 $list->setFilter(function (Property\Predefined $predefined) use ($filter) {
  297.                     foreach ($predefined->getObjectVars() as $value) {
  298.                         if ($value) {
  299.                             $cellValues is_array($value) ? $value : [$value];
  300.                             foreach ($cellValues as $cellValue) {
  301.                                 if (stripos((string)$cellValue$filter) !== false) {
  302.                                     return true;
  303.                                 }
  304.                             }
  305.                         }
  306.                     }
  307.                     return false;
  308.                 });
  309.             }
  310.             $properties = [];
  311.             foreach ($list->getProperties() as $property) {
  312.                 $data $property->getObjectVars();
  313.                 $data['writeable'] = $property->isWriteable();
  314.                 $properties[] = $data;
  315.             }
  316.             return $this->adminJson(['data' => $properties'success' => true'total' => $list->getTotalCount()]);
  317.         }
  318.         return $this->adminJson(['success' => false]);
  319.     }
  320.     /**
  321.      * @Route("/get-system", name="pimcore_admin_settings_getsystem", methods={"GET"})
  322.      *
  323.      * @param Request $request
  324.      * @param Config $config
  325.      *
  326.      * @return JsonResponse
  327.      */
  328.     public function getSystemAction(Request $requestConfig $config)
  329.     {
  330.         $this->checkPermission('system_settings');
  331.         $valueArray = [
  332.             'general' => $config['general'],
  333.             'documents' => $config['documents'],
  334.             'assets' => $config['assets'],
  335.             'objects' => $config['objects'],
  336.             'branding' => $config['branding'],
  337.             'email' => $config['email'],
  338.         ];
  339.         $locales Tool::getSupportedLocales();
  340.         $languageOptions = [];
  341.         $validLanguages = [];
  342.         foreach ($locales as $short => $translation) {
  343.             if (!empty($short)) {
  344.                 $languageOptions[] = [
  345.                     'language' => $short,
  346.                     'display' => $translation " ($short)",
  347.                 ];
  348.                 $validLanguages[] = $short;
  349.             }
  350.         }
  351.         $valueArray['general']['valid_language'] = explode(','$valueArray['general']['valid_languages']);
  352.         //for "wrong" legacy values
  353.         foreach ($valueArray['general']['valid_language'] as $existingValue) {
  354.             if (!in_array($existingValue$validLanguages)) {
  355.                 $languageOptions[] = [
  356.                     'language' => $existingValue,
  357.                     'display' => $existingValue,
  358.                 ];
  359.             }
  360.         }
  361.         $response = [
  362.             'values' => $valueArray,
  363.             'config' => [
  364.                 'languages' => $languageOptions,
  365.             ],
  366.         ];
  367.         return $this->adminJson($response);
  368.     }
  369.     /**
  370.      * @Route("/set-system", name="pimcore_admin_settings_setsystem", methods={"PUT"})
  371.      *
  372.      * @param Request $request
  373.      * @param LocaleServiceInterface $localeService
  374.      *
  375.      * @return JsonResponse
  376.      */
  377.     public function setSystemAction(
  378.         LocaleServiceInterface $localeService,
  379.         Request $request,
  380.         KernelInterface $kernel,
  381.         EventDispatcherInterface $eventDispatcher,
  382.         CoreCacheHandler $cache,
  383.         Filesystem $filesystem,
  384.         CacheClearer $symfonyCacheClearer
  385.     ) {
  386.         $this->checkPermission('system_settings');
  387.         $values $this->decodeJson($request->get('data'));
  388.         $existingValues = [];
  389.         try {
  390.             $file Config::locateConfigFile('system.yml');
  391.             $existingValues Config::getConfigInstance($filetrue);
  392.         } catch (\Exception $e) {
  393.             // nothing to do
  394.         }
  395.         // localized error pages
  396.         $localizedErrorPages = [];
  397.         // fallback languages
  398.         $fallbackLanguages = [];
  399.         $existingValues['pimcore']['general']['fallback_languages'] = [];
  400.         $languages explode(','$values['general.validLanguages']);
  401.         $filteredLanguages = [];
  402.         foreach ($languages as $language) {
  403.             if (isset($values['general.fallbackLanguages.' $language])) {
  404.                 $fallbackLanguages[$language] = str_replace(' '''$values['general.fallbackLanguages.' $language]);
  405.             }
  406.             // localized error pages
  407.             if (isset($values['documents.error_pages.localized.' $language])) {
  408.                 $localizedErrorPages[$language] = $values['documents.error_pages.localized.' $language];
  409.             }
  410.             if ($localeService->isLocale($language)) {
  411.                 $filteredLanguages[] = $language;
  412.             }
  413.         }
  414.         // check if there's a fallback language endless loop
  415.         foreach ($fallbackLanguages as $sourceLang => $targetLang) {
  416.             $this->checkFallbackLanguageLoop($sourceLang$fallbackLanguages);
  417.         }
  418.         $settings['pimcore'] = [
  419.             'general' => [
  420.                 'domain' => $values['general.domain'],
  421.                 'redirect_to_maindomain' => $values['general.redirect_to_maindomain'],
  422.                 'language' => $values['general.language'],
  423.                 'valid_languages' => implode(','$filteredLanguages),
  424.                 'fallback_languages' => $fallbackLanguages,
  425.                 'default_language' => $values['general.defaultLanguage'],
  426.                 'debug_admin_translations' => $values['general.debug_admin_translations'],
  427.             ],
  428.             'documents' => [
  429.                 'versions' => [
  430.                     'days' => $values['documents.versions.days'] ?? null,
  431.                     'steps' => $values['documents.versions.steps'] ?? null,
  432.                 ],
  433.                 'error_pages' => [
  434.                     'default' => $values['documents.error_pages.default'],
  435.                     'localized' => $localizedErrorPages,
  436.                 ],
  437.             ],
  438.             'objects' => [
  439.                 'versions' => [
  440.                     'days' => $values['objects.versions.days'] ?? null,
  441.                     'steps' => $values['objects.versions.steps'] ?? null,
  442.                 ],
  443.             ],
  444.             'assets' => [
  445.                 'versions' => [
  446.                     'days' => $values['assets.versions.days'] ?? null,
  447.                     'steps' => $values['assets.versions.steps'] ?? null,
  448.                 ],
  449.                 'hide_edit_image' => $values['assets.hide_edit_image'],
  450.                 'disable_tree_preview' => $values['assets.disable_tree_preview'],
  451.             ],
  452.         ];
  453.         //branding
  454.         $settings['pimcore_admin'] = [
  455.             'branding' =>
  456.                 [
  457.                     'login_screen_invert_colors' => $values['branding.login_screen_invert_colors'],
  458.                     'color_login_screen' => $values['branding.color_login_screen'],
  459.                     'color_admin_interface' => $values['branding.color_admin_interface'],
  460.                     'color_admin_interface_background' => $values['branding.color_admin_interface_background'],
  461.                     'login_screen_custom_image' => str_replace('%''%%'$values['branding.login_screen_custom_image']),
  462.                 ],
  463.         ];
  464.         if (array_key_exists('email.debug.emailAddresses'$values) && $values['email.debug.emailAddresses']) {
  465.             $settings['pimcore']['email']['debug']['email_addresses'] = $values['email.debug.emailAddresses'];
  466.         }
  467.         $settingsYml Yaml::dump($settings5);
  468.         $configFile Config::locateConfigFile('system.yml');
  469.         File::put($configFile$settingsYml);
  470.         // clear all caches
  471.         $this->clearSymfonyCache($request$kernel$eventDispatcher$symfonyCacheClearer);
  472.         $this->stopMessengerWorkers();
  473.         $eventDispatcher->addListener(KernelEvents::TERMINATE, function (TerminateEvent $event) use (
  474.             $cache$eventDispatcher$filesystem
  475.         ) {
  476.             // we need to clear the cache with a delay, because the cache is used by messenger:stop-workers
  477.             // to send the stop signal to all worker processes
  478.             sleep(2);
  479.             $this->clearPimcoreCache($cache$eventDispatcher$filesystem);
  480.         });
  481.         return $this->adminJson(['success' => true]);
  482.     }
  483.     /**
  484.      * @param string $source
  485.      * @param array $definitions
  486.      * @param array $fallbacks
  487.      *
  488.      * @throws \Exception
  489.      */
  490.     protected function checkFallbackLanguageLoop($source$definitions$fallbacks = [])
  491.     {
  492.         if (isset($definitions[$source])) {
  493.             $targets explode(','$definitions[$source]);
  494.             foreach ($targets as $l) {
  495.                 $target trim($l);
  496.                 if ($target) {
  497.                     if (in_array($target$fallbacks)) {
  498.                         throw new \Exception("Language `$source` | `$target` causes an infinte loop.");
  499.                     }
  500.                     $fallbacks[] = $target;
  501.                     $this->checkFallbackLanguageLoop($target$definitions$fallbacks);
  502.                 }
  503.             }
  504.         } else {
  505.             throw new \Exception("Language `$source` doesn't exist");
  506.         }
  507.     }
  508.     /**
  509.      * @Route("/get-web2print", name="pimcore_admin_settings_getweb2print", methods={"GET"})
  510.      *
  511.      * @param Request $request
  512.      *
  513.      * @return JsonResponse
  514.      */
  515.     public function getWeb2printAction(Request $request)
  516.     {
  517.         $this->checkPermission('web2print_settings');
  518.         $values Config::getWeb2PrintConfig();
  519.         $valueArray $values->toArray();
  520.         $optionsString = [];
  521.         if ($valueArray['wkhtml2pdfOptions'] ?? false) {
  522.             foreach ($valueArray['wkhtml2pdfOptions'] as $key => $value) {
  523.                 $tmpStr '--'.$key;
  524.                 if ($value !== null && $value !== '') {
  525.                     $tmpStr .= ' '.$value;
  526.                 }
  527.                 $optionsString[] = $tmpStr;
  528.             }
  529.         }
  530.         $valueArray['wkhtml2pdfOptions'] = implode("\n"$optionsString);
  531.         $response = [
  532.             'values' => $valueArray,
  533.         ];
  534.         return $this->adminJson($response);
  535.     }
  536.     /**
  537.      * @Route("/set-web2print", name="pimcore_admin_settings_setweb2print", methods={"PUT"})
  538.      *
  539.      * @param Request $request
  540.      *
  541.      * @return JsonResponse
  542.      */
  543.     public function setWeb2printAction(Request $request)
  544.     {
  545.         $this->checkPermission('web2print_settings');
  546.         $values $this->decodeJson($request->get('data'));
  547.         unset($values['documentation']);
  548.         unset($values['additions']);
  549.         unset($values['json_converter']);
  550.         if ($values['wkhtml2pdfOptions']) {
  551.             $optionArray = [];
  552.             $lines explode("\n"$values['wkhtml2pdfOptions']);
  553.             foreach ($lines as $line) {
  554.                 $parts explode(' 'substr($line2));
  555.                 $key trim($parts[0]);
  556.                 if ($key) {
  557.                     $value trim($parts[1] ?? '');
  558.                     $optionArray[$key] = $value;
  559.                 }
  560.             }
  561.             $values['wkhtml2pdfOptions'] = $optionArray;
  562.         }
  563.         \Pimcore\Web2Print\Config::save($values);
  564.         return $this->adminJson(['success' => true]);
  565.     }
  566.     /**
  567.      * @Route("/clear-cache", name="pimcore_admin_settings_clearcache", methods={"DELETE"})
  568.      *
  569.      * @param Request $request
  570.      * @param KernelInterface $kernel
  571.      * @param EventDispatcherInterface $eventDispatcher
  572.      * @param CoreCacheHandler $cache
  573.      * @param Filesystem $filesystem
  574.      * @param CacheClearer $symfonyCacheClearer
  575.      *
  576.      * @return JsonResponse
  577.      */
  578.     public function clearCacheAction(
  579.         Request $request,
  580.         KernelInterface $kernel,
  581.         EventDispatcherInterface $eventDispatcher,
  582.         CoreCacheHandler $cache,
  583.         Filesystem $filesystem,
  584.         CacheClearer $symfonyCacheClearer
  585.     ) {
  586.         $this->checkPermissionsHasOneOf(['clear_cache''system_settings']);
  587.         $result = [
  588.             'success' => true,
  589.         ];
  590.         $clearPimcoreCache = !(bool)$request->get('only_symfony_cache');
  591.         $clearSymfonyCache = !(bool)$request->get('only_pimcore_cache');
  592.         if ($clearPimcoreCache) {
  593.             $this->clearPimcoreCache($cache$eventDispatcher$filesystem);
  594.         }
  595.         if ($clearSymfonyCache) {
  596.             $this->clearSymfonyCache($request$kernel$eventDispatcher$symfonyCacheClearer);
  597.         }
  598.         $response = new JsonResponse($result);
  599.         if ($clearSymfonyCache) {
  600.             // we send the response directly here and exit to make sure no code depending on the stale container
  601.             // is running after this
  602.             $response->sendHeaders();
  603.             $response->sendContent();
  604.             exit;
  605.         }
  606.         return $response;
  607.     }
  608.     private function clearPimcoreCache(
  609.         CoreCacheHandler $cache,
  610.         EventDispatcherInterface $eventDispatcher,
  611.         Filesystem $filesystem,
  612.     ): void {
  613.         // empty document cache
  614.         $cache->clearAll();
  615.         if ($filesystem->exists(PIMCORE_CACHE_DIRECTORY)) {
  616.             $filesystem->remove(PIMCORE_CACHE_DIRECTORY);
  617.         }
  618.         // PIMCORE-1854 - recreate .dummy file => should remain
  619.         File::put(PIMCORE_CACHE_DIRECTORY '/.gitkeep''');
  620.         $eventDispatcher->dispatch(new GenericEvent(), SystemEvents::CACHE_CLEAR);
  621.     }
  622.     private function clearSymfonyCache(
  623.         Request $request,
  624.         KernelInterface $kernel,
  625.         EventDispatcherInterface $eventDispatcher,
  626.         CacheClearer $symfonyCacheClearer,
  627.     ): void {
  628.         // pass one or move env parameters to clear multiple envs
  629.         // if no env is passed it will use the current one
  630.         $environments $request->get('env'$kernel->getEnvironment());
  631.         if (!is_array($environments)) {
  632.             $environments trim((string)$environments);
  633.             if (empty($environments)) {
  634.                 $environments = [];
  635.             } else {
  636.                 $environments = [$environments];
  637.             }
  638.         }
  639.         if (empty($environments)) {
  640.             $environments = [$kernel->getEnvironment()];
  641.         }
  642.         $result['environments'] = $environments;
  643.         if (in_array($kernel->getEnvironment(), $environments)) {
  644.             // remove terminate and exception event listeners for the current env as they break with a
  645.             // cleared container - see #2434
  646.             foreach ($eventDispatcher->getListeners(KernelEvents::TERMINATE) as $listener) {
  647.                 $eventDispatcher->removeListener(KernelEvents::TERMINATE$listener);
  648.             }
  649.             foreach ($eventDispatcher->getListeners(KernelEvents::EXCEPTION) as $listener) {
  650.                 $eventDispatcher->removeListener(KernelEvents::EXCEPTION$listener);
  651.             }
  652.         }
  653.         foreach ($environments as $environment) {
  654.             try {
  655.                 $symfonyCacheClearer->clear($environment);
  656.             } catch (\Throwable $e) {
  657.                 $errors $result['errors'] ?? [];
  658.                 $errors[] = $e->getMessage();
  659.                 $result array_merge($result, [
  660.                     'success' => false,
  661.                     'errors' => $errors,
  662.                 ]);
  663.             }
  664.         }
  665.     }
  666.     /**
  667.      * @Route("/clear-output-cache", name="pimcore_admin_settings_clearoutputcache", methods={"DELETE"})
  668.      *
  669.      * @param EventDispatcherInterface $eventDispatcher
  670.      *
  671.      * @return JsonResponse
  672.      */
  673.     public function clearOutputCacheAction(EventDispatcherInterface $eventDispatcher)
  674.     {
  675.         $this->checkPermission('clear_fullpage_cache');
  676.         // remove "output" out of the ignored tags, if a cache lifetime is specified
  677.         Cache::removeIgnoredTagOnClear('output');
  678.         // empty document cache
  679.         Cache::clearTags(['output''output_lifetime']);
  680.         $eventDispatcher->dispatch(new GenericEvent(), SystemEvents::CACHE_CLEAR_FULLPAGE_CACHE);
  681.         return $this->adminJson(['success' => true]);
  682.     }
  683.     /**
  684.      * @Route("/clear-temporary-files", name="pimcore_admin_settings_cleartemporaryfiles", methods={"DELETE"})
  685.      *
  686.      * @param EventDispatcherInterface $eventDispatcher
  687.      *
  688.      * @return JsonResponse
  689.      */
  690.     public function clearTemporaryFilesAction(EventDispatcherInterface $eventDispatcher)
  691.     {
  692.         $this->checkPermission('clear_temp_files');
  693.         // public files
  694.         Tool\Storage::get('thumbnail')->deleteDirectory('/');
  695.         Db::get()->executeQuery('TRUNCATE TABLE assets_image_thumbnail_cache');
  696.         Tool\Storage::get('asset_cache')->deleteDirectory('/');
  697.         // system files
  698.         recursiveDelete(PIMCORE_SYSTEM_TEMP_DIRECTORYfalse);
  699.         $eventDispatcher->dispatch(new GenericEvent(), SystemEvents::CACHE_CLEAR_TEMPORARY_FILES);
  700.         return $this->adminJson(['success' => true]);
  701.     }
  702.     /**
  703.      * @Route("/staticroutes", name="pimcore_admin_settings_staticroutes", methods={"POST"})
  704.      *
  705.      * @param Request $request
  706.      *
  707.      * @return JsonResponse
  708.      */
  709.     public function staticroutesAction(Request $request)
  710.     {
  711.         if ($request->get('data')) {
  712.             $this->checkPermission('routes');
  713.             $data $this->decodeJson($request->get('data'));
  714.             if (is_array($data)) {
  715.                 foreach ($data as &$value) {
  716.                     if (is_string($value)) {
  717.                         $value trim($value);
  718.                     }
  719.                 }
  720.             }
  721.             if ($request->get('xaction') == 'destroy') {
  722.                 $data $this->decodeJson($request->get('data'));
  723.                 $id $data['id'];
  724.                 $route Staticroute::getById($id);
  725.                 if (!$route->isWriteable()) {
  726.                     throw new ConfigWriteException();
  727.                 }
  728.                 $route->delete();
  729.                 return $this->adminJson(['success' => true'data' => []]);
  730.             } elseif ($request->get('xaction') == 'update') {
  731.                 // save routes
  732.                 $route Staticroute::getById($data['id']);
  733.                 if (!$route->isWriteable()) {
  734.                     throw new ConfigWriteException();
  735.                 }
  736.                 $route->setValues($data);
  737.                 $route->save();
  738.                 return $this->adminJson(['data' => $route->getObjectVars(), 'success' => true]);
  739.             } elseif ($request->get('xaction') == 'create') {
  740.                 if (!(new Staticroute())->isWriteable()) {
  741.                     throw new ConfigWriteException();
  742.                 }
  743.                 unset($data['id']);
  744.                 // save route
  745.                 $route = new Staticroute();
  746.                 $route->setValues($data);
  747.                 $route->save();
  748.                 $responseData $route->getObjectVars();
  749.                 $responseData['writeable'] = $route->isWriteable();
  750.                 return $this->adminJson(['data' => $responseData'success' => true]);
  751.             }
  752.         } else {
  753.             // get list of routes
  754.             $list = new Staticroute\Listing();
  755.             if ($filter $request->get('filter')) {
  756.                 $list->setFilter(function (Staticroute $staticRoute) use ($filter) {
  757.                     foreach ($staticRoute->getObjectVars() as $value) {
  758.                         if (!is_scalar($value)) {
  759.                             continue;
  760.                         }
  761.                         if (stripos((string)$value$filter) !== false) {
  762.                             return true;
  763.                         }
  764.                     }
  765.                     return false;
  766.                 });
  767.             }
  768.             $routes = [];
  769.             foreach ($list->getRoutes() as $routeFromList) {
  770.                 $route $routeFromList->getObjectVars();
  771.                 $route['writeable'] = $routeFromList->isWriteable();
  772.                 if (is_array($routeFromList->getSiteId())) {
  773.                     $route['siteId'] = implode(','$routeFromList->getSiteId());
  774.                 }
  775.                 $routes[] = $route;
  776.             }
  777.             return $this->adminJson(['data' => $routes'success' => true'total' => $list->getTotalCount()]);
  778.         }
  779.         return $this->adminJson(['success' => false]);
  780.     }
  781.     /**
  782.      * @Route("/get-available-admin-languages", name="pimcore_admin_settings_getavailableadminlanguages", methods={"GET"})
  783.      *
  784.      * @param Request $request
  785.      *
  786.      * @return JsonResponse
  787.      */
  788.     public function getAvailableAdminLanguagesAction(Request $request)
  789.     {
  790.         $langs = [];
  791.         $availableLanguages Tool\Admin::getLanguages();
  792.         $locales Tool::getSupportedLocales();
  793.         foreach ($availableLanguages as $lang) {
  794.             if (array_key_exists($lang$locales)) {
  795.                 $langs[] = [
  796.                     'language' => $lang,
  797.                     'display' => $locales[$lang],
  798.                 ];
  799.             }
  800.         }
  801.         usort($langs, function ($a$b) {
  802.             return strcmp($a['display'], $b['display']);
  803.         });
  804.         return $this->adminJson($langs);
  805.     }
  806.     /**
  807.      * @Route("/glossary", name="pimcore_admin_settings_glossary", methods={"POST"})
  808.      *
  809.      * @param Request $request
  810.      *
  811.      * @return JsonResponse
  812.      */
  813.     public function glossaryAction(Request $request)
  814.     {
  815.         if ($request->get('data')) {
  816.             $this->checkPermission('glossary');
  817.             Cache::clearTag('glossary');
  818.             if ($request->get('xaction') == 'destroy') {
  819.                 $data $this->decodeJson($request->get('data'));
  820.                 $id $data['id'];
  821.                 $glossary Glossary::getById($id);
  822.                 $glossary->delete();
  823.                 return $this->adminJson(['success' => true'data' => []]);
  824.             } elseif ($request->get('xaction') == 'update') {
  825.                 $data $this->decodeJson($request->get('data'));
  826.                 // save glossary
  827.                 $glossary Glossary::getById($data['id']);
  828.                 if (!empty($data['link'])) {
  829.                     if ($doc Document::getByPath($data['link'])) {
  830.                         $data['link'] = $doc->getId();
  831.                     }
  832.                 }
  833.                 $glossary->setValues($data);
  834.                 $glossary->save();
  835.                 if ($link $glossary->getLink()) {
  836.                     if ((int)$link 0) {
  837.                         if ($doc Document::getById((int)$link)) {
  838.                             $glossary->setLink($doc->getRealFullPath());
  839.                         }
  840.                     }
  841.                 }
  842.                 return $this->adminJson(['data' => $glossary'success' => true]);
  843.             } elseif ($request->get('xaction') == 'create') {
  844.                 $data $this->decodeJson($request->get('data'));
  845.                 unset($data['id']);
  846.                 // save glossary
  847.                 $glossary = new Glossary();
  848.                 if (!empty($data['link'])) {
  849.                     if ($doc Document::getByPath($data['link'])) {
  850.                         $data['link'] = $doc->getId();
  851.                     }
  852.                 }
  853.                 $glossary->setValues($data);
  854.                 $glossary->save();
  855.                 if ($link $glossary->getLink()) {
  856.                     if ((int)$link 0) {
  857.                         if ($doc Document::getById((int)$link)) {
  858.                             $glossary->setLink($doc->getRealFullPath());
  859.                         }
  860.                     }
  861.                 }
  862.                 return $this->adminJson(['data' => $glossary->getObjectVars(), 'success' => true]);
  863.             }
  864.         } else {
  865.             // get list of glossaries
  866.             $list = new Glossary\Listing();
  867.             $list->setLimit($request->get('limit'));
  868.             $list->setOffset($request->get('start'));
  869.             $sortingSettings \Pimcore\Bundle\AdminBundle\Helper\QueryParams::extractSortingSettings(array_merge($request->request->all(), $request->query->all()));
  870.             if ($sortingSettings['orderKey']) {
  871.                 $list->setOrderKey($sortingSettings['orderKey']);
  872.                 $list->setOrder($sortingSettings['order']);
  873.             }
  874.             if ($request->get('filter')) {
  875.                 $list->setCondition('`text` LIKE ' $list->quote('%'.$request->get('filter').'%'));
  876.             }
  877.             $list->load();
  878.             $glossaries = [];
  879.             foreach ($list->getGlossary() as $glossary) {
  880.                 if ($link $glossary->getLink()) {
  881.                     if ((int)$link 0) {
  882.                         if ($doc Document::getById((int)$link)) {
  883.                             $glossary->setLink($doc->getRealFullPath());
  884.                         }
  885.                     }
  886.                 }
  887.                 $glossaries[] = $glossary->getObjectVars();
  888.             }
  889.             return $this->adminJson(['data' => $glossaries'success' => true'total' => $list->getTotalCount()]);
  890.         }
  891.         return $this->adminJson(['success' => false]);
  892.     }
  893.     /**
  894.      * @Route("/get-available-sites", name="pimcore_admin_settings_getavailablesites", methods={"GET"})
  895.      *
  896.      * @param Request $request
  897.      *
  898.      * @return JsonResponse
  899.      */
  900.     public function getAvailableSitesAction(Request $request)
  901.     {
  902.         try {
  903.             // we need to check documents permission for listing purposes in sites ext model & url-slugs
  904.             $this->checkPermission('documents');
  905.         } catch (AccessDeniedHttpException $e) {
  906.             Logger::log('[Startup] Sites are not loaded as "documents" permission is missing');
  907.             //return empty string to avoid error on startup
  908.             return $this->adminJson([]);
  909.         }
  910.         $excludeMainSite $request->get('excludeMainSite');
  911.         $sitesList = new Model\Site\Listing();
  912.         $sitesObjects $sitesList->load();
  913.         $sites = [];
  914.         if (!$excludeMainSite) {
  915.             $sites[] = [
  916.                 'id' => 'default',
  917.                 'rootId' => 1,
  918.                 'domains' => '',
  919.                 'rootPath' => '/',
  920.                 'domain' => $this->translator->trans('main_site'),
  921.             ];
  922.         }
  923.         foreach ($sitesObjects as $site) {
  924.             if ($site->getRootDocument()) {
  925.                 if ($site->getMainDomain()) {
  926.                     $sites[] = [
  927.                         'id' => $site->getId(),
  928.                         'rootId' => $site->getRootId(),
  929.                         'domains' => implode(','$site->getDomains()),
  930.                         'rootPath' => $site->getRootPath(),
  931.                         'domain' => $site->getMainDomain(),
  932.                     ];
  933.                 }
  934.             } else {
  935.                 // site is useless, parent doesn't exist anymore
  936.                 $site->delete();
  937.             }
  938.         }
  939.         return $this->adminJson($sites);
  940.     }
  941.     /**
  942.      * @Route("/get-available-countries", name="pimcore_admin_settings_getavailablecountries", methods={"GET"})
  943.      *
  944.      * @param LocaleServiceInterface $localeService
  945.      *
  946.      * @return JsonResponse
  947.      */
  948.     public function getAvailableCountriesAction(LocaleServiceInterface $localeService)
  949.     {
  950.         $countries $localeService->getDisplayRegions();
  951.         asort($countries);
  952.         $options = [];
  953.         foreach ($countries as $short => $translation) {
  954.             if (strlen($short) == 2) {
  955.                 $options[] = [
  956.                     'key' => $translation ' (' $short ')',
  957.                     'value' => $short,
  958.                 ];
  959.             }
  960.         }
  961.         $result = ['data' => $options'success' => true'total' => count($options)];
  962.         return $this->adminJson($result);
  963.     }
  964.     /**
  965.      * @Route("/thumbnail-adapter-check", name="pimcore_admin_settings_thumbnailadaptercheck", methods={"GET"})
  966.      *
  967.      * @param Request $request
  968.      * @param TranslatorInterface $translator
  969.      *
  970.      * @return Response
  971.      */
  972.     public function thumbnailAdapterCheckAction(Request $requestTranslatorInterface $translator)
  973.     {
  974.         $content '';
  975.         $instance \Pimcore\Image::getInstance();
  976.         if ($instance instanceof \Pimcore\Image\Adapter\GD) {
  977.             $content '<span style="color: red; font-weight: bold;padding: 10px;margin:0 0 20px 0;border:1px solid red;display:block;">' .
  978.                 $translator->trans('important_use_imagick_pecl_extensions_for_best_results_gd_is_just_a_fallback_with_less_quality', [], 'admin') .
  979.                 '</span>';
  980.         }
  981.         return new Response($content);
  982.     }
  983.     /**
  984.      * @Route("/thumbnail-tree", name="pimcore_admin_settings_thumbnailtree", methods={"GET", "POST"})
  985.      *
  986.      * @return JsonResponse
  987.      */
  988.     public function thumbnailTreeAction()
  989.     {
  990.         $this->checkPermission('thumbnails');
  991.         $thumbnails = [];
  992.         $list = new Asset\Image\Thumbnail\Config\Listing();
  993.         $groups = [];
  994.         foreach ($list->getThumbnails() as $item) {
  995.             if ($item->getGroup()) {
  996.                 if (empty($groups[$item->getGroup()])) {
  997.                     $groups[$item->getGroup()] = [
  998.                         'id' => 'group_' $item->getName(),
  999.                         'text' => htmlspecialchars($item->getGroup()),
  1000.                         'expandable' => true,
  1001.                         'leaf' => false,
  1002.                         'allowChildren' => true,
  1003.                         'iconCls' => 'pimcore_icon_folder',
  1004.                         'group' => $item->getGroup(),
  1005.                         'children' => [],
  1006.                     ];
  1007.                 }
  1008.                 $groups[$item->getGroup()]['children'][] =
  1009.                     [
  1010.                         'id' => $item->getName(),
  1011.                         'text' => $item->getName(),
  1012.                         'leaf' => true,
  1013.                         'iconCls' => 'pimcore_icon_thumbnails',
  1014.                         'cls' => 'pimcore_treenode_disabled',
  1015.                         'writeable' => $item->isWriteable(),
  1016.                     ];
  1017.             } else {
  1018.                 $thumbnails[] = [
  1019.                     'id' => $item->getName(),
  1020.                     'text' => $item->getName(),
  1021.                     'leaf' => true,
  1022.                     'iconCls' => 'pimcore_icon_thumbnails',
  1023.                     'cls' => 'pimcore_treenode_disabled',
  1024.                     'writeable' => $item->isWriteable(),
  1025.                 ];
  1026.             }
  1027.         }
  1028.         foreach ($groups as $group) {
  1029.             $thumbnails[] = $group;
  1030.         }
  1031.         return $this->adminJson($thumbnails);
  1032.     }
  1033.     /**
  1034.      * @Route("/thumbnail-downloadable", name="pimcore_admin_settings_thumbnaildownloadable", methods={"GET"})
  1035.      *
  1036.      * @return JsonResponse
  1037.      */
  1038.     public function thumbnailDownloadableAction()
  1039.     {
  1040.         $thumbnails = [];
  1041.         $list = new Asset\Image\Thumbnail\Config\Listing();
  1042.         $list->setFilter(function (Asset\Image\Thumbnail\Config $config) {
  1043.             return $config->isDownloadable();
  1044.         });
  1045.         foreach ($list->getThumbnails() as $item) {
  1046.             $thumbnails[] = [
  1047.                 'id' => $item->getName(),
  1048.                 'text' => $item->getName(),
  1049.             ];
  1050.         }
  1051.         return $this->adminJson($thumbnails);
  1052.     }
  1053.     /**
  1054.      * @Route("/thumbnail-add", name="pimcore_admin_settings_thumbnailadd", methods={"POST"})
  1055.      *
  1056.      * @param Request $request
  1057.      *
  1058.      * @return JsonResponse
  1059.      */
  1060.     public function thumbnailAddAction(Request $request)
  1061.     {
  1062.         $this->checkPermission('thumbnails');
  1063.         $success false;
  1064.         $pipe Asset\Image\Thumbnail\Config::getByName($request->get('name'));
  1065.         if (!$pipe) {
  1066.             $pipe = new Asset\Image\Thumbnail\Config();
  1067.             if (!$pipe->isWriteable()) {
  1068.                 throw new ConfigWriteException();
  1069.             }
  1070.             $pipe->setName($request->get('name'));
  1071.             $pipe->save();
  1072.             $success true;
  1073.         } else {
  1074.             if (!$pipe->isWriteable()) {
  1075.                 throw new ConfigWriteException();
  1076.             }
  1077.         }
  1078.         return $this->adminJson(['success' => $success'id' => $pipe->getName()]);
  1079.     }
  1080.     /**
  1081.      * @Route("/thumbnail-delete", name="pimcore_admin_settings_thumbnaildelete", methods={"DELETE"})
  1082.      *
  1083.      * @param Request $request
  1084.      *
  1085.      * @return JsonResponse
  1086.      */
  1087.     public function thumbnailDeleteAction(Request $request)
  1088.     {
  1089.         $this->checkPermission('thumbnails');
  1090.         $pipe Asset\Image\Thumbnail\Config::getByName($request->get('name'));
  1091.         if (!$pipe->isWriteable()) {
  1092.             throw new ConfigWriteException();
  1093.         }
  1094.         $pipe->delete();
  1095.         return $this->adminJson(['success' => true]);
  1096.     }
  1097.     /**
  1098.      * @Route("/thumbnail-get", name="pimcore_admin_settings_thumbnailget", methods={"GET"})
  1099.      *
  1100.      * @param Request $request
  1101.      *
  1102.      * @return JsonResponse
  1103.      */
  1104.     public function thumbnailGetAction(Request $request)
  1105.     {
  1106.         $this->checkPermission('thumbnails');
  1107.         $pipe Asset\Image\Thumbnail\Config::getByName($request->get('name'));
  1108.         $data $pipe->getObjectVars();
  1109.         $data['writeable'] = $pipe->isWriteable();
  1110.         return $this->adminJson($data);
  1111.     }
  1112.     /**
  1113.      * @Route("/thumbnail-update", name="pimcore_admin_settings_thumbnailupdate", methods={"PUT"})
  1114.      *
  1115.      * @param Request $request
  1116.      *
  1117.      * @return JsonResponse
  1118.      */
  1119.     public function thumbnailUpdateAction(Request $request)
  1120.     {
  1121.         $this->checkPermission('thumbnails');
  1122.         $pipe Asset\Image\Thumbnail\Config::getByName($request->get('name'));
  1123.         if (!$pipe->isWriteable()) {
  1124.             throw new ConfigWriteException();
  1125.         }
  1126.         $settingsData $this->decodeJson($request->get('settings'));
  1127.         $mediaData $this->decodeJson($request->get('medias'));
  1128.         $mediaOrder $this->decodeJson($request->get('mediaOrder'));
  1129.         foreach ($settingsData as $key => $value) {
  1130.             $setter 'set' ucfirst($key);
  1131.             if (method_exists($pipe$setter)) {
  1132.                 $pipe->$setter($value);
  1133.             }
  1134.         }
  1135.         $pipe->resetItems();
  1136.         uksort($mediaData, function ($a$b) use ($mediaOrder) {
  1137.             if ($a === 'default') {
  1138.                 return -1;
  1139.             }
  1140.             return ($mediaOrder[$a] < $mediaOrder[$b]) ? -1;
  1141.         });
  1142.         foreach ($mediaData as $mediaName => $items) {
  1143.             if (preg_match('/["<>]/'$mediaName)) {
  1144.                 throw new \Exception('Invalid media query name');
  1145.             }
  1146.             foreach ($items as $item) {
  1147.                 $type $item['type'];
  1148.                 unset($item['type']);
  1149.                 $pipe->addItem($type$item$mediaName);
  1150.             }
  1151.         }
  1152.         $pipe->save();
  1153.         return $this->adminJson(['success' => true]);
  1154.     }
  1155.     /**
  1156.      * @Route("/video-thumbnail-adapter-check", name="pimcore_admin_settings_videothumbnailadaptercheck", methods={"GET"})
  1157.      *
  1158.      * @param Request $request
  1159.      * @param TranslatorInterface $translator
  1160.      *
  1161.      * @return Response
  1162.      */
  1163.     public function videoThumbnailAdapterCheckAction(Request $requestTranslatorInterface $translator)
  1164.     {
  1165.         $content '';
  1166.         if (!\Pimcore\Video::isAvailable()) {
  1167.             $content '<span style="color: red; font-weight: bold;padding: 10px;margin:0 0 20px 0;border:1px solid red;display:block;">' .
  1168.                 $translator->trans('php_cli_binary_and_or_ffmpeg_binary_setting_is_missing', [], 'admin') .
  1169.                 '</span>';
  1170.         }
  1171.         return new Response($content);
  1172.     }
  1173.     /**
  1174.      * @Route("/video-thumbnail-tree", name="pimcore_admin_settings_videothumbnailtree", methods={"GET", "POST"})
  1175.      *
  1176.      * @return JsonResponse
  1177.      */
  1178.     public function videoThumbnailTreeAction()
  1179.     {
  1180.         $this->checkPermission('thumbnails');
  1181.         $thumbnails = [];
  1182.         $list = new Asset\Video\Thumbnail\Config\Listing();
  1183.         $groups = [];
  1184.         foreach ($list->getThumbnails() as $item) {
  1185.             if ($item->getGroup()) {
  1186.                 if (empty($groups[$item->getGroup()])) {
  1187.                     $groups[$item->getGroup()] = [
  1188.                         'id' => 'group_' $item->getName(),
  1189.                         'text' => htmlspecialchars($item->getGroup()),
  1190.                         'expandable' => true,
  1191.                         'leaf' => false,
  1192.                         'allowChildren' => true,
  1193.                         'iconCls' => 'pimcore_icon_folder',
  1194.                         'group' => $item->getGroup(),
  1195.                         'children' => [],
  1196.                     ];
  1197.                 }
  1198.                 $groups[$item->getGroup()]['children'][] =
  1199.                     [
  1200.                         'id' => $item->getName(),
  1201.                         'text' => $item->getName(),
  1202.                         'leaf' => true,
  1203.                         'iconCls' => 'pimcore_icon_videothumbnails',
  1204.                         'cls' => 'pimcore_treenode_disabled',
  1205.                         'writeable' => $item->isWriteable(),
  1206.                     ];
  1207.             } else {
  1208.                 $thumbnails[] = [
  1209.                     'id' => $item->getName(),
  1210.                     'text' => $item->getName(),
  1211.                     'leaf' => true,
  1212.                     'iconCls' => 'pimcore_icon_videothumbnails',
  1213.                     'cls' => 'pimcore_treenode_disabled',
  1214.                     'writeable' => $item->isWriteable(),
  1215.                 ];
  1216.             }
  1217.         }
  1218.         foreach ($groups as $group) {
  1219.             $thumbnails[] = $group;
  1220.         }
  1221.         return $this->adminJson($thumbnails);
  1222.     }
  1223.     /**
  1224.      * @Route("/video-thumbnail-add", name="pimcore_admin_settings_videothumbnailadd", methods={"POST"})
  1225.      *
  1226.      * @param Request $request
  1227.      *
  1228.      * @return JsonResponse
  1229.      */
  1230.     public function videoThumbnailAddAction(Request $request)
  1231.     {
  1232.         $this->checkPermission('thumbnails');
  1233.         $success false;
  1234.         $pipe Asset\Video\Thumbnail\Config::getByName($request->get('name'));
  1235.         if (!$pipe) {
  1236.             $pipe = new Asset\Video\Thumbnail\Config();
  1237.             if (!$pipe->isWriteable()) {
  1238.                 throw new ConfigWriteException();
  1239.             }
  1240.             $pipe->setName($request->get('name'));
  1241.             $pipe->save();
  1242.             $success true;
  1243.         } else {
  1244.             if (!$pipe->isWriteable()) {
  1245.                 throw new ConfigWriteException();
  1246.             }
  1247.         }
  1248.         return $this->adminJson(['success' => $success'id' => $pipe->getName()]);
  1249.     }
  1250.     /**
  1251.      * @Route("/video-thumbnail-delete", name="pimcore_admin_settings_videothumbnaildelete", methods={"DELETE"})
  1252.      *
  1253.      * @param Request $request
  1254.      *
  1255.      * @return JsonResponse
  1256.      */
  1257.     public function videoThumbnailDeleteAction(Request $request)
  1258.     {
  1259.         $this->checkPermission('thumbnails');
  1260.         $pipe Asset\Video\Thumbnail\Config::getByName($request->get('name'));
  1261.         if (!$pipe->isWriteable()) {
  1262.             throw new ConfigWriteException();
  1263.         }
  1264.         $pipe->delete();
  1265.         return $this->adminJson(['success' => true]);
  1266.     }
  1267.     /**
  1268.      * @Route("/video-thumbnail-get", name="pimcore_admin_settings_videothumbnailget", methods={"GET"})
  1269.      *
  1270.      * @param Request $request
  1271.      *
  1272.      * @return JsonResponse
  1273.      */
  1274.     public function videoThumbnailGetAction(Request $request)
  1275.     {
  1276.         $this->checkPermission('thumbnails');
  1277.         $pipe Asset\Video\Thumbnail\Config::getByName($request->get('name'));
  1278.         $data $pipe->getObjectVars();
  1279.         $data['writeable'] = $pipe->isWriteable();
  1280.         return $this->adminJson($data);
  1281.     }
  1282.     /**
  1283.      * @Route("/video-thumbnail-update", name="pimcore_admin_settings_videothumbnailupdate", methods={"PUT"})
  1284.      *
  1285.      * @param Request $request
  1286.      *
  1287.      * @return JsonResponse
  1288.      */
  1289.     public function videoThumbnailUpdateAction(Request $request)
  1290.     {
  1291.         $this->checkPermission('thumbnails');
  1292.         $pipe Asset\Video\Thumbnail\Config::getByName($request->get('name'));
  1293.         if (!$pipe->isWriteable()) {
  1294.             throw new ConfigWriteException();
  1295.         }
  1296.         $settingsData $this->decodeJson($request->get('settings'));
  1297.         $mediaData $this->decodeJson($request->get('medias'));
  1298.         $mediaOrder $this->decodeJson($request->get('mediaOrder'));
  1299.         foreach ($settingsData as $key => $value) {
  1300.             $setter 'set' ucfirst($key);
  1301.             if (method_exists($pipe$setter)) {
  1302.                 $pipe->$setter($value);
  1303.             }
  1304.         }
  1305.         $pipe->resetItems();
  1306.         uksort($mediaData, function ($a$b) use ($mediaOrder) {
  1307.             if ($a === 'default') {
  1308.                 return -1;
  1309.             }
  1310.             return ($mediaOrder[$a] < $mediaOrder[$b]) ? -1;
  1311.         });
  1312.         foreach ($mediaData as $mediaName => $items) {
  1313.             foreach ($items as $item) {
  1314.                 $type $item['type'];
  1315.                 unset($item['type']);
  1316.                 $pipe->addItem($type$itemhtmlspecialchars($mediaName));
  1317.             }
  1318.         }
  1319.         $pipe->save();
  1320.         return $this->adminJson(['success' => true]);
  1321.     }
  1322.     /**
  1323.      * @Route("/robots-txt", name="pimcore_admin_settings_robotstxtget", methods={"GET"})
  1324.      *
  1325.      * @return JsonResponse
  1326.      */
  1327.     public function robotsTxtGetAction()
  1328.     {
  1329.         $this->checkPermission('robots.txt');
  1330.         $config Config::getRobotsConfig();
  1331.         $config $config->toArray();
  1332.         return $this->adminJson([
  1333.             'success' => true,
  1334.             'data' => $config,
  1335.             'onFileSystem' => file_exists(PIMCORE_WEB_ROOT '/robots.txt'),
  1336.         ]);
  1337.     }
  1338.     /**
  1339.      * @Route("/robots-txt", name="pimcore_admin_settings_robotstxtput", methods={"PUT"})
  1340.      *
  1341.      * @param Request $request
  1342.      *
  1343.      * @return JsonResponse
  1344.      */
  1345.     public function robotsTxtPutAction(Request $request)
  1346.     {
  1347.         $this->checkPermission('robots.txt');
  1348.         $values $request->get('data');
  1349.         if (!is_array($values)) {
  1350.             $values = [];
  1351.         }
  1352.         foreach ($values as $siteId => $robotsContent) {
  1353.             SettingsStore::set('robots.txt-' $siteId$robotsContent'string''robots.txt');
  1354.         }
  1355.         return $this->adminJson([
  1356.             'success' => true,
  1357.         ]);
  1358.     }
  1359.     /**
  1360.      * @Route("/website-settings", name="pimcore_admin_settings_websitesettings", methods={"POST"})
  1361.      *
  1362.      * @param Request $request
  1363.      *
  1364.      * @return JsonResponse
  1365.      *
  1366.      * @throws \Exception
  1367.      */
  1368.     public function websiteSettingsAction(Request $request)
  1369.     {
  1370.         $this->checkPermission('website_settings');
  1371.         if ($request->get('data')) {
  1372.             $data $this->decodeJson($request->get('data'));
  1373.             if (is_array($data)) {
  1374.                 foreach ($data as &$value) {
  1375.                     $value trim($value);
  1376.                 }
  1377.             }
  1378.             if ($request->get('xaction') == 'destroy') {
  1379.                 $id $data['id'];
  1380.                 $setting WebsiteSetting::getById($id);
  1381.                 if ($setting instanceof WebsiteSetting) {
  1382.                     $setting->delete();
  1383.                     return $this->adminJson(['success' => true'data' => []]);
  1384.                 }
  1385.             } elseif ($request->get('xaction') == 'update') {
  1386.                 // save routes
  1387.                 $setting WebsiteSetting::getById($data['id']);
  1388.                 if ($setting instanceof WebsiteSetting) {
  1389.                     switch ($setting->getType()) {
  1390.                         case 'document':
  1391.                         case 'asset':
  1392.                         case 'object':
  1393.                             if (isset($data['data'])) {
  1394.                                 $element Element\Service::getElementByPath($setting->getType(), $data['data']);
  1395.                                 $data['data'] = $element;
  1396.                             }
  1397.                             break;
  1398.                     }
  1399.                     $setting->setValues($data);
  1400.                     $setting->save();
  1401.                     $data $this->getWebsiteSettingForEditMode($setting);
  1402.                     return $this->adminJson(['data' => $data'success' => true]);
  1403.                 }
  1404.             } elseif ($request->get('xaction') == 'create') {
  1405.                 unset($data['id']);
  1406.                 // save route
  1407.                 $setting = new WebsiteSetting();
  1408.                 $setting->setValues($data);
  1409.                 $setting->save();
  1410.                 return $this->adminJson(['data' => $setting->getObjectVars(), 'success' => true]);
  1411.             }
  1412.         } else {
  1413.             $list = new WebsiteSetting\Listing();
  1414.             $list->setLimit($request->get('limit'));
  1415.             $list->setOffset($request->get('start'));
  1416.             $sortingSettings \Pimcore\Bundle\AdminBundle\Helper\QueryParams::extractSortingSettings(array_merge($request->request->all(), $request->query->all()));
  1417.             if ($sortingSettings['orderKey']) {
  1418.                 $list->setOrderKey($sortingSettings['orderKey']);
  1419.                 $list->setOrder($sortingSettings['order']);
  1420.             } else {
  1421.                 $list->setOrderKey('name');
  1422.                 $list->setOrder('asc');
  1423.             }
  1424.             if ($request->get('filter')) {
  1425.                 $list->setCondition('`name` LIKE ' $list->quote('%'.$request->get('filter').'%'));
  1426.             }
  1427.             $totalCount $list->getTotalCount();
  1428.             $list $list->load();
  1429.             $settings = [];
  1430.             foreach ($list as $item) {
  1431.                 $resultItem $this->getWebsiteSettingForEditMode($item);
  1432.                 $settings[] = $resultItem;
  1433.             }
  1434.             return $this->adminJson(['data' => $settings'success' => true'total' => $totalCount]);
  1435.         }
  1436.         return $this->adminJson(['success' => false]);
  1437.     }
  1438.     /**
  1439.      * @param WebsiteSetting $item
  1440.      *
  1441.      * @return array
  1442.      */
  1443.     private function getWebsiteSettingForEditMode($item)
  1444.     {
  1445.         $resultItem = [
  1446.             'id' => $item->getId(),
  1447.             'name' => $item->getName(),
  1448.             'language' => $item->getLanguage(),
  1449.             'type' => $item->getType(),
  1450.             'data' => null,
  1451.             'siteId' => $item->getSiteId(),
  1452.             'creationDate' => $item->getCreationDate(),
  1453.             'modificationDate' => $item->getModificationDate(),
  1454.         ];
  1455.         switch ($item->getType()) {
  1456.             case 'document':
  1457.             case 'asset':
  1458.             case 'object':
  1459.                 $element $item->getData();
  1460.                 if ($element) {
  1461.                     $resultItem['data'] = $element->getRealFullPath();
  1462.                 }
  1463.                 break;
  1464.             default:
  1465.                 $resultItem['data'] = $item->getData();
  1466.                 break;
  1467.         }
  1468.         return $resultItem;
  1469.     }
  1470.     /**
  1471.      * @Route("/get-available-algorithms", name="pimcore_admin_settings_getavailablealgorithms", methods={"GET"})
  1472.      *
  1473.      * @param Request $request
  1474.      *
  1475.      * @return JsonResponse
  1476.      */
  1477.     public function getAvailableAlgorithmsAction(Request $request)
  1478.     {
  1479.         $options = [
  1480.             [
  1481.                 'key' => 'password_hash',
  1482.                 'value' => 'password_hash',
  1483.             ],
  1484.         ];
  1485.         $algorithms hash_algos();
  1486.         foreach ($algorithms as $algorithm) {
  1487.             $options[] = [
  1488.                 'key' => $algorithm,
  1489.                 'value' => $algorithm,
  1490.             ];
  1491.         }
  1492.         $result = ['data' => $options'success' => true'total' => count($options)];
  1493.         return $this->adminJson($result);
  1494.     }
  1495.     /**
  1496.      * deleteViews
  1497.      * delete views for localized fields when languages are removed to
  1498.      * prevent mysql errors
  1499.      *
  1500.      * @param string $language
  1501.      * @param string $dbName
  1502.      */
  1503.     protected function deleteViews($language$dbName)
  1504.     {
  1505.         $db \Pimcore\Db::get();
  1506.         $views $db->fetchAllAssociative('SHOW FULL TABLES IN ' $db->quoteIdentifier($dbName) . " WHERE TABLE_TYPE LIKE 'VIEW'");
  1507.         foreach ($views as $view) {
  1508.             if (preg_match('/^object_localized_[0-9]+_' $language '$/'$view['Tables_in_' $dbName])) {
  1509.                 $sql 'DROP VIEW ' $db->quoteIdentifier($view['Tables_in_' $dbName]);
  1510.                 $db->executeQuery($sql);
  1511.             }
  1512.         }
  1513.     }
  1514.     /**
  1515.      * @Route("/test-web2print", name="pimcore_admin_settings_testweb2print", methods={"GET"})
  1516.      *
  1517.      * @param Request $request
  1518.      *
  1519.      * @return Response
  1520.      */
  1521.     public function testWeb2printAction(Request $request)
  1522.     {
  1523.         $this->checkPermission('web2print_settings');
  1524.         $response $this->render('@PimcoreAdmin/Admin/Settings/testWeb2print.html.twig');
  1525.         $html $response->getContent();
  1526.         $adapter \Pimcore\Web2Print\Processor::getInstance();
  1527.         $params = [];
  1528.         if ($adapter instanceof \Pimcore\Web2Print\Processor\WkHtmlToPdf) {
  1529.             $params['adapterConfig'] = '-O landscape';
  1530.         } elseif ($adapter instanceof \Pimcore\Web2Print\Processor\PdfReactor) {
  1531.             $params['adapterConfig'] = [
  1532.                 'javaScriptMode' => 0,
  1533.                 'addLinks' => true,
  1534.                 'appendLog' => true,
  1535.                 'enableDebugMode' => true,
  1536.             ];
  1537.         } elseif ($adapter instanceof \Pimcore\Web2Print\Processor\HeadlessChrome) {
  1538.             $params Config::getWeb2PrintConfig();
  1539.             $params $params->get('headlessChromeSettings');
  1540.             $params json_decode($paramstrue);
  1541.         }
  1542.         $responseOptions = [
  1543.             'Content-Type' => 'application/pdf',
  1544.         ];
  1545.         $pdfData $adapter->getPdfFromString($html$params);
  1546.         return new \Symfony\Component\HttpFoundation\Response(
  1547.             $pdfData,
  1548.             200,
  1549.             $responseOptions
  1550.         );
  1551.     }
  1552. }