<?php

/**
 * Contao Bootstrap
 *
 * @package    contao-bootstrap
 * @subpackage Core
 * @author     David Molineus <david.molineus@netzmacht.de>
 * @copyright  2017 netzmacht David Molineus. All rights reserved.
 * @license    LGPL-3.0 https://github.com/contao-bootstrap/core
 * @filesource
 */

declare(strict_types=1);

namespace ContaoBootstrap\Core\Listener;

use ContaoBootstrap\Core\Config;
use ContaoBootstrap\Core\Environment\ApplicationContext;
use ContaoBootstrap\Core\Environment\ThemeContext;
use ContaoBootstrap\Core\Message\Command\InitializeEnvironment;
use ContaoBootstrap\Core\Message\Command\BuildContextConfig;
use ContaoBootstrap\Core\Message\Command\InitializeLayout;
use Doctrine\DBAL\Connection;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

/**
 * Class ConfigSubscriber handles config loading from the database.
 *
 * @package ContaoBootstrap\Core\Subscriber
 */
final class ConfigSubscriber implements EventSubscriberInterface
{
    /**
     * Database connection.
     *
     * @var Connection
     */
    private $connection;

    /**
     * Bootstrap application config.
     *
     * @var Config
     */
    private $config;

    /**
     * ConfigSubscriber constructor.
     *
     * @param Connection $connection Database connection.
     * @param Config     $config     Bootstrap application config.
     */
    public function __construct(Connection $connection, Config $config)
    {
        $this->connection = $connection;
        $this->config     = $config;
    }

    /**
     * {@inheritdoc}
     */
    public static function getSubscribedEvents(): array
    {
        return [
            InitializeEnvironment::NAME => 'enterApplicationContext',
            InitializeLayout::NAME      => 'enterThemeContext',
            BuildContextConfig::NAME    => 'buildContextConfig',
        ];
    }

    /**
     * Initialize environment.
     *
     * @param InitializeEnvironment $event The event.
     *
     * @return void
     */
    public function enterApplicationContext(InitializeEnvironment $event): void
    {
        $event->getEnvironment()->enterContext(ApplicationContext::create());
    }

    /**
     * Enter the heme context.
     *
     * @param InitializeLayout $event The subscribed event.
     *
     * @return void
     */
    public function enterThemeContext(InitializeLayout $event): void
    {
        $event->getEnvironment()->enterContext(ThemeContext::forTheme((int) $event->getLayoutModel()->pid));
    }

    /**
     * Build context config.
     *
     * @param BuildContextConfig $command Command.
     *
     * @return void
     */
    public function buildContextConfig(BuildContextConfig $command): void
    {
        $context = $command->getContext();

        if ($context instanceof ApplicationContext) {
            $command->setConfig($this->config);
        }
    }
}


<?php

/**
 * Contao Bootstrap
 *
 * @package    contao-bootstrap
 * @subpackage Core
 * @author     David Molineus <david.molineus@netzmacht.de>
 * @copyright  2017 netzmacht David Molineus. All rights reserved.
 * @license    LGPL-3.0 https://github.com/contao-bootstrap/core
 * @filesource
 */

declare(strict_types=1);

namespace ContaoBootstrap\Core\Helper;

/**
 * Class ColorRotate.
 *
 * Inspired by https://github.com/menatwork/semantic_html5/blob/master/src/Backend/Helper.php.
 *
 * @package ContaoBootstrap\Grid\Helper
 */
final class ColorRotate
{
    /**
     * Color cache.
     *
     * @var array
     */
    private $cache = [];

    /**
     * Rotating color value.
     *
     * @var string
     */
    private $rotatingColor;

    /**
     * Initial saturation.
     *
     * @var float
     */
    private $saturation;

    /**
     * Color Value.
     *
     * @var float
     */
    private $value;

    /**
     * ColorRotate constructor.
     *
     * @param float|string $rotatingColor Initial hue value.
     * @param float        $saturation    Saturation.
     * @param float        $value         Value.
     */
    public function __construct(float $rotatingColor = .5, float $saturation = 0.7, float $value = .7)
    {
        $this->rotatingColor = $rotatingColor;
        $this->saturation    = $saturation;
        $this->value         = $value;
    }

    /**
     * Get the color for an identifier.
     *
     * @param string $identifier Identifier.
     *
     * @return string
     */
    public function getColor(string $identifier): string
    {
        if (!isset($this->cache[$identifier])) {
            $this->cache[$identifier] = $this->rotateColor();
        }

        return $this->cache[$identifier];
    }

    /**
     * Rotate the color value.
     *
     * @return string
     */
    private function rotateColor(): string
    {
        $color                = $this->convertHSVtoRGB($this->rotatingColor, $this->saturation, $this->value);
        $this->rotatingColor += .3;

        if ($this->rotatingColor > 1) {
            $this->rotatingColor -= 1;
        }

        return $color;
    }

    /**
     * Convert hsv value to rgb value.
     *
     * @param float $hue        Hue.
     * @param float $saturation Saturation.
     * @param float $value      Color value.
     *
     * @return string
     * @see    http://stackoverflow.com/a/3597447
     *
     * @SuppressWarnings(PHPMD.ShortVariable)
     */
    private function convertHSVtoRGB(float $hue, float $saturation, float $value): string
    {
        // First
        $hue *= 6;

        // Second
        $i = floor($hue);
        $f = ($hue - $i);

        // Third
        $m = ($value * (1 - $saturation));
        $n = ($value * (1 - $saturation * $f));
        $k = ($value * (1 - $saturation * (1 - $f)));

        // Forth
        switch ($i) {
            case 0:
                list($red, $green, $blue) = array($value, $k, $m);
                break;
            case 1:
                list($red, $green, $blue) = array($n, $value, $m);
                break;
            case 2:
                list($red, $green, $blue) = array($m, $value, $k);
                break;
            case 3:
                list($red, $green, $blue) = array($m, $n, $value);
                break;
            case 4:
                list($red, $green, $blue) = array($k, $m, $value);
                break;
            case 5:
            case 6:
                // for when $H=1 is given
            default:
                list($red, $green, $blue) = array($value, $m, $n);
                break;
        }

        return sprintf('#%02x%02x%02x', ($red * 255), ($green * 255), ($blue * 255));
    }
}


<?php

