<?php
/**
 * YAWIK
 *
 * @filesource
 * @copyright (c) 2013 - 2016 Cross Solution (http://cross-solution.de)
 * @license   MIT
 */

/** Core forms */
namespace Core\Form;

use Zend\Form\Element;
use Zend\Form\FieldsetInterface;
use Zend\Stdlib\PriorityList;
use Zend\View\Renderer\PhpRenderer as Renderer;
use Core\Entity\EntityInterface;
use Zend\ServiceManager\ServiceLocatorInterface;

/**
 * Manages a group of formulars.
 *
 * The container is responsible for creating, populating and binding the formulars from or to
 * the corresponding entities.
 *
 * Formulars are lazy loaded. So it is possible to only retrieve one formular from the container
 * for asynchronous saving using ajax calls.
 *
 * @author Mathias Gelhausen <gelhausen@cross-solution.de>
 */
class Container extends Element implements
    DisableElementsCapableInterface,
    FormParentInterface,
    \IteratorAggregate,
    \Countable
{
    /**
     * Available/Loaded forms or specification.
     * @var array
     */
    protected $forms = array();

    /**
     * Active formulars keys.
     *
     * Formulars which key is herein are included in the iterator.
     * @see getIterator()
     * @var array
     */
    protected $activeForms = array();

    /**
     * The form element manager.
     * @var \Zend\Form\FormElementManager\FormElementManagerV3Polyfill
     */
    protected $formElementManager;

    /**
     * Entity to bind to the formulars.
     *
     * @var \Core\Entity\EntityInterface[]
     */
    protected $entities;

    /**
     * Parameters to pass to the formulars.
     *
     * @var array
     */
    protected $params = array();

    protected $parent;

    /**
     * @param ServiceLocatorInterface $formElementManager
     * @return Container
     */
    public function setFormElementManager(ServiceLocatorInterface $formElementManager)
    {
        $this->formElementManager = $formElementManager;
        return $this;
    }

    /**
     * Gets an iterator to iterate over the enabled formulars.
     *
     * @return \ArrayIterator
     * @see IteratorAggregate::getIterator()
     */
    public function getIterator()
    {
        $iterator = new PriorityList();
        $iterator->isLIFO(false);

        foreach ($this->activeForms as $key) {
            $spec = $this->forms[$key];
            $priority = isset($spec['priority']) ? $spec['priority'] : 0;

            $iterator->insert($key, $this->getForm($key), $priority);
        }

        return $iterator;
    }

    /**
     * Gets the count of enabled formulars
     *
     * @return int
     * @see Countable::count()
     */
    public function count()
    {
        return count($this->activeForms);
    }

    /**
     * @param bool $flag
     * @return $this
     */
    public function setIsDisableCapable($flag)
    {
        $this->options['is_disable_capable'] = $flag;

        return $this;
    }

    /**
     * @return bool
     */
    public function isDisableCapable()
    {
        return isset($this->options['is_disable_capable'])
               ? $this->options['is_disable_capable'] : true;
    }

    /**
     * @param bool $flag
     * @return $this
     */
    public function setIsDisableElementsCapable($flag)
    {
        $this->options['is_disable_elements_capable'] = $flag;

        return $this;
    }

    /**
     * @return bool
     */
    public function isDisableElementsCapable()
    {
        return isset($this->options['is_disable_elements_capable'])
               ? $this->options['is_disable_elements_capable'] : true;
    }

    /**
     * @param array $map
     */
    public function disableElements(array $map)
    {
        foreach ($map as $key => $name) {
            if (is_numeric($key)) {
                if (isset($this->forms[$name])) {
                    $form = $this->getForm($name);
                    if (false !== $form->getOption('is_disable_capable')) {
                        $this->disableForm($name);
                    }
                }
                continue;
            }

            if (!isset($this->forms[$key])) {
                continue;
            }

            if (isset($this->forms[$key]['__instance__'])) {
                $form = $this->forms[$key]['__instance__'];

                if ($form instanceof DisableElementsCapableInterface
                    && $form->isDisableElementsCapable()
                ) {
                    $form->disableElements($name);
                }
            }
            $this->forms[$key]['disable_elements'] = $name;
        }
    }

    public function setOptions($options)
    {
        parent::setOptions($options);

        if (isset($this->options['forms'])) {
            $this->setForms($this->options['forms']);
        }

        return $this;
    }

    /**
     * Sets formular parameters.
     *
     * @param array $params
     * @return \Core\Form\Container
     */
    public function setParams(array $params)
    {
        $this->params = array_merge($this->params, $params);

        foreach ($this->forms as $form) {
            if (isset($form['__instance__'])
                && is_object($form['__instance__'])
                && method_exists($form['__instance__'], 'setParams')
            ) {
                $form['__instance__']->setParams($params);
            }
        }
        return $this;
    }

    /**
     * Gets the formular parameters.
     *
     * @return array:
     */
    public function getParams()
    {
        return $this->params;
    }

    /**
     * Sets a formular parameter.
     *
     * @param string $key
     * @param mixed $value
     * @return \Core\Form\Container
     */
    public function setParam($key, $value)
    {
        $this->params[$key] = $value;

        foreach ($this->forms as $form) {
            if (isset($form['__instance__'])
                && is_object($form['__instance__'])
                && method_exists($form['__instance__'], 'setParam')
            ) {
                $form['__instance__']->setParam($key, $value);
            }
        }
        return $this;
    }

    /**
     * Gets the value of a formular parameter.
     *
     * Returns the provided $default value or null, if parameter does
     * not  exist.
     *
     * @param string $key
     * @param mixed $default
     * @return mixed
     */
    public function getParam($key, $default = null)
    {
        return isset($this->params[$key]) ? $this->params[$key] : $default;
    }

    /**
     * Gets a specific formular.
     *
     * This formular will be created upon the first retrievement.
     * If created, the formular gets passed the formular parameters set in this container.
     *
     * @param string $key
     * @param bool $asInstance if set to false, the specification array is returned, and no instance created.
     *
     * @return null|\Core\Form\Container|\Zend\Form\FormInterface
     * @since 0,25 added $asInstance parameter
     */
    public function getForm($key, $asInstance = true)
    {
        if (false !== strpos($key, '.')) {
            list($key, $childKey) = explode('.', $key, 2);
            $container = $this->getForm($key);
            return $container->getForm($childKey);
        }

        if (!isset($this->forms[$key])) {
            return null;
        }

        $form = $this->forms[$key];

        if (!$asInstance) {
            return $form;
        }

        if (isset($form['__instance__']) && is_object($form['__instance__'])) {
            return $form['__instance__'];
        }

        $options = isset($form['options']) ? $form['options'] : array();
        if (!isset($options['name'])) {
            $options['name'] = isset($form['name']) ? $form['name'] : $key;
        }
        if (!isset($options['use_post_array'])) {
            $options['use_post_array'] = true;
        }
        if (!isset($options['use_files_array'])) {
            $options['use_files_array'] = false;
        }

        //@TODO: [ZF3] Passing options in $formElementManager->get is not working need to do manually set options
        $formInstance = $this->formElementManager->get($form['type'], $options);
        $formInstance->setOptions(array_merge($formInstance->getOptions(), $options));
        $formInstance->setParent($this);

        if (isset($form['attributes'])) {
            $formInstance->setAttributes($form['attributes']);
        }

        $formName = $this->formatAction($form['name']);
        $formInstance->setName($formName);
        $formAction = $formInstance->getAttribute('action');

        if (empty($formAction)) {
            $formInstance->setAttribute('action', '?form=' . $formName);
        }

        // @TODO: [ZF3] which one is correct? $form[options][label] or $form[options]
        if (isset($form['label'])) {
            $formLabel = $form['label'];
        } elseif (isset($form['options']['label'])) {
            $formLabel = $form['options']['label'];
        }

        if (isset($formLabel)) {
            $formInstance->setLabel($formLabel);
        }

        if (isset($form['disable_elements'])
            && $formInstance instanceof DisableElementsCapableInterface
            && $formInstance->isDisableElementsCapable()
        ) {
            $formInstance->disableElements($form['disable_elements']);
        }

        $entity = $this->getEntity($form['entity']);
        if ($entity) {
            $this->mapEntity($formInstance, $entity, isset($form['property']) ? $form['property'] : $key);
        }

        $formInstance->setParams($this->getParams());

        $this->forms[$key]['__instance__'] = $formInstance;
        $this->forms[$key]['options'] = $options;
        return $formInstance;
    }

    /**
     * Execute an arbitrary action
     *
     * @param string $name Name of an action
     * @param array $data Arbitrary data
     * @return array
     */
    public function executeAction($name, array $data = [])
    {
        if (false !== strpos($name, '.')) {
            list($name, $childKey) = explode('.', $name, 2);
            $container = $this->getForm($name);

            // execute child container's action
            return $container->executeAction($childKey, $data);
        }

        // this container defines no actions
        return [];
    }

    /**
     * Sets a form or form specification.
     *
     * if $spec is a string, it is used as form type, name is set to $key
     *
     * @param string       $key
     * @param string|array $spec
     * @param boolean      $enabled Should the formular be enabled or not
     *
     * @return self
     */
    public function setForm($key, $spec, $enabled = true)
    {
        if (is_object($spec)) {
            if ($spec instanceof FormParentInterface) {
                $spec->setParent($this);
            }

            $spec = [ '__instance__' => $spec, 'name' => $key, 'entity' => '*' ];
        }

        if (!is_array($spec)) {
            $spec = array('type' => $spec, 'name' => $key);
        }
        if (!isset($spec['name'])) {
            $spec['name'] = $key;
        }
        if (!isset($spec['entity'])) {
            $spec['entity'] = '*';
        }

        $this->forms[$key] = $spec;

        if ($enabled) {
            $this->enableForm($key);
        } elseif (true === $this->activeForms) {
            $this->activeForms = false;
        }
        return $this;
    }

    /**
     * Sets formulars or specifications.
     *
     * $forms must be in the format:
     *

     *    'name' => [spec]
     *

     *
     * $spec must be compatible with {@link setForm}.
     * Additionally you can include a key 'enabled' in the spec, which will override
     * $enabled only for the current formular.
     *
     * @param array $forms
     * @param boolean $enabled
     * @return \Core\Form\Container
     */
    public function setForms(array $forms, $enabled = true)
    {
        foreach ($forms as $key => $spec) {
            if (is_array($spec) && isset($spec['enabled'])) {
                $currentEnabled = $spec['enabled'];
                unset($spec['enabled']);
            } else {
                $currentEnabled = $enabled;
            }
            $this->setForm($key, $spec, $currentEnabled);
        }
        return $this;
    }

    /**
     * Enables a formular.
     *
     * Enabled formulars are included in the {@link getIterator()}
     *
     * Traverses in child containers through .dot-Notation.
     *
     * @param string $key
     * @return \Core\Form\Container
     */
    public function enableForm($key = null)
    {
        if (null === $key) {
            $this->activeForms = array_keys($this->forms);
            return $this;
        }

        if (!is_array($key)) {
            $key = array($key);
        }

        foreach ($key as $k) {
            if (false !== strpos($k, '.')) {
                // this seems not to be childkey.childform but actualkey.childkey
                list($childKey, $childForm) = explode('.', $k, 2);
                $child = $this->getForm($childKey);
                $child->enableForm($childForm);
            } else {
                if (isset($this->forms[$k]) && !in_array($k, $this->activeForms)) {
                    $this->activeForms[] = $k;
                }
            }
        }

        return $this;
    }

    /**
     * Disables a formular.
     *
     * @param string $key
     *
     * @return self
     */
    public function disableForm($key = null)
    {
        if (null === $key) {
            $this->activeForms = array();
            return $this;
        }

        if (!is_array($key)) {
            $key = array($key);
        }

        foreach ($key as $k) {
            if (false !== strpos($k, '.')) {
                list($childKey, $childForm) = explode('.', $k, 2);
                $child = $this->getForm($childKey);
                $child->disableForm($childForm);
            } elseif (isset($this->forms[$k]['__instance__'])) {
                unset($this->forms[$k]['__instance__']);
            }
        }
        $this->activeForms = array_filter(
            $this->activeForms,
            function ($item) use ($key) {
                return !in_array($item, $key);
            }
        );

        return $this;
    }

    /**
     * @param mixed $entity
     * @param string $key
     * @throws \InvalidArgumentException
     * @return Container
     */
    public function setEntity($entity, $key='*')
    {
        if (!$entity instanceof EntityInterface) {
            throw new \InvalidArgumentException(sprintf('$entity must be instance of %s', EntityInterface::class));
        }

        $this->entities[$key] = $entity;

        foreach ($this->forms as $formKey => $form) {
            if (isset($form['__instance__']) && is_object($form['__instance__']) && $key == $form['entity']) {
                $this->mapEntity($form['__instance__'], $entity, isset($form['property']) ? $form['property'] : $formKey);
            }
        }
        return $this;
    }

    /**
     * Gets the entity.
     *
     * @return \Core\Entity\EntityInterface
     */
    public function getEntity($key='*')
    {
        return isset($this->entities[$key]) ? $this->entities[$key] : null;
    }

    /**
     * Maps entity property to forms or child containers.
     *
     * @param \Zend\Form\FormInterface $form
     * @param \Core\Entity\EntityInterface $entity
     * @param string $property
     * @return void
     */
    protected function mapEntity($form, $entity, $property)
    {
        if (false === $property) {
            return;
        }

        if (true === $property) {
            $mapEntity = $entity;
        } elseif ($entity->hasProperty($property) || is_callable([$entity, "get$property"])) {
            $getter = "get$property";
            $mapEntity = $entity->$getter();
        } else {
            return;
        }
        if ($form instanceof Container) {
            $form->setEntity($mapEntity);
        } else {
            $form->bind($mapEntity);
        }
    }

    /**
     * Return isValid
     *
     * @return bool
     */
    public function isValid()
    {
        $isValid = true;
        foreach ($this->activeForms as $activeFormKey) {
            $activeForm = $this->getForm($activeFormKey);
            $isValid &= $activeForm->isValid();
        }
        return $isValid;
    }

    /**
     * if fieldsets there is get method to have access to any element by name
     * this method is similar
     * get('form') gets a form
     * get('element') gets an element, if an element has the same name as a form, the form get's first access
     * get('form.element') gets an element of a form, this is more efficent because it doesn't expand all forms in the container,
     *      but just the one adressed
     * @param $key string
     * @return null|\Zend\Form\ElementInterface
     */
    public function get($key)
    {
        $return   = null;
        $lastKey  = null;
        $searchIn = $this->activeForms;
        $keySplit = explode('.', $key);

        while (0 < count($keySplit)) {
            $lastKey = array_shift($keySplit);
            foreach ($searchIn as $activeFormKey) {
                if ($lastKey == $activeFormKey) {
                    $searchIn = $this->getForm($activeFormKey);
                    unset($lastKey);
                    break;
                }
            }
        }
        if (!isset($lastKey) && !empty($keySplit)) {
            $lastKey = array_shift($keySplit);
        }
        if (isset($lastKey) && empty($keySplit)) {
            if ($searchIn instanceof FieldsetInterface) {
                // has reached a fieldset to search in
                $return = $searchIn->get($lastKey);
                unset($lastKey);
            } elseif (is_array($searchIn) || $searchIn instanceof \Traversable) {
                // is probably still in the container
                foreach ($searchIn as $activeKey) {
                    $activeForm = $this->getForm($activeKey);
                    if ($activeForm instanceof FieldsetInterface) {
                        $return = $activeForm->get($lastKey);
                    }
                }
            }
        }
        if (!isset($lastKey) && empty($keySplit) && !isset($return)) {
            $return = $searchIn;
        }
        return $return;
    }

    /**
     * @param $data
     * @return $this
     */
    public function setData($data)
    {
        $filteredData = array();
        foreach ($data as $key => $elem) {
            if (!array_key_exists($key, $this->params) && $key != 'formName') {
                $filteredData[$key] = $elem;
            }
            if ($key == 'formName' && is_string($elem)) {
                // you can activate a specific form with postData
                foreach ($this->activeForms as $activeFormKey) {
                    if ($activeFormKey == $elem) {
                        $this->enableForm($activeFormKey);
                    } else {
                        $this->disableForm($activeFormKey);
                    }
                }
            }
        }
        foreach ($this->activeForms as $activeFormKey) {
            $activeForm = $this->getForm($activeFormKey);
            $activeForm->setData($filteredData);
        }
        return $this;
    }

    /**
     * @param $parent
     * @return $this
     */
    public function setParent($parent)
    {
        $this->parent = $parent;
        return $this;
    }

    /**
     * @return mixed
     */
    public function getParent()
    {
        return $this->parent;
    }

    /**
     * @return bool
     */
    public function hasParent()
    {
        return isset($this->parent);
    }

    /**
     * @param Renderer $renderer
     * @return string
     */
    public function renderPre(Renderer $renderer)
    {
        return '';
    }

    /**
     * @param Renderer $renderer
     * @return string
     */
    public function renderPost(Renderer $renderer)
    {
        return '';
    }

    /**
     * get the actual active Form
     * @param bool $setDefault
     * @return mixed|null
     */
    public function getActiveFormActual($setDefault = true)
    {
        $key = null;
        if (!empty($this->activeForms)) {
            $key = $this->activeForms[0];
        }
        if (!isset($key) && $setDefault) {
            $formsAvailable = array_keys($this->forms);
            $key = array_shift($formsAvailable);
        }
        return $key;
    }

    /**
     * get the form before the actual active
     * @return null
     */
    public function getActiveFormPrevious()
    {
        $key = null;
        $actualKey = $this->getActiveFormActual();
        if (isset($actualKey)) {
            $forms = array_keys($this->forms);
            $formsFlip =  array_flip($forms);
            $index = $formsFlip[$actualKey];
            if (0 < $index) {
                $key = $forms[$index-1];
            }
        }
        return $key;
    }

    /**
     * Gets the form after the actual active
     * @return null
     */
    public function getActiveFormNext()
    {
        $key = null;
        $actualKey = $this->getActiveFormActual();
        if (isset($actualKey)) {
            $forms = array_keys($this->forms);
            $formsFlip =  array_flip($forms);
            $index = $formsFlip[$actualKey];
            if ($index < count($forms) - 1) {
                $key = $forms[$index+1];
            }
        }
        return $key;
    }

    /**
     * Format an action name
     *
     * @param string $name Name of an action
     * @return string Formatted name of an action
     */
    public function formatAction($name)
    {
        return sprintf('%s%s', $this->hasParent() ? $this->getName() . '.' : '', $name);
    }

    /**
     * @param $key
     * @return string|null
     */
    public function getActionFor($key)
    {
        if (isset($this->forms[$key])) {
            return '?form=' . $this->formatAction($this->forms[$key]['name']);
        }
    }
}


