<?php

/**
 * This file is part of MetaModels/core.
 *
 * (c) 2012-2019 The MetaModels team.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * This project is provided in good faith and hope to be usable by anyone.
 *
 * @package    MetaModels/core
 * @author     Christian Schiffler <c.schiffler@cyberspectrum.de>
 * @author     Sven Baumann <baumann.sv@gmail.com>
 * @copyright  2012-2019 The MetaModels team.
 * @license    https://github.com/MetaModels/core/blob/master/LICENSE LGPL-3.0-or-later
 * @filesource
 */

namespace MetaModels\CoreBundle\EventListener\DcGeneral\DefinitionBuilder;

use ContaoCommunityAlliance\DcGeneral\Contao\DataDefinition\Definition\Contao2BackendViewDefinition;
use ContaoCommunityAlliance\DcGeneral\Contao\DataDefinition\Definition\Contao2BackendViewDefinitionInterface;
use ContaoCommunityAlliance\DcGeneral\DataDefinition\Definition\View\DefaultModelFormatterConfig;
use ContaoCommunityAlliance\DcGeneral\DataDefinition\Definition\View\GroupAndSortingDefinitionInterface;
use ContaoCommunityAlliance\DcGeneral\DataDefinition\Definition\View\GroupAndSortingInformationInterface;
use ContaoCommunityAlliance\DcGeneral\DataDefinition\Definition\View\ListingConfigInterface;
use ContaoCommunityAlliance\DcGeneral\Exception\DcGeneralInvalidArgumentException;
use MetaModels\CoreBundle\Assets\IconBuilder;
use MetaModels\DcGeneral\DataDefinition\IMetaModelDataDefinition;
use MetaModels\IFactory;
use MetaModels\IMetaModel;
use MetaModels\Render\Setting\IRenderSettingFactory;
use MetaModels\ViewCombination\ViewCombination;

/**
 * This class builds the Contao2 backend view definition.
 */
class Contao2BackendViewDefinitionBuilder
{
    use MetaModelDefinitionBuilderTrait;

    /**
     * The view combinations.
     *
     * @var ViewCombination
     */
    private $viewCombination;

    /**
     * The render setting factory.
     *
     * @var IRenderSettingFactory
     */
    private $renderSettingFactory;

    /**
     * The container being built (only set during build phase).
     *
     * @var IMetaModelDataDefinition
     */
    private $container;

    /**
     * The backend view definition (only set during build phase).
     *
     * @var Contao2BackendViewDefinitionInterface
     */
    private $definition;

    /**
     * The input screen (only set during build phase).
     *
     * @var array
     */
    private $inputScreen;

    /**
     * The MetaModel that is the scope (only set during build phase).
     *
     * @var IMetaModel
     */
    private $metaModel;

    /**
     * The MetaModels factory.
     *
     * @var IFactory
     */
    private $factory;

    /**
     * The icon builder.
     *
     * @var IconBuilder
     */
    private $iconBuilder;

    /**
     * Create a new instance.
     *
     * @param ViewCombination       $viewCombination      The view combinations.
     * @param IFactory              $factory              The MetaModels factory.
     * @param IRenderSettingFactory $renderSettingFactory The render setting factory.
     * @param IconBuilder           $iconBuilder          The icon builder.
     */
    public function __construct(
        ViewCombination $viewCombination,
        IFactory $factory,
        IRenderSettingFactory $renderSettingFactory,
        IconBuilder $iconBuilder
    ) {
        $this->viewCombination      = $viewCombination;
        $this->factory              = $factory;
        $this->renderSettingFactory = $renderSettingFactory;
        $this->iconBuilder          = $iconBuilder;
    }

    /**
     * Parse and build the backend view definition for the old Contao2 backend view.
     *
     * @param IMetaModelDataDefinition $container The data container.
     *
     * @throws DcGeneralInvalidArgumentException When the contained view definition is of invalid type.
     *
     * @return void
     */
    protected function build(IMetaModelDataDefinition $container)
    {
        $this->container   = $container;
        $this->definition  = $this->getOrCreateDefinition();
        $this->inputScreen = $this->viewCombination->getScreen($container->getName());
        $this->metaModel   = $this->factory->getMetaModel($container->getName());

        $this->parseListing();

        $this->container   = null;
        $this->definition  = null;
        $this->inputScreen = null;
        $this->metaModel   = null;
    }

    /**
     * Get or create the definition.
     *
     * @return Contao2BackendViewDefinitionInterface
     *
     * @throws DcGeneralInvalidArgumentException When the contained view definition is of invalid type.
     */
    private function getOrCreateDefinition()
    {
        if ($this->container->hasDefinition(Contao2BackendViewDefinitionInterface::NAME)) {
            $view = $this->container->getDefinition(Contao2BackendViewDefinitionInterface::NAME);
            if (!$view instanceof Contao2BackendViewDefinitionInterface) {
                throw new DcGeneralInvalidArgumentException(
                    'Configured BackendViewDefinition does not implement Contao2BackendViewDefinitionInterface.'
                );
            }
            return $view;
        }
        $this->container->setDefinition(
            Contao2BackendViewDefinitionInterface::NAME,
            $view = new Contao2BackendViewDefinition()
        );

        return $view;
    }

    /**
     * Parse the listing configuration.
     *
     * @return void
     */
    private function parseListing()
    {
        $listing = $this->definition->getListingConfig();

        if (null === $listing->getRootLabel()) {
            $listing->setRootLabel($this->metaModel->get('name'));
        }

        if (null === $listing->getRootIcon()) {
            $listing->setRootIcon($this->iconBuilder->getBackendIcon($this->inputScreen['meta']['backendicon']));
        }

        $this->parseListSorting($listing);
        $this->parseListLabel($listing);

        $listing->setShowColumns((bool) $this->inputScreen['meta']['showColumns']);
    }

    /**
     * Parse the sorting part of listing configuration.
     *
     * @param ListingConfigInterface $listing The listing configuration.
     *
     * @return void
     */
    private function parseListSorting(ListingConfigInterface $listing)
    {
        if (null === $this->inputScreen) {
            return;
        }
        $definitions = $listing->getGroupAndSortingDefinition();
        foreach ($this->inputScreen['groupSort'] as $information) {
            $definition = $definitions->add();
            $definition->setName($information['name']);
            if ($information['isdefault'] && !$definitions->hasDefault()) {
                $definitions->markDefault($definition);
            }

            $this->handleSorting($information, $definition);

            $groupType = $this->convertRenderGroupType($information['rendergrouptype']);
            if ($groupType !== GroupAndSortingInformationInterface::GROUP_NONE
                && $information['col_name']
            ) {
                $propertyInformation = $definition->add(0);
                $propertyInformation
                    ->setProperty($information['col_name'])
                    ->setGroupingMode($groupType)
                    ->setGroupingLength($information['rendergrouplen'])
                    ->setSortingMode($information['rendersort']);
            }
        }
    }

    /**
     * Set the correct sorting value.
     *
     * @param array                              $information The sorting and group information.
     * @param GroupAndSortingDefinitionInterface $definition  The sorting and group definition.
     *
     * @return void
     */
    private function handleSorting(
        $information,
        GroupAndSortingDefinitionInterface $definition
    ) {
        if ($information['ismanualsort']) {
            $definition
                ->add()
                ->setManualSorting()
                ->setProperty('sorting')
                ->setSortingMode(GroupAndSortingInformationInterface::SORT_ASC);
            return;
        }
        if ($information['col_name']) {
            $definition
                ->add()
                ->setProperty($information['col_name'])
                ->setSortingMode($information['rendersort']);
        }
    }

    /**
     * Convert a render group type from InputScreen value to GroupAndSortingInformationInterface value.
     *
     * @param string $type The group type.
     *
     * @return string
     */
    private function convertRenderGroupType($type)
    {
        $lookup = [
            'char'    => GroupAndSortingInformationInterface::GROUP_CHAR,
            'digit'   => GroupAndSortingInformationInterface::GROUP_DIGIT,
            'day'     => GroupAndSortingInformationInterface::GROUP_DAY,
            'weekday' => GroupAndSortingInformationInterface::GROUP_WEEKDAY,
            'week'    => GroupAndSortingInformationInterface::GROUP_WEEK,
            'month'   => GroupAndSortingInformationInterface::GROUP_MONTH,
            'year'    => GroupAndSortingInformationInterface::GROUP_YEAR,
        ];
        if (array_key_exists($type, $lookup)) {
            return $lookup[$type];
        }

        return GroupAndSortingInformationInterface::GROUP_NONE;
    }

    /**
     * Parse the sorting part of listing configuration.
     *
     * @param ListingConfigInterface $listing The listing config.
     *
     * @return void
     */
    private function parseListLabel(ListingConfigInterface $listing)
    {
        $providerName = $this->container->getBasicDefinition()->getDataProvider();
        if (!$listing->hasLabelFormatter($providerName)) {
            $formatter = new DefaultModelFormatterConfig();
            $listing->setLabelFormatter($providerName, $formatter);
        } else {
            $formatter = $listing->getLabelFormatter($providerName);
        }

        $renderSetting = $this->renderSettingFactory->createCollection(
            $this->metaModel,
            $this->container->getMetaModelDefinition()->getActiveRenderSetting()
        );

        $formatter->setPropertyNames(
            array_merge($formatter->getPropertyNames(), $renderSetting->getSettingNames())
        );

        $formatter->setFormat(str_repeat('%s ', count($formatter->getPropertyNames())));
    }
}


<?php

/**
 * This file is part of MetaModels/core.
 *
 * (c) 2012-2019 The MetaModels team.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * This project is provided in good faith and hope to be usable by anyone.
 *
 * @package    MetaModels/core
 * @author     Christian Schiffler <c.schiffler@cyberspectrum.de>
 * @author     David Molineus <david.molineus@netzmacht.de>
 * @copyright  2012-2019 The MetaModels team.
 * @license    https://github.com/MetaModels/core/blob/master/LICENSE LGPL-3.0-or-later
 * @filesource
 */

namespace MetaModels\CoreBundle\EventListener\DcGeneral\Table;