/**
 * Contao Bootstrap
 *
 * @package    contao-bootstrap
 * @subpackage Core
 * @author     David Molineus <david.molineus@netzmacht.de>
 * @copyright  2017 netzmacht David Molineus. All rights reserved.
 * @license    LGPL-3.0 https://github.com/contao-bootstrap/core
 * @filesource
 */

namespace ContaoBootstrap\Core;

use Contao\LayoutModel;
use ContaoBootstrap\Core\Config\ArrayConfig;
use ContaoBootstrap\Core\Environment\Context;
use ContaoBootstrap\Core\Exception\LeavingContextFailed;
use ContaoBootstrap\Core\Message\Event\ContextEntered;
use ContaoBootstrap\Core\Message\Command\BuildContextConfig;
use Symfony\Component\EventDispatcher\EventDispatcherInterface as MessageBus;

/**
 * Class Environment contain all things being provided in the bootstrap environment.
 *
 * @package ContaoBootstrap\Core
 */
final class Environment
{
    /**
     * Bootstrap enabled state.
     *
     * @var bool
     */
    protected $enabled = false;

    /**
     * Bootstrap config.
     *
     * @var Config
     */
    protected $config;

    /**
     * Layout model of current page.
     *
     * @var \LayoutModel
     */
    private $layout;

    /**
     * Current context.
     *
     * @var Context
     */
    private $context;

    /**
     * List of contexts.
     *
     * @var Context[]
     */
    private $contextStack;

    /**
     * MessageBus.
     *
     * @var MessageBus
     */
    private $messageBus;

    /**
     * Construct.
     *
     * @param MessageBus $messageBus Message bus.
     */
    public function __construct(MessageBus $messageBus)
    {
        $this->messageBus = $messageBus;
        $this->config     = new ArrayConfig();
    }

    /**
     * Get bootstrap config.
     *
     * @return Config
     */
    public function getConfig(): Config
    {
        return $this->config;
    }

    /**
     * Enter a context.
     *
     * @param Context $context Context.
     *
     * @return void
     */
    public function enterContext(Context $context): void
    {
        // Already in the context.
        if ($this->context && $this->context->match($context)) {
            return;
        }

        $this->switchContext($context, true);
    }

    /**
     * Leave current context and enter the context which was used before.
     *
     * @param Context|null $currentContext Optional expected current context. Won't do anything if context not match.
     *
     * @return void
     * @throws LeavingContextFailed When context stack is empty.
     */
    public function leaveContext(?Context $currentContext = null): void
    {
        if (!$this->context) {
            throw LeavingContextFailed::noContext();
        }

        // Not in expected context. Just quit.
        if ($currentContext && !$currentContext->match($this->context)) {
            return;
        }

        // Get last know context which was used before current context.
        $context = array_pop($this->contextStack);

        if ($context === null) {
            throw LeavingContextFailed::inContext($this->context);
        }

        $this->switchContext($context);
    }

    /**
     * Switch to another context.
     *
     * @param Context $context            New context.
     * @param bool    $keepCurrentInStack If true current context is added to the stack.
     *
     * @return void
     */
    private function switchContext(Context $context, bool $keepCurrentInStack = false): void
    {
        $command = new BuildContextConfig($this, $context, $this->config);
        $this->messageBus->dispatch($command::NAME, $command);

        if ($command->getConfig()) {
            $this->config = $command->getConfig();
        }

        if ($keepCurrentInStack && $this->context) {
            $this->contextStack[] = $this->context;
        }

        $this->context = $context;

        $event = new ContextEntered($this, $context);
        $this->messageBus->dispatch($event::NAME, $event);
    }

    /**
     * Consider if bootstrap theme is enabled.
     *
     * @return bool
     */
    public function isEnabled(): bool
    {
        return $this->enabled;
    }

    /**
     * Enable current bootstrap theme.
     *
     * @param bool $enabled Enabled state.
     *
     * @return $this
     */
    public function setEnabled(bool $enabled): self
    {
        $this->enabled = $enabled;

        return $this;
    }

    /**
     * Set the layout.
     *
     * @param LayoutModel $layout Page layout.
     *
     * @return $this
     */
    public function setLayout(LayoutModel $layout): self
    {
        $this->layout = $layout;

        return $this;
    }

    /**
     * Get the page layout.
     *
     * @return LayoutModel|null
     */
    public function getLayout()
    {
        return $this->layout;
    }
}


<?php

/**
 * Contao Bootstrap
 *
 * @package    contao-bootstrap
 * @subpackage Core
 * @author     David Molineus <david.molineus@netzmacht.de>
 * @copyright  2017 netzmacht David Molineus. All rights reserved.
 * @license    LGPL-3.0 https://github.com/contao-bootstrap/core
 * @filesource
 */

declare(strict_types=1);

namespace ContaoBootstrap\Core\Config;

use ContaoBootstrap\Core\Config;
use ContaoBootstrap\Core\Util\ArrayUtil;

/**
 * Class Config.
 *
 * @package ContaoBootstrap
 */
final class ArrayConfig implements Config
{
    /**
     * Config values.
     *
     * @var array
     */
    protected $config = array();

    /**
     * Construct.
     *
     * @param array $config Initial config values.
     */
    public function __construct(array $config = array())
    {
        $this->config = $config;
    }

    /**
     * {@inheritdoc}
     */
    public function get($key, $default = null)
    {
        $chunks = $this->path($key);
        $value  = $this->config;

        while (($chunk = array_shift($chunks)) !== null) {
            if (!array_key_exists($chunk, $value)) {
                return $default;
            }

            $value = $value[$chunk];
        }

        return $value;
    }

    /**
     * {@inheritdoc}
     */
    public function has($key)
    {
        $chunks = $this->path($key);
        $value  = $this->config;

        while (($chunk = array_shift($chunks)) !== null) {
            if (!array_key_exists($chunk, $value)) {
                return false;
            }

            $value = $value[$chunk];
        }

        return true;
    }

    /**
     * {@inheritdoc}
     */
    public function merge(array $data): Config
    {
        return new static(ArrayUtil::merge($this->config, $data));
    }

    /**
     * Convert string path to array, so that always an array is used.
     *
     * @param mixed $path Passed path value.
     *
     * @return array
     */
    private function path($path)
    {
        if (is_string($path)) {
            return explode('.', $path);
        }

        return (array) $path;
    }
}