<?php
/**
 * YAWIK
 *
 * @filesource
 * @license MIT
 * @copyright  2013 - 2017 Cross Solution <http://cross-solution.de>
 */

/** */
namespace Core\Form;

use Traversable;
use Zend\Form\Exception;
use Zend\Form\Form as ZfForm;
use Zend\Json\Json;
use Zend\Stdlib\ArrayUtils;
use Zend\Stdlib\PriorityList;

/**
 * ${CARET}
 *
 * @author Mathias Gelhausen <gelhausen@cross-solution.de>
 * @todo write test
 */
class SearchForm extends ZfForm
{
    use HydratorStrategyAwareTrait;

    protected $attributes = [
        'class'          => 'form-inline search-form',
        'data-handle-by' => 'script',
        'method'         => 'get',
    ];

    /**
     *
     *
     * @var \Zend\Stdlib\PriorityList
     */
    protected $buttonsIterator;

    protected $multiValueFields = [];

    protected $bindOnValidate = self::BIND_MANUAL;

    public function __construct($name = null, $options = [])
    {
        parent::__construct($name, $options);
        $this->buttonsIterator = new PriorityList();
        $this->buttonsIterator->isLIFO(false);
    }

    public function setButtonElement($name)
    {
        return $this->setOption('button_element', $name);
    }

    public function getButtonElement()
    {
        return $this->getOption('button_element');
    }

    /**
     * Sets the column map.
     *
     * @param array $map
     *
     * @see \Core\Form\View\Helper\SearchForm
     * @return self
     */
    public function setColumnMap($map)
    {
        $this->setOption('column_map', $map);

        return $this;
    }

    /**
     * Gets the column map.
     *
     * Generates the column map from the element options,
     * if none is set.
     *
     * @return array
     */
    public function getColumnMap()
    {
        $map = $this->getOption('column_map');

        if (null === $map) {
            $map = [];
            foreach ($this as $element) {
                $col = $element->getOption('span');
                if (null !== $col) {
                    $map[$element->getName()] = $col;
                }
            }

            $this->setOption('column_map', $map);
        }

        return $map;
    }

    public function setMultiValueFields(array $fields)
    {
        $multiValues = [];

        foreach ($fields as $name => $separator) {
            if (is_numeric($name)) {
                $name = $separator;
                $separator = ',';
            }

            $multiValues[$name] = $separator;
        }

        $this->multiValuesFields = $multiValues;
        $this->setAttribute('data-multivalues', Json::encode($multiValues));

        return $this;
    }

    public function setData($data)
    {
        foreach ($this->multiValueFields as $name => $separator) {
            if (array_key_exists($name, $data)) {
                $data[$name] = explode($separator, $data[$name]);
            }
        }

        return parent::setData($data); // TODO: Change the autogenerated stub
    }