use ContaoCommunityAlliance\DcGeneral\DataDefinition\ConditionChainInterface;
use ContaoCommunityAlliance\DcGeneral\DataDefinition\ConditionInterface;
use ContaoCommunityAlliance\DcGeneral\DataDefinition\Palette\Condition\Property\PropertyConditionChain;
use ContaoCommunityAlliance\DcGeneral\DataDefinition\Palette\Legend;
use ContaoCommunityAlliance\DcGeneral\DataDefinition\Palette\LegendInterface;
use ContaoCommunityAlliance\DcGeneral\DataDefinition\Palette\PaletteInterface;
use ContaoCommunityAlliance\DcGeneral\DataDefinition\Palette\Property;
use ContaoCommunityAlliance\DcGeneral\DataDefinition\Palette\PropertyInterface;

/**
 * This is an abstract base to build palette restrictions for properties.
 */
class AbstractPaletteRestrictionListener
{

    /**
     * Retrieve the legend with the given name.
     *
     * @param string           $name       Name of the legend.
     *
     * @param PaletteInterface $palette    The palette.
     *
     * @param LegendInterface  $prevLegend The previous legend.
     *
     * @return LegendInterface
     */
    protected function getLegend($name, $palette, $prevLegend = null)
    {
        if (strpos($name, '+') === 0) {
            $name = substr($name, 1);
        }

        if (!$palette->hasLegend($name)) {
            $palette->addLegend(new Legend($name), $prevLegend);
        }

        return $palette->getLegend($name);
    }

    /**
     * Retrieve a property from a legend or create a new one.
     *
     * @param string          $name   The legend name.
     *
     * @param LegendInterface $legend The legend instance.
     *
     * @return PropertyInterface
     */
    protected function getProperty($name, $legend)
    {
        foreach ($legend->getProperties() as $property) {
            if ($property->getName() === $name) {
                return $property;
            }
        }

        $property = new Property($name);
        $legend->addProperty($property);

        return $property;
    }

    /**
     * Add a condition to a property.
     *
     * @param PropertyInterface  $property  The property.
     *
     * @param ConditionInterface $condition The condition to add.
     *
     * @return void
     */
    protected function addCondition($property, $condition)
    {
        $currentCondition = $property->getVisibleCondition();
        if ((!($currentCondition instanceof ConditionChainInterface))
            || (ConditionChainInterface::OR_CONJUNCTION !== $currentCondition->getConjunction())
        ) {
            if ($currentCondition === null) {
                $currentCondition = new PropertyConditionChain([$condition]);
            } else {
                $currentCondition = new PropertyConditionChain([$currentCondition, $condition]);
            }
            $currentCondition->setConjunction(ConditionChainInterface::OR_CONJUNCTION);
            $property->setVisibleCondition($currentCondition);
        } else {
            $currentCondition->addCondition($condition);
        }
    }
}


<?php

/**
 * This file is part of MetaModels/core.
 *
 * (c) 2012-2019 The MetaModels team.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * This project is provided in good faith and hope to be usable by anyone.
 *
 * @package    MetaModels/core
 * @author     Christian Schiffler <c.schiffler@cyberspectrum.de>
 * @author     Stefan Heimes <stefan_heimes@hotmail.com>
 * @author     Christopher Boelter <christopher@boelter.eu>
 * @author     Sven Baumann <baumann.sv@gmail.com>
 * @copyright  2012-2019 The MetaModels team.
 * @license    https://github.com/MetaModels/core/blob/master/LICENSE LGPL-3.0-or-later
 * @filesource
 */

namespace MetaModels\DcGeneral\Events\MetaModel;

use ContaoCommunityAlliance\DcGeneral\Event\PreDuplicateModelEvent;
use MetaModels\IFactory;

/**
 * This class handles the paste into or after handling for variants.
 */
class DuplicateModel
{
    /**
     * The MetaModels factory.
     *
     * @var IFactory
     */
    private $factory;

    /**
     * Create a new instance.
     *
     * @param IFactory $factory The factory.
     */
    public function __construct(IFactory $factory)
    {
        $this->factory = $factory;
    }

    /**
     * Handle the paste into and after event.
     *
     * @param PreDuplicateModelEvent $event The event.
     *
     * @return void
     */
    public function handle(PreDuplicateModelEvent $event)
    {
        $model = $event->getModel();

        $metaModel = $this->factory->getMetaModel($model->getProviderName());

        if (!$metaModel || !$metaModel->hasVariants()) {
            return;
        }

        // If we have a varbase, reset the vargroup because we got a new id.
        if ($model->getProperty('varbase') == 1) {
            $model->setProperty('vargroup', null);
        }
    }
}


<?php

/**
 * This file is part of MetaModels/core.
 *
 * (c) 2012-2019 The MetaModels team.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * This project is provided in good faith and hope to be usable by anyone.
 *
 * @package    MetaModels/core
 * @author     Christian Schiffler <c.schiffler@cyberspectrum.de>
 * @author     Sven Baumann <baumann.sv@gmail.com>
 * @copyright  2012-2019 The MetaModels team.
 * @license    https://github.com/MetaModels/core/blob/master/LICENSE LGPL-3.0-or-later
 * @filesource
 */

namespace MetaModels\CoreBundle\EventListener;

use MetaModels\Attribute\IAttributeFactory;
use MetaModels\Events\CreateMetaModelEvent;

/**
 * This listener adds the MetaModels attributes to a created MetaModel instance.
 */
class AttributeAddingListener
{
    /**
     * The attribute factory.
     *
     * @var IAttributeFactory
     */
    private $attributeFactory;

    /**
     * Create a new instance.
     *
     * @param IAttributeFactory $attributeFactory The attribute factory.
     */
    public function __construct(IAttributeFactory $attributeFactory)
    {
        $this->attributeFactory = $attributeFactory;
    }

    /**
     * Add attributes to the MetaModel.
     *
     * @param CreateMetaModelEvent $event The event.
     *
     * @return void
     */
    public function handle(CreateMetaModelEvent $event)
    {
        if (null === $metaModel = $event->getMetaModel()) {
            return;
        }

        foreach ($this->attributeFactory->createAttributesForMetaModel($metaModel) as $attribute) {
            $metaModel->addAttribute($attribute);
        }
    }
}


<?php

/**
 * This file is part of MetaModels/core.
 *
 * (c) 2012-2019 The MetaModels team.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * This project is provided in good faith and hope to be usable by anyone.
 *
 * @package    MetaModels/core
 * @author     Andreas Isaak <info@andreas-isaak.de>
 * @author     Christian Schiffler <c.schiffler@cyberspectrum.de>
 * @author     Christopher Boelter <christopher@boelter.eu>
 * @author     Stefan Heimes <stefan_heimes@hotmail.com>
 * @author     Ingolf Steinhardt <info@e-spin.de>
 * @author     Sven Baumann <baumann.sv@gmail.com>
 * @author     David Molineus <david.molineus@netzmacht.de>
 * @copyright  2012-2019 The MetaModels team.
 * @license    https://github.com/MetaModels/core/blob/master/LICENSE LGPL-3.0-or-later
 * @filesource
 */

namespace MetaModels\FrontendIntegration;

use Contao\CoreBundle\Exception\RedirectResponseException;
use Contao\Input;
use Contao\System;
use ContaoCommunityAlliance\Contao\Bindings\ContaoEvents;
use ContaoCommunityAlliance\Contao\Bindings\Events\Controller\RedirectEvent;
use Doctrine\DBAL\Connection;
use MetaModels\Filter\FilterUrl;
use MetaModels\Filter\FilterUrlBuilder;
use MetaModels\FrontendIntegration\Content\FilterClearAll as ContentElementFilterClearAll;
use MetaModels\FrontendIntegration\Module\FilterClearAll as ModuleFilterClearAll;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;

/**
 * FE-filtering for Contao MetaModels.
 */
class FrontendFilter
{
    /**
     * Filter config.
     *
     * @var HybridFilterBlock
     */
    protected $objFilterConfig;

    /**
     * The form id to use.
     *
     * @var string
     */
    protected $formId = 'mm_filter_';

    /**
     * Database connection.
     *
     * @var Connection
     */
    private $connection;

    /**
     * The filter URL builder.
     *
     * @var FilterUrlBuilder
     */
    private $filterUrlBuilder;

    /**
     * FrontendFilter constructor.
     *
     * @param Connection       $connection       Database connection.
     * @param FilterUrlBuilder $filterUrlBuilder The filter URL builder.
     */
    public function __construct(Connection $connection = null, FilterUrlBuilder $filterUrlBuilder = null)
    {
        if (null === $connection) {
            // @codingStandardsIgnoreStart
            @trigger_error(
                'Connection is missing. It has to be passed in the constructor. Fallback will be dropped.',
                E_USER_DEPRECATED
            );
            // @codingStandardsIgnoreEnd
            $connection = System::getContainer()->get('database_connection');
        }
        if (null === $filterUrlBuilder) {
            // @codingStandardsIgnoreStart
            @trigger_error(
                'FilterUrlBuilder is missing. It has to be passed in the constructor. Fallback will be dropped.',
                E_USER_DEPRECATED
            );
            // @codingStandardsIgnoreEnd
            $filterUrlBuilder = System::getContainer()->get('metamodels.filter_url');
        }

        $this->connection       = $connection;
        $this->filterUrlBuilder = $filterUrlBuilder;
    }

    /**
     * Retrieve the event dispatcher.
     *
     * @return EventDispatcherInterface
     *
     * @SuppressWarnings(PHPMD.Superglobals)
     * @SuppressWarnings(PHPMD.CamelCaseVariableName)
     */
    protected function getDispatcher()
    {
        return $GLOBALS['container']['event-dispatcher'];
    }

    /**
     * Configure the filter module.
     *
     * @param HybridFilterBlock $objFilterConfig The content element or module using this filter.
     *
     * @return array
     */
    public function getMetaModelFrontendFilter(HybridFilterBlock $objFilterConfig)
    {
        $this->objFilterConfig = $objFilterConfig;

        $this->formId .= $this->objFilterConfig->id;
        return $this->getFilters();
    }

