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

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