    public function init()
    {
        $this->setName($this->getOption('name') ?: 'searchform');

        $this->addTextElement(
            $this->getOption('text_name') ?: 'q',
            $this->getOption('text_label') ?: /*@translate*/ 'Search',
            $this->getOption('text_placeholder') ?: /*@translate*/ 'Search query',
            $this->getOption('text_span') ?: 12,
            50,
            true
        );

        $this->addButton(/*@translate*/ 'Search', -1000, 'submit');
        $this->addButton(/*@translate*/ 'Clear', -1001, 'reset');

        $this->addElements();
    }

    protected function addElements()
    {
    }

    public function addTextElement($name, $label, $placeholder, $span = 12, $priority = 0, $isButtonElement = false)
    {
        $this->add(
            [
                'type' => 'Text',
                'options' => [
                    'label' => $label,
                    'span' => $span,
                ],
                'attributes' => [
                    'placeholder' => $placeholder,
                    'class' => 'form-control',
                ],
            ],
            [
                'name' => $name,
                'priority' => $priority,
            ]
        );

        if ($isButtonElement) {
            $this->setOption('button_element', $name);
        }
    }

    public function getButtons()
    {
        return $this->buttonsIterator;
    }

    public function addButton($name, $priority = 0, $type = 'button')
    {
        if (is_array($name)) {
            $label = $name[1];
            $name = $name[0];
        } else {
            $label = $name;
            $name = strtolower($name);
        }

        $factory = $this->getFormFactory();

        $button = $factory->create(
            [
                'type' => 'Button',
                'options' => [
                    'label' => $label,
                ],
                'attributes' => [
                    'class' => 'btn btn-' . ('submit' == $type ? 'primary' : 'default'),
                    'type'  => $type,
                ],
            ]
        );
        $button->setName($name);

        $this->buttonsIterator->insert($name, $button, $priority);

        return $this;
    }

    /**
     * Sets the initial search params.
     *
     * That means, the values for the elements
     * which should be set, if the form resets.
     *
     * @param array|\Traversable $params
     *
     * @return self
     */
    public function setSearchParams($params)
    {
        if ($params instanceof \Traversable) {
            $params = ArrayUtils::iteratorToArray($params);
        }

        $params = Json::encode($params);
        $this->setAttribute('data-search-params', $params);

        return $this;
    }
}


<?php
/**
 * @author Rik van der Kemp <rik@zicht.nl>
 * @copyright Zicht Online <http://www.zicht.nl>
 */

namespace Zicht\Bundle\PageBundle\Security\Voter;

use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface;
use Zicht\Bundle\PageBundle\Model\ScheduledContentInterface;

/**
 * Check content against the scheduled dates
 *
 * @package Zicht\Bundle\PageBundle\Security\Voter
 */
class ScheduledContentVoter extends AbstractAdminAwareVoter
{
    /**
     * Decide based on the current date and time what the vote should be. Static so it's strategy can easily be accessed
     * by other components as well, without the actual need for the voter instance.
     *
     * @param ScheduledContentInterface $object
     * @param array $attributes
     * @return int
     */
    public static function decide(ScheduledContentInterface $object, array $attributes = [])
    {
        $now = new \DateTimeImmutable();
        $vote = VoterInterface::ACCESS_ABSTAIN;
        $from = $object->isScheduledFrom();
        $till = $object->isScheduledTill();

        if (!$object->isPublic() || false === self::notEmpty($from, $till))  {
            return $vote;
        }

        switch (true) {
            case is_null($from):
                $vote = $till >= $now ? VoterInterface::ACCESS_GRANTED : VoterInterface::ACCESS_DENIED;
                break;
            case is_null($till):
                switch (true) {
                    case ($from <= $now):
                        $vote = VoterInterface::ACCESS_GRANTED;
                        break;
                    case ($from > $now && self::hasCmsAttribute($attributes)):
                        $vote = VoterInterface::ACCESS_GRANTED;
                        break;
                    default:
                        $vote = VoterInterface::ACCESS_DENIED;
                }
                break;
            default:
                switch (true) {
                    case ($from <= $now && $till >= $now):
                        $vote = VoterInterface::ACCESS_GRANTED;
                        break;
                    case (($from > $now && $till >= $now) && self::hasCmsAttribute($attributes)):
                        $vote = VoterInterface::ACCESS_GRANTED;
                        break;
                    default:
                        $vote = VoterInterface::ACCESS_DENIED;
                }
        }

        return $vote;
    }

    /**
     * Checks if the voter supports the given class.
     *
     * @param string $class A class name
     *
     * @return Boolean true if this Voter can process the class
     */
    public function supportsClass($class)
    {
        return in_array(ScheduledContentInterface::class, class_implements($class));
    }

    /**
     * @{inheritDoc}
     */
    public function vote(TokenInterface $token, $object, array $attributes)
    {
        // Abstract class checks if user is admin, if not so it will return VoterInterface::ACCESS_ABSTAIN
        $vote = parent::vote($token, $object, $attributes);

        /** @var ScheduledContentInterface $object */
        if ($vote === VoterInterface::ACCESS_ABSTAIN && !is_null($object) && $this->supportsClass(get_class($object))) {
            foreach ($attributes as $attribute) {
                if (!$this->supportsAttribute($attribute)) {
                    continue;
                }

                $vote = self::decide($object, $attributes);
            }
        }

        return $vote;
    }
}


<?php

namespace Core\Controller\Plugin;

use Interop\Container\ContainerInterface;
use Zend\EventManager\EventManagerInterface;
use Zend\Log\LoggerInterface;
use Zend\Mail\Transport\TransportInterface;
use Zend\ModuleManager\ModuleManagerInterface;
use Zend\Mvc\Controller\Plugin\PluginInterface;
use Zend\Stdlib\DispatchableInterface as Dispatchable;
use Zend\Mail\Message;
use Zend\Mail\Transport\Sendmail;
use Zend\Mail\AddressList;
use Zend\EventManager\Event;
use Zend\Stdlib\Parameters;
use Zend\Stdlib\ArrayUtils;
use Zend\View\Resolver\ResolverInterface;

class Mail extends Message implements PluginInterface
{
    /**
     * @var Dispatchable
     */
    protected $controller;

    /**
     * @var array
     */
    protected $param = array();

    /**
     * @var array
     */
    protected $config = array();

    /**
     * @var LoggerInterface
     */
    protected $mailLogger;

    /**
     * @var ResolverInterface
     */
    protected $viewResolver;

    /**
     * @var EventManagerInterface
     */
    protected $eventManager;

    /**
     * @var ModuleManagerInterface
     */
    protected $moduleManager;

    /**
     * @var TransportInterface
     */
    protected $transport;

    /**
     * Mail constructor.
     * @param LoggerInterface $mailLogger
     * @param ResolverInterface $viewResolver
     * @param EventManagerInterface $eventManager
     * @param ModuleManagerInterface $moduleManager
     */
    public function __construct(
        LoggerInterface $mailLogger,
        ResolverInterface $viewResolver,
        EventManagerInterface $eventManager,
        ModuleManagerInterface $moduleManager
    ) {
        $this->mailLogger       = $mailLogger;
        $this->viewResolver     = $viewResolver;
        $this->eventManager     = $eventManager;
        $this->moduleManager    = $moduleManager;
        $this->transport        = new Sendmail();
    }

    /**
     * Set the current controller instance
     *
     * @param  Dispatchable $controller
     * @return void
     */
    public function setController(Dispatchable $controller)
    {
        $this->controller = $controller;
    }

    /**
     * Get the current controller instance
     *
     * @return null|Dispatchable
     */
    public function getController()
    {
        return $this->controller;
    }

    /**
     * Set mail transport to be use
     *
     * @param TransportInterface $transport
     * @return $this
     */
    public function setTransport(TransportInterface $transport)
    {
        $this->transport = $transport;

        return $this;
    }

    /**
     * @return TransportInterface
     */
    public function getTransport()
    {
        return $this->transport;
    }

    public function __invoke(array $param = array())
    {
        $this->param = $param;
        $this->config = array();
        return $this;
    }

    protected function stringFromMailHeader($header)
    {
        $erg = '';
        if ($header instanceof AddressList) {
            $A = ArrayUtils::iteratorToArray($header);
            $AA = array();
            while (!empty($A)) {
                $AA[] = array_shift($A)->toString();
            }
            $erg = implode(',', $AA);
        }
        return $erg;
    }

    public function __toString()
    {
        $template = $this->getTemplate();
        $to = $this->stringFromMailHeader($this->getTo());
        $cc = $this->stringFromMailHeader($this->getCc());
        $bcc = $this->stringFromMailHeader($this->getBcc());
        $from = $this->stringFromMailHeader($this->getFrom());
        $replyTo = $this->stringFromMailHeader($this->getReplyTo());

        return str_pad($template, 30)
                . 'to: ' . str_pad($to, 50)
                . 'cc: ' . str_pad($cc, 50)
                . 'bcc: ' . str_pad($bcc, 50)
                . 'from: ' . str_pad($from, 50)
                . 'replyTo: ' . str_pad($replyTo, 50)
                //. str_pad(implode(',', ArrayUtils::iteratorToArray($this->getSender())),50)
                . 'subject: ' . str_pad($this->getSubject(), 50);
    }

    public function template($template)
    {
        $controller =  is_object($this->controller) ? get_class($this->controller):'null';

        $event = new Event();
        $eventManager = $this->eventManager;
        // @TODO: check if change this value into ['Mail'] not causing any errors!
        $eventManager->setIdentifiers(['Mail']);
        $p = new Parameters(array('mail' => $this, 'template' => $template));
        $event->setParams($p);
        $eventManager->trigger('template.pre', $event);

        // get all loaded modules
        $moduleManager = $this->moduleManager;
        $loadedModules = $moduleManager->getModules();
        //get_called_class
        $controllerIdentifier = strtolower(substr($controller, 0, strpos($controller, '\\')));
        $viewResolver = $this->viewResolver;

        $templateHalf = 'mail/' . $template;
        $resource = $viewResolver->resolve($templateHalf);

        if (empty($resource)) {
            $templateFull = $controllerIdentifier . '/mail/' . $template;
            $resource = $viewResolver->resolve($templateFull);
        }

        $__vars = $this->param;
        if (array_key_exists('this', $__vars)) {
            unset($__vars['this']);
        }
        extract($__vars);
        unset($__vars); // remove $__vars from local scope

        if ($resource) {
            try {
                ob_start();
                include $resource;
                $content = ob_get_clean();
                $this->setBody($content);
            } catch (\Exception $ex) {
                ob_end_clean();
                throw $ex;
            }
            $__vars = get_defined_vars();
            foreach ($this->param as $key => $value) {
                if (isset($__vars[$key])) {
                    unset($__vars[$key]);
                }
            }
            unset($__vars['content'],$__vars['controllerIdentifier'],$__vars['controller'],$__vars['resource'],$__vars['template'],$__vars['viewResolver']);
            $this->config = $__vars;
        }
    }