    /**
     * Generate an url determined by the given params and configured jumpTo page.
     *
     * @param array $arrParams The URL parameters to use.
     *
     * @return string the generated URL.
     *
     * @SuppressWarnings(PHPMD.Superglobals)
     * @SuppressWarnings(PHPMD.CamelCaseVariableName)
     *
     * @deprecated Do not use.
     */
    protected function getJumpToUrl($arrParams)
    {
        // @codingStandardsIgnoreStart
        @trigger_error(
            sprintf('"%1$s" has been deprecated in favor of the new "FilterUrlBuilder"', __METHOD__),
            E_USER_DEPRECATED
        );
        // @codingStandardsIgnoreEnd

        $strFilterAction = '';
        foreach ($arrParams as $strName => $varParam) {
            // Skip the magic "language" parameter.
            if (($strName == 'language') && $GLOBALS['TL_CONFIG']['addLanguageToUrl']) {
                continue;
            }

            $strValue = $varParam;

            if (is_array($varParam)) {
                $strValue = implode(',', array_filter($varParam));
            }

            if (strlen($strValue)) {
                // Shift auto_item to the front.
                if ($strName == 'auto_item') {
                    $strFilterAction = '/' . rawurlencode(rawurlencode($strValue)) . $strFilterAction;
                    continue;
                }

                $strFilterAction .= sprintf(
                    $GLOBALS['TL_CONFIG']['disableAlias'] ? '&%s=%s' : '/%s/%s',
                    rawurlencode($strName),
                    // Double rawurlencode to encode all special characters.
                    // Look at http://php.net/manual/en/function.rawurlencode.php .
                    rawurlencode(rawurlencode($strValue))
                );
            }
        }
        return $strFilterAction;
    }

    /**
     * Redirect the browser to the url determined by the given params (configured jumpTo page will get used).
     *
     * This will exit the script!
     *
     * @param array $arrParams The URL parameters to use.
     *
     * @return void
     *
     * @deprecated Do not use.
     */
    protected function redirectPost($arrParams)
    {
        // @codingStandardsIgnoreStart
        @trigger_error(
            sprintf('"%1$s" has been deprecated in favor of the new "FilterUrlBuilder"', __METHOD__),
            E_USER_DEPRECATED
        );
        // @codingStandardsIgnoreEnd
        $jumpTo     = $this->objFilterConfig->getJumpTo();
        $dispatcher = $this->getDispatcher();
        $filterUrl  = new FilterUrl($jumpTo, [], $arrParams);
        $dispatcher->dispatch(
            ContaoEvents::CONTROLLER_REDIRECT,
            new RedirectEvent($this->filterUrlBuilder->generate($filterUrl))
        );
    }

    /**
     * Retrieve the list of parameter names that shall be evaluated.
     *
     * @return array
     */
    protected function getWantedNames()
    {
        return (array) unserialize($this->objFilterConfig->metamodel_fef_params);
    }

    /**
     * Retrieve the parameter values.
     *
     * @return array
     *
     * @SuppressWarnings(PHPMD.Superglobals)
     * @SuppressWarnings(PHPMD.CamelCaseVariableName)
     *
     * @deprecated Do not use.
     */
    protected function getParams()
    {
        // @codingStandardsIgnoreStart
        @trigger_error(
            sprintf('"%1$s" has been deprecated in favor of the new "FilterUrlBuilder"', __METHOD__),
            E_USER_DEPRECATED
        );
        // @codingStandardsIgnoreEnd
        $arrWantedParam = $this->getWantedNames();
        $arrMyParams    = $arrOtherParams = array();

        if ($_GET) {
            foreach (array_keys($_GET) as $strParam) {
                if (in_array($strParam, $arrWantedParam)) {
                    $arrMyParams[$strParam] = Input::get($strParam);
                } elseif ($strParam != 'page') {
                    // Add only to the array if param is not page.
                    $arrOtherParams[$strParam] = Input::get($strParam);
                }
            }
        }

        // if POST, translate to proper GET url
        if ($_POST && (Input::post('FORM_SUBMIT') == $this->formId)) {
            foreach (array_keys($_POST) as $strParam) {
                if (in_array($strParam, $arrWantedParam)) {
                    $arrMyParams[$strParam] = Input::post($strParam);
                }
            }
        }

        return array
        (
            'filter' => $arrMyParams,
            'other' => $arrOtherParams,
            'all' => array_merge($arrOtherParams, $arrMyParams)
        );
    }

    /**
     * Parse a single filter widget.
     *
     * @param array                 $widget        The widget configuration.
     *
     * @param FrontendFilterOptions $filterOptions The filter options to apply.
     *
     * @return array
     */
    protected function renderWidget($widget, $filterOptions)
    {
        $filter       = $widget;
        $templateName = $filter['raw']['eval']['template'];
        $template     = new \FrontendTemplate($templateName ? $templateName : 'mm_filteritem_default');

        $template->setData($filter);

        $template->submit = $filterOptions->isAutoSubmit();
        $filter['value']  = $template->parse();

        return $filter;
    }

    /**
     * Check if we want to redirect to another url.
     *
     * @param array $widgets         The widgets.
     *
     * @param array $wantedParameter The wanted parameters.
     *
     * @param array $allParameter    The current parameters.
     *
     * @return void
     *
     * @deprecated Do not use.
     */
    protected function checkRedirect($widgets, $wantedParameter, $allParameter)
    {
        // @codingStandardsIgnoreStart
        @trigger_error(
            sprintf('"%1$s" has been deprecated in favor of the new "FilterUrlBuilder"', __METHOD__),
            E_USER_DEPRECATED
        );
        // @codingStandardsIgnoreEnd

        // If we have POST data, we need to redirect now.
        if (Input::post('FORM_SUBMIT') != $this->formId) {
            return;
        }
        $redirectParameters = $allParameter['other'];
        foreach ($wantedParameter as $widgetName) {
            $filter = $widgets[$widgetName];
            if ($filter['urlvalue'] !== null) {
                $redirectParameters[$widgetName] = $filter['urlvalue'];
            }
        }

        $filterUrl  = new FilterUrl($this->objFilterConfig->getJumpTo(), [], $redirectParameters);
        $dispatcher = $this->getDispatcher();
        $dispatcher->dispatch(
            ContaoEvents::CONTROLLER_REDIRECT,
            new RedirectEvent($this->filterUrlBuilder->generate($filterUrl))
        );
    }

    /**
     * Get the frontend filter options to use.
     *
     * @return FrontendFilterOptions
     */
    protected function getFrontendFilterOptions()
    {
        $objFrontendFilterOptions = new FrontendFilterOptions();
        $objFrontendFilterOptions->setAutoSubmit($this->objFilterConfig->metamodel_fef_autosubmit ? true : false);
        $objFrontendFilterOptions->setHideClearFilter(
            $this->objFilterConfig->metamodel_fef_hideclearfilter ? true : false
        );
        $objFrontendFilterOptions->setShowCountValues(
            $this->objFilterConfig->metamodel_available_values ? true : false
        );

        return $objFrontendFilterOptions;
    }

    /**
     * Get the filters.
     *
     * @return array
     *
     * @SuppressWarnings(PHPMD.Superglobals)
     * @SuppressWarnings(PHPMD.CamelCaseVariableName)
     *
     * @throws RedirectResponseException When there was a POST request and we have to reload the page.
     */
    protected function getFilters()
    {
        $filterOptions     = $this->getFrontendFilterOptions();
        $jumpToInformation = $this->objFilterConfig->getJumpTo();
        $filterSetting     = $this->objFilterConfig->getFilterCollection();
        $wantedNames       = $this->getWantedNames();

        $this->buildParameters(
            $other = new FilterUrl($jumpToInformation),
            $all   = new FilterUrl($jumpToInformation),
            $wantedNames
        );

        // DAMN Contao - we have to "mark" the keys in the Input class as used as we get an 404 otherwise.
        foreach ($wantedNames as $name) {
            if ($all->hasSlug($name)) {
                Input::get($name);
            }
        }

        $arrWidgets = $filterSetting->getParameterFilterWidgets(
            $all->getSlugParameters(),
            $jumpToInformation,
            $filterOptions
        );

        // If we have POST data, we need to redirect now.
        if (Input::post('FORM_SUBMIT') === $this->formId) {
            foreach ($wantedNames as $widgetName) {
                $filter = $arrWidgets[$widgetName];
                if (null !== $filter['urlvalue']) {
                    $other->setSlug($widgetName, $filter['urlvalue']);
                }
            }

            throw new RedirectResponseException($this->filterUrlBuilder->generate($other));
        }

        $renderedWidgets = [];

        // Render the widgets through the filter templates.
        foreach ($wantedNames as $strWidget) {
            $renderedWidgets[$strWidget] = $this->renderWidget($arrWidgets[$strWidget], $filterOptions);
        }

        // Return filter data.
        return [
            'action'     => $this->filterUrlBuilder->generate($other),
            'formid'     => $this->formId,
            'filters'    => $renderedWidgets,
            'submit'     => (
                $filterOptions->isAutoSubmit()
                    ? ''
                    : $GLOBALS['TL_LANG']['metamodels_frontendfilter']['submit']
                )
        ];
    }

    /**
     * Retrieve the parameter values.
     *
     * @param FilterUrl $other       Destination for "other" parameters (not originating from current filter module).
     * @param FilterUrl $all         Destination for "all" parameters.
     * @param string[]  $wantedNames The wanted parameter names.
     *
     * @return void
     */
    protected function buildParameters(FilterUrl $other, FilterUrl $all, array $wantedNames): void
    {
        $current = $this->filterUrlBuilder->getCurrentFilterUrl([
            'postAsSlug'  => $wantedNames,
            'postAsGet'   => [],
            'preserveGet' => true
        ]);
        foreach ($current->getSlugParameters() as $name => $value) {
            $all->setSlug($name, $value);
            if (!in_array($name, $wantedNames)) {
                $other->setSlug($name, $value);
            }
        }
        foreach ($current->getGetParameters() as $name => $value) {
            $all->setGet($name, $value);
            if (!in_array($name, $wantedNames)) {
                $other->setGet($name, $value);
            }
        }
    }

    /**
     * Render a content element.
     *
     * @param string $content   The html content in which to replace.
     *
     * @param string $replace   The string within the html to be replaced.
     *
     * @param int    $contentId The id of the content element to be inserted for the replace string.
     *
     * @return string
     */
    protected function generateContentElement($content, $replace, $contentId)
    {
        return $this->generateElement('tl_content', $content, $replace, $contentId);
    }