<?php

/**
 * Contao Bootstrap
 *
 * @package    contao-bootstrap
 * @subpackage Core
 * @author     David Molineus <david.molineus@netzmacht.de>
 * @copyright  2017 netzmacht David Molineus. All rights reserved.
 * @license    LGPL-3.0 https://github.com/contao-bootstrap/core
 * @filesource
 */

declare(strict_types=1);

namespace ContaoBootstrap\Core\View\Template\Filter;

use Contao\Template;

/**
 * Class TemplatePreRenderFilter.
 *
 * @package ContaoBootstrap\Core\View\Template\Filter
 */
class TemplatePreRenderFilter implements PreRenderFilter
{
    /**
     * Post render filters.
     *
     * @var PreRenderFilter[]
     */
    private $filters;

    /**
     * TemplatePreRenderFilter constructor.
     *
     * @param PreRenderFilter[]|array $filters Post render filters
     */
    public function __construct(array $filters)
    {
        $this->filters = $filters;
    }

    /**
     * {@inheritdoc}
     */
    public function supports(Template $template): bool
    {
        foreach ($this->filters as $filter) {
            if ($filter->supports($template)) {
                return true;
            }
        }

        return false;
    }

    /**
     * {@inheritdoc}
     */
    public function filter(Template $template): void
    {
        foreach ($this->filters as $filter) {
            if ($filter->supports($template)) {
                $filter->filter($template);
            }
        }
    }
}


<?php

/**
 * Contao Bootstrap
 *
 * @package    contao-bootstrap
 * @subpackage Core
 * @author     David Molineus <david.molineus@netzmacht.de>
 * @copyright  2017 netzmacht David Molineus. All rights reserved.
 * @license    LGPL-3.0 https://github.com/contao-bootstrap/core
 * @filesource
 */

declare(strict_types=1);

namespace ContaoBootstrap\Core\View\Template\Filter;

/**
 * Class TemplatePostRenderFilter.
 *
 * @package ContaoBootstrap\Core\View\Template\Filter
 */
class TemplatePostRenderFilter implements PostRenderFilter
{
    /**
     * Post render filters.
     *
     * @var PostRenderFilter[]
     */
    private $filters;

    /**
     * TemplatePostRenderFilter constructor.
     *
     * @param PostRenderFilter[]|array $filters Post render filters
     */
    public function __construct(array $filters)
    {
        $this->filters = $filters;
    }

    /**
     * {@inheritdoc}
     */
    public function supports(string $templateName): bool
    {
        foreach ($this->filters as $filter) {
            if ($filter->supports($templateName)) {
                return true;
            }
        }

        return false;
    }

    /**
     * {@inheritdoc}
     */
    public function filter(string $buffer, string $templateName): string
    {
        foreach ($this->filters as $filter) {
            if ($filter->supports($templateName)) {
                $buffer = $filter->filter($buffer, $templateName);
            }
        }

        return $buffer;
    }
}


<?php

/**
 * Contao Bootstrap
 *
 * @package    contao-bootstrap
 * @subpackage Core
 * @author     David Molineus <david.molineus@netzmacht.de>
 * @copyright  2017 netzmacht David Molineus. All rights reserved.
 * @license    LGPL-3.0 https://github.com/contao-bootstrap/core
 * @filesource
 */

declare(strict_types=1);

namespace ContaoBootstrap\Core\DependencyInjection;

use ContaoBootstrap\Core\Util\ArrayUtil;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface as CompilerPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\Yaml\Yaml;

/**
 * Class ConfigPass.
 *
 * @package ContaoBootstrap\Core\DependencyInjection
 */
final class ConfigPass implements CompilerPass
{
    /**
     * {@inheritdoc}
     */
    public function process(ContainerBuilder $container)
    {
        $this->loadConfigFromBundles($container);
        $this->setConfigTypesArgument($container);
    }

    /**
     * Load configuration from bundle files.
     *
     * @param ContainerBuilder $container Container builder.
     *
     * @return void
     */
    private function loadConfigFromBundles(ContainerBuilder $container)
    {
        $config = [];

        foreach ($container->getParameter('kernel.bundles') as $bundleClass) {
            $refClass   = new \ReflectionClass($bundleClass);
            $bundleDir  = dirname($refClass->getFileName());
            $configFile = $bundleDir . '/Resources/config/contao_bootstrap.yml';

            if (file_exists($configFile)) {
                $config = ArrayUtil::merge($config, Yaml::parse(file_get_contents($configFile)));
            }
        }

        $container->setParameter('contao_bootstrap.config', $config);
    }

    /**
     * Set the config types arguments.
     *
     * @param ContainerBuilder $container Container builder.
     *
     * @return void
     */
    private function setConfigTypesArgument(ContainerBuilder $container): void
    {
        if (!$container->has('contao_bootstrap.config.type_manager')) {
            return;
        }

        $definition       = $container->findDefinition('contao_bootstrap.config.type_manager');
        $taggedServiceIds = $container->findTaggedServiceIds('contao_bootstrap.config.type');
        $services         = (array) $definition->getArgument(1);

        foreach (array_keys($taggedServiceIds) as $serviceId) {
            $services[] = new Reference($serviceId);
        }

        $definition->replaceArgument(1, $services);
    }
}


<?php

/**
 * Contao Bootstrap
 *
 * @package    contao-bootstrap
 * @subpackage Core
 * @author     David Molineus <david.molineus@netzmacht.de>
 * @copyright  2017 netzmacht David Molineus. All rights reserved.
 * @license    LGPL-3.0 https://github.com/contao-bootstrap/core
 * @filesource
 */

declare(strict_types=1);

namespace ContaoBootstrap\Core\Listener\Dca;

use Contao\BackendUser;
use Contao\Controller;
use Contao\Database;
use Contao\DataContainer;
use Contao\Image;
use Contao\Input;
use MultiColumnWizard;

/**
 * Class Module is used for tl_module.
 *
 * @package ContaoBootstrap\Core\DataContainer
 */
