<?php

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

namespace Core\View\Helper;

use Interop\Container\ContainerInterface;
use Zend\View\ViewEvent;
use Core\View\Helper\InsertFile\FileEvent;

class InsertFile extends AbstractEventsHelper
{
    /**
     * @var ContainerInterface
     */
    protected $serviceManager;

    protected $files = array();

    protected $ListenersUnaware = true;

    protected $event;

    /**
     * @param ContainerInterface $serviceManager
     * @param string $identifiers
     */
    public function __construct(ContainerInterface $serviceManager, $identifiers = null)
    {
        parent::__construct($identifiers);
        $this->serviceManager = $serviceManager;
    }

    /**
     * render a File-Object
     *
     * @param string
     * @return string
     */
    public function __invoke($fileName, $parameter = array())
    {
        $this->listenToRenderer();
        $event = $this->getEvent();
        $event->addFilename($fileName);
        $event->setRenderParameter($parameter);
        $return = 'file not found';

        // ensure, that we have a file-object
        $result = $this->trigger(FileEvent::GETFILE, $event);
        if (!empty($result)) {
            // ask someone else for rendering
            $result = $this->trigger(FileEvent::RENDERFILE, $event);
            $return = $result->last();
        }
        return $return;
    }

    protected function getEvent()
    {
        if (!isset($this->event)) {
            $this->event = new FileEvent();
        }
        return $this->event;
    }

    /**
     * hook into the rendering-process to provide a summary of all included files
     */
    public function listenToRenderer()
    {
        if ($this->ListenersUnaware) {
            // set a listener at the end of the Rendering-Process
            // to announce what files have been inserted
            $this->ListenersUnaware = false;
            $view = $this->serviceManager->get('View');
            $viewEvents = $view->getEventManager();
            // rendering ist over
            // get the attached Files very early
            // before any other postprocessing has started
            $viewEvents->attach(ViewEvent::EVENT_RESPONSE, array($this, 'anounceAttachedFiles'), 1000);
        }
    }

    public function anounceAttachedFiles(ViewEvent $e)
    {
        $event = $this->getEvent();
        $this->trigger(FileEvent::INSERTFILE, $event);
    }

    /**
     * @param ContainerInterface $container
     *
     * @return InsertFile
     */
    public static function factory(ContainerInterface $container)
    {
        return new static($container);
    }
}


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

/** */
namespace Core\Decorator;

/**
 * Proxy Decorator boilerplate
 *
 * Allows proxying to the wrapped object and returns self, if wrapped object method returns itself.
 *
 * @author Mathias Gelhausen <gelhausen@cross-solution.de>
 * @since 0.20
 */
class ProxyDecorator extends Decorator
{

    /**
     * Proxies to the wrapped entity class.
     *
     * The first argument must be the method name to proxy to, all further arguments
     * passed in are passed to the proxied method.
     *
     * If the wrapped object returns itself, this method will return this decorator instead.
     *
     * @return Decorator|mixed
     * @throws \BadMethodCallException If wrapped entity does not have the specified method.
     */
    protected function proxy()
    {
        $args = func_get_args();
        $method = array_shift($args);
        $callback = array($this->object, $method);

        if (!is_callable($callback)) {
            throw new \BadMethodCallException(
                sprintf(
                    'Cannot proxy "%s" to "%s": Unknown method.',
                    $method,
                    get_class($this->object)
                )
            );
        }

        $return = call_user_func_array($callback, $args);

        if ($return === $this->object) {
            // Return this decorator instead of the wrapped entity.
            $return = $this;
        }

        return $return;
    }
}


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

/** Core forms view helpers */
namespace Core\Form\View\Helper;

use Core\Form\ViewPartialProviderInterface;
use Core\Form\ExplicitParameterProviderInterface;
use Core\Form\Element\ViewHelperProviderInterface;
use Core\Form\Container;
use Zend\Form\View\Helper\AbstractHelper;
use Core\Form\SummaryForm as CoreSummaryForm;

/**
 * Helper for rendering form containers
 *
 * @author Mathias Gelhausen <gelhausen@cross-solution.de>
 */
class FormContainer extends AbstractHelper
{

    /**
     * Invoke as function.
     *
     * Proxies to {@link render()} or returns self.
     *
     * @param  null|Container $container
     * @param string $layout
     * @param array $parameter
     * @return FormContainer|string
     */
    public function __invoke(Container $container = null, $layout = Form::LAYOUT_HORIZONTAL, $parameter = array())
    {
        if (!$container) {
            return $this;
        }

        return $this->render($container, $layout, $parameter);
    }

    /**
     * Renders the forms of a container.
     *
     * @param Container $container
     * @param string $layout
     * @param array $parameter
     * @return string
     */
    public function render(Container $container, $layout = Form::LAYOUT_HORIZONTAL, $parameter = array())
    {
        $content = '';

        $content .= $container->renderPre($this->getView());

        if ($container instanceof ViewPartialProviderInterface) {
            return $this->getView()->partial($container->getViewPartial(), array('element' => $container));
        }

        if (isset($parameter['render_label']) && $parameter['render_label'] && ($label = $container->getLabel())) {
            $content .= '

' . $this->getView()->translate($label) . '

';
        }
        foreach ($container as $element) {
            $content .= $this->renderElement($element, $layout, $parameter);
        }

        $content .= $container->renderPost($this->getView());

        return $content;
    }

    public function renderElement($element, $layout, $parameter)
    {
        $parameterPartial = $parameter;
        $content = '';
        if ($element instanceof ExplicitParameterProviderInterface) {
            $parameterPartial = array_merge($element->getParams(), $parameterPartial);
        }
        if ($element instanceof ViewPartialProviderInterface) {
            $parameterPartial = array_merge(array('element' => $element, 'layout' => $layout), $parameterPartial);
            $content .= $this->getView()->partial(
                             $element->getViewPartial(),
                             $parameterPartial
            );
        } elseif ($element instanceof ViewHelperProviderInterface) {
            $helper = $element->getViewHelper();
            if (is_string($helper)) {
                $helper = $this->getView()->plugin($helper);
            }
            $content .= $helper($element);
        } elseif ($element instanceof CoreSummaryForm) {
            $content .= $this->getView()->summaryForm($element);
        } elseif ($element instanceof Container) {
            $content.= $this->render($element, $layout, $parameter);
        } else {
            $content.= $this->getView()->form($element, $layout, $parameter);
        }

        return $content;
    }
}


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

/** */
namespace Core\Repository\DoctrineMongoODM\Event;

use Core\Entity\PermissionsAwareInterface;
use Doctrine\Common\Collections\Collection;
use Doctrine\Common\EventSubscriber;
use Doctrine\ODM\MongoDB\DocumentManager;
use Doctrine\ODM\MongoDB\Event\OnFlushEventArgs;
use Doctrine\ODM\MongoDB\Events;
use Doctrine\ODM\MongoDB\UnitOfWork;
use Zend\Stdlib\ArrayUtils;

/**
 * Boilerplate for Files permissions update subscriber.
 *
 * updates the permissions of embedded files if the permissions on the parent document
 * had changed.
 *
 * @author Mathias Gelhausen <gelhausen@cross-solution.de>
 * @author Miroslav Fedeleš <miroslav.fedeles@gmail.com>
 * @since 0.26
 */
abstract class AbstractUpdateFilesPermissionsSubscriber implements EventSubscriber
{
    /**
     * List of properties where embedded files can be retreived.
     *
     * Note: entries will be prepended with "get"
     *
     * @var string[]
     */
    protected $filesProperties = [];

    /**
     * The document class that should be watched.
     *
     * @var string
     */
    protected $targetDocument;

    public function getSubscribedEvents()
    {
        return [ Events::onFlush ];
    }

    /**
     * Updates permissions on embedded files.
     *
     * @param OnFlushEventArgs $args
     */
    public function onFlush(OnFlushEventArgs $args)
    {
        $dm = $args->getDocumentManager();
        $uow = $dm->getUnitOfWork();

        $filter = function ($element) {
            return $element instanceof $this->targetDocument
                   && $element instanceof PermissionsAwareInterface
                   && $element->getPermissions()->hasChanged();
        };

        $inserts = array_filter($uow->getScheduledDocumentInsertions(), $filter);
        $updates = array_filter($uow->getScheduledDocumentUpdates(), $filter);

        $this->process($inserts, $dm, $uow, true);
        $this->process($updates, $dm, $uow);
    }

    /**
     * @param PermissionsAwareInterface[] $documents
     * @param DocumentManager $dm
     * @param UnitOfWork $uow
     * @param bool $insert
     */
    protected function process($documents, DocumentManager $dm, UnitOfWork $uow, $insert = false)
    {
        foreach ($documents as $document) {
            $perms = $document->getPermissions();
            $files = $this->getFiles($document);

            foreach ($files as $file) {
                $filePermissions = $file
                    ->getPermissions()
                    ->clear()
                    ->inherit($perms);

                if ($insert) {
                    $dm->persist($filePermissions);
                }

                $uow->computeChangeSet(
                    $dm->getClassMetadata(get_class($file)),
                    $file
                );
            }
        }
    }

