vendor/metamodels/core/src/ViewCombination/InputScreenInformationBuilder.php line 86

Open in your IDE?
  1. <?php
  2. /**
  3.  * This file is part of MetaModels/core.
  4.  *
  5.  * (c) 2012-2020 The MetaModels team.
  6.  *
  7.  * For the full copyright and license information, please view the LICENSE
  8.  * file that was distributed with this source code.
  9.  *
  10.  * This project is provided in good faith and hope to be usable by anyone.
  11.  *
  12.  * @package    MetaModels/core
  13.  * @author     Christian Schiffler <c.schiffler@cyberspectrum.de>
  14.  * @author     David Molineus <david.molineus@netzmacht.de>
  15.  * @author     Sven Baumann <baumann.sv@gmail.com>
  16.  * @author     Ingolf Steinhardt <info@e-spin.de>
  17.  * @copyright  2012-2020 The MetaModels team.
  18.  * @license    https://github.com/MetaModels/core/blob/master/LICENSE LGPL-3.0-or-later
  19.  * @filesource
  20.  */
  21. namespace MetaModels\ViewCombination;
  22. use Contao\StringUtil;
  23. use Doctrine\DBAL\Connection;
  24. use MetaModels\IFactory;
  25. use MetaModels\IMetaModel;
  26. /**
  27.  * This class obtains information from the database about input screens.
  28.  */
  29. class InputScreenInformationBuilder
  30. {
  31.     /**
  32.      * The database connection.
  33.      *
  34.      * @var Connection
  35.      */
  36.     private $connection;
  37.     /**
  38.      * The MetaModels factory.
  39.      *
  40.      * @var IFactory
  41.      */
  42.     private $factory;
  43.     /**
  44.      * Create a new instance.
  45.      *
  46.      * @param Connection $connection The database connection.
  47.      * @param IFactory   $factory    The MetaModels factory.
  48.      */
  49.     public function __construct(Connection $connectionIFactory $factory)
  50.     {
  51.         $this->connection $connection;
  52.         $this->factory    $factory;
  53.     }
  54.     /**
  55.      * Fetch information about an input screen.
  56.      *
  57.      * @param array $idList The ids of the input screens to obtain (table name => id).
  58.      *
  59.      * @return array
  60.      */
  61.     public function fetchInputScreens($idList): array
  62.     {
  63.         $idList  array_filter($idList);
  64.         $builder $this->connection->createQueryBuilder();
  65.         $screens $builder
  66.             ->select('d.*')
  67.             ->from('tl_metamodel_dca''d')
  68.             ->leftJoin('d''tl_metamodel''m''m.id=d.pid')
  69.             ->where($builder->expr()->in('d.id'':idList'))
  70.             ->setParameter('idList'$idListConnection::PARAM_STR_ARRAY)
  71.             ->orderBy('m.sorting')
  72.             ->execute()
  73.             ->fetchAll(\PDO::FETCH_ASSOC);
  74.         $result = [];
  75.         $keys   array_flip($idList);
  76.         foreach ($screens as $screen) {
  77.             $metaModelName          $keys[$screen['id']];
  78.             $result[$metaModelName] = $this->prepareInputScreen($metaModelName$screen);
  79.         }
  80.         return $result;
  81.     }
  82.     /**
  83.      * Prepare the input screen data.
  84.      *
  85.      * @param string $modelName The MetaModel name.
  86.      * @param array  $screen    The screen meta data.
  87.      *
  88.      * @return array
  89.      *
  90.      * @throws \InvalidArgumentException When the MetaModel can not be retrieved.
  91.      */
  92.     private function prepareInputScreen($modelName$screen): array
  93.     {
  94.         if (null === $metaModel $this->factory->getMetaModel($modelName)) {
  95.             throw new \InvalidArgumentException('Could not retrieve MetaModel ' $modelName);
  96.         }
  97.         $caption     = ['' => $metaModel->getName()];
  98.         $description = ['' => $metaModel->getName()];
  99.         foreach (StringUtil::deserialize($screen['backendcaption'], true) as $languageEntry) {
  100.             $langCode               $languageEntry['langcode'];
  101.             $caption[$langCode]     = !empty($label $languageEntry['label']) ? $label $caption[''];
  102.             $description[$langCode] = !empty($title $languageEntry['description']) ? $title $description[''];
  103.             if ($metaModel->getFallbackLanguage() === $langCode) {
  104.                 $caption['']     = $label;
  105.                 $description[''] = $title;
  106.             }
  107.         }
  108.         $result = [
  109.             'meta'        => $screen,
  110.             'properties'  => $this->fetchPropertiesFor($screen['id'], $metaModel),
  111.             'conditions'  => $this->fetchConditions($screen['id']),
  112.             'groupSort'   => $this->fetchGroupSort($screen['id'], $metaModel),
  113.             'label'       => $caption,
  114.             'description' => $description
  115.         ];
  116.         $bySetting         $this->buildConditionTree($result['conditions']);
  117.         $result['legends'] = $this->convertLegends($result['properties'], $metaModel$bySetting);
  118.         return $result;
  119.     }
  120.     /**
  121.      * Build condition tree.
  122.      *
  123.      * @param array $conditions The condition information.
  124.      *
  125.      * @return array
  126.      */
  127.     private function buildConditionTree(array $conditions): array
  128.     {
  129.         // Build condition tree.
  130.         $conditionMap = [];
  131.         $bySetting    = [];
  132.         foreach ($conditions as $condition) {
  133.             unset($converted);
  134.             // Check if already mapped, if so, we need to set the values.
  135.             if (array_key_exists($condition['id'], $conditionMap)) {
  136.                 $converted = &$conditionMap[$condition['id']];
  137.                 foreach ($condition as $key => $value) {
  138.                     $converted[$key] = $value;
  139.                 }
  140.             } else {
  141.                 $converted                      = \array_slice($condition0);
  142.                 $conditionMap[$condition['id']] = &$converted;
  143.             }
  144.             // Is on root level - add to setting now.
  145.             if (empty($condition['pid'])) {
  146.                 $bySetting[$condition['settingId']][] = &$converted;
  147.                 continue;
  148.             }
  149.             // Is a child, check if parent already added.
  150.             if (!isset($conditionMap[$condition['pid']])) {
  151.                 $temp                            = ['children' => []];
  152.                 $conditionMap[$condition['pid']] = &$temp;
  153.             }
  154.             // Add child to parent now.
  155.             $conditionMap[$condition['pid']]['children'][] = &$converted;
  156.         }
  157.         return $bySetting;
  158.     }
  159.     /**
  160.      * Fetch all properties for the passed input screen.
  161.      *
  162.      * @param string     $inputScreenId The input screen to obtain properties for.
  163.      * @param IMetaModel $metaModel     The MetaModel to fetch properties for.
  164.      *
  165.      * @return array
  166.      */
  167.     private function fetchPropertiesFor($inputScreenIdIMetaModel $metaModel): array
  168.     {
  169.         $builder $this->connection->createQueryBuilder();
  170.         return array_map(function ($column) use ($inputScreenId$metaModel) {
  171.             if ('attribute' !== $column['dcatype']) {
  172.                 return $column;
  173.             }
  174.             if (!($attribute $metaModel->getAttributeById($column['attr_id']))) {
  175.                 // @codingStandardsIgnoreStart
  176.                 @trigger_error(
  177.                     'Unknown attribute "' $column['attr_id'] . '" in input screen "' $inputScreenId '"',
  178.                     E_USER_WARNING
  179.                 );
  180.                 // @codingStandardsIgnoreEnd
  181.                 return $column;
  182.             }
  183.             $column array_merge(
  184.                 $column,
  185.                 $attribute->getFieldDefinition($column),
  186.                 ['col_name' => $attribute->getColName()]
  187.             );
  188.             return $column;
  189.         }, $builder
  190.             ->select('*')
  191.             ->from('tl_metamodel_dcasetting')
  192.             ->where('pid=:pid')
  193.             ->andWhere('published=:published')
  194.             ->setParameter('pid'$inputScreenId)
  195.             ->setParameter('published'1)
  196.             ->orderBy('sorting')
  197.             ->execute()
  198.             ->fetchAll(\PDO::FETCH_ASSOC));
  199.     }
  200.     /**
  201.      * Fetch conditions for an input screen.
  202.      *
  203.      * @param string $inputScreenId The input screen to obtain conditions for.
  204.      *
  205.      * @return array
  206.      */
  207.     private function fetchConditions($inputScreenId): array
  208.     {
  209.         $builder $this->connection->createQueryBuilder();
  210.         return $builder
  211.             ->select('cond.*''setting.attr_id AS setting_attr_id')
  212.             ->from('tl_metamodel_dcasetting_condition''cond')
  213.             ->leftJoin('cond''tl_metamodel_dcasetting''setting''cond.settingId=setting.id')
  214.             ->leftJoin('setting''tl_metamodel_dca''dca''setting.pid=dca.id')
  215.             ->where('cond.enabled=1')
  216.             ->andWhere('setting.published=1')
  217.             ->andWhere('dca.id=:screenId')
  218.             ->setParameter('screenId'$inputScreenId)
  219.             ->orderBy('pid')
  220.             ->addOrderBy('sorting')
  221.             ->execute()
  222.             ->fetchAll(\PDO::FETCH_ASSOC);
  223.     }
  224.     /**
  225.      * Fetch groupings for an input screen.
  226.      *
  227.      * @param string     $inputScreenId The input screen to obtain properties for.
  228.      * @param IMetaModel $metaModel     The MetaModel to fetch properties for.
  229.      *
  230.      * @return array
  231.      */
  232.     private function fetchGroupSort($inputScreenIdIMetaModel $metaModel): array
  233.     {
  234.         $builder $this->connection->createQueryBuilder();
  235.         return array_map(function ($information) use ($inputScreenId$metaModel) {
  236.             $information['isdefault']      = (bool) $information['isdefault'];
  237.             $information['ismanualsort']   = (bool) $information['ismanualsort'];
  238.             $information['rendergrouplen'] = (int) $information['rendergrouplen'];
  239.             if ($information['ismanualsort']) {
  240.                 $information['rendergrouptype'] = 'none';
  241.             }
  242.             if (!empty($information['rendersortattr'])) {
  243.                 if (!($attribute $metaModel->getAttributeById($information['rendersortattr']))) {
  244.                     // @codingStandardsIgnoreStart
  245.                     @trigger_error(
  246.                         sprintf(
  247.                             'Unknown attribute "%1$s" in group sorting "%2$s.%3$s"',
  248.                             $information['rendersortattr'],
  249.                             $inputScreenId,
  250.                             $information['id']
  251.                         ),
  252.                         E_USER_WARNING
  253.                     );
  254.                     // @codingStandardsIgnoreEnd
  255.                     return $information;
  256.                 }
  257.                 $information['col_name'] = $attribute->getColName();
  258.             }
  259.             return $information;
  260.         }, $builder
  261.             ->select('*')
  262.             ->from('tl_metamodel_dca_sortgroup')
  263.             ->where('pid=:screenId')
  264.             ->setParameter('screenId'$inputScreenId)
  265.             ->orderBy('sorting')
  266.             ->execute()
  267.             ->fetchAll(\PDO::FETCH_ASSOC));
  268.     }
  269.     /**
  270.      * Convert property list to legend list.
  271.      *
  272.      * @param array      $properties The property and legend information.
  273.      * @param IMetaModel $metaModel  The MetaModel to fetch properties for.
  274.      *
  275.      * @param array      $conditions The conditions for the entries.
  276.      *
  277.      * @return array
  278.      */
  279.     private function convertLegends(array $propertiesIMetaModel $metaModel, array $conditions): array
  280.     {
  281.         $result = [];
  282.         $label  = [];
  283.         if ($trans $metaModel->isTranslated()) {
  284.             foreach ($metaModel->getAvailableLanguages() as $availableLanguage) {
  285.                 $label[$availableLanguage] = $metaModel->getName();
  286.             }
  287.         } else {
  288.             $label['default'] = $metaModel->getName();
  289.         }
  290.         $legend = [
  291.             'label'      => $label,
  292.             'hide'       => false,
  293.             'properties' => []
  294.         ];
  295.         $condition = function ($property) use ($conditions) {
  296.             if (!isset($conditions[$property['id']])) {
  297.                 return null;
  298.             }
  299.             return [
  300.                 'type'     => 'conditionand',
  301.                 'children' => $conditions[$property['id']]
  302.             ];
  303.         };
  304.         $fallbackLanguage $trans $metaModel->getFallbackLanguage() : null;
  305.         foreach ($properties as $property) {
  306.             switch ($property['dcatype']) {
  307.                 case 'legend':
  308.                     $this->convertLegend($property$fallbackLanguage$condition$legend$result);
  309.                     break;
  310.                 case 'attribute':
  311.                     $this->convertAttribute($property$condition$legend);
  312.                     break;
  313.                 default:
  314.                     break;
  315.             }
  316.         }
  317.         if (!empty($legend['properties'])) {
  318.             $result['legend' . (\count($result) + 1)] = $legend;
  319.         }
  320.         return $result;
  321.     }
  322.     /**
  323.      * Convert a legend property.
  324.      *
  325.      * @param array       $property  The property information to convert.
  326.      * @param string|null $fallback  The fallback language if the MetaModel is translated or null otherwise.
  327.      * @param callable    $condition The condition transformer.
  328.      * @param array       $legend    The current legend information.
  329.      * @param array       $result    The resulting information.
  330.      *
  331.      * @return void
  332.      */
  333.     private function convertLegend(array $property, ?string $fallback$condition, array &$legend, array &$result)
  334.     {
  335.         if (!empty($legend['properties'])) {
  336.             $result['legend' . (\count($result) + 1)] = $legend;
  337.         }
  338.         if (null === $fallback) {
  339.             $label = ['default' => $property['legendtitle']];
  340.         } else {
  341.             $label            unserialize($property['legendtitle'], ['allowed_classes' => false]);
  342.             $label['default'] = $label[$fallback];
  343.         }
  344.         $legend = [
  345.             'label'      => $label,
  346.             'hide'       => (bool) $property['legendhide'],
  347.             'properties' => [],
  348.             'condition' => $condition($property)
  349.         ];
  350.     }
  351.     /**
  352.      * Convert an attribute property.
  353.      *
  354.      * @param array    $property  The property information to convert.
  355.      * @param callable $condition The condition transformer.
  356.      * @param array    $legend    The current legend information.
  357.      *
  358.      * @return void
  359.      */
  360.     private function convertAttribute(array $property$condition, array &$legend)
  361.     {
  362.         if (!isset($property['col_name'])) {
  363.             return;
  364.         }
  365.         $legend['properties'][] = [
  366.             'name'       => $property['col_name'],
  367.             'condition' => $condition($property)
  368.         ];
  369.     }
  370. }