final class ModuleDcaListener
{
    /**
     * Get all templates. A templatePrefix can be defined using eval.templatePrefix.
     *
     * @param DataContainer $dataContainer The data container driver.
     *
     * @return array
     *
     * @SuppressWarnings(PHPMD.Superglobals)
     */
    public function getTemplates(DataContainer $dataContainer): array
    {
        $config = array();
        $prefix = '';

        // MCW compatibility
        if ($dataContainer instanceof MultiColumnWizard) {
            $field = $dataContainer->strField;
            $table = $dataContainer->strTable;
        } else {
            $field = $dataContainer->field;
            $table = $dataContainer->table;
        }

        if (array_key_exists('eval', $GLOBALS['TL_DCA'][$table]['fields'][$field])) {
            $config = $GLOBALS['TL_DCA'][$table]['fields'][$field]['eval'];
        }

        if (array_key_exists('templatePrefix', $config)) {
            $prefix = $config['templatePrefix'];
        }

        return \Controller::getTemplateGroup($prefix);
    }

    /**
     * Generate the page picker.
     *
     * @param DataContainer $dataContainer The data container driver.
     *
     * @return string
     *
     * @SuppressWarnings(PHPMD.Superglobals)
     */
    public function pagePicker(DataContainer $dataContainer): string
    {
        $template  = ' %s';

        return sprintf(
            $template,
            Input::get('do'),
            $dataContainer->table,
            $dataContainer->field,
            str_replace(array('{{link_url::', '}}'), '', $dataContainer->value),
            specialchars($GLOBALS['TL_LANG']['MSC']['pagepicker']),
            specialchars(str_replace("'", "\\'", $GLOBALS['TL_LANG']['MOD']['page'][0])),
            $dataContainer->field,
            $dataContainer->field . ((\Input::get('act') == 'editAll') ? '_' . $dataContainer->id : ''),
            Image::getHtml(
                'pickpage.gif',
                $GLOBALS['TL_LANG']['MSC']['pagepicker'],
                'style="vertical-align:top;cursor:pointer"'
            )
        );
    }

    /**
     * Get all articles and return them as array.
     *
     * @return array
     *
     * @SuppressWarnings(PHPMD.Superglobals)
     */
    public function getAllArticles(): array
    {
        $user     = BackendUser::getInstance();
        $pids     = array();
        $articles = array();

        // Limit pages to the user's pagemounts
        if ($user->isAdmin) {
            $objArticle = Database::getInstance()->execute(
                'SELECT a.id, a.pid, a.title, a.inColumn, p.title AS parent FROM tl_article a
                LEFT JOIN tl_page p ON p.id=a.pid ORDER BY parent, a.sorting'
            );
        } else {
            foreach ($user->pagemounts as $id) {
                $pids[] = $id;
                $pids   = array_merge($pids, Database::getInstance()->getChildRecords($id, 'tl_page'));
            }

            if (empty($pids)) {
                return $articles;
            }

            $pids = implode(',', array_map('intval', array_unique($pids)));

            $objArticle = Database::getInstance()->execute(
                'SELECT a.id, a.pid, a.title, a.inColumn, p.title AS parent
                FROM tl_article a LEFT JOIN tl_page p ON p.id=a.pid WHERE a.pid IN(' . $pids . ')
                ORDER BY parent, a.sorting'
            );
        }

        // Edit the result
        if ($objArticle->numRows) {
            Controller::loadLanguageFile('tl_article');

            while ($objArticle->next()) {
                $key                             = $objArticle->parent . ' (ID ' . $objArticle->pid . ')';
                $articles[$key][$objArticle->id] = $objArticle->title
                    . ' (' . ($GLOBALS['TL_LANG']['tl_article'][$objArticle->inColumn] ?: $objArticle->inColumn)
                    . ', ID ' . $objArticle->id . ')';
            }
        }

        return $articles;
    }

    /**
     * Get all modules prepared for select wizard.
     *
     * @return array
     */
    public function getAllModules(): array
    {
        $modules = array();
        $query   = 'SELECT m.id, m.name, t.name AS theme FROM tl_module m LEFT JOIN tl_theme t ON m.pid=t.id';

        if (Input::get('table') == 'tl_module' && \Input::get('act') == 'edit') {
            $query .= ' WHERE m.id != ?';
        }

        $query .= ' ORDER BY t.name, m.name';
        $result = Database::getInstance()
            ->prepare($query)
            ->execute(Input::get('id'));

        while ($result->next()) {
            $modules[$result->theme][$result->id] = $result->name . ' (ID ' . $result->id . ')';
        }

        return $modules;
    }
}


<?php

/**
 * Contao Bootstrap
 *
 * @package    contao-bootstrap
 * @subpackage Core
 * @author     David Molineus <david.molineus@netzmacht.de>
 * @copyright  2017 netzmacht David Molineus. All rights reserved.
 * @license    LGPL-3.0 https://github.com/contao-bootstrap/core
 * @filesource
 */

declare(strict_types=1);

namespace ContaoBootstrap\Core\Environment;

/**
 * Class ThemeContext.
 *
 * @package ContaoBootstrap\Core\Config\Context
 */
final class ThemeContext extends AbstractContext
{
    /**
     * Theme id.
     *
     * @var int
     */
    private $themeId;

    /**
     * ThemeContext constructor.
     *
     * @param int $themeId Theme id.
     */
    private function __construct(int $themeId)
    {
        $this->themeId = $themeId;
    }

    /**
     * {@inheritDoc}
     */
    public function supports(Context $context): bool
    {
        if ($context instanceof ApplicationContext) {
            return true;
        }

        if ($context instanceof ThemeContext) {
            return $this->match($context);
        }

        return false;
    }

    /**
     * Create context for a theme.
     *
     * @param int $themeId Theme id.
     *
     * @return static
     */
    public static function forTheme(int $themeId): self
    {
        return new static($themeId);
    }

    /**
     * Get themeId.
     *
     * @return int
     */
    public function getThemeId(): int
    {
        return $this->themeId;
    }

    /**
     * {@inheritdoc}
     */
    public function __toString(): string
    {
        return 'theme:' . $this->themeId;
    }
}


<?php

/**
 * Contao Bootstrap
 *
 * @package    contao-bootstrap
 * @subpackage Core
 * @author     David Molineus <david.molineus@netzmacht.de>
 * @copyright  2017 netzmacht David Molineus. All rights reserved.
 * @license    LGPL-3.0 https://github.com/contao-bootstrap/core
 * @filesource
 */

declare(strict_types=1);

namespace ContaoBootstrap\Core\Listener;