    /**
     *
     *
     * @param \Core\Entity\EntityInterface $document
     *
     * @return PermissionsAwareInterface[]
     */
    protected function getFiles($document)
    {
        $files = [];

        foreach ($this->filesProperties as $prop) {
            $getter = "get$prop";
            $file   = $document->$getter();
            if ($file instanceof Collection) {
                $files = array_merge($files, ArrayUtils::iteratorToArray($file));
            } else {
                $files[] = $file;
            }
        }

        return array_filter($files, function ($i) {
            return $i instanceof PermissionsAwareInterface;
        });
    }
}


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

/** */
namespace Core\Entity\Hydrator;

use Core\Entity\ImageSet;
use Core\Entity\ImageSetInterface;
use Core\Options\ImageSetOptions;
use Doctrine\MongoDB\GridFSFile;
use Imagine\Image\Box;
use Imagine\Image\ImageInterface;
use Imagine\Image\ImagineInterface;
use Zend\Hydrator\HydratorInterface;

/**
 * Hydrator for ImageSets.
 *
 * @see \Core\Entity\ImageSetInterface
 * @author Mathias Gelhausen <gelhausen@cross-solution.de>
 * @since 0.29
 */
class ImageSetHydrator implements HydratorInterface
{

    /**
     * Imagine
     *
     * @var \Imagine\Image\ImagineInterface
     */
    protected $imagine;

    /**
     * Options
     *
     * @var ImageSetOptions
     */
    protected $options;

    public function __construct(ImagineInterface $imagine, ImageSetOptions $options)
    {
        $this->imagine = $imagine;
        $this->options = $options;
    }

    /**
     * Extract values from an object
     *
     * @param object $object
     *
     * @return array
     */
    public function extract($object)
    {
        if (!$object instanceof ImageSet || !($image = $object->get(ImageSetInterface::ORIGINAL))) {
            return [];
        }

        return [$this->options->getFormElementName() => $image->getId()];
    }

    /**
     * Hydrate $object with the provided $data.
     *
     * @param  array  $data
     * @param  object $object
     *
     * @return object
     */
    public function hydrate(array $data, $object)
    {
        if (!isset($data['original']) || UPLOAD_ERR_OK !== $data['original']['error']) {
            return $object;
        }

        $data = $data['original'];
        $file  = $data['tmp_name'];

        $image = $this->imagine->open($file);
        $imageSpecs = $this->options->getImages();

        $images = [ ImageSetInterface::ORIGINAL => $this->createEntity($file, $data) ];

        foreach ($imageSpecs as $key => $size) {
            $newImage = ImageSetInterface::THUMBNAIL == $key
                ? $image->thumbnail(new Box($size[0], $size[1]), ImageInterface::THUMBNAIL_INSET)
                : $this->createImage($image, $size);

            if ($newImage) {
                $entity   = $this->createEntity($newImage, $data, $key);
                $images[$key] = $entity;
            }
        }

        $object->setImages($images);

        return $object;
    }

    private function createImage(ImageInterface $image, $size)
    {
        $imageSize = $image->getSize();

        if ($imageSize->getWidth() <= $size[0] && $imageSize->getHeight() <= $size[1]) {
            return null;
        }

        if ($imageSize->getWidth() > $size[0]) {
            $imageSize = $imageSize->widen($size[0]);
        }

        if ($imageSize->getHeight() > $size[1]) {
            $imageSize = $imageSize->heighten($size[1]);
        }

        $image = $image->resize($imageSize);

        return $image;
    }

    private function createEntity($image, &$data, $prefix = '')
    {
        /* @var \Core\Entity\ImageInterface $entity */
        $entity = $this->options->getEntity();

        if (is_string($image)) {
            $file = $image;
        } else {
            $format = str_replace('image/', '', $data['type']);

            $file = new GridFSFile();
            $file->setBytes($image->get($format));
        }

        $entity
            ->setFile($file)
            ->setName(($prefix ? "$prefix-" : '') . $data['name'])
            ->setType($data['type'])
        ;

        return $entity;
    }
}


<?php

namespace Core\Listener;

use Zend\EventManager\EventManagerInterface;
use Zend\EventManager\ListenerAggregateInterface;
use Zend\EventManager\SharedEventManager;
use Zend\Http\Request;
use Zend\Http\Response;
use Zend\Mvc\MvcEvent;
use Zend\View\Model\JsonModel;

/**
 *
 * @author Carsten Bleek <bleek@cross-solution.de>
 * @author Mathias Gelhausen <gelhausen@cross-solution.de>
 * @todo   write test
 * @since 0.30 - do nothing if no route matched.
 */
class XmlRenderListener implements ListenerAggregateInterface
{

    /**
     * @var \Zend\Stdlib\CallbackHandler[]
     */
    protected $listeners = array();

    /**
     * @var \Zend\Stdlib\CallbackHandler[]
     */
    protected $sharedListeners = array();

    /**
     * Attach to an event manager
     *
     * @param  EventManagerInterface $events
     */
    public function attach(EventManagerInterface $events, $priority = 1)
    {
        $callback = array($this, 'injectXmlTemplate');
        /*
         * We need to hack a little, because injectViewModelListener is attached to the
         * shared event manager and triggered in Controller, we need to attach to the
         * EVENT_DISPATCH event in the shared manager, to be sure that this listener is
         * run before injectViewModelListener
         */
        $this->sharedListeners[] = $events->getSharedManager()->attach(
            'Zend\Stdlib\DispatchableInterface',
            MvcEvent::EVENT_DISPATCH,
            $callback,
            -96
        );
        $this->listeners[] = $events->attach(MvcEvent::EVENT_DISPATCH_ERROR, $callback, -96);
        $this->listeners[] = $events->attach(MvcEvent::EVENT_RENDER_ERROR, $callback, -96);
    }

    /**
     * Detach all our listeners from the event manager
     *
     * @param  EventManagerInterface $events
     * @return void
     */
    public function detach(EventManagerInterface $events)
    {
        foreach ($this->listeners as $index => $listener) {
            if ($events->detach($listener)) {
                unset($this->listeners[$index]);
            }
        }
        /* @var SharedEventManager $sharedEvents */
        $sharedEvents = $events->getSharedManager();
        foreach ($this->sharedListeners as $index => $listener) {
            if ($sharedEvents->detach($listener)) {
                unset($this->sharedListeners[$index]);
            }
        }
    }

    /**
     *
     *
     * @param MvcEvent $e
     *
     * @since 0.30 - Return early if no $routeMatch is set.
     */
    public function injectXmlTemplate(MvcEvent $e)
    {
        if (!($routeMatch = $e->getRouteMatch())) {
            return;
        };

        $format = $e->getRouteMatch()->getParam('format', "html");
        $channel = $e->getRouteMatch()->getParam('channel', "default");

        if ('xml' == $format) {
            $viewModel = $e->getResult();
            if ($viewModel instanceof JsonModel) {
                return;
            }
            $resolver = $e->getApplication()->getServiceManager()->get('ViewResolver');

            $templateDefault = $viewModel->getTemplate() . '.xml.phtml';
            $templateChannel = $viewModel->getTemplate() . '.' . $channel . '.xml.phtml';

            if ($channel != 'default' && $resolver->resolve($templateChannel)) {
                $viewModel->setTemplate($templateChannel);
            } elseif ($resolver->resolve($templateDefault)) {
                $viewModel->setTemplate($templateDefault);
            } else {
            }
            /*
             * Disable layout. This works because InjectViewModelListener is executed after us.
             */
            $viewModel->setTerminal(true);

            /* @var Response $response */
            $response = $e->getResponse();
            $response->getHeaders()->addHeaderLine('Content-Type', 'application/xml');
        }
    }
}


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

/** Core forms view helpers */
namespace Core\Form\View\Helper;

use Zend\Form\View\Helper\Form as ZendForm;
use Zend\Form\FormInterface;
use Zend\Form\FieldsetInterface;
use Core\Form\ViewPartialProviderInterface;
use Core\Form\ExplicitParameterProviderInterface;
use Core\Form\Element\ViewHelperProviderInterface;
use Core\Form\DescriptionAwareFormInterface;

/**
 * Helper to render a formular.
 *
 * @author Mathias Gelhausen <gelhausen@cross-solution.de>
 */
class Form extends ZendForm
{
    /**#@+
     * Layout constants.
     * @var string
     */
    const LAYOUT_HORIZONTAL = 'form-horizontal';
    const LAYOUT_INLINE     = 'form-inline';
    const LAYOUT_VERTICAL   = '';
    const LAYOUT_BARE       = 'form-bare';
    /**#@-*/