    /**
     * Render a module.
     *
     * @param string $content  The html content in which to replace.
     *
     * @param string $replace  The string within the html to be replaced.
     *
     * @param int    $moduleId The id of the module to be inserted for the replace string.
     *
     * @return string
     */
    protected function generateModule($content, $replace, $moduleId)
    {
        return $this->generateElement('tl_module', $content, $replace, $moduleId);
    }

    /**
     * Render a module or content element.
     *
     * @param string $table     The name of the table.
     *
     * @param string $content   The html content in which to replace.
     *
     * @param string $replace   The string within the html to be replaced.
     *
     * @param int    $elementId The id of the module/ce-element to be inserted for the replace string.
     *
     * @return string
     *
     * @throws \Doctrine\DBAL\DBALException When a database error occur.
     */
    protected function generateElement($table, $content, $replace, $elementId)
    {
        $sql = sprintf('SELECT * FROM %s WHERE id=? AND type="metamodels_frontendclearall"', $table);

        $statement = $this->connection->prepare($sql);
        $statement->bindValue(1, $elementId);
        $statement->execute();

        $objDbResult = $statement->fetch(\PDO::FETCH_OBJ);

        // Check if we have a existing module or ce element.
        if ($objDbResult === false) {
            return str_replace($replace, '', $content);
        }

        // Get instance and call generate function.
        if ($table == 'tl_module') {
            $objElement = new ModuleFilterClearAll($objDbResult);
        } elseif ($table == 'tl_content') {
            $objElement = new ContentElementFilterClearAll($objDbResult);
        } else {
            return str_replace($replace, '', $content);
        }

        return str_replace($replace, $objElement->generateReal(), $content);
    }

    /**
     * Add the "clear all Filter".
     *
     * This is called via parseTemplate HOOK to inject the "clear all" filter into fe_page.
     *
     * @param string $strContent  The whole page content.
     *
     * @param string $strTemplate The name of the template being parsed.
     *
     * @return string
     *
     * @throws \RuntimeException When an invalid selector has been used (different than "ce" or "mod").
     */
    public function generateClearAll($strContent, $strTemplate)
    {
        if (substr($strTemplate, 0, 3) === 'fe_') {
            if (preg_match_all(
                '#\[\[\[metamodelfrontendfilterclearall::(ce|mod)::([^\]]*)\]\]\]#',
                $strContent,
                $arrMatches,
                PREG_SET_ORDER
            )) {
                foreach ($arrMatches as $arrMatch) {
                    switch ($arrMatch[1]) {
                        case 'ce':
                            $strContent = $this->generateContentElement($strContent, $arrMatch[0], $arrMatch[2]);
                            break;

                        case 'mod':
                            $strContent = $this->generateModule($strContent, $arrMatch[0], $arrMatch[2]);
                            break;

                        default:
                            throw new \RuntimeException('Unexpected element determinator encountered: ' . $arrMatch[1]);
                    }
                }
            }
        }

        return $strContent;
    }
}


<?php

/**
 * This file is part of MetaModels/core.
 *
 * (c) 2012-2019 The MetaModels team.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * This project is provided in good faith and hope to be usable by anyone.
 *
 * @package    MetaModels/core
 * @author     Christian Schiffler <c.schiffler@cyberspectrum.de>
 * @author     Sven Baumann <baumann.sv@gmail.com>
 * @author     David Molineus <david.molineus@netzmacht.de>
 * @copyright  2012-2019 The MetaModels team.
 * @license    https://github.com/MetaModels/core/blob/master/LICENSE LGPL-3.0-or-later
 * @filesource
 */

namespace MetaModels\Filter\Setting;

/**
 * This is an abstract factory to query instances of attributes.
 *
 * Extend your own attribute factories from this class and register them when the create attribute factory event is
 * triggered.
 */
abstract class AbstractFilterSettingTypeFactory implements IFilterSettingTypeFactory
{
    /**
     * The type name.
     *
     * @var string
     */
    private $typeName;

    /**
     * The name of the attribute class of this type.
     *
     * @var string
     */
    private $typeClass;

    /**
     * The icon representing this filter setting type.
     *
     * @var string
     */
    private $typeIcon;

    /**
     * The maximum amount of children allowed.
     *
     * If null, unlimited.
     *
     * @var int|null
     */
    private $maxChildren;

    /**
     * List of valid attribute types that can be filtered with this filter.
     *
     * @var string[]
     */
    private $attributeTypes;

    /**
     * Cache lookup variable.
     *
     * @var bool
     */
    private $isNestedType;

    /**
     * Create a new instance.
     */
    protected function __construct()
    {
        // Nothing to do, aside from making the constructor protected.
    }

    /**
     * Set the type class.
     *
     * @param string $typeClass The name of the class.
     *
     * @return AbstractFilterSettingTypeFactory
     */
    protected function setTypeClass($typeClass)
    {
        $this->typeClass = $typeClass;

        return $this;
    }

    /**
     * Get the type class.
     *
     * @return string|null
     */
    protected function getTypeClass(): ?string
    {
        return $this->typeClass;
    }

    /**
     * Set the type name.
     *
     * @param string $typeName The type name.
     *
     * @return AbstractFilterSettingTypeFactory
     */
    protected function setTypeName($typeName)
    {
        $this->typeName = $typeName;

        return $this;
    }

    /**
     * {@inheritdoc}
     */
    public function getTypeName()
    {
        return $this->typeName;
    }

    /**
     * Set the type icon.
     *
     * @param string $typeIcon The type icon to use.
     *
     * @return AbstractFilterSettingTypeFactory
     */
    protected function setTypeIcon($typeIcon)
    {
        $this->typeIcon = $typeIcon;

        return $this;
    }

    /**
     * {@inheritdoc}
     */
    public function getTypeIcon()
    {
        return $this->typeIcon;
    }

    /**
     * {@inheritdoc}
     */
    public function createInstance($information, $filterSettings)
    {
        return new $this->typeClass($filterSettings, $information);
    }

    /**
     * Check if the type allows children.
     *
     * @return bool
     */
    public function isNestedType()
    {
        if (!isset($this->isNestedType)) {
            $this->isNestedType = in_array(
                'MetaModels\Filter\Setting\IWithChildren',
                class_implements($this->typeClass, true)
            );
        }

        return $this->isNestedType;
    }

    /**
     * Set the maximum amount of allowed children (only valid when isNestedType() == true).
     *
     * @param int|null $maxChildren The amount of children.
     *
     * @return AbstractFilterSettingTypeFactory
     *
     * @throws \LogicException When the filter setting can not handle children (is not nested type).
     */
    protected function setMaxChildren($maxChildren)
    {
        if (!$this->isNestedType()) {
            throw new \LogicException('Filter setting ' . $this->typeClass . ' can not handle children.');
        }

        $this->maxChildren = $maxChildren;

        return $this;
    }

    /**
     * {@inheritdoc}
     */
    public function getMaxChildren()
    {
        return $this->isNestedType() ? $this->maxChildren : 0;
    }

    /**
     * Setup the allowance of attribute types to be added to this factory.
     *
     * This must be called before any calls to addKnownAttributeType() is allowed.
     *
     * You can pass as many parameters as you need.
     *
     * Either pass one parameter as array of string or pass 1 to n parameters as string.
     *
     * @param string|string[] $initialType1toN One or more attribute type names to be available initially (optional).
     *
     * @return AbstractFilterSettingTypeFactory
     *
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
     */
    protected function allowAttributeTypes($initialType1toN = null)
    {
        if (is_array($initialType1toN)) {
            $this->attributeTypes = $initialType1toN;
        } else {
            $this->attributeTypes = func_get_args();
        }

        return $this;
    }

    /**
     * Retrieve the list of known attribute types.
     *
     * @return string[] The list of attribute names or null if no attributes are allowed.
     */
    public function getKnownAttributeTypes()
    {
        return $this->attributeTypes;
    }

    /**
     * Retrieve the list of known attribute types.
     *
     * @param string $typeName The attribute type name.
     *
     * @return IFilterSettingTypeFactory
     *
     * @throws \LogicException When the filter setting can not handle attributes.
     */
    public function addKnownAttributeType($typeName)
    {
        if (!is_array($this->attributeTypes)) {
            throw new \LogicException('Filter setting ' . $this->typeClass . ' can not handle attributes.');
        }

        $this->attributeTypes[$typeName] = $typeName;

        return $this;
    }
}


<?php

/**
 * This file is part of MetaModels/core.
 *
 * (c) 2012-2019 The MetaModels team.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * This project is provided in good faith and hope to be usable by anyone.
 *
 * @package    MetaModels/core
 * @author     Christian Schiffler <c.schiffler@cyberspectrum.de>
 * @author     Sven Baumann <baumann.sv@gmail.com>
 * @copyright  2012-2019 The MetaModels team.
 * @license    https://github.com/MetaModels/core/blob/master/LICENSE LGPL-3.0-or-later
 * @filesource
 */

namespace MetaModels\Filter\Setting;

use MetaModels\Filter\IFilter;
use MetaModels\Filter\Rules\StaticIdList as FilterRuleIdList;

/**
 * Filter setting implementation of a static list of matching ids.
 */
class IdList extends Simple
{
    /**
     * {@inheritDoc}
     *
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
     */
    public function prepareRules(IFilter $objFilter, $arrFilterUrl)
    {
        if ($this->get('items')) {
            $arrItems = explode(',', (string) $this->get('items'));
        } else {
            $arrItems = array();
        }
        $objFilter->addFilterRule(new FilterRuleIdList($arrItems));
    }
}


<?php

/**
 * This file is part of MetaModels/core.
 *
 * (c) 2012-2019 The MetaModels team.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * This project is provided in good faith and hope to be usable by anyone.
 *
 * @package    MetaModels/core
 * @author     Christian Schiffler <c.schiffler@cyberspectrum.de>
 * @author     Sven Baumann <baumann.sv@gmail.com>
 * @copyright  2012-2019 The MetaModels team.
 * @license    https://github.com/MetaModels/core/blob/master/LICENSE LGPL-3.0-or-later
 * @filesource
 */