use Contao\Template;
use ContaoBootstrap\Core\View\Template\Filter\PostRenderFilter;
use ContaoBootstrap\Core\View\Template\Filter\PreRenderFilter;

/**
 * Class TemplateModifier contains all template modifiers used by bootstrap config.
 *
 * @package ContaoBootstrap
 */
final class TemplateParseListener
{
    /**
     * Pre render filter.
     *
     * @var PreRenderFilter
     */
    private $preRenderFilter;

    /**
     * Post render filter.
     *
     * @var PostRenderFilter
     */
    private $postRenderFilter;

    /**
     * Modifier constructor.
     *
     * @param PreRenderFilter  $preRenderFilter  Pre render filter.
     * @param PostRenderFilter $postRenderFilter Post render filter.
     */
    public function __construct(
        PreRenderFilter $preRenderFilter,
        PostRenderFilter $postRenderFilter
    ) {
        $this->preRenderFilter  = $preRenderFilter;
        $this->postRenderFilter = $postRenderFilter;
    }

    /**
     * Execute all registered template modifiers.
     *
     * @param Template $template Current template.
     *
     * @return void
     */
    public function prepare(Template $template): void
    {
        if ($this->preRenderFilter->supports($template)) {
            $this->preRenderFilter->filter($template);
        }
    }

    /**
     * Parse current template.
     *
     * @param string $buffer       Parsed template.
     * @param string $templateName Name of the template.
     *
     * @return string
     */
    public function parse(string $buffer, string $templateName): string
    {
        if ($this->postRenderFilter->supports($templateName)) {
            $buffer = $this->postRenderFilter->filter($buffer, $templateName);
        }

        return $buffer;
    }
}


<?php

/**
 * Contao Bootstrap
 *
 * @package    contao-bootstrap
 * @subpackage Core
 * @author     David Molineus <david.molineus@netzmacht.de>
 * @copyright  2017 netzmacht David Molineus. All rights reserved.
 * @license    LGPL-3.0 https://github.com/contao-bootstrap/core
 * @filesource
 */

declare(strict_types=1);

namespace ContaoBootstrap\Core\DependencyInjection;

use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;

/**
 * Class TemplateModifierPass.
 *
 * @package ContaoBootstrap\Core\DependencyInjection
 */
final class TemplateFilterPass implements CompilerPassInterface
{
    /**
     * {@inheritdoc}
     */
    public function process(ContainerBuilder $container)
    {
        $this->processPreRenderFilters($container);
        $this->processPostRenderFilters($container);
    }

    /**
     * Process tagged pre render filters.
     *
     * @param ContainerBuilder $container Container builder.
     *
     * @return void
     */
    private function processPreRenderFilters(ContainerBuilder $container): void
    {
        $this->registerTaggedServices(
            $container,
            'contao_bootstrap.view.template.pre_render_filter',
            'contao_bootstrap.pre_render_filter'
        );
    }

    /**
     * Process tagged post render filters.
     *
     * @param ContainerBuilder $container Container builder.
     *
     * @return void
     */
    private function processPostRenderFilters(ContainerBuilder $container): void
    {
        $this->registerTaggedServices(
            $container,
            'contao_bootstrap.view.template.post_render_filter',
            'contao_bootstrap.post_render_filter'
        );
    }

    /**
     * Register a tagged services to an definition argument. Returns false if service does not exist.
     *
     * @param ContainerBuilder $container     Container builder.
     * @param string           $definitionId  Service definition id.
     * @param string           $tagName       Tag name.
     * @param int              $argumentIndex Index of the argument being replaced.
     *
     * @return bool
     */
    private function registerTaggedServices(
        ContainerBuilder $container,
        string $definitionId,
        string $tagName,
        $argumentIndex = 0
    ): bool {
        if (!$container->has($definitionId)) {
            return false;
        }

        $definition       = $container->findDefinition($definitionId);
        $taggedServiceIds = $container->findTaggedServiceIds($tagName);
        $services         = (array) $definition->getArgument($argumentIndex);

        foreach (array_keys($taggedServiceIds) as $serviceId) {
            $services[] = new Reference($serviceId);
        }

        $definition->replaceArgument(0, $services);

        return true;
    }
}


<?php

/**
 * Contao Bootstrap
 *
 * @package    contao-bootstrap
 * @subpackage Core
 * @author     David Molineus <david.molineus@netzmacht.de>
 * @copyright  2017 netzmacht David Molineus. All rights reserved.
 * @license    LGPL-3.0 https://github.com/contao-bootstrap/core
 * @filesource
 */

declare(strict_types=1);

namespace ContaoBootstrap\Core\Listener;

use ContaoBootstrap\Core\Environment;
use ContaoBootstrap\Core\Message\Command\InitializeEnvironment;
use ContaoBootstrap\Core\Message\Command\InitializeLayout;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;

/**
 * Class Hooks contains hooks being called from Contao.
 *
 * @package ContaoBootstrap\Core\Contao
 */
final class HookListener
{
    /**
     * The event dispatcher.
     *
     * @var EventDispatcherInterface
     */
    protected $eventDispatcher;

    /**
     * The bootstrap environment.
     *
     * @var Environment
     */
    protected $environment;

    /**
     * Construct.
     *
     * @param EventDispatcherInterface $eventDispatcher The event dispatcher.
     * @param Environment              $environment     The bootstrap environment.
     *
     * @SuppressWarnings(PHPMD.Superglobals)
     */
    public function __construct(EventDispatcherInterface $eventDispatcher, Environment $environment)
    {
        $this->eventDispatcher = $eventDispatcher;
        $this->environment     = $environment;
    }

    /**
     * Initialize bootstrap at initialize system hook.
     *
     * @return void
     */
    public function initializeSystem(): void
    {
        $this->initializeEnvironment();
    }

    /**
     * Initialize bootstrap environment.
     *
     * @return void
     */
    protected function initializeEnvironment(): void
    {
        $event = new InitializeEnvironment($this->environment);
        $this->eventDispatcher->dispatch($event::NAME, $event);
    }

    /**
     * Initialize Layout.
     *
     * @param \PageModel   $page   Current page.
     * @param \LayoutModel $layout Page layout.
     *
     * @return void
     */
    public function initializeLayout(\PageModel $page, \LayoutModel $layout): void
    {
        $environment = $this->environment;
        $environment->setLayout($layout);
        $environment->setEnabled($layout->layoutType == 'bootstrap');

        $event = new InitializeLayout($environment, $layout, $page);
        $this->eventDispatcher->dispatch($event::NAME, $event);
    }
}