    /**
     * Invoke as function
     *
     * @param  null|FormInterface $form
     * @param string $layout
     * @param array $parameter
     * @return string
     */
    public function __invoke(FormInterface $form = null, $layout = self::LAYOUT_HORIZONTAL, $parameter = array())
    {
        if (!$form) {
            return $this;
        }

        return $this->render($form, $layout, $parameter);
    }

    /**
     * Render a form from the provided $form,
     *
     * @param FormInterface $form
     * @param string $layout
     * @param array $parameter
     * @return string
     */
    public function renderBare(FormInterface $form, $layout = self::LAYOUT_HORIZONTAL, $parameter = array())
    {
        /* @var $renderer \Zend\View\Renderer\PhpRenderer
         * @var $headscript \Zend\View\Helper\HeadScript
         * @var $basepath \Zend\View\Helper\BasePath */
        $renderer   = $this->getView();
        $headscript = $renderer->plugin('headscript');
        $basepath   = $renderer->plugin('basepath');

        $headscript->appendFile($basepath('modules/Core/js/core.spinnerbutton.js'))
                   //->appendFile($basepath('/assets/select2/js/select2.min.js'))
                   ->appendFile($basepath('modules/Core/js/core.forms.js'));

        /* @noinspection PhpParamsInspection */
        //$renderer->headLink()->appendStylesheet($basepath('/assets/select2/css/select2.css'));

        if ($scripts = $form->getOption('headscript')) {
            if (!is_array($scripts)) {
                $scripts = array($scripts);
            }
            foreach ($scripts as $script) {
                $headscript->appendFile($basepath($script));
            }
        }

        $class = $form->getAttribute('class');
        $class = preg_replace('~\bform-[^ ]+\b~', '', $class);
        $class .= ' ' . $layout;

        $form->setAttribute('class', $class);

        $formId = $form->getAttribute('id') ?: $form->getName();
        $formId = preg_replace(
            array('~[^A-Za-z0-9_-]~', '~--+~', '~^-|-$~'),
            array('-'              , '-'    , ''       ),
            $formId
        );
        $form->setAttribute(
            'id',
            $formId

        );

        if (method_exists($form, 'prepare')) {
            $form->prepare();
        }

        $formContent = '';

        if ($form instanceof ViewPartialProviderInterface) {
            return $renderer->partial($form->getViewPartial(), array_merge(['element' => $form], $parameter));
        }

        /* @var $element \Zend\Form\ElementInterface */
        foreach ($form as $element) {
            $parameterPartial = $parameter;
            $elementId = $element->getAttribute('id');
            if (!$elementId) {
                $elementId = preg_replace(
                    array('~[^A-Za-z0-9_-]~', '~--+~', '~^-|-$~'),
                    array('-'             , '-',     ''),
                    $element->getName()
                );
            }
            $element->setAttribute('id', "$formId-$elementId");
            $element->setOption('__form_id__', $formId);
            if ($element instanceof ExplicitParameterProviderInterface) {
                /* @var $element ExplicitParameterProviderInterface */
                $parameterPartial = array_merge($element->getParams(), $parameterPartial);
            }

            if ($element instanceof ViewPartialProviderInterface) {
                /* @var $element ViewPartialProviderInterface */
                $parameterPartial = array_merge(array('element' => $element, 'layout' => $layout), $parameterPartial);
                /** @noinspection PhpToStringImplementationInspection */
                $formContent .= $renderer->partial(
                    $element->getViewPartial(),
                    $parameterPartial
                );
            } elseif ($element instanceof FieldsetInterface) {
                if ($element instanceof ViewHelperProviderInterface) {
                    /* @var $element ViewHelperProviderInterface */
                    $helper = $element->getViewHelper();
                    if (is_string($helper)) {
                        $helper = $renderer->plugin($helper);
                    }

                    $formContent .= $helper($element);
                } else {
                    $formContent .= $renderer->formCollection($element, true, $layout);
                }
            } elseif (false !== $element->getOption('use_formrow_helper')) {
                $formContent .= $renderer->formRow($element, null, null, $layout);
            } else {
                $formContent .= $renderer->formElement($element);
            }
        }

        return $this->openTag($form) . $formContent . $this->closeTag();
    }

    /**
     * Renders a form from the provided form.
     * Wraps this form in a div-container and renders the label,
     * if any.
     *
     * @param FormInterface $form
     * @param string $layout
     * @param array $parameter
     * @uses renderBare()
     * @see \Zend\Form\View\Helper\Form::render()
     * @return string
     */
    public function render(FormInterface $form, $layout = self::LAYOUT_HORIZONTAL, $parameter = array())
    {
        /* @var $renderer \Zend\View\Renderer\PhpRenderer */
        $formContent = $this->renderBare($form, $layout, $parameter);
        $renderer    = $this->getView();

        if ($form instanceof DescriptionAwareFormInterface && $form->isDescriptionsEnabled()) {
            /* @var $form DescriptionAwareFormInterface|FormInterface */
            $renderer->headscript()->appendFile(
                    $renderer->basepath('modules/Core/js/forms.descriptions.js')
                );

            if ($desc = $form->getOption('description', '')) {
                $descriptionParams=$form->getOption('description_params');
                $translator = $this->getTranslator();
                $textDomain = $this->getTranslatorTextDomain();
                $desc = $translator->translate($desc, $textDomain);
                if ($descriptionParams) {
                    array_unshift($descriptionParams, $desc);
                    $desc = call_user_func_array('sprintf', $descriptionParams);
                }
            }

            $formContent = sprintf(
                    '

%s

%s

',
                    $formContent,
                    $desc
                );
        } else {
            $formContent = '
' . $formContent . '
';
        }

        $markup = '
'
                . '%s'
                . '%s'
                . '
';

        if ($label = $form->getLabel()) {
            $label = '

' . $renderer->translate($label) . '

';
        }

        return sprintf(
            $markup,
            $form->getAttribute('id') ?: $form->getName(),
            $label,
            $formContent
        );
    }
}


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

/** */
namespace Core\Form\Event;

use Core\Form\Container;
use Zend\EventManager\Event;
use Zend\EventManager\Exception;
use Zend\Form\FormInterface;

/**
 * An event class to handle all kinds of form events.
 *
 * @author Mathias Gelhausen <gelhausen@cross-solution.de>
 * @since  0.24
 */
class FormEvent extends Event
{
    /**#@+
     * @var string
     */

    /**
     * Event triggered while form initializes.
     */
    const EVENT_INIT = 'INIT';

    /**
     * Event triggered when data is set to the form.
     */
    const EVENT_SET_DATA = 'SET_DATA';

    /**
     * Event triggered when a form parameter is set.
     */
    const EVENT_SET_PARAM = 'SET_PARAM';

    /**
     * Event triggered when the form validates.
     */
    const EVENT_VALIDATE = 'VALIDATE';

    /**
     * Event triggered when the associated object is set. Either through binding or explicitely setObject.
     */
    const EVENT_SET_OBJECT = 'SET_OBJECT';

    /**#@-*/

    /**
     * The form instance triggered this event.
     *
     * @var FormInterface|Container
     */
    protected $form;

    /**
     * Gets the form instance.
     *
     * @return Container|FormInterface
     */
    public function getForm()
    {
        return $this->form;
    }

    /**
     * Sets the form instance.
     *
     * @param FormInterface|Container $form
     *
     * @return self
     * @throws \InvalidArgumentException
     */
    public function setForm($form)
    {
        if (!$form instanceof FormInterface && !$form instanceof Container) {
            throw new \InvalidArgumentException('Form must either implement \Zend\Form\FormInterface or extend from \Core\Form\Container');
        }

        $this->form = $form;

        return $this;
    }

    public function setTarget($target)
    {
        if ($target instanceof FormInterface || $target instanceof Container) {
            $this->setForm($target);
        }
        parent::setTarget($target);

        return $this;
    }

    public function setParams($params)
    {
        parent::setParams($params);

        $form = $this->getParam('form');
        if ($form instanceof FormInterface || $form instanceof Container) {
            $this->setForm($form);
        }

        return $this;
    }
}


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

/** Core view helpers */
namespace Core\View\Helper;

use Zend\View\Helper\AbstractHelper;
use Zend\I18n\View\Helper\DateFormat as ZfDateFormat;
use IntlDateFormatter;

/**
 * Helper to format DateTime objects to localized strings.
 *
 * This is an enhancement of \Zend\I18n\View\Helper\DateFormat.
 *
 *
 *      // see ZF2 docs for date format types.
 *
 *      // Formats date and time in LONG format
 *      $this->formatDate($date, DateFormat::LONG);
 *
 *      // Formats date and time in SHORT format
 *      $this->formatDate($date);
 *      $this->formatDate($date, 'short');
 *
 *      // Formats date in long and time in short format
 *      $this->formatDate($date, 'long', 'short');
 *
 *
 *
 * @author Mathias Gelhausen <gelhausen@cross-solution.de>
 */
