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

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