<?php

declare(strict_types=1);

namespace WsdlToPhp\PhpGenerator\Element;

class PhpInterface extends PhpClass
{
    /**
     * @var string
     */
    const PHP_DECLARATION = 'interface';
    /**
     * @var string
     */
    const PHP_IMPLEMENTS_KEYWORD = 'extends';
    /**
     * An interface is never abstract
     * @return bool
     */
    public function getAbstract(): bool
    {
        return false;
    }
    /**
     * An interface never implements, it extends,
     * so we use interfaces property to store this information (tricky indeed)
     * @return null
     */
    public function getExtends()
    {
        return null;
    }
    /**
     * defines authorized children element types
     * @return string[]
     */
    public function getChildrenTypes(): array
    {
        return [
            'string',
            PhpAnnotationBlock::class,
            PhpMethod::class,
            PhpConstant::class,
        ];
    }
    /**
     * ensure method has no body
     * @see \WsdlToPhp\PhpGenerator\Element\AbstractElement::addChild()
     * @param mixed
     */
    public function addChild($child): AbstractElement
    {
        if ($child instanceof PhpMethod) {
            $child->setHasBody(false);
        }
        return parent::addChild($child);
    }
}


<?php

declare(strict_types=1);

namespace WsdlToPhp\PhpGenerator\Element;

abstract class AbstractElement implements GenerateableInterface
{
    /**
     * @var string
     */
    protected $name;
    /**
     * @var AbstractElement[]|mixed[]
     */
    protected $children;
    /**
     * @var int
     */
    protected $indentation;
    /**
     * @param string $name
     */
    public function __construct(string $name)
    {
        $this->setName($name);
        $this->children = [];
        $this->indentation = 0;
    }
    /**
     * @throws \InvalidArgumentException
     * @param string $name
     * @return AbstractElement
     */
    public function setName(string $name)
    {
        if (!self::nameIsValid($name)) {
            throw new \InvalidArgumentException(sprintf('Name "%s" is invalid when instantiating %s object', $name, $this->getCalledClass()));
        }
        $this->name = $name;
        return $this;
    }
    /**
     * @return string
     */
    public function getName()
    {
        return $this->name;
    }
    /**
     * @param string $name
     * @param bool $allowBackslash
     * @return bool
     */
    public static function nameIsValid(string $name, bool $allowBackslash = false)
    {
        $pattern = '/[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/';
        if ($allowBackslash === true) {
            $pattern = '/[a-zA-Z_\x7f-\xff\\\][a-zA-Z0-9_\x7f-\xff\\\]*/';
        }
        return preg_match($pattern, (string) $name);
    }
    /**
     * @param mixed $string
     * @param bool $checkName
     * @param bool $allowBackslash
     * @return bool
     */
    public static function stringIsValid($string, bool $checkName = true, bool $allowBackslash = false): bool
    {
        return (is_string($string) && !empty($string) && (!$checkName || self::nameIsValid($string, $allowBackslash)));
    }
    /**
     * @param mixed $object
     * @param mixed $checkClass
     * @return bool
     */
    public static function objectIsValid($object, ?string $checkClass = null): bool
    {
        return (is_object($object) && ($checkClass === null || get_class($object) === $checkClass));
    }
    /**
     * @see \WsdlToPhp\PhpGenerator\Element\GenerateableInterface::toString()
     * @param int $indentation
     * @return string
     */
    public function toString(int $indentation = null): string
    {
        $lines = [
            $this->getToStringDeclaration($indentation),
            $this->getToStringBeforeChildren($indentation),
        ];
        foreach ($this->getChildren() as $child) {
            $lines[] = $this->getChildContent($child, $indentation + ($this->useBracketsForChildren() ? 1 : 0));
        }
        $lines[] = $this->getToStringAfterChildren($indentation);
        return implode(self::BREAK_LINE_CHAR, self::cleanArrayToString($lines));
    }
    /**
     * @param int $indentation
     * @return string|null
     */
    private function getToStringDeclaration(int $indentation = null): ?string
    {
        $declaration = $this->getPhpDeclaration();
        if (!empty($declaration)) {
            return $this->getIndentedString($declaration, $indentation);
        }
        return null;
    }
    /**
     * @param int $indentation
     * @return string|null
     */
    private function getToStringBeforeChildren(int $indentation = null): ?string
    {
        $before = $this->getContextualLineBeforeChildren($indentation);
        if (!empty($before)) {
            return $before;
        }
        return null;
    }
    /**
     * @param int $indentation
     * @return string|null
     */
    private function getToStringAfterChildren(int $indentation = null): ?string
    {
        $after = $this->getContextualLineAfterChildren($indentation);
        if (!empty($after)) {
            return $after;
        }
        return null;
    }
    /**
     * @param array $array
     * @return array
     */
    private static function cleanArrayToString(array $array): array
    {
        $newArray = [];
        foreach ($array as $line) {
            if ($line !== null) {
                $newArray[] = $line;
            }
        }
        return $newArray;
    }
    /**
     * @throws \InvalidArgumentException
     * @param string|AbstractElement $child
     * @param int $indentation
     * @return string
     */
    protected function getChildContent($child, int $indentation = null): string
    {
        $content = '';
        if (is_string($child)) {
            $content = $this->getIndentedString($child, $indentation);
        } elseif ($child instanceof AbstractElement) {
            $content = $child->toString($indentation === null ? $this->getIndentation() : $indentation);
        }
        return $content;
    }
    /**
     * @return string
     */
    public function getPhpName(): string
    {
        return sprintf('%s', $this->getName());
    }
    /**
     * @throws \InvalidArgumentException
     * @param mixed $child
     * @return AbstractElement
     */
    public function addChild($child): AbstractElement
    {
        if (!$this->childIsValid($child)) {
            $types = $this->getChildrenTypes();
            if (empty($types)) {
                throw new \InvalidArgumentException('This element does not accept any child element');
            } else {
                throw new \InvalidArgumentException(sprintf('Element of type "%s:%s" is not authorized, please provide one of these types: %s', gettype($child), is_object($child) ? get_class($child) : 'unknown', implode(', ', $this->getChildrenTypes())));
            }
        }
        $this->children[] = $child;
        return $this;
    }
    /**
     * @param mixed $child
     * @return bool
     */
    protected function childIsValid($child): bool
    {
        $valid = false;
        $authorizedTypes = $this->getChildrenTypes();
        if (!empty($authorizedTypes)) {
            foreach ($authorizedTypes as $authorizedType) {
                $valid |= (gettype($child) === $authorizedType) || self::objectIsValid($child, $authorizedType);
            }
        }
        return (bool) $valid;
    }
    /**
     * @return AbstractElement[]|mixed[]
     */
    public function getChildren(): array
    {
        return $this->children;
    }
    /**
     * @return string
     */
    abstract public function getPhpDeclaration(): string;
    /**
     * defines authorized children element types
     * @return string[]
     */
    abstract public function getChildrenTypes(): array;
    /**
     * @param int $indentation
     * @return string
     */
    private function getContextualLineBeforeChildren(int $indentation = null): string
    {
        if ($this->useBracketsForChildren()) {
            $line = $this->getBracketBeforeChildren($indentation);
        } else {
            $line = $this->getLineBeforeChildren($indentation);
        }
        return $line;
    }
    /**
     * @param int $indentation
     * @return string
     */
    private function getContextualLineAfterChildren(int $indentation = null): string
    {
        if ($this->useBracketsForChildren()) {
            $line = $this->getBracketAfterChildren($indentation);
        } else {
            $line = $this->getLineAfterChildren($indentation);
        }
        return $line;
    }
    /**
     * Allows to generate content before children content is generated
     * @param int $indentation
     * @return string
     */
    public function getLineBeforeChildren(int $indentation = null): string
    {
        return '';
    }
    /**
     * Allows to generate content after children content is generated
     * @param int $indentation
     * @return string
     */
    public function getLineAfterChildren(int $indentation = null): string
    {
        return '';
    }
    /**
     * Allows to indicate that children are contained by brackets,
     * in the case the method returns true, getBracketBeforeChildren
     * is called instead of getLineBeforeChildren and getBracketAfterChildren
     * is called instead of getLineAfterChildren, but be aware that these methods
     * call the two others
     * @return bool
     */
    public function useBracketsForChildren(): bool
    {
        return false;
    }
    /**
     * Allows to generate content before children content is generated
     * @param int $indentation
     * @return string
     */
    public function getBracketBeforeChildren(int $indentation = null): string
    {
        $line = $this->getIndentedString(self::OPEN_BRACKET, $indentation);
        $this->setIndentation(($indentation === null ? $this->getIndentation() : $indentation) + 1);
        return $line;
    }
    /**
     * Allows to generate content after children content is generated
     * @param int $indentation
     * @return string
     */
    public function getBracketAfterChildren(int $indentation = null): string
    {
        $this->setIndentation(($indentation === null ? $this->getIndentation() : $indentation) - 1);
        return $this->getIndentedString(self::CLOSE_BRACKET, $indentation);
    }
    /**
     * @param int $indentation
     * @return AbstractElement
     */
    public function setIndentation(int $indentation): AbstractElement
    {
        $this->indentation = $indentation;
        return $this;
    }
    /**
     * @return int
     */
    public function getIndentation(): int
    {
        return $this->indentation;
    }
    /**
     * @see \WsdlToPhp\PhpGenerator\Element\GenerateableInterface::getIndentationString()
     * @param int $indentation
     * @return string
     */
    public function getIndentationString(int $indentation = null): string
    {
        return str_repeat(self::INDENTATION_CHAR, $indentation === null ? $this->getIndentation() : $indentation);
    }
    /**
     * @param string $string
     * @param int $indentation
     * @return string
     */
    public function getIndentedString(string $string, int $indentation = null): string
    {
        $strings = explode(self::BREAK_LINE_CHAR, $string);
        foreach ($strings as $i => $s) {
            $strings[$i] = sprintf('%s%s', $this->getIndentationString($indentation), $s);
        }
        return implode(self::BREAK_LINE_CHAR, $strings);
    }
    /**
     * @return string
     */
    final public function getCalledClass(): string
    {
        return substr(get_called_class(), strrpos(get_called_class(), '\\') + 1);
    }
}