class DateFormat extends ZfDateFormat
{
    const FULL  = 'full';
    const LONG  = 'long';
    const MEDIUM= 'medium';
    const SHORT = 'short';
    const NONE  = 'none';

    /**
     * Formats a date.
     *
     * Pass $dateTime and/or $timeType as string or constant.
     * Sets $timeType to same format as $dateType if not given.
     * Proxies to parent method for rendering.
     *
     * @see \Zend\I18n\View\Helper\DateFormat::__invoke()
     *
     * @param \DateTime $data|string
     * @param string $dateType
     * @return string
     */
    public function __invoke(
        $date,
        $dateType = self::SHORT,
        $timeType = null,
        $locale = null,
        $pattern = null
    ) {
        if (is_string($dateType)) {
            $dateType = $this->detectType($dateType);
            if (null === $timeType) {
                $timeType = $dateType;
            }
        }
        if (is_string($date)) {
            $date = date_create($date);
        }
        if (is_string($timeType)) {
            $timeType = $this->detectType($timeType);
        }
        return parent::__invoke($date, $dateType, $timeType, $locale, $pattern);
    }

    /**
     * Maps strings and constants to IntlDateFormatter constants (int).
     *
     * @param string $type
     * @return int
     */
    protected function detectType($type)
    {
        $type     = strtoupper($type);
        $constant = "\IntlDateFormatter::$type";
        $value    = @constant($constant);
        return null !== $value ? $value : IntlDateFormatter::NONE;
    }
}


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

/** */
namespace Core\Controller;

use Zend\EventManager\Event;
use Zend\Stdlib\PriorityList;
use Zend\View\Model\ViewModel;

/**
 * Admin Controller Event
 *
 * @author Mathias Gelhausen <gelhausen@cross-solution.de>
 * @since 0.25
 */
class AdminControllerEvent extends Event
{
    /**
     * Fetch dashboard widgets event.
     *
     * @var string
     */
    const EVENT_DASHBOARD = 'DASHBOARD';

    /**
     * List of dashboard widget view models.
     *
     * @var \Zend\Stdlib\PriorityList
     */
    protected $models;

    /**
     * Creates an instance.
     *
     * Instantiates a new PriorityList for the view models.
     *
     * @param string|null $name
     * @param string|null $target
     * @param array|null $params
     */
    public function __construct($name = null, $target = null, $params = null)
    {
        parent::__construct($name, $target, $params);
        $this->models = new PriorityList();
    }

    /**
     * Adds a view model.
     *
     * @param string    $name Name of the captureTo key.
     * @param ViewModel    $model
     * @param int $priority
     *
     * @return self
     */
    public function addViewModel($name, $model, $priority=0)
    {
        $this->models->insert($name, $model, $priority);

        return $this;
    }

    /**
     * Creates a view model with template and adds it to the list.
     *
     * @param string      $name Name of the captureTo key.
     * @param string      $template Name of the template (resolvable from view template resolver)
     * @param array $vars   additional variables for the view.
     * @param int   $priority
     *
     * @return AdminControllerEvent
     */
    public function addViewTemplate($name, $template, $vars = [], $priority = 0)
    {
        if (is_int($vars)) {
            $priority = $vars;
            $vars = [];
        }

        $model = new ViewModel($vars);
        $model->setTemplate($template);

        return $this->addViewModel($name, $model, $priority);
    }

    /**
     * Gets the iterator of the view model list.
     *
     * @return PriorityList Sorted list for iteration.
     */
    public function getViewModels()
    {
        return $this->models->getIterator();
    }

    /**
     * Creates a view model with default template,
     *
     * For syntax of the $data array, see the default template
     * .. Core/view/core/admin/dashboard-widget.phtml
     *
     * @param string      $name Name of the captureTo key.
     * @param array $data
     * @param int   $priority
     *
     * @return AdminControllerEvent
     * @throws \DomainException if no name is passed.
     */
    public function addViewVariables($name, $data = [], $priority = 0)
    {
        if (is_array($name)) {
            if (!isset($name['name'])) {
                throw new \DomainException('Key "name" must be specified, if array is passed as first parameter.');
            }
            if (is_int($data)) {
                $priority = $data;
            }
            $data = $name;
            $name = $data['name'];
        } elseif (is_int($data)) {
            $priority = $data;
            $data = [];
        }

        if (!isset($data['name'])) {
            $data['name'] = $name;
        }

        return $this->addViewTemplate($name, "core/admin/dashboard-widget", $data, $priority);
    }
}


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

/** */
namespace Core\Form\Hydrator;

use Core\Entity\MetaDataProviderInterface;
use Zend\Hydrator\HydratorInterface;

/**
 * Hydrator for entity meta data.
 *
 * @author Mathias Gelhausen <gelhausen@cross-solution.de>
 * @since 0.29
 */
class MetaDataHydrator implements HydratorInterface
{
    /**
     * Extract meta data from an entity.
     *
     * @param  object $object
     *
     * @return array
     */
    public function extract($object)
    {
        if (!$object instanceof MetaDataProviderInterface) {
            return [];
        }

        $data = $object->getMetaData();

        return $data;
    }

    /**
     * Hydrate $object with the provided meta data array.
     *
     * @param  array  $data
     * @param  object $object
     *
     * @return object
     */
    public function hydrate(array $data, $object)
    {
        if (!$object instanceof MetaDataProviderInterface) {
            return $object;
        }

        foreach ($data as $key => $value) {
            $object->setMetaData($key, $value);
        }

        return $object;
    }
}


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

/** Core view helpers */
namespace Core\View\Helper;

use Zend\View\Helper\AbstractHelper;
use Zend\Mvc\MvcEvent;

/**
 * This helper exposes request params to view scripts.
 *
 *
 *      // Gets route match param or event param or null.
 *      $param = $this->params('routeoreventparam');
 *
 *      // Gets route match param or event param or returns the default
 *      $param = $this->param('routeoreventparam', 'defaultValue');
 *
 *      // access helper methods:
 *      $this->params()->fromRoute('routeParam');
 *      $this->params()->fromQuery('queryParam', 'default');
 *
 *      // All methods:
 *      // - fromEvent() : Gets event parameters.
 *      // - fromFiles() : Gets uploaded files.
 *      // - fromHeader(): Gets request headers.
 *      // - fromPost()  : Gets post parameters.
 *      // - fromQuery() : Gets query parameters (e.g. ?param=value&param_two=VAL)
 *      // - fromRoute() : Gets route match parameters
 *
 *
 * @author Mathias Gelhausen <gelhausen@cross-solution.de>
 */
class Params extends AbstractHelper
{

    /**
     * The Mvc Event
     * @var MvcEvent
     */
    protected $event;

    /**
     * Creates an instance.
     *
     * @param MvcEvent $e
     */
    public function __construct(MvcEvent $e)
    {
        $this->event = $e;
    }

    /**
     * Grabs a param from route match or event by default.
     *
     * If $param is NULL returns itself.
     *
     * Tries to grab a param from route match first.
     * If route match does not have a param called $param,
     * it tries to grab this param from the event.
     *
     * If the event does not have the param, it returns $default
     *
     *
     * @param string $param
     * @param mixed $default
     * @return mixed
     */
    public function __invoke($param = null, $default = null)
    {
        if ($param === null) {
            return $this;
        }

        $value = $this->fromRoute($param, null);
        return $value ? $value : $this->fromEvent($param, $default);
    }

    /**
     * Return all files or a single file.
     *
     * @param  string $name File name to retrieve, or null to get all.
     * @param  mixed $default Default value to use when the file is missing.
     * @return array|\ArrayAccess|null
     */
    public function fromFiles($name = null, $default = null)
    {
        if ($name === null) {
            return $this->event->getRequest()->getFiles($name, $default)->toArray();
        }

        return $this->event->getRequest()->getFiles($name, $default);
    }

    /**
     * Return all header parameters or a single header parameter.
     *
     * @param  string $header Header name to retrieve, or null to get all.
     * @param  mixed $default Default value to use when the requested header is missing.
     * @return null|\Zend\Http\Header\HeaderInterface
     */
    public function fromHeader($header = null, $default = null)
    {
        if ($header === null) {
            return $this->event->getRequest()->getHeaders($header, $default)->toArray();
        }

        return $this->event->getRequest()->getHeaders($header, $default);
    }

    /**
     * Return all post parameters or a single post parameter.
     *
     * @param string $param Parameter name to retrieve, or null to get all.
     * @param mixed $default Default value to use when the parameter is missing.
     * @return mixed
     */
    public function fromPost($param = null, $default = null)
    {
        if ($param === null) {
            return $this->event->getRequest()->getPost($param, $default)->toArray();
        }

        return $this->event->getRequest()->getPost($param, $default);
    }