namespace MetaModels\CoreBundle\Controller\Backend;

use MetaModels\Attribute\IAttribute;
use MetaModels\Attribute\IInternal;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

/**
 * This controller provides the add-all action in input screens.
 */
class InputScreenAddAllController extends AbstractAddAllController
{
    /**
     * Invoke this.
     *
     * @param string  $metaModel   The MetaModel name.
     * @param string  $inputScreen The input screen id.
     * @param Request $request     The request.
     *
     * @return Response
     */
    public function __invoke($metaModel, $inputScreen, Request $request)
    {
        return $this->process('tl_metamodel_dcasetting', $metaModel, $inputScreen, $request);
    }

    /**
     * {@inheritDoc}
     *
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
     */
    protected function createEmptyDataFor(IAttribute $attribute, $parentId, $activate, $sort)
    {
        return [
            'dcatype'   => 'attribute',
            'tl_class'  => '',
            'attr_id'   => $attribute->get('id'),
            'pid'       => $parentId,
            'sorting'   => $sort,
            'tstamp'    => time(),
            'published' => $activate ? '1' : ''
        ];
    }

    /**
     * Test if the passed attribute is acceptable.
     *
     * @param IAttribute $attribute The attribute to check.
     *
     * @return bool
     */
    protected function accepts(IAttribute $attribute)
    {
        return !($attribute instanceof IInternal) && !empty($attribute->get('id'));
    }
}


<?php

/**
 * This file is part of MetaModels/core.
 *
 * (c) 2012-2019 The MetaModels team.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * This project is provided in good faith and hope to be usable by anyone.
 *
 * @package    MetaModels/core
 * @author     Christian Schiffler <c.schiffler@cyberspectrum.de>
 * @author     Sven Baumann <baumann.sv@gmail.com>
 * @copyright  2012-2019 The MetaModels team.
 * @license    https://github.com/MetaModels/core/blob/master/LICENSE LGPL-3.0-or-later
 * @filesource
 */

namespace MetaModels\CoreBundle\EventListener\DcGeneral\Table\DcaSettingCondition;

use ContaoCommunityAlliance\DcGeneral\Contao\RequestScopeDeterminator;
use ContaoCommunityAlliance\DcGeneral\Contao\View\Contao2BackendView\Event\GetPropertyOptionsEvent;
use ContaoCommunityAlliance\DcGeneral\Event\AbstractEnvironmentAwareEvent;
use Doctrine\DBAL\Connection;
use MetaModels\CoreBundle\DcGeneral\PropertyConditionFactory;
use MetaModels\IFactory;
use Symfony\Component\Translation\TranslatorInterface;

/**
 * This handles the type options for conditions.
 */
class TypeOptionsListener extends AbstractConditionFactoryUsingListener
{
    /**
     * The translator.
     *
     * @var TranslatorInterface
     */
    private $translator;

    /**
     * Create a new instance.
     *
     * @param RequestScopeDeterminator $scopeDeterminator The scope determinator.
     * @param IFactory                 $factory           The MetaModel factory.
     * @param Connection               $connection        The database connection.
     * @param PropertyConditionFactory $conditionFactory  The condition factory.
     * @param TranslatorInterface      $translator        The translator.
     */
    public function __construct(
        RequestScopeDeterminator $scopeDeterminator,
        IFactory $factory,
        Connection $connection,
        PropertyConditionFactory $conditionFactory,
        TranslatorInterface $translator
    ) {
        parent::__construct($scopeDeterminator, $factory, $connection, $conditionFactory);
        $this->translator = $translator;
    }

    /**
     * Provide options for property condition types.
     *
     * @param GetPropertyOptionsEvent $event The event.
     *
     * @return void
     *
     * @SuppressWarnings(PHPMD.Superglobals)
     * @SuppressWarnings(PHPMD.CamelCaseVariableName)
     */
    public function handle(GetPropertyOptionsEvent $event)
    {
        if (!$this->wantToHandle($event)) {
            return;
        }

        $options = [];
        foreach ($this->conditionFactory->getTypeNames() as $condition) {
            $options[$condition] = $this->translator->trans(
                'tl_metamodel_dcasetting_condition.conditionnames.' . $condition,
                [],
                'contao_tl_metamodel_dcasetting_condition'
            );
        }

        $event->setOptions($options);
    }

    /**
     * {@inheritDoc}
     */
    protected function wantToHandle(AbstractEnvironmentAwareEvent $event)
    {
        /** @var GetPropertyOptionsEvent $event */
        return parent::wantToHandle($event) && ('type' === $event->getPropertyName());
    }
}


<?php

/**
 * This file is part of MetaModels/core.
 *
 * (c) 2012-2019 The MetaModels team.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * This project is provided in good faith and hope to be usable by anyone.
 *
 * @package    MetaModels/core
 * @author     Christian Schiffler <c.schiffler@cyberspectrum.de>
 * @author     Sven Baumann <baumann.sv@gmail.com>
 * @author     Cliff Parnitzky <github@cliff-parnitzky.de>
 * @author     David Molineus <david.molineus@netzmacht.de>
 * @copyright  2012-2019 The MetaModels team.
 * @license    https://github.com/MetaModels/core/blob/master/LICENSE LGPL-3.0-or-later
 * @filesource
 */

namespace MetaModels\DcGeneral\DataDefinition\Palette\Condition\Palette;

use Contao\System;
use ContaoCommunityAlliance\DcGeneral\Data\ModelInterface;
use ContaoCommunityAlliance\DcGeneral\Data\PropertyValueBag;
use ContaoCommunityAlliance\DcGeneral\DataDefinition\Palette\Condition\Palette\AbstractWeightAwarePaletteCondition;
use Doctrine\DBAL\Connection;

/**
 * Condition for the default palette.
 */
class RenderSettingAttributeIs extends AbstractWeightAwarePaletteCondition
{
    /**
     * The expected property value.
     *
     * @var mixed
     */
    protected $attributeType;

    /**
     * Buffer the attribute types to ease lookup.
     *
     * @var array
     */
    protected static $attributeTypes = array();

    /**
     * Database connection.
     *
     * @var Connection
     */
    private $connection;

    /**
     * Create a new instance.
     *
     * @param string          $attributeType The attribute type name.
     *
     * @param int             $weight        The weight of this condition to apply.
     *
     * @param Connection|null $connection    Database connection.
     */
    public function __construct($attributeType, $weight = 1, Connection $connection = null)
    {
        $this->attributeType = $attributeType;
        $this->setWeight($weight);

        if (null === $connection) {
            // @codingStandardsIgnoreStart
            @trigger_error(
                'Connection is missing. It has to be passed in the constructor. Fallback will be dropped.',
                E_USER_DEPRECATED
            );
            // @codingStandardsIgnoreEnd
            $connection = System::getContainer()->get('database_connection');
        }

        $this->connection = $connection;
    }

    /**
     * Set the attribute type name.
     *
     * @param string $attributeType The attribute type name.
     *
     * @return RenderSettingAttributeIs
     */
    public function setAttributeType($attributeType)
    {
        $this->attributeType = $attributeType;

        return $this;
    }

    /**
     * Retrieve the attribute type name.
     *
     * @return mixed
     */
    public function getAttributeType()
    {
        return $this->attributeType;
    }

    /**
     * Retrieve the type name from an attribute.
     *
     * @param int $value The id of an attribute.
     *
     * @return string
     *
     * @throws \Doctrine\DBAL\DBALException When an database error occurs.
     */
    public function getTypeOfAttribute($value)
    {
        if (!isset(self::$attributeTypes[$value])) {
            $statement = $this->connection->prepare('SELECT type FROM tl_metamodel_attribute WHERE id=? LIMIT 0,1');
            $statement->bindValue(1, $value);
            $statement->execute();

            self::$attributeTypes[$value] = $statement->fetch(\PDO::FETCH_OBJ)->type;
        }

        return self::$attributeTypes[$value];
    }

    /**
     * {@inheritdoc}
     */
    public function getMatchCount(ModelInterface $model = null, PropertyValueBag $input = null)
    {
        if ($input && $input->hasPropertyValue('attr_id')) {
            $value = $input->getPropertyValue('attr_id');
        } elseif ($model) {
            $value = $model->getProperty('attr_id');
        } else {
            return false;
        }

        return ($this->getTypeOfAttribute($value) == $this->getAttributeType()) ? $this->getWeight() : false;
    }

    /**
     * {@inheritdoc}
     */
    public function __clone()
    {
    }

    /**
     * Retrieve the service container.
     *
     * @return IMetaModelsServiceContainer
     *
     * @SuppressWarnings(PHPMD.Superglobals)
     * @SuppressWarnings(PHPMD.CamelCaseVariableName)
     */
    protected function getServiceContainer()
    {
        return $GLOBALS['container']['metamodels-service-container'];
    }
}


<?php

/**
 * This file is part of MetaModels/core.
 *
 * (c) 2012-2019 The MetaModels team.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * This project is provided in good faith and hope to be usable by anyone.
 *
 * @package    MetaModels/core
 * @author     David Molineus <david.molineus@netzmacht.de>
 * @author     Sven Baumann <baumann.sv@gmail.com>
 * @copyright  2012-2019 The MetaModels team.
 * @license    https://github.com/MetaModels/core/blob/master/LICENSE LGPL-3.0-or-later
 * @filesource
 */

namespace MetaModels\Exceptions\Database;

/**
 * Class TableDoesNotExistException
 */
class ColumnExistsException extends \RuntimeException
{
    /**
     * Create a new exception for an existing column.
     *
     * @param string     $columnName The column name.
     * @param string     $tableName  The table name.
     * @param int        $code       The optional Exception code.
     * @param \Exception $previous   The optional previous throwable used for the exception chaining.
     *
     * @return static
     */
    public static function withName($columnName, $tableName, $code = 0, $previous = null)
    {
        return new static(
            sprintf('Column "%s" already exists on table "%s', $columnName, $tableName),
            $code,
            $previous
        );
    }
}


<?php