<?php

declare(strict_types=1);

namespace WsdlToPhp\PhpGenerator\Element;

class PhpAnnotationBlock extends AbstractElement
{
    /**
     * @param array $annotations
     */
    public function __construct(array $annotations = [])
    {
        parent::__construct('_');
        $this->setAnnotations($annotations);
    }
    /**
     * @throws \InvalidArgumentException
     * @param string[]|array[]|PhpAnnotation[] $annotations
     * @return PhpAnnotationBlock
     */
    protected function setAnnotations(array $annotations): PhpAnnotationBlock
    {
        if (!self::annotationsAreValid($annotations)) {
            throw new \InvalidArgumentException('Annotations are not valid');
        }
        $this->children = self::transformAnnotations($annotations);
        return $this;
    }
    /**
     * @param string[]|array[]|PhpAnnotation[] $annotations
     * @return PhpAnnotation[]
     */
    protected static function transformAnnotations(array $annotations): array
    {
        $finalAnnotations = [];
        foreach ($annotations as $annotation) {
            $finalAnnotations[] = self::transformAnnotation($annotation);
        }
        return $finalAnnotations;
    }
    /**
     * @throws \InvalidArgumentException
     * @param string|array|PhpAnnotation $annotation
     * @return PhpAnnotation
     */
    protected static function transformAnnotation($annotation): PhpAnnotation
    {
        if ($annotation instanceof PhpAnnotation) {
            return $annotation;
        } elseif (is_string($annotation)) {
            return new PhpAnnotation(PhpAnnotation::NO_NAME, $annotation);
        } elseif (is_array($annotation) && array_key_exists('content', $annotation)) {
            return new PhpAnnotation(array_key_exists('name', $annotation) ? $annotation['name'] : PhpAnnotation::NO_NAME, $annotation['content']);
        } else {
            throw new \InvalidArgumentException(sprintf('Annotation parameter "%s" is invalid', gettype($annotation)));
        }
    }
    /**
     * @param string[]|array[]|PhpAnnotation[] $annotations
     * @return bool
     */
    protected static function annotationsAreValid(array $annotations): bool
    {
        $valid = true;
        foreach ($annotations as $annotation) {
            $valid &= self::annotationIsValid($annotation);
        }
        return (bool) $valid;
    }
    /**
     * @param string|array|PhpAnnotation $annotation
     * @return bool
     */
    protected static function annotationIsValid($annotation): bool
    {
        return self::stringIsValid($annotation, false) || (is_array($annotation) && array_key_exists('content', $annotation)) || $annotation instanceof PhpAnnotation;
    }
    /**
     * @throws \InvalidArgumentException
     * @param mixed $child
     * @return PhpAnnotationBlock
     */
    public function addChild($child): AbstractElement
    {
        if (!$this->childIsValid($child)) {
            return parent::addChild($child);
        }
        $this->children[] = $this->transformAnnotation($child);
        return $this;
    }
    /**
     * @see \WsdlToPhp\PhpGenerator\Element\AbstractElement::getPhpDeclaration()
     * @return string
     */
    public function getPhpDeclaration(): string
    {
        return '';
    }
    /**
     * defines authorized children element types
     * @return string[]
     */
    public function getChildrenTypes(): array
    {
        return [
            'array',
            'string',
            PhpAnnotation::class,
        ];
    }
    /**
     * Allows to generate content before children content is generated
     * @param int $indentation
     * @return string
     */
    public function getLineBeforeChildren(int $indentation = null): string
    {
        return $this->getIndentedString(parent::OPEN_ANNOTATION, $indentation);
    }
    /**
     * Allows to generate content after children content is generated
     * @param int $indentation
     * @return string
     */
    public function getLineAfterChildren(int $indentation = null): string
    {
        return $this->getIndentedString(parent::CLOSE_ANNOTATION, $indentation);
    }
}