    /**
     * Return all query parameters or a single query parameter.
     *
     * @param string $param Parameter name to retrieve, or null to get all.
     * @param mixed $default Default value to use when the parameter is missing.
     * @return mixed
     */
    public function fromQuery($param = null, $default = null)
    {
        if ($param === null) {
            return $this->event->getRequest()->getQuery($param, $default)->toArray();
        }

        return $this->event->getRequest()->getQuery($param, $default);
    }

    /**
     * Return all route parameters or a single route parameter.
     *
     * @param string $param Parameter name to retrieve, or null to get all.
     * @param mixed $default Default value to use when the parameter is missing.
     * @return mixed
     * @throws RuntimeException
     */
    public function fromRoute($param = null, $default = null)
    {
        if (!$this->event->getRouteMatch()) {
            return $default;
        }
        if ($param === null) {
            return $this->event->getRouteMatch()->getParams();
        }
        return $this->event->getRouteMatch()->getParam($param, $default);
    }

    /**
     * Return all event parameters or a single event parameter.
     *
     * @param string $param Parameter name to retrieve, or null to get all.
     * @param mixed $efault Default value to use when the parameter is missing.
     * @return mixed
     * @throws RuntimeException
     */
    public function fromEvent($param = null, $default = null)
    {
        if (null === $param) {
            return $this->event->getParams();
        }
        return $this->event->getParam($param, $default);
    }
}


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

/** */
namespace Core\Log\Processor;

use Zend\Log\Processor\RequestId;

/**
 * ${CARET}
 *
 * @author Mathias Gelhausen <gelhausen@cross-solution.de>
 * @todo write test
 */
class UniqueId extends RequestId
{

    /**
     * Processes a log message before it is given to the writers
     *
     * @param  array $event
     *
     * @return array
     */
    public function process(array $event)
    {
        $event = parent::process($event);

        $event['uniqueId'] = substr($event['extra']['requestId'], 0, 7);
        unset($event['extra']['requestId']);

        return $event;
    }
}


<?php
/**
 * @author Gerard van Helden <gerard@zicht.nl>
 * @copyright Zicht Online <http://zicht.nl>
 */

namespace Zicht\Bundle\PageBundle\Type;

use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormView;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Translation\TranslatorInterface;
use Zicht\Bundle\PageBundle\Model\ContentItemContainer;
use Zicht\Util\Str;

/**
 * Provides a type for selecting the region of the content item.
 */
class ContentItemRegionType extends AbstractType
{
    /**
     * @var string $contentItemClassName
     */
    protected $contentItemClassName;

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

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

    /**
     * Constructor.
     *
     * @param string $contentItemClassName
     * @param array $defaultRegions
     * @param TranslatorInterface $translator
     */
    public function __construct($contentItemClassName, array $defaultRegions, TranslatorInterface $translator)
    {
        $this->contentItemClassName = $contentItemClassName;
        $this->defaultRegions = $defaultRegions;
        $this->translator = $translator;
    }

    /**
     * {@inheritDoc}
     */
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(
            array(
                'inherit_data' => true,
                'data_class' => $this->contentItemClassName,
                'container' => '',
                'default_regions' => $this->defaultRegions,
                'translation_domain' => 'admin',
            )
        );
    }

    /**
     * @{inheritDoc}
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $container = $options['container'];
        if ($container
            && $container instanceof ContentItemContainer
            && (null !== ($matrix = $container->getContentItemMatrix()))
        ) {
            $choices = array();
            foreach ($matrix->getRegions() as $c) {
                $choices[$c] = $c;
            }
            $builder->add(
                'region',
                'choice',
                array(
                    'choices' => $choices,
                    'translation_domain' => 'admin',
                    'placeholder' => $this->translator->trans('content_item_region.empty_value', array(), 'admin')
                )
            );
        } else {
            $builder->add('region', 'choice', array('choices' => $options['default_regions'], 'translation_domain' => 'admin'));
        }
    }

    /**
     * @{inheritDoc}
     */
    public function finishView(FormView $view, FormInterface $form, array $options)
    {
        $matrix = array();
        $fullmatrix = $options['container']->getContentItemMatrix()->getMatrix();

        foreach ($fullmatrix as $region => $classNames) {
            foreach ($classNames as $className) {
                $snakeCasedClassName = strtolower(str_replace(' ', '_', Str::humanize($className)));
                $placeholder = sprintf('content_item.type.%s', $snakeCasedClassName);
                $matrix[$region][$className] = $this->translator->trans($placeholder, array(), 'admin', 'nl');
            }
        }

        // todo: the matrix says something over both the DiscriminatorMapType and the ContentItemRegionType,
        // hence it should be moved to the ContentItemTypeType
        $view->vars['matrix'] = json_encode($matrix);
    }

    /**
     * Returns the name of this type.
     *
     * @return string The name of this type
     */
    public function getName()
    {
        return 'zicht_content_item_region';
    }

    /**
     * {@inheritDoc}
     */
    public function getBlockPrefix()
    {
        return 'zicht_content_item_region';
    }
}


<?php
/**
 * @author Gerard van Helden <gerard@zicht.nl>
 * @copyright Zicht Online <http://zicht.nl>
 */
namespace Zicht\Bundle\PageBundle\Entity;

use Zicht\Util\Str;
use Zicht\Bundle\PageBundle\Model\ContentItemInterface;

/**
 * Base class for ContentItem entities.
 */
abstract class ContentItem implements ContentItemInterface
{
    /**
     * Returns a (dash notated) short type that can be used in databases, css classes, etc.
     *
     * @param string $infix
     * @return string
     */
    public function getShortType($infix = '-')
    {
        $shortType = Str::infix(lcfirst(Str::classname(Str::rstrip($this->getType(), 'ContentItem'))), $infix);

        if ($template = $this->getTemplateName()) {
            $shortType .= $infix . $template;
        }

        return $shortType;
    }

    /**
     * Copies all properties from the source to the target, if the target has the specified properties.
     *
     * @param ContentItemInterface $from
     * @param ContentItemInterface $to
     * @return ContentItemInterface
     */
    public static function convert(ContentItemInterface $from, ContentItemInterface $to)
    {
        $reflectionFrom = new \ReflectionClass($from);
        $reflectionTo = new \ReflectionClass($to);

        foreach ($reflectionFrom->getProperties() as $property) {
            $property->setAccessible(true);
            $method = 'set' . ucfirst($property->getName());
            if ($reflectionTo->hasMethod($method)) {
                $to->$method($property->getValue($from));
            }
        }

        return $to;
    }

    /**
     * Returns the type of the class.
     *
     * @return string
     */
    final public function getType()
    {
        return get_class($this);
    }

    protected $convertToType = null;

    /**
     * Return string
     *
     * @return string
     */
    final public function getConvertToType()
    {
        if (null !== $this->convertToType) {
            return $this->convertToType;
        }
        return $this->getType();
    }

    /**
     * Set the type to convert to.
     *
     * @param string $type
     * @return void
     */
    public function setConvertToType($type)
    {
        $this->convertToType = $type;
    }

    /**
     * If needed, you can add a custom template name to the content item
     *
     * @return null|string
     */
    public function getTemplateName()
    {
        return null;
    }

    /**
     * @return string
     */
    public function getInternalName()
    {
        return (string)$this;
    }

    /**
     * get region of content item, for BC just
     * setting as empty place holder.
     *
     * @return string
     */
    public function getRegion()
    {
    }
}


<?php
/**
 * @copyright Zicht Online <http://zicht.nl>
 */
namespace Zicht\Bundle\PageBundle\AdminMenu;

use Sonata\AdminBundle\Admin\Pool;
use Symfony\Component\EventDispatcher\Event;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Zicht\Bundle\AdminBundle\Event\AdminEvents;
use Zicht\Bundle\AdminBundle\Event\MenuEvent;
use Zicht\Bundle\AdminBundle\Event\PropagationInterface;
use Zicht\Bundle\PageBundle\Event\PageViewEvent;
use Zicht\Bundle\UrlBundle\Url\Provider;

/**
 * Add links to edit a page to the zicht admin menu
 */
class EventPropagationBuilder implements PropagationInterface
{
    /**
     * @var Pool
     */
    protected $sonata;

    /**
     * @var Provider
     */
    protected $pageUrlProvider;

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

    /**
     * Construct with the specified admin pool
     *
     * @param Pool $sonata
     * @param Provider $pageUrlProvider
     */
    public function __construct(Pool $sonata = null, Provider $pageUrlProvider = null, EventDispatcherInterface $eventDispatcher)
    {
        $this->sonata = $sonata;
        $this->pageUrlProvider = $pageUrlProvider;
        $this->eventDispatcher = $eventDispatcher;
    }

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

        $page = $event->getPage();
        $admin = $this->sonata->getAdminByClass(get_class($page));

        if ($admin === null) {
            $admin = $this->sonata->getAdminByClass(get_parent_class($page));
        }