    protected function getTemplate()
    {
        $template = null;
        if (isset($this->config['templateFull'])) {
            $template = $this->config['templateFull'];
        } elseif (isset($this->config['templateHalf'])) {
            $template = $this->config['templateHalf'];
        } else {
            throw new \InvalidArgumentException('No template provided for Mail.');
        }
        return $template;
    }

    public function informationComplete()
    {
        $log = $this->mailLogger;
        $template = $this->getTemplate();
        if (isset($this->config['from'])) {
            $from = $this->config['from'];
        } else {
            $log->err('A from email address must be provided (Variable $from) in Template: ' . $template);
            throw new \InvalidArgumentException('A from email address must be provided (Variable $from) in Template: ' . $template);
        }
        if (isset($this->config['fromName'])) {
            $fromName = $this->config['fromName'];
        } else {
            $log->err('A from name must be provided (Variable $fromName) in Template: ' . $template);
            throw new \InvalidArgumentException('A from name must be provided (Variable $fromName) in Template: ' . $template);
        }
        if (isset($this->config['subject'])) {
            $subject = $this->config['subject'];
        } else {
            $log->err('A subject must be provided (Variable $subject) in Template: ' . $template);
            throw new \InvalidArgumentException('A subject must be provided (Variable $subject) in Template: ' . $template);
        }
        $this->setFrom($from, $fromName);
        $this->setSubject($subject);
        return $this;
    }

    public function send()
    {
        $log = $this->mailLogger;
        $this->getHeaders()->addHeaderLine('X-Mailer', 'php/YAWIK');

        $this->getHeaders()->addHeaderLine('Content-Type', 'text/plain; charset=UTF-8');

        $transport = $this->transport;
        $erg = false;
        try {
            $transport->send($this);
            $erg = true;
            $log->info($this);
        } catch (\Exception $e) {
            $log->err('Mail failure ' . $e->getMessage());
        }
        return $erg;
    }

    /**
     * @param ContainerInterface $container
     *
     * @return static
     */
    public static function factory(ContainerInterface $container)
    {
        //@TODO: need to define transport to be use during ::send()
        $mailLog        = $container->get('Log/Core/Mail');
        $viewResolver   = $container->get('ViewResolver');
        $eventManager   = $container->get('EventManager');
        $moduleManager  = $container->get('ModuleManager');
        return new static($mailLog,$viewResolver,$eventManager,$moduleManager);
    }
}


<?php
/**
 * @copyright Zicht Online <http://zicht.nl>
 */

namespace Zicht\Bundle\PageBundle\Admin;

use Sonata\AdminBundle\Admin\Admin;
use Sonata\AdminBundle\Datagrid\DatagridMapper;
use Sonata\AdminBundle\Datagrid\ListMapper;
use Sonata\AdminBundle\Form\FormMapper;
use Sonata\AdminBundle\Show\ShowMapper;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Zicht\Bundle\AdminBundle\Util\AdminUtil;
use Zicht\Bundle\MenuBundle\Entity\MenuItem;
use Zicht\Bundle\MenuBundle\Form\MenuItemType;
use Zicht\Bundle\MenuBundle\Form\Subscriber\MenuItemPersistenceSubscriber;
use Zicht\Bundle\MenuBundle\Manager\MenuManager;
use Zicht\Bundle\PageBundle\Entity\ContentItem;
use Zicht\Bundle\PageBundle\Manager\PageManager;
use Zicht\Bundle\PageBundle\Model\ContentItemContainer;
use Zicht\Bundle\PageBundle\Model\PageInterface;
use Zicht\Bundle\UrlBundle\Url\Provider;
use Zicht\Util\Str;

/**
 * Admin for the messages catalogue
 */
class PageAdmin extends Admin
{
    /**
     * @var bool
     */
    protected $persistFilters = true;

    /**
     * @var array
     */
    protected $templates = array();

    /**
     * @var PageManager
     */
    protected $pageManager;

    /**
     * @var MenuManager
     */
    protected $menuManager = null;

    /**
     * @var string
     */
    protected $contentItemAdminCode;

    /**
     * @var Provider|null
     */
    private $urlProvider = null;

    /**
     * Constructor, overridden to be able to set the (required) content item admin code.
     *
     * @param string $code
     * @param string $class
     * @param string $baseControllerName
     * @param string $contentItemAdminCode
     */
    public function __construct($code, $class, $baseControllerName, $contentItemAdminCode)
    {
        parent::__construct($code, $class, $baseControllerName);

        $this->contentItemAdminCode = $contentItemAdminCode;
    }

    /**
     * Set the page manager
     *
     * @param \Zicht\Bundle\PageBundle\Manager\PageManager $pageManager
     * @return void
     */
    public function setPageManager(PageManager $pageManager)
    {
        $this->pageManager = $pageManager;
    }

    /**
     * Set the menumanager, which is needed for flushing the menu items to the persistence layer whenever a page
     * is updated.
     *
     * @param \Zicht\Bundle\MenuBundle\Manager\MenuManager $manager
     * @return void
     */
    public function setMenuManager(MenuManager $manager)
    {
        $this->menuManager = $manager;
    }

    /**
     * Sets the url provider
     *
     * @param Provider $urlProvider
     * @return void
     */
    public function setUrlProvider(Provider $urlProvider)
    {
        $this->urlProvider = $urlProvider;
    }

    /**
     * @{inheritDoc}
     */
    public function configureShowFields(ShowMapper $showMapper)
    {
        return $showMapper->add('title');
    }

    /**
     * @{inheritDoc}
     */
    public function configureListFields(ListMapper $listMapper)
    {
        return $listMapper
            ->addIdentifier('title')
            ->add('displayType')
            ->add('date_updated')
            ->add(
                '_action',
                'actions',
                array(
                    'actions' => array(
                        'view' => array(),
                        'edit' => array(),
                        'delete' => array()
                    )
                )
            );
    }

    /**
     * @{inheritDoc}
     */
    public function configureFormFields(FormMapper $formMapper)
    {
        $formMapper
            ->tab('admin.tab.general')
                ->add('title', null, array('required' => true))
            ->end()->end();

        if (($subject = $this->getSubject()) && $subject->getId()) {
            if ($subject->getContentItemMatrix() && $subject->getContentItemMatrix()->getTypes()) {
                if (!($subject instanceof ContentItemContainer)) {
                    throw new \RuntimeException(sprintf('The zicht/page-bundle assumes that entity %s implements the ContentItemContainer interface.', get_class($subject)));
                }

                $formMapper
                    ->tab('admin.tab.content')
                    ->add(
                        'contentItems',
                        'sonata_type_collection',
                        array(
                            'btn_add' => 'content_item.add'
                        ),
                        array(
                            'edit'   => 'inline',
                            'inline' => 'table',
                            'sortable' => 'weight',
                            'admin_code' => $this->code . '|' . $this->contentItemAdminCode
                        )
                    )
                    ->end()->end();

                $formMapper->getFormBuilder()->addEventListener(
                    FormEvents::SUBMIT,
                    function (FormEvent $e) {
                        /** @var PageInterface $pageData */
                        $pageData = $e->getData();

                        $contentItems = $pageData->getContentItems();

                        foreach ($contentItems as $data) {
                            if (null === $data) {
                                continue;
                            }
                            $type = $data->getConvertToType();

                            if (!$data->getId() && $type !== get_class($data)) {
                                $item = new $type;

                                ContentItem::convert($data, $item);

                                $pageData->removeContentItem($data);
                                $pageData->addContentItem($item);
                            }
                        }
                        $e->setData($pageData);
                    },
                    64
                );
            }
            $formMapper
                ->tab('admin.tab.menu')
                ->add('menu_item', MenuItemType::class, array('translation_domain' => $this->getTranslationDomain()))
                ->end()
                ->end();

            $formMapper
                ->getFormBuilder()
                ->addEventSubscriber(
                    new MenuItemPersistenceSubscriber(
                        $this->menuManager,
                        $this->urlProvider,
                        'menu_item'
                    )
                );
        }
    }

    /**
     * @{inheritDoc}
     */
    protected function configureDatagridFilters(DatagridMapper $filter)
    {
        $filter->add('title')
            ->add('id');
    }

    /**
     * @{inheritDoc}
     */
    public function preUpdate($object)
    {
        $this->fixOneToMany($object);
    }

    /**
     * @{inheritDoc}
     */
    public function prePersist($object)
    {
        $this->fixOneToMany($object);
    }

    /**
     * Fixes the many-to-one side of the one-to-many content items and flushes the menu manager.
     *
     * @param \Zicht\Bundle\PageBundle\Model\PageInterface $object
     * @return void
     */
    protected function fixOneToMany(PageInterface $object)
    {
        $items = $object->getContentItems();
        if ($items) {
            foreach ($object->getContentItems() as $item) {
                $item->setPage($object);
            }
        }
        if ($this->menuManager) {
            $this->menuManager->flush();
        }
    }

    /**
     * Pre remove function
     *
     * @param mixed $object
     */
    public function preRemove($object)
    {
        if (!is_null($this->urlProvider) && !is_null($this->menuManager)) {
            $url      = $this->urlProvider->url($object);
            $menuItem = $this->menuManager->getItem($url);

            if ($menuItem instanceof MenuItem) {
                $this->menuManager->removeItem($menuItem);
                $this->menuManager->flush();
            }
        }
    }

    /**
     * Reorder tabs
     *
     * @param FormMapper $formMapper
     * @param array $tabOrder
     *
     * @deprecated See Zicht\Bundle\AdminBundle\Util\AdminUtil::reorderTabs
     *
     */
    public function reorderTabs(FormMapper $formMapper, array $tabOrder)
    {
        AdminUtil::reorderTabs($formMapper, $tabOrder);
    }

    /**
     * Removes field (and also removes the tab when the tab/group is empty)
     *
     * @param string|array $fieldNames one fieldname or array of fieldnames
     * @param FormMapper $formMapper
     * @return self
     */
    public function removeFields($fieldNames, FormMapper $formMapper)
    {
        if (!is_array($fieldNames)) {
            $fieldNames = array($fieldNames);
        }

        foreach ($fieldNames as $fieldName) {
            $formMapper->remove($fieldName);
        }

        $this->removeEmptyGroups();

        return $this;
    }

    /**
     * Removes tab and all it's fields in it
     *
     * @param string $tabName
     * @param FormMapper $formMapper
     */
    public function removeTab($tabName, FormMapper $formMapper)
    {
        $tabs = $this->getFormTabs();

        if (array_key_exists($tabName, $tabs)) {
            $groups = $this->getFormGroups();

            if (!is_array($groups)) {
                return;
            }

            foreach ($tabs[$tabName]['groups'] as $group) {
                if (isset($groups[$group])) {
                    foreach ($groups[$group]['fields'] as $field) {
                        $formMapper->remove($field);
                    }
                }
                unset($groups[$group]);
            }

            $this->setFormGroups($groups);
            $this->removeEmptyGroups();
        }
    }