<?php

declare(strict_types=1);

namespace WsdlToPhp\PhpGenerator\Element;

class PhpMethod extends PhpFunction
{
    /**
     * @var bool
     */
    protected $final;
    /**
     * @var bool
     */
    protected $static;
    /**
     * @var bool
     */
    protected $abstract;
    /**
     * @var bool
     */
    protected $hasBody;
    /**
     * @param string $name
     * @param string[]|PhpFunctionParameter[] $parameters
     * @param string $access
     * @param bool $abstract
     * @param bool $static
     * @param bool $final
     * @param bool $hasBody
     */
    public function __construct(string $name, array $parameters = [], string $access = parent::ACCESS_PUBLIC, bool $abstract = false, bool $static = false, bool $final = false, bool $hasBody = true)
    {
        parent::__construct($name, $parameters);
        $this
            ->setAccess($access)
            ->setAbstract($abstract)
            ->setStatic($static)
            ->setFinal($final)
            ->setHasBody($hasBody);
    }
    /**
     * @param bool $abstract
     * @return PhpMethod
     */
    public function setAbstract(bool $abstract): PhpMethod
    {
        $this->abstract = $abstract;
        return $this;
    }
    /**
     * @return bool
     */
    public function getAbstract(): bool
    {
        return $this->abstract;
    }
    /**
     * @return string
     */
    protected function getPhpAbstract(): string
    {
        return $this->getAbstract() === true ? 'abstract ' : '';
    }
    /**
     * @param bool $final
     * @return PhpMethod
     */
    public function setFinal(bool $final): PhpMethod
    {
        $this->final = $final;
        return $this;
    }
    /**
     * @return bool
     */
    public function getFinal(): bool
    {
        return $this->final;
    }
    /**
     * @return string
     */
    protected function getPhpFinal(): string
    {
        return $this->getFinal() === true ? 'final ' : '';
    }
    /**
     * @param bool $static
     * @return PhpMethod
     */
    public function setStatic(bool $static): PhpMethod
    {
        $this->static = $static;
        return $this;
    }
    /**
     * @return bool
     */
    public function getStatic(): bool
    {
        return $this->static;
    }
    /**
     * @return string
     */
    protected function getPhpStatic(): string
    {
        return $this->getStatic() === true ? 'static ' : '';
    }
    /**
     * @param bool $hasBody
     * @return PhpMethod
     */
    public function setHasBody(bool $hasBody): PhpMethod
    {
        $this->hasBody = $hasBody;
        return $this;
    }
    /**
     * @return bool
     */
    public function getHasBody(): bool
    {
        return $this->hasBody;
    }
    /**
     * @return string
     */
    protected function getPhpDeclarationEnd(): string
    {
        return ($this->getHasBody() === false || $this->getAbstract() === true) ? ';' : '';
    }
    /**
     * @see \WsdlToPhp\PhpGenerator\Element\AbstractAccessRestrictedElement::getPhpDeclaration()
     * @return string
     */
    public function getPhpDeclaration(): string
    {
        return sprintf('%s%s%s%sfunction %s(%s)%s', $this->getPhpFinal(), $this->getPhpAbstract(), $this->getPhpAccess(), $this->getPhpStatic(), $this->getPhpName(), $this->getPhpParameters(), $this->getPhpDeclarationEnd());
    }
    /**
     * indicates if the current element has accessibility constraint
     * @return bool
     */
    public function hasAccessibilityConstraint(): bool
    {
        return true;
    }
    /**
     * Allows to generate content before children content is generated
     * @param int $indentation
     * @return string
     */
    public function getLineBeforeChildren(int $indentation = null): string
    {
        if ($this->getHasBody() === true) {
            return parent::getLineBeforeChildren($indentation);
        }
        return '';
    }
    /**
     * Allows to generate content after children content is generated
     * @param int $indentation
     * @return string
     */
    public function getLineAfterChildren(int $indentation = null): string
    {
        if ($this->getHasBody() === true) {
            return parent::getLineAfterChildren($indentation);
        }
        return '';
    }
    /**
     * @see \WsdlToPhp\PhpGenerator\Element\AbstractElement::getChildren()
     * @return array
     */
    public function getChildren(): array
    {
        if ($this->getHasBody() === true) {
            return parent::getChildren();
        }
        return [];
    }
    /**
     * Allows to indicate that children are contained by brackets,
     * in the case the method returns true, getBracketBeforeChildren
     * is called instead of getLineBeforeChildren and getBracketAfterChildren
     * is called instead of getLineAfterChildren, but be aware that these methods
     * call the two others
     * @return bool
     */
    public function useBracketsForChildren(): bool
    {
        return $this->getHasBody();
    }
}