        if ($page->getId() && $admin !== null) {
            $title = $event->getPage()->getTitle();
            /** @var \Zicht\Bundle\PageBundle\Event\PageViewEvent $event */
            /** @var \Zicht\Bundle\PageBundle\Event\PageViewEvent $e */
            $this->eventDispatcher->dispatch(
                AdminEvents::MENU_EVENT,
                new MenuEvent(
                    $admin->generateObjectUrl('edit', $event->getPage()),
                    sprintf(
                        'Beheer pagina "%s"',
                        strlen($title) > 20 ? substr($title, 0, 20) . '...' : $title
                    )
                )
            );
        }
    }
}


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

/** */
namespace Core\Form\Hydrator;

use Core\Entity\Tree\NodeInterface;
use Doctrine\Common\Collections\Collection;
use Zend\Hydrator\HydratorInterface;

/**
 * This hydrator handles trees for usage in forms.
 *
 * Flatten the tree structure when extracting and
 * rebuilds the tree when hydrating.
 *
 * @author Mathias Gelhausen <gelhausen@cross-solution.de>
 * @since 0.29
 */
class TreeHydrator implements HydratorInterface
{

    /**
     * Hydratable data.
     *
     * @internal
     *      Used as interim storage.
     *
     * @var array
     */
    protected $hydrateData = [];

    /**
     * Extract tree items.
     *
     * Flattens the tree structure to an one dimensional array and returns it in an array
     * under the key'items'.
     *
     * The returned array can be directly bound to \Core\Form\Tree\ManagementFieldset.
     *
     * @param  object $object The root of the tree.
     *
     * @return array
     */
    public function extract($object)
    {
        $data = [];
        $this->flattenTree($object, $data);

        return ['items' => $data ];
    }

    /**
     * Recursively flattens a tree structure.
     *
     * @param NodeInterface $tree
     * @param array $data
     * @param string $curId
     */
    private function flattenTree($tree, &$data, $curId = '1')
    {
        $data[] =
        new \ArrayObject([
            'id' => $tree->getId(),
            'current' => $curId,
            'name' => $tree->getName(),
            'value' => $tree->getValue(),
            'priority' => $tree->getPriority(),
            'do' => 'nothing',
        ]);

        if ($tree->hasChildren()) {
            foreach ($tree->getChildren() as $i => $child) {
                $this->flattenTree($child, $data, $curId . '-' . ($i + 1));
            }
        }
    }

    /**
     * Hydrate a tree structure from form values.
     *
     * Takes the post values for a \Core\Tree\ManegementFieldset and rebuilds the
     * tree structure.
     *
     * @param  array  $data Form values
     * @param  Collection $object
     *
     * @return object
     */
    public function hydrate(array $data, $object)
    {
        $this->prepareHydrateData($data);

        return $this->hydrateTree($object);
    }

    /**
     * Prepares the form values for hydrating.
     *
     * @internal
     *      Populates the {@link hydrateData} array
     *
     * @param array $data
     */
    private function prepareHydrateData(array $data)
    {
        /*
         * unflatten tree
         */
        $items = $data['items'];
        $tree = [ '__root__' => array_shift($items) ];

        foreach ($items as $item) {
            $parent = substr($item['current'], 0, strrpos($item['current'], '-'));
            $tree[$parent][] = $item;
        }

        $this->hydrateData = $tree;
    }

    /**
     * Recursively hydrate the tree structure.
     *
     * Items not present in the {@link hydrateData} are removed,
     * new items are created accordingly.
     *
     * @param NodeInterface $object
     * @param \ArrayObject $currentData
     *
     * @return NodeInterface
     */
    private function hydrateTree(NodeInterface $object, \ArrayObject $currentData = null)
    {
        if (null === $currentData) {
            $currentData = $this->hydrateData['__root__'];
        }

        if ('set' == $currentData['do']) {
            $object
                ->setName($currentData['name'])
                ->setValue($currentData['value'])
                ->setPriority($currentData['priority'])
            ;
        }

        if (isset($this->hydrateData[$currentData['current']])) {
            foreach ($this->hydrateData[$currentData['current']] as $childData) {
                $child = $this->findOrCreateChild($object, $childData['id']);
                if ('remove' == $childData['do']) {
                    $object->removeChild($child);
                } else {
                    $this->hydrateTree($child, $childData);
                }
            }
        }

        return $object;
    }

    /**
     * Finds an item in a tree structure or create a new item.
     *
     * @param NodeInterface $tree
     * @param $id
     *
     * @return NodeInterface
     */
    private function findOrCreateChild($tree, $id)
    {
        /* @var NodeInterface $node */
        foreach ($tree->getChildren() as $node) {
            if ($id && $node->getId() == $id) {
                return $node;
            }
        }

        $nodeClass = get_class($tree);
        $node = new $nodeClass();
        $tree->addChild($node);

        return $node;
    }
}


<?php

/*
 * This file is part of the YAWIK project.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Core\Controller\Console;

use Interop\Container\ContainerInterface;
use Symfony\Component\Console\Input\ArgvInput;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\ConsoleOutput;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Filesystem\Filesystem;
use Yawik\Composer\AssetsInstaller;
use Zend\ModuleManager\ModuleManager;
use Zend\Mvc\Console\Controller\AbstractConsoleController;

/**
 * Class AssetsInstallController
 *
 * @package     Core\Controller\Console
 * @author      Anthonius Munthi <me@itstoni.com>
 * @since       0.32.0
 */
class AssetsInstallController extends AbstractConsoleController
{
    /**
     * @var Filesystem
     */
    private $filesystem;

    /**
     * An array list of injected modules
     * @var array
     */
    private $modules = [];

    /**
     * @var InputInterface
     */
    private $input;

    /**
     * @var OutputInterface
     */
    private $output;

    /**
     * @var AssetsInstaller
     */
    protected $installer;

    /**
     * AssetsInstallController constructor.
     * @param array $modules List of installed modules
     */
    public function __construct(array $modules = [])
    {
        $this->modules      = $modules;
        $this->filesystem   = new Filesystem();
        $this->input        = new ArgvInput();
        $this->output       = new ConsoleOutput();
        $this->installer    = new AssetsInstaller();
    }

    /**
     * Creates new object
     * @param   ContainerInterface $container
     * @return AssetsInstallController
     */
    public static function factory(ContainerInterface $container)
    {
        /* @var ModuleManager $manager */
        $manager = $container->get('ModuleManager');
        $modules = $manager->getLoadedModules();

        return new static($modules);
    }

    /**
     * @param InputInterface $input
     * @return AssetsInstallController
     */
    public function setInput($input)
    {
        $this->input = $input;

        return $this;
    }

    /**
     * @param OutputInterface $output
     * @return AssetsInstallController
     */
    public function setOutput($output)
    {
        $this->output = $output;

        return $this;
    }

    public function setInstaller(AssetsInstaller $installer)
    {
        $this->installer = $installer;
    }

    public function indexAction()
    {
        /* @var \Zend\Console\Request $request */
        $modules        = $this->modules;
        $request        = $this->getRequest();
        $symlink        = $request->getParam('symlink');
        $relative       = $request->getParam('relative');
        $installer      = $this->installer;
        $assets         = $installer->getModulesAsset($modules);

        // setup expected method
        if ($relative) {
            $expectedMethod = AssetsInstaller::METHOD_RELATIVE_SYMLINK;
        } elseif ($symlink) {
            $expectedMethod = AssetsInstaller::METHOD_ABSOLUTE_SYMLINK;
        } else {
            $expectedMethod = AssetsInstaller::METHOD_COPY;
        }

        $installer->setInput($this->input);
        $installer->setOutput($this->output);
        $installer->install($assets, $expectedMethod);
    }
}


<?php

namespace Core\Repository;

use Core\Entity\EntityInterface;
use Doctrine\ODM\MongoDB as ODM;
use Zend\ServiceManager\ServiceLocatorInterface;

abstract class AbstractRepository extends ODM\DocumentRepository implements RepositoryInterface
{
    protected $entityPrototype;

    /**
     * @param ODM\DocumentManager       $dm
     * @param ODM\UnitOfWork            $uow
     * @param ODM\Mapping\ClassMetadata $class
     */
    public function __construct(ODM\DocumentManager $dm, ODM\UnitOfWork $uow, ODM\Mapping\ClassMetadata $class)
    {
        parent::__construct($dm, $uow, $class);
        $eventArgs = new DoctrineMongoODM\Event\EventArgs(
            array(
            'repository' => $this
            )
        );
        $dm->getEventManager()->dispatchEvent(DoctrineMongoODM\Event\RepositoryEventsSubscriber::postConstruct, $eventArgs);
    }

    /**
     * @param ServiceLocatorInterface $serviceLocator
     */
    public function init(ServiceLocatorInterface $serviceLocator)
    {
    }