/**
 * This file is part of MetaModels/core.
 *
 * (c) 2012-2019 The MetaModels team.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * This project is provided in good faith and hope to be usable by anyone.
 *
 * @package    MetaModels/core
 * @author     Christian Schiffler <c.schiffler@cyberspectrum.de>
 * @author     Sven Baumann <baumann.sv@gmail.com>
 * @copyright  2012-2019 The MetaModels team.
 * @license    https://github.com/MetaModels/core/blob/master/LICENSE LGPL-3.0-or-later
 * @filesource
 */

namespace MetaModels\CoreBundle\EventListener\DcGeneral\Table\DcaSortGroup;

use ContaoCommunityAlliance\DcGeneral\Contao\RequestScopeDeterminator;
use ContaoCommunityAlliance\DcGeneral\Data\ModelInterface;
use ContaoCommunityAlliance\DcGeneral\Exception\DcGeneralInvalidArgumentException;
use Doctrine\DBAL\Connection;
use MetaModels\IFactory;
use MetaModels\IMetaModel;

/**
 * This provides a way to obtain a MetaModel.
 */
abstract class AbstractListener extends AbstractAbstainingListener
{
    /**
     * The MetaModel factory.
     *
     * @var IFactory
     */
    protected $factory;

    /**
     * The database connection.
     *
     * @var Connection
     */
    protected $connection;

    /**
     * Create a new instance.
     *
     * @param RequestScopeDeterminator $scopeDeterminator The scope determinator.
     * @param IFactory                 $factory           The MetaModel factory.
     * @param Connection               $connection        The database connection.
     */
    public function __construct(
        RequestScopeDeterminator $scopeDeterminator,
        IFactory $factory,
        Connection $connection
    ) {
        parent::__construct($scopeDeterminator);
        $this->factory    = $factory;
        $this->connection = $connection;
    }

    /**
     * Retrieve the MetaModel the given model is attached to.
     *
     * @param ModelInterface $model The input screen model for which to retrieve the MetaModel.
     *
     * @return IMetaModel
     *
     * @throws DcGeneralInvalidArgumentException When an invalid model has been passed or the model does not have an id.
     */
    protected function getMetaModelFromModel(ModelInterface $model)
    {
        if (!(($model->getProviderName() == 'tl_metamodel_dca_sortgroup') && $model->getProperty('pid'))) {
            throw new DcGeneralInvalidArgumentException(
                sprintf(
                    'Model must originate from tl_metamodel_dca_sortgroup and be saved, this one originates from %s ' .
                    'and has pid %s',
                    $model->getProviderName(),
                    $model->getProperty('pid')
                )
            );
        }

        $metaModelId = $this->connection->createQueryBuilder()
            ->select('pid')
            ->from('tl_metamodel_dca')
            ->where('id=:id')
            ->setParameter('id', $model->getProperty('pid'))
            ->execute()
            ->fetchColumn();

        $tableName = $this->factory->translateIdToMetaModelName($metaModelId);

        return $this->factory->getMetaModel($tableName);
    }
}


<?php

/**
 * This file is part of MetaModels/core.
 *
 * (c) 2012-2019 The MetaModels team.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * This project is provided in good faith and hope to be usable by anyone.
 *
 * @package    MetaModels/core
 * @author     Christian Schiffler <c.schiffler@cyberspectrum.de>
 * @author     Stefan Heimes <stefan_heimes@hotmail.com>
 * @author     Sven Baumann <baumann.sv@gmail.com>
 * @copyright  2012-2019 The MetaModels team.
 * @license    https://github.com/MetaModels/core/blob/master/LICENSE LGPL-3.0-or-later
 * @filesource
 */

namespace MetaModels\DcGeneral\DataDefinition\Palette\Condition\Property;

use ContaoCommunityAlliance\DcGeneral\Data\ModelInterface;
use ContaoCommunityAlliance\DcGeneral\Data\PropertyValueBag;
use ContaoCommunityAlliance\DcGeneral\DataDefinition\Palette\Condition\Property\PropertyConditionInterface;
use ContaoCommunityAlliance\DcGeneral\DataDefinition\Palette\LegendInterface;
use ContaoCommunityAlliance\DcGeneral\DataDefinition\Palette\PropertyInterface;

/**
 * This condition matches as soon as all of the following apply:
 * 1. the MetaModel supports variants.
 * 2. the current item is not a variant base.
 * 3. the attribute is not an invariant attribute.
 */
class IsVariantAttribute implements PropertyConditionInterface
{
    /**
     * {@inheritdoc}
     */
    public function match(
        ModelInterface $model = null,
        PropertyValueBag $input = null,
        PropertyInterface $property = null,
        LegendInterface $legend = null
    ) {
        if ($property === null) {
            return false;
        }

        /** @var $model \MetaModels\DcGeneral\Data\Model */

        $nativeItem = $model->getItem();
        $metaModel  = $nativeItem->getMetaModel();

        if ($metaModel->hasVariants() && !$nativeItem->isVariantBase()) {
            return !in_array($property->getName(), array_keys($metaModel->getInVariantAttributes()));
        }

        return true;
    }

    /**
     * {@inheritdoc}
     */
    public function __clone()
    {
    }
}


<?php

/**
 * This file is part of MetaModels/core.
 *
 * (c) 2012-2019 The MetaModels team.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * This project is provided in good faith and hope to be usable by anyone.
 *
 * @package    MetaModels/core
 * @author     Christian Schiffler <c.schiffler@cyberspectrum.de>
 * @author     Sven Baumann <baumann.sv@gmail.com>
 * @copyright  2012-2019 The MetaModels team.
 * @license    https://github.com/MetaModels/core/blob/master/LICENSE LGPL-3.0-or-later
 * @filesource
 */

namespace MetaModels\CoreBundle\EventListener\DcGeneral\Table\Attribute;

use ContaoCommunityAlliance\DcGeneral\Contao\RequestScopeDeterminator;
use ContaoCommunityAlliance\DcGeneral\Contao\View\Contao2BackendView\Event\GetPropertyOptionsEvent;
use ContaoCommunityAlliance\DcGeneral\Event\AbstractEnvironmentAwareEvent;
use MetaModels\Attribute\IAttributeFactory;
use MetaModels\IFactory;
use Symfony\Component\HttpFoundation\RequestStack;

/**
 * This class provides the attribute type names.
 */
class GetAttributeTypeListener extends BaseListener
{
    /**
     * The request stack.
     *
     * @var RequestStack
     */
    protected $requestStack;

    /**
     * Create a new instance.
     *
     * @param RequestStack             $requestStack      The request stack.
     * @param RequestScopeDeterminator $scopeDeterminator The scope determinator.
     * @param IAttributeFactory        $attributeFactory  The attribute factory.
     * @param IFactory                 $factory           The factory.
     */
    public function __construct(
        RequestStack $requestStack,
        RequestScopeDeterminator $scopeDeterminator,
        IAttributeFactory $attributeFactory,
        IFactory $factory
    ) {
        parent::__construct($scopeDeterminator, $attributeFactory, $factory);
        $this->requestStack = $requestStack;
    }

    /**
     * Provide options for attribute type selection.
     *
     * @param GetPropertyOptionsEvent $event The event.
     *
     * @return void
     */
    public function getOptions(GetPropertyOptionsEvent $event)
    {
        if (!$this->wantToHandle($event)) {
            return;
        }

        $translator   = $event->getEnvironment()->getTranslator();
        $objMetaModel = $this->getMetaModelByModelPid($event->getModel());
        $flags        = IAttributeFactory::FLAG_ALL_UNTRANSLATED;

        if ($objMetaModel->isTranslated()) {
            $flags |= IAttributeFactory::FLAG_INCLUDE_TRANSLATED;
        }

        $options      = [];
        $optionsTrans = [];
        foreach ($this->attributeFactory->getTypeNames($flags) as $attributeType) {
            // Differentiate translated and simple.
            if ($this->attributeFactory->getTypeFactory($attributeType)->isTranslatedType()) {
                $optionsTrans[$attributeType] = $translator->translate(
                    'typeOptions.' . $attributeType,
                    'tl_metamodel_attribute'
                );
            } else {
                $options[$attributeType] = $translator->translate(
                    'typeOptions.' . $attributeType,
                    'tl_metamodel_attribute'
                );
            }
        }
        asort($options);

        // Add translated attributes.
        if ($objMetaModel->isTranslated()) {
            asort($optionsTrans);
            $options = array_merge($options, $optionsTrans);
        }

        $event->setOptions($options);
    }

    /**
     * Test if we want to handle the event.
     *
     * @param AbstractEnvironmentAwareEvent $event The event to evaluate.
     *
     * @return bool
     */
    protected function wantToHandle(AbstractEnvironmentAwareEvent $event)
    {
        /** @var GetPropertyOptionsEvent $event */
        if (!parent::wantToHandle($event)) {
            return false;
        }
        if ($event->getPropertyName() !== 'type') {
            return false;
        }

        $request = $this->requestStack->getCurrentRequest();
        if ($request->request->get('act', null) === 'select' && !$event->getModel()->getId()) {
            return false;
        }

        return true;
    }
}


<?php

/**
 * This file is part of MetaModels/core.
 *
 * (c) 2012-2019 The MetaModels team.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * This project is provided in good faith and hope to be usable by anyone.
 *
 * @package    MetaModels/core
 * @author     Christian Schiffler <c.schiffler@cyberspectrum.de>
 * @author     Sven Baumann <baumann.sv@gmail.com>
 * @copyright  2012-2019 The MetaModels team.
 * @license    https://github.com/MetaModels/core/blob/master/LICENSE LGPL-3.0-or-later
 * @filesource
 */

namespace MetaModels\Widgets;

use Contao\StringUtil;
use Contao\Widget;

/**
 * Form field with more than 1 input, based on form field by Leo Feyer.
 */
class MultiTextWidget extends Widget
{
    /**
     * Submit user input.
     *
     * @var boolean
     */
    protected $blnSubmitInput = true;

    /**
     * The template to use.
     *
     * @var string
     */
    protected $strTemplate = 'form_widget';

