"Fossies" - the Fresh Open Source Software Archive

Member "contao-4.11.5/core-bundle/src/Picker/AbstractTablePickerProvider.php" (23 Jun 2021, 8003 Bytes) of package /linux/www/contao-4.11.5.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) PHP source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "AbstractTablePickerProvider.php" see the Fossies "Dox" file reference documentation.

    1 <?php
    2 
    3 declare(strict_types=1);
    4 
    5 /*
    6  * This file is part of Contao.
    7  *
    8  * (c) Leo Feyer
    9  *
   10  * @license LGPL-3.0-or-later
   11  */
   12 
   13 namespace Contao\CoreBundle\Picker;
   14 
   15 use Contao\CoreBundle\Framework\ContaoFramework;
   16 use Contao\DcaLoader;
   17 use Doctrine\DBAL\Connection;
   18 use Doctrine\DBAL\Driver\Result;
   19 use Knp\Menu\FactoryInterface;
   20 use Knp\Menu\ItemInterface;
   21 use Symfony\Component\Routing\RouterInterface;
   22 use Symfony\Contracts\Translation\TranslatorInterface;
   23 
   24 abstract class AbstractTablePickerProvider implements PickerProviderInterface, DcaPickerProviderInterface, PickerMenuInterface
   25 {
   26     private const PREFIX = 'dc.';
   27     private const PREFIX_LENGTH = 3;
   28 
   29     /**
   30      * @var ContaoFramework
   31      */
   32     private $framework;
   33 
   34     /**
   35      * @var FactoryInterface
   36      */
   37     private $menuFactory;
   38 
   39     /**
   40      * @var RouterInterface
   41      */
   42     private $router;
   43 
   44     /**
   45      * @var TranslatorInterface
   46      */
   47     private $translator;
   48 
   49     /**
   50      * @var Connection
   51      */
   52     private $connection;
   53 
   54     public function __construct(ContaoFramework $framework, FactoryInterface $menuFactory, RouterInterface $router, TranslatorInterface $translator, Connection $connection)
   55     {
   56         $this->framework = $framework;
   57         $this->menuFactory = $menuFactory;
   58         $this->router = $router;
   59         $this->translator = $translator;
   60         $this->connection = $connection;
   61     }
   62 
   63     public function getUrl(PickerConfig $config): string
   64     {
   65         $table = $this->getTableFromContext($config->getContext());
   66         $modules = $this->getModulesForTable($table);
   67 
   68         if (0 === \count($modules)) {
   69             throw new \RuntimeException(sprintf('Table "%s" is not in any back end module (context: %s)', $table, $config->getContext()));
   70         }
   71 
   72         $module = array_keys($modules)[0];
   73         [$ptable, $pid] = $this->getPtableAndPid($table, $config->getValue());
   74 
   75         if ($ptable) {
   76             foreach ($modules as $key => $tables) {
   77                 if (\in_array($ptable, $tables, true)) {
   78                     $module = $key;
   79                     break;
   80                 }
   81             }
   82         }
   83 
   84         // If the table is the first in the module, we do not need to add table=xy to the URL
   85         if (0 === array_search($table, $modules[$module], true)) {
   86             return $this->getUrlForValue($config, $module);
   87         }
   88 
   89         return $this->getUrlForValue($config, $module, $table, $pid);
   90     }
   91 
   92     public function addMenuItems(ItemInterface $menu, PickerConfig $config): void
   93     {
   94         $modules = array_keys($this->getModulesForTable($this->getTableFromContext($config->getContext())));
   95 
   96         foreach ($modules as $name) {
   97             $params = [
   98                 'do' => $name,
   99                 'popup' => '1',
  100                 'picker' => $config->cloneForCurrent($this->getName().'.'.$name)->urlEncode(),
  101             ];
  102 
  103             $menu->addChild($this->menuFactory->createItem(
  104                 $name,
  105                 [
  106                     'label' => $this->translator->trans('MOD.'.$name.'.0', [], 'contao_default'),
  107                     'linkAttributes' => ['class' => $name],
  108                     'current' => $this->isCurrent($config) && $name === substr($config->getCurrent(), \strlen($this->getName().'.')),
  109                     'uri' => $this->router->generate('contao_backend', $params),
  110                 ]
  111             ));
  112         }
  113     }
  114 
  115     public function createMenuItem(PickerConfig $config): ItemInterface
  116     {
  117         $menu = $this->menuFactory->createItem('picker');
  118 
  119         $this->addMenuItems($menu, $config);
  120 
  121         return $menu->getFirstChild();
  122     }
  123 
  124     public function supportsContext($context): bool
  125     {
  126         if (0 !== strpos($context, self::PREFIX)) {
  127             return false;
  128         }
  129 
  130         $table = $this->getTableFromContext($context);
  131 
  132         $this->framework->initialize();
  133         $this->framework->createInstance(DcaLoader::class, [$table])->load();
  134 
  135         return isset($GLOBALS['TL_DCA'][$table]['config']['dataContainer'])
  136             && $this->getDataContainer() === $GLOBALS['TL_DCA'][$table]['config']['dataContainer']
  137             && 0 !== \count($this->getModulesForTable($table));
  138     }
  139 
  140     public function supportsValue(PickerConfig $config): bool
  141     {
  142         return true;
  143     }
  144 
  145     public function isCurrent(PickerConfig $config): bool
  146     {
  147         return 0 === strpos($config->getCurrent(), $this->getName().'.');
  148     }
  149 
  150     public function getDcaTable(PickerConfig $config = null): string
  151     {
  152         if (null === $config) {
  153             return '';
  154         }
  155 
  156         return $this->getTableFromContext($config->getContext());
  157     }
  158 
  159     public function getDcaAttributes(PickerConfig $config): array
  160     {
  161         $attributes = ['fieldType' => 'radio'];
  162 
  163         if ($fieldType = $config->getExtra('fieldType')) {
  164             $attributes['fieldType'] = $fieldType;
  165         }
  166 
  167         if ($source = $config->getExtra('source')) {
  168             $attributes['preserveRecord'] = $source;
  169         }
  170 
  171         if ($value = $config->getValue()) {
  172             $attributes['value'] = array_map('\intval', explode(',', $value));
  173         }
  174 
  175         return $attributes;
  176     }
  177 
  178     public function convertDcaValue(PickerConfig $config, $value)
  179     {
  180         return (int) $value;
  181     }
  182 
  183     protected function getModulesForTable(string $table): array
  184     {
  185         $modules = [];
  186 
  187         foreach ($GLOBALS['BE_MOD'] as $v) {
  188             foreach ($v as $name => $module) {
  189                 if (
  190                     isset($module['tables'])
  191                     && \is_array($module['tables'])
  192                     && \in_array($table, $module['tables'], true)
  193                 ) {
  194                     $modules[$name] = array_values($module['tables']);
  195                 }
  196             }
  197         }
  198 
  199         return $modules;
  200     }
  201 
  202     protected function getTableFromContext(string $context): string
  203     {
  204         return substr($context, self::PREFIX_LENGTH);
  205     }
  206 
  207     protected function getUrlForValue(PickerConfig $config, string $module, string $table = null, int $pid = null): string
  208     {
  209         $params = [
  210             'do' => $module,
  211             'popup' => '1',
  212             'picker' => $config->cloneForCurrent($this->getName().'.'.$module)->urlEncode(),
  213         ];
  214 
  215         if (null !== $table) {
  216             $params['table'] = $table;
  217 
  218             if (null !== $pid) {
  219                 $params['id'] = $pid;
  220             }
  221         }
  222 
  223         return $this->router->generate('contao_backend', $params);
  224     }
  225 
  226     protected function getPtableAndPid(string $table, string $value): array
  227     {
  228         // Use the first value if array to find a database record
  229         $id = (int) explode(',', $value)[0];
  230 
  231         if (!$value) {
  232             return [null, null];
  233         }
  234 
  235         $this->framework->initialize();
  236         $this->framework->createInstance(DcaLoader::class, [$table])->load();
  237 
  238         $pid = null;
  239         $ptable = $GLOBALS['TL_DCA'][$table]['config']['ptable'] ?? null;
  240         $dynamicPtable = $GLOBALS['TL_DCA'][$table]['config']['dynamicPtable'] ?? false;
  241 
  242         if (!$ptable && !$dynamicPtable) {
  243             return [null, null];
  244         }
  245 
  246         $qb = $this->connection->createQueryBuilder();
  247         $qb->select('pid')->from($table)->where($qb->expr()->eq('id', $id));
  248 
  249         if ($dynamicPtable) {
  250             $qb->addSelect('ptable');
  251         }
  252 
  253         /** @var Result $result */
  254         $result = $qb->execute();
  255         $data = $result->fetchAssociative();
  256 
  257         if (false === $data) {
  258             return [null, null];
  259         }
  260 
  261         $pid = (int) $data['pid'];
  262 
  263         if ($dynamicPtable) {
  264             $ptable = $data['ptable'] ?: $ptable;
  265 
  266             if (!$ptable) {
  267                 $ptable = 'tl_article'; // backwards compatibility
  268             }
  269         }
  270 
  271         return [$ptable, $pid];
  272     }
  273 
  274     /**
  275      * Returns the DataContainer name supported by this picker (e.g. "Table" for DC_Table).
  276      */
  277     abstract protected function getDataContainer(): string;
  278 }