    /**
     * @param $name
     *
     * @return mixed
     */
    public function getService($name)
    {
        /* @TODO: [ZF3] ->getServiceLocator() should be removed in future */
        $config = $this->dm->getConfiguration();
        return $this->dm->getConfiguration()->getServiceLocator()->get($name);
    }

    /**
     * @param EntityInterface $entity
     *
     * @return $this
     */
    public function setEntityPrototype(EntityInterface $entity)
    {
        $this->entityPrototype = $entity;
        return $this;
    }

    /**
     * @param array $data
     *
     * @return mixed
     */
    public function create(array $data = null, $persist = false)
    {
        if (null === $this->entityPrototype) {
            throw new \RuntimeException('Could not create an entity. No prototype is set!');
        }

        $entity = clone $this->entityPrototype;

        $eventArgs = new DoctrineMongoODM\Event\EventArgs([
            'entity' => $entity
        ]);
        $this->dm->getEventManager()
            ->dispatchEvent(DoctrineMongoODM\Event\RepositoryEventsSubscriber::postCreate, $eventArgs);

        if (null !== $data) {
            foreach ($data as $property => $value) {
                $setter = "set$property";

                if (method_exists($entity, $setter)) {
                    $entity->$setter($value);
                }
            }
        }

        if ($persist) {
            $this->dm->persist($entity);
        }

        return $entity;
    }

    public function count(array $criteria = [])
    {
        $qb = $this->createQueryBuilder();

        foreach ($criteria as $field => $value) {
            $qb->field($field)->equals($value);
        }
        $qb->count();
        $q = $qb->getQuery();
        $r = $q->execute();

        return $r;
    }

    /**
     * @param $entity
     * @throws \InvalidArgumentException
     * @return self
     */
    public function store($entity)
    {
        $this->checkEntityType($entity);
        $this->dm->persist($entity);
        $this->dm->flush($entity);

        return $this;
    }

    public function remove($entity, $flush=false)
    {
        $this->checkEntityType($entity);
        $this->dm->remove($entity);
        if ($flush) {
            $this->dm->flush($entity);
        }
        return $this;
    }

    protected function checkEntityType($entity)
    {
        if (!($entity instanceof $this->entityPrototype)) {
            throw new \InvalidArgumentException(sprintf(
                                                    'Entity must be of type %s but recieved %s instead',
                                                    get_class($this->entityPrototype),
                                                    get_class($entity)
                                                ));
        }
    }
}


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

namespace Core\Mail;

use Zend\Mail\Transport\File as BaseFileTransport;
use Zend\Mail\Transport\Exception\RuntimeException;

/**
 * A class to handle mail transport during tests
 *
 * @package Core\Mail
 * @author Anthonius Munthi <me@itstoni.com>
 * @since 0.30.1
 */
class FileTransport extends BaseFileTransport
{
    /**
     * Saves e-mail message to a file
     *
     * @param \Zend\Mail\Message $message
     * @throws RuntimeException on not writable target directory or
     * on file_put_contents() failure
     */
    public function send(\Zend\Mail\Message $message)
    {
        $options  = $this->options;
        $filename = call_user_func($options->getCallback(), $this);
        $file     = $options->getPath() . DIRECTORY_SEPARATOR . $filename;

        $contents = $message->toString();
        $umask = umask();
        umask(022);
        if (false === file_put_contents($file, $contents, LOCK_EX)) {
            throw new RuntimeException(sprintf(
                'Unable to write mail to file (directory "%s")',
                $options->getPath()
            ));
        }
        umask($umask);
        $this->lastFile = $file;
    }
}


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

/** */
namespace Core\Service\EntityEraser;

use Zend\Filter\FilterInterface;

/**
 * Filter to map route parameters to repository names.
 *
 * @author Mathias Gelhausen <gelhausen@cross-solution.de>
 * @todo write test
 */
class NameFilter implements FilterInterface
{
    /**
     *
     *
     * @var array
     */
    private $map;

    /**
     * NameFilter constructor.
     *
     * @param array $map
     */
    public function __construct(array $map)
    {
        $this->map = $map;
    }

    /**
     * Returns the mapped or unfiltered value.
     *
     * @param string $value
     *
     * @return string
     */
    public function filter($value)
    {
        return isset($this->map[$value]) ? $this->map[$value] : $value;
    }
}


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

/** */
namespace Core\Controller\Plugin;

use Zend\Form\Form;
use Zend\Form\FormElementManager\FormElementManagerV3Polyfill as FormElementManager;
use Zend\Mvc\Controller\Plugin\AbstractPlugin;
use Zend\Stdlib\Parameters;

/**
 * Fetches a text search form.
 *
 * @author Mathias Gelhausen <gelhausen@cross-solution.de>
 * @since 0.25
 */
class SearchForm extends AbstractPlugin
{

    /**
     * The form element manager.
     *
     * @var FormElementManager
     */
    protected $formElementManager;

    /**
     * Creates an instance.
     *
     * @param FormElementManager $forms
     */
    public function __construct(FormElementManager $forms)
    {
        $this->formElementManager = $forms;
    }

    /**
     * Direct invokation.
     *
     * Proxies to {@link get()}
     *
     * @param string|array     $elementsFieldset
     * @param null|string $buttonsFieldset
     *
     * @return \Core\Form\TextSearchForm
     */
    public function __invoke($form, $options = null, $params = null)
    {
        return $this->get($form, $options, $params);
    }

    /**
     * Fetches a text search form.
     *
     * If only the service for an element fieldset ist passed,
     * it will fetch a "Core/TextSearch" form and pass the
     * elements fieldset along.
     *
     * @param string|Form     $form
     * @param array|null $options
     * @param Parameters $params
     *
     * @return \Core\Form\SearchForm
     */
    public function get($form, $options = null, $params = null)
    {
        if (!is_object($form)) {
            $form             = $this->formElementManager->get($form, $options);
        }

        /** @noinspection PhpUndefinedMethodInspection */
        $params           = $params ?: clone $this->getController()->getRequest()->getQuery();

        /* I tried using form methods (bind, isValid)...
         * but because the search form could be in an invalidated state
         * when the page is loaded, we need to hydrate the params manually.
         */
        $hydrator = $form->getHydrator();
        $data     = $hydrator->extract($params);
        $form->setData($data);

        $hydrator->hydrate($data, $params);

        return $form;
    }
}


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

/** ActionController of Core */
namespace Core\Controller;

use Core\Listener\DefaultListener;
use Interop\Container\ContainerInterface;
use Zend\ModuleManager\ModuleManager;
use Zend\ModuleManager\ModuleManagerInterface;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;

/**
 * Main Action Controller for the application.
 * Responsible for displaying the home site.
 *
 * @author Anthonius Munthi <me@itstoni.com>
 */
class IndexController extends AbstractActionController
{
    /** @var  DefaultListener */
    private $defaultListener;

    private $config;

    /**
     * @var ModuleManager
     */
    private $moduleManager;

    public function __construct(
        ModuleManagerInterface $moduleManager,
        $config
    ) {
        $this->config = $config;
        $this->moduleManager = $moduleManager;
    }

    /**
     * Home site
     *
     */
    public function indexAction()
    {
        $auth = $this->Auth();
        $config = $this->config;
        if (array_key_exists('startpage', $config['view_manager']['template_map'])) {
            $this->layout()->setTerminal(true)->setTemplate('startpage');
        }
        return ['auth' => $auth];
    }

    public function dashboardAction()
    {
        $model = new ViewModel();
        $model->setTemplate('core/index/dashboard');
        $modules = $this->moduleManager->getLoadedModules();
        foreach ($this->config('dashboard', array_keys($modules)) as $module => $cfg) {
            if (!isset($cfg['enabled']) || true !== $cfg['enabled']) {
                continue;
            }
            foreach ($cfg['widgets'] as $captureTo => $spec) {
                if (isset($spec['controller'])) {
                    $params = array('action' => 'dashboard');
                    if (isset($spec['params'])) {
                        $params = array_merge($params, $spec['params']);
                    }

                    $viewModel = $this->forward()->dispatch($spec['controller'], $params);
                    // we ignore all errors and simply continue with the error template as widget content
                    $response = $this->getResponse();
                    if (200 != $response->getStatusCode()) {
                        $response->setStatusCode(200);
                        $viewModel = array(
                            'content' => 'Error loading widget.',
                        );
                    }
                    if (!$viewModel instanceof ViewModel) {
                        $viewModel = new ViewModel($viewModel);
                    }
                    if ($template = $viewModel->getTemplate()) {
                        $viewModel->setVariable('script', $template);
                    }
                } elseif (isset($spec['script'])) {
                    $viewModel = new ViewModel(array('script' => $spec['script']));
                } elseif (isset($spec['content'])) {
                    $viewModel = new ViewModel(array('content' => $spec['content']));
                }

                $viewModel->setTemplate('core/index/dashboard-widget.phtml');
                $model->addChild($viewModel, "dashboard_{$module}_{$captureTo}");
            }
        }
        return $model;
    }