    /**
     * Removes the empty tabs from the groups
     */
    public function removeEmptyGroups()
    {
        $tabs = $this->getFormTabs();

        if (!is_array($tabs)) {
            return;
        }

        $groups = $this->getFormGroups();

        foreach ($tabs as $tabKey => $tab) {
            foreach ($tab['groups'] as $tabGroup) {
                if (!array_key_exists($tabGroup, $groups)) {
                    unset($tabs[$tabKey]);
                }
            }
        }

        $this->setFormTabs($tabs);
    }

    /**
     * @{inheritDoc}
     */
    public function getLabel()
    {
        return sprintf('admin.label.%s', Str::infix(lcfirst(Str::classname(get_class($this))), '_'));
    }
}


<?php
/**
 * YAWIK
 *
 * @filesource
 * @license MIT
 * @copyright  2013 - 2016 Cross Solution <http://cross-solution.de>
 */

/** */
namespace Core\Factory\EventManager;

use Core\EventManager\EventProviderInterface;
use Interop\Container\ContainerInterface;
use Interop\Container\Exception\ContainerException;
use Zend\EventManager\ListenerAggregateInterface;
use Zend\ServiceManager\Factory\AbstractFactoryInterface;
use Zend\ServiceManager\Exception\ServiceNotCreatedException;
use Zend\ServiceManager\Exception\ServiceNotFoundException;
use Zend\ServiceManager\ServiceLocatorInterface;
use Zend\Stdlib\ArrayUtils;

/**
 * Creates event manager instances.
 *
 * Optionally configures these instances with options set in array with the key "event_manager" in the main config
 * array. Also creates listeners which are preconfigured in the options and automatically attaches them.
 *
 * The options array:
 * [
 *      'event_manager' => [
 *          'Meaningful/Service.Name/Events' => [
 *              'service' => string: Service name or class name of the event manager to create.
 *              'event'   => string: Service name or class name of the event class to be used.
 *              'configure' => bool: Wether or not to configure the service manager through THIS factory.
 *              'identifiers' => array: list of identifiers for the event manager.
 *              'listeners' => array: preconfigured listeners which will ONLY be created, when the
 *                                    event manager is created. (lazy loading)
 *      ]
 * ]
 *
 * The listeners array:
 *
 * [
 *      string:listener => string:event, // creates the listener with the key as name (or class) and attaches it
 *                                       // to the event manager on the provided event.
 *
 *      // If you need more options or need to attach to multiple events, you can use following syntax: //
 *      string:listener => [ string|array:event{, string:methodName}{, int:priority}{, bool:lazy }],
 *                      // First string item or any array item is used as event(s)
 *                      // Any string item (if event is already set) and any following string items set (and override previous) method names
 *                      // (the method name is the name of the method to be called upon the listener when the event happens.)
 *                      // Any int item set and override previously set priority.
 *                      // Any boolean item set and override previously set lazy option.
 *                      // (lazy option does provide even more lazy loading. The listener is only created, if
 *                      //  the event it listens to is actually triggered. (accomplished by \Core\Listener\DeferredListenerAggregate)
 *
 *      string:aggregate, // Creates an ListenerAggregate and call its attach method with the instance of the event manager
 *      string:aggregate => int:priority // Same as above, but passes the priority value along.
 * ]
 *
 * If you need to attach more than one method or two events with different priorities you can do so using the
 * verbose style in the listener array:
 *
 * [
 *      string:listener => [
 *          'events' => [
 *              string:eventName,
 *              string:eventName => int:priority,
 *              string:eventName' => string:method,
 *              string:eventName => [
 *                  'method' => string:method,
 *                  'method' => [ string:method, string:method, ... ],
 *                  'method' => [ string:method => int:priority, string:method' => int:priority ],
 *                  'priority' => int:priority,
 *              ],
 *          ],
 *          'method' => string:defaultMethod,
 *          'priority' => int:defaultPriority,
 *          'lazy' => bool
 *      ],
 * ]
 *
 * Example:
 * Attach one listener to two methods on one event:
 * [
 *      'Listener' => [ 'events' => [ 'eventName' => [ 'method' => ['method1', 'method2'] ] ] ],
 * ]
 *
 * Use default priority on method1 and different priority on method2:
 * [
 *      'Listener' => [ 'events' => [ 'eventName' => [ 'method' => ['method1', 'method2' => 12] ] ] ], 'priority' => 5 ],
 * ]
 *
 * Attach one listener to two events with different priority:
 * [
 *      'Listener' => [ 'events' => [ 'event1' => 1, 'event2' => 2 ] ],
 * ]
 *
 * Each specific event -> method -> priority triple will be attached searately to the event manager using the
 * same listener instance.
 *
 *
 * @author Mathias Gelhausen <gelhausen@cross-solution.de>
 * @since 0.25
 */
class EventManagerAbstractFactory implements AbstractFactoryInterface
{
    /**
     * Create an object
     *
     * @param  ContainerInterface $container
     * @param  string             $requestedName
     * @param  null|array         $options
     *
     * @return object
     * @throws ServiceNotFoundException if unable to resolve the service.
     * @throws ServiceNotCreatedException if an exception is raised when
     *     creating a service.
     * @throws ContainerException if any other error occurs
     */
    public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
    {
        $config = $this->getConfig($container, $requestedName);
        $events = $this->createEventManager($container, $config);

        $this->attachListeners($container, $events, $config['listeners']);
        return $events;
    }

    /**
     * Can the factory create an instance for the service?
     *
     * @param  ContainerInterface $container
     * @param  string             $requestedName
     *
     * @return bool
     */
    public function canCreate(ContainerInterface $container, $requestedName)
    {
        /* We check, if $requestedName ends with the string '/Events'.
         * Instead of parsing the string with regular expressions (eg. ~/Events$~),
         * it's more efficient to just check with strpos, if the reversed string starts
         * with the reverted '/Events' string.
         */
        return 0 === strpos(strrev($requestedName), 'stnevE/');
    }

    public function canCreateServiceWithName(ServiceLocatorInterface $serviceLocator, $name, $requestedName)
    {
        return $this->canCreate($serviceLocator, $requestedName);
    }

    /**
     * Creates an event manager and attaches preconfigured listeners.
     *
     * @param ServiceLocatorInterface $serviceLocator
     * @param string                  $name
     * @param string                  $requestedName
     *
     * @return \Zend\EventManager\EventManagerInterface
     * @throws \UnexpectedValueException
     */
    public function createServiceWithName(ServiceLocatorInterface $serviceLocator, $name, $requestedName)
    {
        return $this($serviceLocator, $requestedName);
    }

    /**
     * Gets configuration for an event manager.
     *
     * Merges the default config with configuration from the main config,
     * if a key $name exists in the array under the "event_manager" array in the main config.
     *
     * @param ServiceLocatorInterface $services
     * @param string $name
     *
     * @return array
     */
    protected function getConfig($services, $name)
    {
        $defaults = [
            'service' => 'EventManager',
            'configure' => true,
            'identifiers' => [ $name ],
            'event' => '\Zend\EventManager\Event',
            'listeners' => [],
        ];

        $config = $services->get('Config');
        $config = isset($config['event_manager'][$name]) ? $config['event_manager'][$name] : [];

        /*
         * array_merge does not work, because the default values for 'identifiers' and 'listeners'
         * are arrays and array_merge breaks the structure.
         */
        $config = array_replace_recursive($defaults, $config);

        return $config;
    }

    /**
     * Creates an event manager instance.
     *
     * Fetches from the service manager or tries to instantiate direct, if no service
     * exists in the service manager.
     *
     * If the key 'configure' in the config array has the value TRUE (default),
     * the event manager instance will get configured. Which means, the event prototype
     * will be set (after it is fetched from the service manager or instatiated),
     * and the shared event manager will be injected.
     *
     * @param ServiceLocatorInterface $services
     * @param array $config
     *
     * @return \Zend\EventManager\EventManagerInterface
     * @throws \UnexpectedValueException if neither a service exists, nor could a class be found.
     */
    protected function createEventManager($services, $config)
    {
        /* @var \Zend\EventManager\EventManagerInterface|\Core\EventManager\EventProviderInterface $events */

        if ($services->has($config['service'])) {
            $events = $services->get($config['service']);
        } else {
            if (!class_exists($config['service'], true)) {
                throw new \UnexpectedValueException(sprintf(
                    'Class or service %s does not exists. Cannot create event manager instance.',
                    $config['service']
                ));
            }

            $events = new $config['service']();
        }

        if (false === $config['configure']) {
            return $events;
        }

        $events->setIdentifiers($config['identifiers']);

        /* @var \Zend\EventManager\EventInterface $event */
        $event = $services->has($config['event']) ? $services->get($config['event']) : new $config['event']();
        $events->setEventPrototype($event);

        if ('EventManager' != $config['service'] && method_exists($events, 'setSharedManager') && $services->has('SharedEventManager')) {
            /* @var \Zend\EventManager\SharedEventManagerInterface $sharedEvents */
            $sharedEvents = $services->get('SharedEventManager');
            $events->setSharedManager($sharedEvents);
        }

        return $events;
    }

    /**
     * Attaches listeners provided in the config to the event manager instance.
     *
     * @param ServiceLocatorInterface $services
     * @param \Zend\EventManager\EventManagerInterface $eventManager
     * @param array $listeners
     *
     * @throws \UnexpectedValueException if a listener name cannot be fetched as service or be instantiated.
     */
    protected function attachListeners($services, $eventManager, $listeners)
    {
        $lazyListeners = [];

        foreach ($listeners as $name => $options) {
            $options = $this->normalizeListenerOptions($name, $options);

            if ($options['lazy'] && null !== $options['attach']) {
                foreach ($options['attach'] as $spec) {
                    $lazyListeners[] = [
                        'service' => $options['service'],
                        'event' => $spec['event'],
                        'method' => $spec['method'],
                        'priority' => $spec['priority'],
                    ];
                }
                continue;
            }

            if ($services->has($options['service'])) {
                $listener = $services->get($options['service']);
            } elseif (class_exists($options['service'], true)) {
                $listener = new $options['service']();
            } else {
                throw new \UnexpectedValueException(sprintf(
                                                        'Class or service %s does not exists. Cannot create listener instance.',
                    $options['service']
                                                    ));
            }

            if ($listener instanceof ListenerAggregateInterface) {
                $listener->attach($eventManager, $options['priority']);
                continue;
            }

            foreach ($options['attach'] as $spec) {
                $callback = $spec['method'] ? [ $listener, $spec['method'] ] : $listener;
                $eventManager->attach($spec['event'], $callback, $spec['priority']);
            }
        }

        if (!empty($lazyListeners)) {
            /* @var \Core\Listener\DeferredListenerAggregate $aggregate */
            $aggregate = $services->get('Core/Listener/DeferredListenerAggregate');
            $aggregate->setListeners($lazyListeners)
                      ->attach($eventManager);
        }
    }