    /**
     * Add specific attributes.
     *
     * @param string $strKey   Name of the key to set.
     *
     * @param mixed  $varValue The value to use.
     *
     * @return void
     */
    public function __set($strKey, $varValue)
    {
        switch ($strKey) {
            case 'maxlength':
                if ($varValue > 0) {
                    $this->arrAttributes['maxlength'] = $varValue;
                }
                break;

            case 'mandatory':
                if ($varValue) {
                    $this->arrAttributes['required'] = 'required';
                } else {
                    unset($this->arrAttributes['required']);
                }
                parent::__set($strKey, $varValue);
                break;

            case 'placeholder':
                $this->arrAttributes['placeholder'] = $varValue;
                break;

            default:
                parent::__set($strKey, $varValue);
                break;
        }
    }

    /**
     * Trim the values and validate them.
     *
     * @param mixed $varInput The value to process.
     *
     * @return mixed The processed value
     */
    protected function validator($varInput)
    {
        if (is_array($varInput)) {
            $value = array();
            foreach ($varInput as $key => $input) {
                $value[$key] = parent::validator($input);
            }

            return $value;
        }

        return parent::validator(trim($varInput));
    }

    /**
     * Generate the widget and return it as string.
     *
     * @return string
     */
    public function generate()
    {
        $return = '';
        for ($i = 0; $i < $this->size; $i++) {
            $return .= sprintf(
                '<input type="%s" name="%s[]" id="ctrl_%s_%s" class="text%s%s" value="%s"%s%s',
                'text',
                $this->strName,
                $this->strId,
                $i,
                '',
                (strlen($this->strClass) ? ' ' . $this->strClass : ''),
                StringUtil::specialchars($this->varValue[$i]),
                $this->getAttributes(),
                $this->strTagEnding
            );
        }

        return $return;
    }
}


<?php

/**
 * This file is part of MetaModels/core.
 *
 * (c) 2012-2019 The MetaModels team.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * This project is provided in good faith and hope to be usable by anyone.
 *
 * @package    MetaModels/core
 * @author     Christian Schiffler <c.schiffler@cyberspectrum.de>
 * @author     Sven Baumann <baumann.sv@gmail.com>
 * @copyright  2012-2019 The MetaModels team.
 * @license    https://github.com/MetaModels/core/blob/master/LICENSE LGPL-3.0-or-later
 * @filesource
 */

namespace MetaModels\CoreBundle\EventListener\DcGeneral\Table\MetaModel;

use ContaoCommunityAlliance\DcGeneral\Contao\RequestScopeDeterminator;
use ContaoCommunityAlliance\DcGeneral\Event\PostPersistModelEvent;
use ContaoCommunityAlliance\DcGeneral\Event\PreDeleteModelEvent;
use MetaModels\Helper\TableManipulator;

/**
 * This handles table renaming and table deleting.
 */
class TableUpdatingListener extends AbstractAbstainingListener
{
    /**
     * The table manipulator.
     *
     * @var TableManipulator
     */
    private $tableManipulator;

    /**
     * Create a new instance.
     *
     * @param RequestScopeDeterminator $scopeDeterminator The scope determinator.
     * @param TableManipulator         $tableManipulator  The table manipulator.
     */
    public function __construct(RequestScopeDeterminator $scopeDeterminator, TableManipulator $tableManipulator)
    {
        parent::__construct($scopeDeterminator);
        $this->tableManipulator = $tableManipulator;
    }

    /**
     * Handle the deletion of a MetaModel and all attached data.
     *
     * @param PreDeleteModelEvent $event The event.
     *
     * @return void
     */
    public function handleDelete(PreDeleteModelEvent $event)
    {
        if (!$this->wantToHandle($event)) {
            return;
        }

        try {
            $this->tableManipulator->checkTableExists($tableName = $event->getModel()->getProperty('tableName'));
        } catch (\Exception $exception) {
            // Exit if table does not exist.
            return;
        }

        $this->tableManipulator->deleteTable($tableName);
    }

    /**
     * Handle the update of a MetaModel and all attached data.
     *
     * @param PostPersistModelEvent $event The event.
     *
     * @return void
     */
    public function handleUpdate(PostPersistModelEvent $event)
    {
        if (!$this->wantToHandle($event)) {
            return;
        }

        $old      = $event->getOriginalModel();
        $new      = $event->getModel();
        $oldTable = $old ? $old->getProperty('tableName') : null;
        $newTable = $new->getProperty('tableName');

        // Table name changed?
        if ($oldTable !== $newTable) {
            if (!empty($oldTable)) {
                $this->tableManipulator->renameTable($oldTable, $newTable);
            } else {
                $this->tableManipulator->createTable($newTable);
            }
        }

        $this->tableManipulator->setVariantSupport($newTable, $new->getProperty('varsupport'));
    }
}


<?php

/**
 * This file is part of MetaModels/core.
 *
 * (c) 2012-2019 The MetaModels team.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * This project is provided in good faith and hope to be usable by anyone.
 *
 * @package    MetaModels/core
 * @author     Christian Schiffler <c.schiffler@cyberspectrum.de>
 * @copyright  2012-2019 The MetaModels team.
 * @license    https://github.com/MetaModels/core/blob/master/LICENSE LGPL-3.0-or-later
 * @filesource
 */

namespace MetaModels\CoreBundle\EventListener\DcGeneral\Table\DcaSetting;

use ContaoCommunityAlliance\DcGeneral\Contao\View\Contao2BackendView\Event\GetSelectModeButtonsEvent;

/**
 * This class takes care of removing the override button when select mode is active.
 */
class RemoveOverrideButtonListener
{
    /**
     * Remove the select button when in list view and override/edit all is active.
     *
     * @param GetSelectModeButtonsEvent $event The event.
     *
     * @return void
     */
    public function removeButton(GetSelectModeButtonsEvent $event)
    {
        if (('tl_metamodel_dcasetting' !== $event->getEnvironment()->getDataDefinition()->getName())
            || ('select' !== $event->getEnvironment()->getInputProvider()->getParameter('act'))
        ) {
            return;
        }

        $buttons = $event->getButtons();
        unset($buttons['override']);

        $event->setButtons($buttons);
    }
}


<?php

/**
 * This file is part of MetaModels/core.
 *
 * (c) 2012-2019 The MetaModels team.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * This project is provided in good faith and hope to be usable by anyone.
 *
 * @package    MetaModels/core
 * @author     Christian Schiffler <c.schiffler@cyberspectrum.de>
 * @author     Sven Baumann <baumann.sv@gmail.com>
 * @copyright  2012-2019 The MetaModels team.
 * @license    https://github.com/MetaModels/core/blob/master/LICENSE LGPL-3.0-or-later
 * @filesource
 */

namespace MetaModels\Events;

use MetaModels\IFactory;
use Symfony\Component\EventDispatcher\Event;

/**
 * This event is triggered to collect the names of all known MetaModels.
 */
class CollectMetaModelTableNamesEvent extends Event
{
    /**
     * The event name.
     */
    const NAME = 'metamodels.metamodel.collect-table-names';

    /**
     * The factory calling the event.
     *
     * @var IFactory
     */
    protected $factory;

    /**
     * The names of the MetaModels.
     *
     * @var string[]
     */
    protected $metaModelNames = array();

    /**
     * Create a new instance.
     *
     * @param IFactory $factory The MetaModel factory dispatching this event.
     */
    public function __construct($factory)
    {
        $this->factory = $factory;
    }

    /**
     * Retrieve the factory.
     *
     * @return IFactory
     */
    public function getFactory()
    {
        return $this->factory;
    }

    /**
     * Retrieve the MetaModel name to be created.
     *
     * @return string[]
     */
    public function getMetaModelNames()
    {
        return $this->metaModelNames;
    }

    /**
     * Set the MetaModel instance.
     *
     * @param string[] $metaModelNames The MetaModel names.
     *
     * @return CollectMetaModelTableNamesEvent
     */
    public function setMetaModelNames($metaModelNames)
    {
        $this->metaModelNames = $metaModelNames;

        return $this;
    }

    /**
     * Set the MetaModel instance.
     *
     * @param string[] $metaModelNames The MetaModel names.
     *
     * @return CollectMetaModelTableNamesEvent
     */
    public function addMetaModelNames($metaModelNames)
    {
        $this->metaModelNames = array_unique(array_merge($this->metaModelNames, $metaModelNames));

        return $this;
    }
}


<?php

/**
 * This file is part of MetaModels/core.
 *
 * (c) 2012-2019 The MetaModels team.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * This project is provided in good faith and hope to be usable by anyone.
 *
 * @package    MetaModels/core
 * @author     Christian Schiffler <c.schiffler@cyberspectrum.de>
 * @author     David Molineus <david.molineus@netzmacht.de>
 * @author     Sven Baumann <baumann.sv@gmail.com>
 * @copyright  2012-2019 The MetaModels team.
 * @license    https://github.com/MetaModels/core/blob/master/LICENSE LGPL-3.0-or-later
 * @filesource
 */

namespace MetaModels\CoreBundle\DependencyInjection;

use Doctrine\Common\Cache\ArrayCache;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Extension\Extension;
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;

/**
 * This is the class that loads and manages the bundle configuration
 */
class MetaModelsCoreExtension extends Extension
{
    /**
     * The configuration files.
     *
     * @var string[]
     */
    private static $files = [
        'config.yml',
        'filter-settings.yml',
        'hooks.yml',
        'listeners.yml',
        'property-conditions.yml',
        'services.yml',
        'dc-general/breadcrumb.yml',
        'dc-general/definition-builder.yml',
        'dc-general/environment-populator.yml',
        'dc-general/listener.yml',
        'dc-general/table/tl_attribute.yml',
        'dc-general/table/tl_dca.yml',
        'dc-general/table/tl_dca_combine.yml',
        'dc-general/table/tl_dca_sortgroup.yml',
        'dc-general/table/tl_dcasetting.yml',
        'dc-general/table/tl_dcasetting_condition.yml',
        'dc-general/table/tl_filtersetting.yml',
        'dc-general/table/tl_metamodel.yml',
        'dc-general/table/tl_metamodel_rendersetting.yml',
        'dc-general/table/tl_metamodel_rendersettings.yml',
        'dc-general/table/tl_metamodel_searchable_pages.yml',
    ];