    public function errorAction()
    {
        $viewModel = new ViewModel();
        $viewModel->setTemplate('error/index')
                  ->setVariable('message', 'An unexpected error had occured. Please try again later.');
        return $viewModel;
    }
}


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

/**  */
namespace Core\Repository\DoctrineMongoODM\Types;

use Doctrine\ODM\MongoDB\Types\Type;

/**
 * This is a mapping type for DoctrineMongoODM.
 *
 * It will convert \DateTime objects to an array representation
 * with a \MongoDate object and the Timezone.
 *
 * This works around the fact, that \MongoDate is NOT
 * timezone aware.
 *
 * @version 1.1
 * @author Mathias Gelhausen <gelhausen@cross-solution.de>
 */
class TimezoneAwareDate extends Type
{

    /**
     * Converts a \DateTime object to MongoDB representation.
     *
     * If $value is NULL (or not a \DateTime object),
     * nothing is done and NULL returned.
     *
     * @internal
     *      Resulting value is an array:
     *

     *          array(
     *              'date' => \MongoDate(\DateTime::timestamp),
     *              'tz'   => TimeZone-Identifier (e.g. "Europe/Berlin")
     *          )
     *

     *
     * @param \DateTime|null $value
     * @return null|array
     * @see \Doctrine\ODM\MongoDB\Types\Type::convertToDatabaseValue()
     */
    public function convertToDatabaseValue($value)
    {
        if (!$value instanceof \DateTime) {
            return null;
        }

        $timezone  = $value->getTimezone()->getName();
        $timestamp = $value->getTimestamp();
        $date      = new \MongoDate($timestamp);

        return array(
            'date' => $date,
            'tz'   => $timezone,
        );
    }

    /**
     * PHP code to be used in DoctrineMongoODM-Hydrators.
     *
     * @return string
     * @see convertToDatabaseValue()
     */
    public function closureToDatabase()
    {
        return '
            /* CODE FROM: ' . __METHOD__ . ' */
            if (!$value instanceOf \DateTime) return null;
            $return = array(
                "date" => new \MongoDate($value->getTimestamp()),
                "tz" => $value->getTimestamp()->getName()
            );
            /* ---- */';
    }

    /**
     * Converts a TimezoneAwareDate array to a \DateTime Object.
     *
     * Returns NULL, if $value is an unknown format.
     *
     * @param array $value
     * @return NULL|\DateTime
     */
    public function convertToPhpValue($value)
    {
        if (!is_array($value)
            || !isset($value['date'])
            || !$value['date'] instanceof \MongoDate
            || !isset($value['tz'])
        ) {
            return null;
        }

        $timestamp = $value['date']->sec;
        $date = new \DateTime('@'.$timestamp);
        $date->setTimezone(new \DateTimeZone($value['tz']));
        return $date;
    }

    /**
     * PHP code to be used in DoctrineMongoODM-Hydrators.
     *
     * @return string
     * @see convertToPhpValue()
     */
    public function closureToPhp()
    {
        return '
            /* CODE FROM: ' . __METHOD__ . ' */
            if (!is_array($value)
                || !isset($value["date"])
                || !$value["date"] instanceOf \MongoDate
                || !isset($value["tz"])
            ) {
                $return = null;
            } else {
                $date = new \DateTime("@".$value["date"]->sec);
                $date->setTimezone(new \DateTimeZone($value["tz"]));
                $return = $date;
            }
            /* ---- */
            ';
    }
}


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

namespace Core\Form\View\Helper;

use Zend\Form\ElementInterface;
use Zend\Form\View\Helper\FormTextarea;
use Zend\Json\Json;

class FormEditor extends FormTextarea
{
    /**
     * @var string
     */
    protected $theme = 'modern';

    private $skinUrl = '/dist/tinymce-skins/lightgray';

    /**
     * Default configuration of the form editor
     *
     * @see https://www.tinymce.com/docs/configure/integration-and-setup/
     * @var array
     */
    protected $options = [
        'selector' => 'div.tinymce_modern',
        'inline' => true,
        'theme' => 'modern',
        'toolbar' => 'undo redo | formatselect | bold italic | alignleft aligncenter alignright alignjustify | link | bullist | removeformat',
        'menubar' => false,
        'advlist_bullet_styles' => 'square disc',
        'block_formats' => 'Headings=h4;',
        'removed_menuitems' =>  'newdocument',
        'plugins' => 'autolink lists advlist visualblocks code fullscreen contextmenu paste link',
    ];

    /**
     * Language of tinyMCE
     *
     * @var string
     */
    protected $language="de";

    /**
     * @var
     */
    protected $translator;

    /**
     * @param ElementInterface $element
     *
     * @return string
     */
    public function render(ElementInterface $element)
    {
        $name   = $element->getName();
        if (empty($name) && $name !== 0) {
            throw new \DomainException(
                sprintf(
                    '%s requires that the element has an assigned name; none discovered',
                    __METHOD__
                )
            );
        }

        if ($editorOptions = $element->getOption('editor')) {
            $this->setOptions($editorOptions);
        }
        /* @var \Zend\View\Renderer\PhpRenderer $renderer */
        $renderer = $this->getView();
        /* @var \Zend\View\Helper\HeadScript  $headscript */
        $headscript = $renderer->plugin('headscript');
        /* @var \Zend\View\Helper\BasePath  $basepath */
        $basepath = $renderer->plugin('basepath');

        //$headscript->appendFile($basepath('assets/tinymce/tinymce.min.js'));
        //$headscript->prependFile($basepath('/assets/jquery/jquery.min.js'));

        $headscript->offsetSetScript(
            '1000_tinymce_' . $this->getTheme(),
            '
            $(document).ready(function() {
            tinyMCE.init({' . $this->additionalOptions() . ',
                 skin_url: "'.$this->skinUrl.'",
                 setup:  function(editor) {

                    setPlaceHolder = function(editor, show) {
                        placeHolder = $("#placeholder-" + editor.id);
                        if (placeHolder.length == 1) {
                            if (show && editor.getContent() == "") {
                                placeHolder.show();
                            }
                            else {
                                placeHolder.hide();
                            }
                         }
                    },
                    editor.on("focus", function(e) {
                        setPlaceHolder(editor, false);
                    });
                    editor.on("blur", function(e) {
                        setPlaceHolder(editor, true);
                        if (editor.isDirty()) {
                            //console.log("blur event", e);
                            editor.save();
                            var container = e.target.bodyElement;
                            $(container).parents("html").addClass("yk-changed");
                            var form = $(container).parents("form");
                            //console.log("form", form, container);
                            ' . ($element->getOption('no-submit') ? '' : 'form.submit();').'
                            $(form).on("yk.forms.done", function(){
                                console.log("done");
                                //$(container).parents("html").removeClass("yk-changed");
                            });
                        }
                    });
                },
                init_instance_callback: function (instance)  { instance.save(); }
            });
            });'
        );

        $attributes         = $element->getAttributes();
        $attributes['name'] = $name;
        $attributes['id']   = $name;
        $content            = $element->getValue();
        if (!isset($content)) {
            $content = '';
        }
        if (is_string($content)) {
            $class = array_key_exists('class', $attributes)?$attributes['class']:'';
            $class .= (empty($class)?:' ') . ' tinymce_' . $this->getTheme();
            $attributes['class'] = $class;
            $placeHolder = '';
            $elementOptions = $element->getOptions();
            if (array_key_exists('placeholder', $elementOptions) && !empty($elementOptions['placeholder'])) {
                $placeHolder = '
' . $this->translator->translate($elementOptions['placeholder']) . '
';
            }
            return
                $placeHolder
                . sprintf(
                    '
%s
',
                    $this->createAttributesString($attributes),
                    $content
                );
        } else {
            return (string) $content;
        }
    }

    /**
     * Gets the name of the theme
     *
     * @return string
     */
    protected function getTheme()
    {
        return $this->theme;
    }

    protected function additionalOptions()
    {
        $str = Json::encode($this->options, false, ['enableJsonExprFinder' => true]);

        return  substr($str, 1, -1);
    }

    /**
     * Translations of "Job title" and "Subtitle" are directly made in the tinymce language files
     *
     * @param $language
     */
    public function setLanguage($language)
    {
        $this->language=$language;
    }

    /**
     * Sets the language path for tinyMCE language files
     *
     * @param $languagePath
     */
    public function setLanguagePath($languagePath)
    {
        $this->languagePath=$languagePath;
    }

    /**
     * Set a formular editor option
     *
     * @param $name
     * @param $value
     */
    public function setOption($name, $value)
    {
        $this->options[$name] = $value;

        return $this;
    }

    /**
     * Set formular editor options
     *
     * @param $options
     */
    public function setOptions($options)
    {
        foreach ($options as $key => $val) {
            $this->setOption($key, $val);
        }
    }
}