    /**
     * Normalizes the listener configuration.
     *
     * Converts the options given in the main config file to an array
     * containing key => value pairs for easier consumption in
     * {@link attachListeners()}
     *
     * @param int|string $name Service or class name of the listener. (if int, we have config for an aggregate)
     * @param string|array $options String is either event name or aggregate name (when name is int).
     *                              Array are the options from config. [ [event,..], method, priority, lazy]
     *
     * @return array
     */
    protected function normalizeListenerOptions($name, $options)
    {

        /*
         * $options is an array with following meta-syntax:
         *
         *  $options = [
         *      string:listener => string:event,
         *      string:listener => [ string|array:event{, string:methodName}{, int:priority}{, bool:lazy }],
         *      string:aggregate, // implies integer value as $name
         *      string:aggregate => int:priority,
         *      string:listener => [
         *          'events' => [ 'event', 'event' => priority, 'event' => 'method',
         *                        'event' => [ 'method' => method, 'priority' => priority ],
         *                        'event' => [ 'method' => [ 'method', 'method' => priority ], 'priority' => priority ]
         *                     ],
         *          'method' => method,
         *          'priority' => priority,
         *          'lazy' => bool
         * ]
         */

        $normalized = [
            'service' => $name,
            'attach' => null,
            'priority' => 1,
            'lazy' => false,
        ];

        if (is_int($name)) {
            /* $options must be the name of an aggregate service or class. */
            $normalized['service'] = $options;
            return $normalized;
        }

        if (is_int($options)) {
            /* $name must be the name of an aggregate and the priority is passed. */
            $normalized['priority'] = $options;
            return $normalized;
        }

        if (is_string($options)) {
            /* Only an event name is provided in config */
            $normalized['attach'] = [ [ 'event' => $options, 'method' => null, 'priority' => 1 ] ];
            return $normalized;
        }

        if (ArrayUtils::isHashTable($options)) {
            $normalized['attach'] = $this->normalizeEventsSpec($options);

            if (isset($options['lazy'])) {
                $normalized['lazy'] = $options['lazy'];
            }

            return $normalized;
        }

        $event = $method = null;
        $priority = 1;
        $lazy = false;

        foreach ($options as $opt) {
            if (is_array($opt)) {
                /* Must be event names */
                $event = $opt;
            } elseif (is_string($opt)) {
                if (null === $event) {
                    /* first string found is assumed to be the event name */
                    $event = [ $opt ];
                } else {
                    /* second string found must be a method name. */
                    $method = $opt;
                }
            } elseif (is_int($opt)) {
                /* Integer values must be priority */
                $priority = $opt;
            } elseif (is_bool($opt)) {
                /* Lazy option is passed. */
                $lazy = $opt;
            }
        }

        foreach ($event as &$eventSpec) {
            $eventSpec = [ 'event' => $eventSpec, 'method' => $method, 'priority' => $priority ];
        }

        $normalized['attach'] = $event;
        $normalized['lazy']   = $lazy;

        return $normalized;
    }

    protected function normalizeEventsSpec($options)
    {
        $listenerPriority = isset($options['priority']) ? $options['priority'] : 1;
        $listenerMethod   = isset($options['method'])   ? $options['method']   : '__none__';
        $events = [];

        foreach ($options['events'] as $event => $spec) {
            $eventPriority = isset($spec['priority']) ? $spec['priority'] : $listenerPriority;

            if (is_int($event)) {
                $events[$listenerMethod][$eventPriority][] = $spec;
            } elseif (is_int($spec)) {
                $events[$listenerMethod][$spec][] = $event;
            } elseif (is_string($spec)) {
                $events[$spec][$eventPriority][] = $event;
            } elseif (is_array($spec)) {
                if (isset($spec['method'])) {
                    if (!is_array($spec['method'])) {
                        $spec['method'] = [ $spec['method'] ];
                    }

                    foreach ($spec['method'] as $method => $methodPriority) {
                        if (is_int($method)) {
                            $events[$methodPriority][$eventPriority][] = $event;
                        } elseif (is_int($methodPriority)) {
                            $events[$method][$methodPriority][] = $event;
                        }
                    }
                }
            }
        }

        $eventsSpec = [];
        foreach ($events as $method => $priorities) {
            foreach ($priorities as $priority => $event) {
                foreach ($event as $ev) {
                    $eventsSpec[] = [
                        'event'    => $ev,
                        'method'   => '__none__' == $method ? null : $method,
                        'priority' => $priority,
                    ];
                }
            }
        }

        return $eventsSpec;
    }
}


<?php
/**
 * YAWIK
 *
 * @filesource
 * @license    MIT
 * @copyright  2013 - 2016 Cross Solution <http://cross-solution.de>
 */

/** */
namespace Core\Entity;

use Doctrine\ODM\MongoDB\Mapping\Annotations as ODM;

/**
 * ${CARET}
 *
 * @ODM\MappedSuperclass
 * @author Mathias Gelhausen <gelhausen@cross-solution.de>
 * @todo   write test
 */
abstract class AbstractStatusEntity implements StatusInterface
{
    protected static $orderMap = [];

    public static function getStates()
    {
        $map = static::$orderMap;
        asort($map, SORT_NUMERIC);

        return array_keys($map);
    }

    /**
     * The default status to be set if none provided.
     *
     * @var string
     */
    protected $default;

    /**
     * The status name.
     *
     * @ODM\Field(type="string")
     * @var string
     */
    private $name;

    /**
     * The order priority
     *
     * @ODM\Field(type="int")
     * @var int
     */
    private $order;

    public function __construct($name = null)
    {
        $this->init($name);
    }

    public function __toString()
    {
        return $this->name;
    }

    public function is($name)
    {
        return $this->name == (string) $name;
    }

    /**
     * Initialize this state.
     *
     * @param string $name
     *
     * @throws \InvalidArgumentException
     */
    private function init($name)
    {
        if (null === $name) {
            $name = $this->default;
        }

        if (!isset(static::$orderMap[ $name ])) {
            throw new \InvalidArgumentException(sprintf(
                'Unknown status name "%s" for "%s"',
                $name,
                static::class
            ));
        }

        $this->name  = $name;
        $this->order = static::$orderMap[ $name ];
    }
}


<?php
/**
 * YAWIK
 *
 * @filesource
 * @copyright (c) 2013 - 2016 Cross Solution (http://cross-solution.de)
 * @license   MIT
 */

namespace Core\Controller\Plugin;

use Zend\EventManager\EventInterface;
use Zend\Mvc\Controller\Plugin\AbstractPlugin;
use Zend\View\Model\ViewModel;

/**
 * Class ContentCollector
 *
 * @package Core\Controller\Plugin
 * @author Anthonius Munthi <me@itstoni.com>
 */
class ContentCollector extends AbstractPlugin
{
    /**
     * @var string
     */
    protected $_captureTo;

    /**
     * @var string
     */
    protected $_template;

    /**
     * ContentCollector constructor.
     */
    public function __construct()
    {
        $this->_captureTo = 'content_';
    }

    /**
     * Setting the template name to use
     *
     * @param   string  $template
     * @return  $this
     */
    public function setTemplate($template)
    {
        $this->_template = $template;
        return $this;
    }

    /**
     * Setting capture to
     *
     * @param $captureTo
     * @return $this
     */
    public function captureTo($captureTo)
    {
        $this->_captureTo = $captureTo;
        return $this;
    }

    /**
     * Trigger capture event
     *
     * @param   EventInterface $event
     * @param   mixed|null  $target
     *
     * @return  ViewModel
     */
    public function trigger($event, $target = null)
    {
        if (empty($this->_template) || !is_string($this->_template)) {
            throw new \InvalidArgumentException('ContentCollector must have a template-name');
        }

        $responseCollection = $this->getController()->getEventManager()->trigger($event, $target);
        $viewModel = new ViewModel();
        $viewModel->setTemplate($this->_template);
        foreach ($responseCollection as $i => $response) {
            if (is_string($response)) {
                $template = $response;
                $response = new ViewModel(array('target' => $target));
                $response->setTemplate($template);
            }
            $viewModel->addChild($response, $this->_captureTo . $i);
        }

        return $viewModel;
    }
}


<?php

namespace Core\Form\View\Helper;

use Zend\Form\View\Helper\FormRow as ZendFormRow;
use Zend\Form\View\Helper\AbstractHelper;
use Zend\Form\ElementInterface;

class FormRowCombined extends AbstractHelper
{
    protected $layout;

    public function getFormRowHelper()
    {
        $helper = clone $this->view->plugin('formRow');
        $helper->setShouldWrap(false);
        return $helper;
    }

    /**
     * Utility form helper that renders a label (if it exists), an element and errors
     *
     * @param ElementInterface $elements
     * @return string
     * @throws \Zend\Form\Exception\DomainException
     */
    public function render(array $elements)
    {
        $formRowHelper = $this->getFormRowHelper();
        $labels = array();
        $markups = '';
        $totalSpanWidth = 0;
        foreach ($elements as $spanWidth => $element) {
            $elementErrors = $element->getMessages();
            $markup = $formRowHelper->render($element);
            if (preg_match('~<label.*~isU', $markup, $match)) {
                $labels[] = $match[0];
                $markup = str_replace($match[0], '', $markup);
            } else {
                //$labels[] = false;
            }
            $markups .= sprintf(
                '
%s
',
                $spanWidth,
                empty($elementErrors) ? '' : ' input-error',
                $markup
            );
            $totalSpanWidth += $spanWidth;
        }
        $labelSpanWidth = 12 - $totalSpanWidth;

        $labelMarkup = sprintf(
            '
%s
',
            $labelSpanWidth,
            implode(' / ', $labels)
        );

        $form_row_class = 'row';
        if ($this->layout == 'form-horizontal') {
            $form_row_class = 'form-group';
        }

        return sprintf(
            '
%s%s
',
            $labelMarkup,
            $markups
        );
    }

    /**
     * Invoke helper as function
     *
     * Proxies to {@link render()}.
     *
     * @param null|ElementInterface $element
     * @param null|string           $labelPosition
     * @param bool                  $renderErrors
     * @return string|FormRow
     */
    public function __invoke(array $elements = array(), $labelPosition = null, $renderErrors = null, $layout = null)
    {
        if (empty($elements)) {
            return $this;
        }

        if (null !== $layout) {
            $this->layout = $layout;
        }

        return $this->render($elements);
    }
}


<?php
/**
 * YAWIK
 *
 * @filesource
 * @copyright (c) 2013 - 2016 Cross Solution (http://cross-solution.de)
 * @license   MIT
 */

/** TranslatorAwareMessage.php */
namespace Core\Mail;