    /**
     * {@inheritDoc}
     */
    public function load(array $configs, ContainerBuilder $container)
    {
        $loader = new YamlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config'));
        foreach (self::$files as $file) {
            $loader->load($file);
        }

        $config = $this->processConfiguration($this->getConfiguration($configs, $container), $configs);
        $this->buildCacheService($container, $config);

        $container->setParameter('metamodels.resource_dir', __DIR__ . '/../Resources');
        $container->setParameter('metamodels.assets_dir', $config['assets_dir']);
        $container->setParameter('metamodels.assets_web', $config['assets_web']);

        $this->buildPickerService($container);
    }

    /**
     * {@inheritdoc}
     */
    public function getConfiguration(array $config, ContainerBuilder $container)
    {
        return new Configuration(
            $container->getParameter('kernel.debug'),
            $container->getParameter('kernel.project_dir')
        );
    }

    /**
     * Build the cache service.
     *
     * @param ContainerBuilder $container The container builder.
     * @param array            $config    The configuration.
     *
     * @return void
     */
    private function buildCacheService(ContainerBuilder $container, array $config)
    {
        // if cache disabled, swap it out with the dummy cache.
        if (!$config['enable_cache']) {
            $cache = $container->getDefinition('metamodels.cache');
            $cache->setClass(ArrayCache::class);
            $cache->setArguments([]);
            $container->setParameter('metamodels.cache_dir', null);
            return;
        }

        $container->setParameter('metamodels.cache_dir', $config['cache_dir']);
    }

    /**
     * Build the picker service.
     *
     * @param ContainerBuilder $container The container.
     *
     * @return void
     */
    private function buildPickerService(ContainerBuilder $container)
    {
        $pickerService = $container->getDefinition('metamodels.controller.picker');
        $configs       = $pickerService->getArgument(2);

        // Selectable styles in the palette tl_class definitions.
        $configs['PALETTE_STYLE_PICKER'][] = ['cssclass' => 'w50'];
        $configs['PALETTE_STYLE_PICKER'][] = ['cssclass' => 'w50x'];
        $configs['PALETTE_STYLE_PICKER'][] = ['cssclass' => 'clr'];
        $configs['PALETTE_STYLE_PICKER'][] = ['cssclass' => 'clx'];
        $configs['PALETTE_STYLE_PICKER'][] = ['cssclass' => 'long'];
        $configs['PALETTE_STYLE_PICKER'][] = ['cssclass' => 'wizard'];
        $configs['PALETTE_STYLE_PICKER'][] = ['cssclass' => 'm12'];
        // Selectable panels in the palette panelLayout definitions.
        $configs['PALETTE_PANEL_PICKER'][] = ['cssclass' => 'search'];
        $configs['PALETTE_PANEL_PICKER'][] = ['cssclass' => 'sort'];
        $configs['PALETTE_PANEL_PICKER'][] = ['cssclass' => 'filter'];
        $configs['PALETTE_PANEL_PICKER'][] = ['cssclass' => 'limit'];

        $pickerService->setArgument(2, $configs);
    }
}


<?php

/**
 * This file is part of MetaModels/core.
 *
 * (c) 2012-2019 The MetaModels team.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * This project is provided in good faith and hope to be usable by anyone.
 *
 * @package    MetaModels/core
 * @author     Christian Schiffler <c.schiffler@cyberspectrum.de>
 * @author     Sven Baumann <baumann.sv@gmail.com>
 * @copyright  2012-2019 The MetaModels team.
 * @license    https://github.com/MetaModels/core/blob/master/LICENSE LGPL-3.0-or-later
 * @filesource
 */

namespace MetaModels\CoreBundle\EventListener\DcGeneral\Table\MetaModel;

use ContaoCommunityAlliance\DcGeneral\Contao\RequestScopeDeterminator;
use ContaoCommunityAlliance\DcGeneral\Contao\View\Contao2BackendView\Event\ModelToLabelEvent;
use Doctrine\DBAL\Connection;
use Symfony\Component\Translation\TranslatorInterface;

/**
 * This handles the rendering of models to labels.
 */
class ModelToLabelListener extends AbstractAbstainingListener
{
    /**
     * The database connection.
     *
     * @var Connection
     */
    private $connection;

    /**
     * The translator.
     *
     * @var TranslatorInterface
     */
    private $translator;

    /**
     * Create a new instance.
     *
     * @param RequestScopeDeterminator $scopeDeterminator The scope determinator.
     * @param Connection               $connection        The database connection.
     * @param TranslatorInterface      $translator        The translator.
     */
    public function __construct(
        RequestScopeDeterminator $scopeDeterminator,
        Connection $connection,
        TranslatorInterface $translator
    ) {
        parent::__construct($scopeDeterminator);

        $this->connection = $connection;
        $this->translator = $translator;
    }

    /**
     * Render the html for the input screen condition.
     *
     * @param ModelToLabelEvent $event The event.
     *
     * @return void
     */
    public function handle(ModelToLabelEvent $event)
    {
        if (!$this->wantToHandle($event)) {
            return;
        }

        $model     = $event->getModel();
        $tableName = $model->getProperty('tableName');

        if (!($model && !empty($tableName) && $this->connection->getSchemaManager()->tablesExist([$tableName]))) {
            return;
        }

        // Keep the previous label.
        $label = vsprintf($event->getLabel(), $event->getArgs());
        $image = ((bool) $model->getProperty('translated')) ? 'locale.png' : 'locale_1.png';
        $count = $this->connection->createQueryBuilder()
            ->select('COUNT(*) AS itemCount')
            ->from($tableName)
            ->execute()
            ->fetchColumn();

        switch ($count) {
            case 0:
                $transId = 'tl_metamodel.itemFormatCount.0';
                break;
            case 1:
                $transId = 'tl_metamodel.itemFormatCount.1';
                break;
            default:
                $transId = 'tl_metamodel.itemFormatCount.2:';
        }

        $event
            ->setLabel('

       %2$s
      (%3$s)
      [%4$s]
    ')
            ->setArgs([
                $image,
                $label,
                $tableName,
                $this->translator->trans($transId, [$count], 'contao_tl_metamodel')
            ]);
    }
}


<?php

/**
 * This file is part of MetaModels/core.
 *
 * (c) 2012-2019 The MetaModels team.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * This project is provided in good faith and hope to be usable by anyone.
 *
 * @package    MetaModels/core
 * @author     Christian Schiffler <c.schiffler@cyberspectrum.de>
 * @author     Sven Baumann <baumann.sv@gmail.com>
 * @author     Cliff Parnitzky <github@cliff-parnitzky.de>
 * @copyright  2012-2019 The MetaModels team.
 * @license    https://github.com/MetaModels/core/blob/master/LICENSE LGPL-3.0-or-later
 * @filesource
 */

namespace MetaModels\Filter\Rules;

use Contao\Database;
use Contao\System;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Query\QueryBuilder;
use MetaModels\Filter\FilterRule;

/**
 * This is the MetaModelFilterRule class for executing a simple database query.
 */
class SimpleQuery extends FilterRule
{
    /**
     * The query string.
     *
     * @var string
     */
    private $queryString;

    /**
     * The query parameters.
     *
     * @var array
     */
    private $params;

    /**
     * The name of the id column in the query.
     *
     * @var string
     */
    private $idColumn;

    /**
     * The database instance to use.
     *
     * @var Connection
     */
    private $connection;

    /**
     * The parameter types.
     *
     * @var array
     */
    private $types;

    /**
     * Create a rule instance from the passed query builder.
     *
     * @param QueryBuilder $builder    The builder to extract query information from.
     *
     * @param string       $columnName The column to retrieve.
     *
     * @return SimpleQuery
     */
    public static function createFromQueryBuilder(QueryBuilder $builder, $columnName = 'id')
    {
        return new self(
            $builder->getSQL(),
            $builder->getParameters(),
            $columnName,
            $builder->getConnection(),
            $builder->getParameterTypes()
        );
    }

    /**
     * Creates an instance of a simple query filter rule.
     *
     * @param string     $queryString The query that shall be executed.
     * @param array      $params      The query parameters that shall be used.
     * @param string     $idColumn    The column where the item id is stored in.
     * @param Connection $connection  The database to use.
     * @param array      $types       The types.
     *
     * @throws \RuntimeException Throws invalid id column.
     */
    public function __construct($queryString, $params = [], $idColumn = 'id', $connection = null, $types = [])
    {
        parent::__construct();

        if (empty($idColumn)) {
            throw new \RuntimeException('Invalid id column');
        }

        $this->queryString = $queryString;
        $this->params      = $params;
        $this->idColumn    = (string) $idColumn;
        $this->connection  = $this->sanitizeConnection($connection);
        $this->types       = $types;
    }

    /**
     * {@inheritdoc}
     */
    public function getMatchingIds()
    {
        $matches = $this->connection->executeQuery($this->queryString, $this->params, $this->types);
        $ids     = [];
        foreach ($matches->fetchAll(\PDO::FETCH_ASSOC) as $value) {
            $ids[] = $value[$this->idColumn];
        }

        return $ids;
    }

    /**
     * Sanitize the connection value
     *
     * @param Connection|\Contao\Database $connection The connection value.
     *
     * @return Connection
     *
     * @throws \RuntimeException Throws could not obtain doctrine connection.
     *
     * @deprecated To be removed in 3.0 - you should ALWAYS pass the proper connection.
     */
    private function sanitizeConnection($connection)
    {
        if ($connection instanceof Connection) {
            return $connection;
        }

        // BC layer - we used to accept a Contao database instance here.
        if ($connection instanceof Database) {
            // @codingStandardsIgnoreStart
            @trigger_error(
                '"' . __METHOD__ . '" now accepts doctrine instances - ' .
                'passing Contao database instances is deprecated.',
                E_USER_DEPRECATED
            );
            // @codingStandardsIgnoreEnd
            $reflection = new \ReflectionProperty(Database::class, 'resConnection');
            $reflection->setAccessible(true);
            return $reflection->getValue($connection);
        }
        if (null === $connection) {
            // @codingStandardsIgnoreStart
            @trigger_error(
                'You should pass a doctrine database connection to "' . __METHOD__ . '".',
                E_USER_DEPRECATED
            );
            // @codingStandardsIgnoreEnd
            $connection = System::getContainer()->get('database_connection');
        }

        if (!($connection instanceof Connection)) {
            throw new \RuntimeException('Could not obtain doctrine connection.');
        }

        return $connection;
    }
}