use Zend\I18n\Translator\TranslatorAwareInterface;
use Zend\I18n\Translator\Translator;
use Zend\I18n\Translator\TranslatorInterface;

class TranslatorAwareMessage extends Message implements TranslatorAwareInterface
{
    protected $translator;
    protected $translatorEnabled = false;
    protected $translatorTextDomain = 'default';

    /**
     * @see \Zend\I18n\Translator\TranslatorAwareInterface::getTranslator()
     *
     * @return Translator
     */
    public function getTranslator()
    {
        return $this->translator;
    }

    /* (non-PHPdoc)
     * @see \Zend\I18n\Translator\TranslatorAwareInterface::getTranslatorTextDomain()
     */
    public function getTranslatorTextDomain()
    {
        return $this->translatorTextDomain;
    }

    /* (non-PHPdoc)
     * @see \Zend\I18n\Translator\TranslatorAwareInterface::hasTranslator()
     */
    public function hasTranslator()
    {
        return null !== $this->translator;
    }

    /* (non-PHPdoc)
     * @see \Zend\I18n\Translator\TranslatorAwareInterface::isTranslatorEnabled()
     */
    public function isTranslatorEnabled()
    {
        return $this->hasTranslator() && $this->translatorEnabled;
    }

    /* (non-PHPdoc)
     * @see \Zend\I18n\Translator\TranslatorAwareInterface::setTranslator()
     */
    public function setTranslator(TranslatorInterface $translator = null, $textDomain = null)
    {
        if ($translator) {
            $this->translator = $translator;
        }
        $this->setTranslatorTextDomain($textDomain);
        return $this;
    }

    /* (non-PHPdoc)
     * @see \Zend\I18n\Translator\TranslatorAwareInterface::setTranslatorEnabled()
     */
    public function setTranslatorEnabled($enabled = true)
    {
        $this->translatorEnabled = (bool) $enabled;
        return $this;
    }

    /* (non-PHPdoc)
     * @see \Zend\I18n\Translator\TranslatorAwareInterface::setTranslatorTextDomain()
     */
    public function setTranslatorTextDomain($textDomain = 'default')
    {
        $this->translatorTextDomain = $textDomain;
        return $this;
    }

    /**
     * Sets the message subject.
     *
     * The passed string is automatically translated.
     * Any additional argument is passed in to sprintf to replace
     * placeholders in the subject string.
     *
     * If the $translate is FALSE, the subject is NOT translated.
     *
     * <pre>
     * <?php
     *      $mail->setSubject('translated subject');
     *      $mail->setSubject('translated %s with placeholder', 'subject');
     *      $mail->setSubject('untranslated subject', false);
     * ?>
     * </pre>
     *
     * @param string $subject
     * @param bool|mixed $translate
     *
     * @since 0.19
     * @since 0.29 Add sprintf support for translation
     *
     * @return Message
     */
    public function setSubject($subject, $translate = true)
    {
        if (false !== $translate) {
            $translator = $this->getTranslator();
            $domain     = $this->getTranslatorTextDomain();

            if (true === $translate) {
                $subject = $translator->translate($subject, $domain);
            } else {
                $args = func_get_args();
                $args[0] = $translator->translate($args[0], $domain);
                $subject = call_user_func_array('sprintf', $args);
            }
        }

        return parent::setSubject($subject);
    }

    /**
     *
     *
     * @param $formatString
     *
     * @return \Zend\Mail\Message
     *
     * @deprecated since 0.29 use setSubject(formatString, replacement, ...)
     * @codeCoverageIgnore
     */
    public function setFormattedSubject($formatString)
    {
        $args       = func_get_args();
        $translator = $this->getTranslator();
        $args       = array_slice($args, 1);
        $domain     = $this->getTranslatorTextDomain();
        $subject    = $translator->translate($formatString, $domain);
        array_unshift($args, $subject);
        $subject    = call_user_func_array('sprintf', $args);
        return parent::setSubject($subject);
    }
}


<?php
/**
 * YAWIK
 *
 * @filesource
 * @license MIT
 * @copyright  2013 - 2016 Cross Solution <http://cross-solution.de>
 */

/** */
namespace Core\Entity;

use Doctrine\ODM\MongoDB\Mapping\Annotations as ODM;

/**
 * ${CARET}
 *
 * @property string $permissionsType
 *
 * @author Mathias Gelhausen <gelhausen@cross-solution.de>
 * @todo write test
 *
 */
trait PermissionsAwareTrait
{
    /**
     * The permissions.
     *
     * @ODM\EmbedOne(targetDocument="\Core\Entity\Permissions")
     * @var PermissionsInterface
     */
    private $permissions;

    public function setPermissions(PermissionsInterface $permissions)
    {
        $this->permissions = $permissions;

        return $this;
    }

    /**
     * Gets the permissions entity.
     *
     * @internal
     *      If no permissions entity is set, it creates a
     *      {@link Permissions} instance and set its type to
     *      either the value provided with the property 'permissionsType' or
     *      to the entity class name, where '\\Entity\\' is replaced with '/',
     *      which leads to types such as MODULE/NAME.
     *
     *      Calls a method named 'setupPermissions' and passing the newly
     *      created permissions instance if such a method exists in the using class.
     *
     * @return PermissionsInterface
     */
    public function getPermissions()
    {
        if (!$this->permissions) {
            $type = property_exists($this, 'permissionsType')
                ? $this->permissionsType
                : str_replace('\\Entity\\', '/', static::class);
            $permissions = new Permissions($type);

            if (method_exists($this, 'setupPermissions')) {
                $this->setupPermissions($permissions);
            }

            $this->setPermissions($permissions);
        }

        return $this->permissions;
    }
}


<?php
/**
 * YAWIK
 *
 * @filesource
 * @license MIT
 * @copyright  2013 - 2019 Cross Solution <http://cross-solution.de>
 */

declare(strict_types=1);

/** */
namespace Core\Queue\Strategy;

use SlmQueue\Job\AbstractJob;
use SlmQueue\Job\JobInterface;
use SlmQueue\Strategy\AbstractStrategy;
use SlmQueue\Worker\Event\AbstractWorkerEvent;
use SlmQueue\Worker\Event\BootstrapEvent;
use SlmQueue\Worker\Event\FinishEvent;
use SlmQueue\Worker\Event\ProcessJobEvent;
use Zend\EventManager\EventManagerInterface;
use Zend\Log\LoggerAwareInterface;
use Zend\Log\LoggerInterface;

/**
 * Queue Worker Strategy to log events using an instance of {@link LoggerInterface}
 *
 * If the processed job implements LoggerAwareInterface, the Logger gets injected
 * into the job - unless {@link injectLogger} is false.
 *
 * @author Mathias Gelhausen <gelhausen@cross-solution.de>
 * @todo write test
 */
class LogStrategy extends AbstractStrategy
{
    /**
     * The logger instance.
     *
     * @var LoggerInterface
     */
    private $logger;

    /**
     * Templates for log messages
     *
     * @var array
     */
    private $tmpl = [
        'queue' => '%s queue: %s',
        'job'   => '{ %s } [ %s ] %s',
    ];

    /**
     * Inject the logger in the processed job?
     *
     * @var bool
     */
    private $injectLogger = true;

    /**
     * LogStrategy constructor.
     *
     * @param array|LoggerInterface|null $options
     */
    public function __construct($options = null)
    {
        if (null === $options) { return; }

        if ($options instanceOf LoggerInterface) {
            $options = ['logger' => $options];
        }

        if (!is_array($options)) {
            throw new \InvalidArgumentException('Options must be of type array or ' . LoggerInterface::class);
        }

        parent::__construct($options);
    }

    /**
     * Set the logger instance
     *
     * @param LoggerInterface $logger
     */
    public function setLogger(Loggerinterface $logger) : void
    {
        $this->logger = $logger;
    }

    /**
     * Get the logger instance
     *
     * If no instance is set yet, it will return an instance of
     * an anonymous class implemeting LoggerInterface which does nothing.
     *
     * @return LoggerInterface
     */
    public function getLogger() : LoggerInterface
    {
        if (!$this->logger) {
            $logger = new class implements LoggerInterface
            {
                public function emerg($message, $extra = []) : void {}
                public function alert($message, $extra = []) : void {}
                public function crit($message, $extra = []) : void {}
                public function err($message, $extra = []) : void {}
                public function warn($message, $extra = []) : void {}
                public function notice($message, $extra = []) : void {}
                public function info($message, $extra = []) : void {}
                public function debug($message, $extra = []) : void {}
            };
            $this->setLogger($logger);
        }

        return $this->logger;
    }

    /**
     * Set the template for queue events log messages
     *
     * @param string $template
     */
    public function setLogQueueEventsTemplate(string $template) : void
    {
        $this->tmpl['queue'] = $template;
    }

    /**
     * Set the template for job events log messages.
     *
     * @param string $template
     */
    public function setLogJobEventsTemplate(string $template) : void
    {
        $this->tmpl['job'] = $template;
    }

    /**
     * Set or get the injectLogger flag
     *
     * If called with an argument, sets the flag accordingly and returns
     * it.
     *
     * @param bool|null $flag
     * @return bool
     */
    public function injectLogger(bool $flag = null) : bool
    {
        if (null === $flag) { return $this->injectLogger; }

        $this->injectLogger = $flag;
        return $flag;
    }

    /**
     * Registers itself with an EventManager
     *
     * @param EventManagerInterface $events
     * @param int                   $priority
     */
    public function attach(EventManagerInterface $events, $priority = 1) : void
    {
        $this->listeners[] = $events->attach(AbstractWorkerEvent::EVENT_BOOTSTRAP, [$this, 'logBootstrap'], 1000);
        $this->listeners[] = $events->attach(AbstractWorkerEvent::EVENT_FINISH, [$this, 'logFinish'], 1000);
        $this->listeners[] = $events->attach(AbstractWorkerEvent::EVENT_PROCESS_JOB, [$this, 'logJobStart'], 1000);
        $this->listeners[] = $events->attach(AbstractWorkerEvent::EVENT_PROCESS_JOB, [$this, 'logJobEnd'], -1000);
        $this->listeners[] = $events->attach(AbstractWorkerEvent::EVENT_PROCESS_IDLE, [$this, 'injectLoggerInEvent'], 1000);
        $this->listeners[] = $events->attach(AbstractWorkerEvent::EVENT_PROCESS_STATE, [$this, 'injectLoggerInEvent'], 1000);
    }

    /**
     * Listener method for queue bootstrap event
     *
     * @param BootstrapEvent $event
     */
    public function logBootstrap(BootstrapEvent $event) : void
    {
        $this->getLogger()->info(sprintf(
            $this->tmpl['queue'],
            'Start',
            $event->getQueue()->getName()
        ));

        $this->injectLoggerInObject($event->getWorker());
        $this->injectLoggerInEvent($event);
    }

    /**
     * Listener method for queue finish event
     *
     * @param FinishEvent $event
     */
    public function logFinish(FinishEvent $event) : void
    {
        $this->getLogger()->info(sprintf(
            $this->tmpl['queue'],
            'Stop',
            $event->getQueue()->getName()
        ));

        $this->injectLoggerInEvent($event);
    }

    /**
     * listener method for process job event.
     *
     * Called early due to high priority.
     *
     * @param ProcessJobEvent $event
     */
    public function logJobStart(ProcessJobEvent $event) : void
    {
        $queue  = $event->getQueue();
        $job    = $event->getJob();
        $logger = $this->getLogger();

        $logger->info(sprintf(
            $this->tmpl['job'],
            $queue->getName(),
            'START',
            $this->formatJob($job),
            ''
        ));

        $this->injectLoggerInObject($job);
        $this->injectLoggerInEvent($event);
    }

    /**
     * listener method for process job event
     *
     * Called late due to low priority
     *
     * @param ProcessJobEvent $event
     */
    public function logJobEnd(ProcessJobEvent $event) : void
    {
        $result  = $event->getResult();
        $job     = $event->getJob();
        $queue   = $event->getQueue()->getName();
        $logger  = $this->getLogger();

        switch ($result) {
            default:

                $logger->info(sprintf(
                    $this->tmpl['job'],
                    $queue,
                    'SUCCESS',
                    $this->formatJob($job)
                ));
                break;

            case ProcessJobEvent::JOB_STATUS_FAILURE_RECOVERABLE:
                $logger->warn(sprintf(
                    $this->tmpl['job'],
                    $queue,
                    'RECOVERABLE',
                    $this->formatJob($job)
                ));

                break;

            case ProcessJobEvent::JOB_STATUS_FAILURE:
                $logger->err(sprintf(
                    $this->tmpl['job'],
                    $queue,
                    'FAILURE',
                    $this->formatJob($job)
                ));

                break;
        }
    }

    public function injectLoggerInEvent(AbstractWorkerEvent $event)
    {
        if ($this->injectLogger()) {
            $event->setParam('logger', $this->getLogger());
        }
    }

    private function injectLoggerInObject($object) : void
    {
        if ($this->injectLogger() && $object instanceOf LoggerAwareInterface) {
            $object->setLogger($this->getLogger());
        }
    }

    /**
     * Get a string representation of the processed job instance
     *
     * @param JobInterface $job
     *
     * @return string
     */
    private function formatJob(JobInterface $job) : string
    {
        return get_class($job) . ' [ ' . $job->getId() . ' ] ';
    }

}


<?php
/**
 * YAWIK
 *
 * @filesource
 * @license MIT
 * @copyright  2013 - 2017 Cross Solution <http://cross-solution.de>
 */

/** */
namespace Core\Options;

use Zend\Stdlib\AbstractOptions;

/**
 * Options for fieldset customizations.
 *
 * Holds options for each element of the fieldset in {@link fields}.
 * This will then be merged into the element spec provided by the fieldset class.
 *
 *

 * $fields = [
 *      <fieldname> => [
 *          'enabled'      => BOOL,     // if FALSE, the element WILL NOT BE ADDED.
 *          'required'     => BOOL,     // Sets the attribute "required", and additionally
 *                                         hints to the input filter, that the field is required.
 *          'label'        => STRING,   // override ['options']['label']
 *          'priority'     => INT,      // override ['flags']['priority']
 *          'order'        => INT       // alias for 'priority',
 *
 *          'options'      => ARRAY     // will get merged to the 'options' key in the element spec.
 *          'attributes'   => ARRAY     // merged to the 'attributes' key in the element spec.
 *          'flags'        => ARRAY     // merged into the flags array provided in the method "add"
 *                                         of the fieldset.
 *          'input_filter' => ARRAY,    // merged into the input filter spec of the fieldset.
 * ];
 *

 *
 *
 * @author Mathias Gelhausen <gelhausen@cross-solution.de>
 * @todo since 0.29
 */
class FieldsetCustomizationOptions extends AbstractOptions
{

    /**
     * Field specifications.
     *
     * @var array
     */
    protected $fields = [];

    /**
     * Set the fields options.
     *
     * @param array $fields
     *
     * @return self
     */
    public function setFields(array $fields)
    {
        $this->fields = $fields;

        return $this;
    }

    /**
     * Get the field options.
     *
     * @return array
     */
    public function getFields()
    {
        return $this->fields;
    }

    /**
     * Get the names of all customized fields.
     *
     * @return array
     */
    public function getFieldNames()
    {
        return array_keys($this->getFields());
    }

    /**
     * Has a field customized options?
     *
     * @param string $field
     *
     * @return bool
     */
    public function hasField($field)
    {
        return array_key_exists($field, $this->fields);
    }

    /**
     * Is a field enabled?
     *
     * Returns true, if
     * - There is no customized $field.
     * - The $field spec does not have the key 'enabled'
     * - The key 'enabled' is NOT TRUE.
     *
     * @param string $field
     *
     * @return bool
     */
    public function isEnabled($field)
    {
        return !isset($this->fields[$field]['enabled']) || (bool) $this->fields[$field]['enabled'];
    }

    /**
     * Get the field option array compatible with element spec.
     *
     * @param string $field
     *
     * @return array
     */
    public function getFieldOptions($field)
    {
        if (!$this->hasField($field)) {
            return [];
        }

        if (!isset($this->fields[$field]['__options__'])) {
            $this->fields[$field]['__options__'] = $this->copyArrayValues(
                $this->fields[$field],
                [
                    'attributes',
                    'options',
                    'label' => 'options',
                    'required' => ['key' => ['attributes','*'], 'value' => 'required', 'if' => true],
                    'type',
                ]
            );
        }

        return $this->fields[$field]['__options__'];
    }

    /**
     * Get the field flags array compatible with element flags.
     *
     * @param string $field
     *
     * @return array
     */
    public function getFieldFlags($field)
    {
        if (!$this->hasField($field)) {
            return [];
        }

        if (!isset($this->fields[$field]['__flags__'])) {
            $this->fields[$field]['__flags__'] = $this->copyArrayValues(
                $this->fields[$field],
                [
                    'flags' => [],
                    'order' => ['priority'],
                    'priority'
                ]
            );
        }

        return $this->fields[$field]['__flags__'];
    }

    /**
     * Get input filter spec for a field.
     *
     * @param string $field
     *
     * @return array
     */
    public function getFieldInputSpecification($field)
    {
        if (!$this->hasField($field)) {
            return [];
        }

        if (!isset($this->fields[$field]['__filter__'])) {
            $this->fields[$field]['__filter__'] = $this->copyArrayValues(
                $this->fields[$field],
                [
                    'input_filter' => [],
                    'required',
                ]
            );
        }

        return $this->fields[$field]['__filter__'];
    }

    /**
     * Copy specified keys from source to a new array.
     *
     *

     * $keys = [
     *      <name>,           // copy $source[<name>] to $target[<name>]
     *      <name> => <key>   // copy $source[<name>] to $target[<key][<name>]
     *      <name> => [<key>,<key>,..] // copy $source[<name>] to $target[<key>][<key>]..
     *      <name> => [
     *          'key' => <key>|[<key>,] // copy $source[<name>] to $target[<key]...
     *                                  // using '*' as <key> will be replaced by <name>
     *          'value' => <mixed>,     // do not use $source[<name>] but <mixed> as target value.
     *          'if' => <mixed>,        // only copy, if $source[<name>] equals <mixed>
     *      ]
     * ]
     *

     *
     * @param array $source
     * @param array $keys
     *
     * @return array
     */
    protected function copyArrayValues(array $source, array $keys)
    {
        $target = [];
        foreach ($keys as $key => $spec) {
            if (is_int($key)) {
                $key = $spec;
                $spec = null;
            }

            if (!array_key_exists($key, $source)) {
                continue;
            }

            if (null === $spec) {
                $target[$key] = $source[$key];
                continue;
            }

            if (is_string($spec)) {
                $target[$spec][$key] = $source[$key];
                continue;
            }

            if (isset($spec['if']) && $source[$key] !== $spec['if']) {
                continue;
            }

            if (isset($spec['key'])) {
                $targetKeys = is_array($spec['key']) ? $spec['key'] : [$spec['key']];
                $value = isset($spec['value']) ? $spec['value'] : $source[$key];
            } else {
                $targetKeys = $spec;
                $value = $source[$key];
            }

            $tmpTarget =& $target;
            foreach ($targetKeys as $targetKey) {
                if ('*' == $targetKey) {
                    $targetKey = $key;
                }
                if (!isset($tmpTarget[$targetKey])) {
                    $tmpTarget[$targetKey] = [];
                }
                $tmpTarget =& $tmpTarget[$targetKey];
            }

            $tmpTarget = $value;
        }

        return $target;
    }
}


<?php
/**
 * @copyright Zicht Online <http://zicht.nl>
 */

namespace Zicht\Bundle\PageBundle\AdminMenu;

use Symfony\Component\EventDispatcher\Event;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Routing\Router;
use Zicht\Bundle\AdminBundle\Event\AdminEvents;
use Zicht\Bundle\AdminBundle\Event\MenuEvent;
use Zicht\Bundle\AdminBundle\Event\PropagationInterface;
use Zicht\Bundle\PageBundle\Entity\Page;
use Zicht\Bundle\PageBundle\Event\PageViewEvent;

/**
 * Add links to see zz translations to the zicht admin menu
 */
class TranslatePageEventPropagationBuilder implements PropagationInterface
{
    /** @var Router */
    private $router;

    /**
     * @var EventDispatcher
     */
    private $eventDispatcher;

    /**
     * @param Router $router
     */
    public function __construct(Router $router, EventDispatcherInterface $eventDispatcher)
    {
        $this->router = $router;
        $this->eventDispatcher = $eventDispatcher;
    }

    /**
     * Build the relevant event and forward it.
     *
     * @param \Symfony\Component\EventDispatcher\Event $event
     * @return mixed|void
     */
    public function buildAndForwardEvent(Event $event)
    {
        if (!$event instanceof PageViewEvent) {
            return;
        }

        if (!$this->router) {
            return;
        }

        /** @var Page $page */
        $page = $event->getPage();
        if (!$page->getId()) {
            return;
        }

        $this->eventDispatcher->dispatch(
            AdminEvents::MENU_EVENT,
            new MenuEvent(
                $this->router->generate('zicht_page_page_view', [
                    'id' => $page->getId(),
                    '_locale' => 'zz',
                ]),
                'Vertalingen'
            )
        );

        $this->eventDispatcher->dispatch(
            AdminEvents::MENU_EVENT,
            new MenuEvent(
                $this->router->generate('zicht_page_page_view', [
                    'id' => $page->getId(),
                    '_locale' => $page->getLanguage(),
                ]),
                'Pagina herladen'
            )
        );
    }
}