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

namespace Core\Controller\Plugin;

use Core\Entity\SnapshotGeneratorProviderInterface;
use Core\Service\SnapshotGenerator;
use Zend\Mvc\Controller\Plugin\PluginInterface;
use Zend\Stdlib\DispatchableInterface as Dispatchable;
use Zend\Stdlib\ArrayUtils;
use Core\Entity\Hydrator\EntityHydrator;
use Core\Repository\RepositoryInterface;

/**
 * Class EntitySnapshot
 * @package Core\Controller\Plugin
 */
class EntitySnapshot implements PluginInterface
{
    /**
     * @var
     */
    protected $serviceLocator;

    /**
     * @var RepositoryInterface
     */
    protected $repositories;

    /**
     * @var array
     */
    protected $options;

    /**
     * @var
     */
    protected $entity;

    /**
     * @var SnapshotGenerator
     */
    protected $generator;

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

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

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

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

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

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

    /**
     * @param null $entity
     * @param array $options
     * @return $this
     */
    public function __invoke($entity = null, $options = array())
    {
        if (is_array($entity)) {
            $options = $entity;
            $entity = null;
        }
        $this->entity = $entity;
        $this->options = $options;
        $this->generator = null;
        if (!isset($entity)) {
            return $this;
        }
        $this->snapshot();
        return $this;
    }

    /**
     * @param null $entity
     * @return $this
     */
    public function snapshot($entity = null)
    {
        if (isset($entity)) {
            $this->entity = $entity;
        }
        if (!isset($this->entity)) {
            // or throw an exception ? since we expect to get a snapshot
            return $this;
        }

        if ($this->entity instanceof SnapshotGeneratorProviderInterface) {
            $generator = $this->getGenerator();
            $data = $generator->getSnapshot();

            // snapshot-class
            $target = $this->getTarget();

            if (isset($target)) {
                $target->__invoke($data);
                $className = get_class($this->entity);
                // @TODO, have to be abstract
                $snapShotMetaClassName = '\\' . $className . 'SnapshotMeta';
                $meta = new $snapShotMetaClassName;
                $meta->setEntity($target);
                $meta->setSourceId($this->entity->id);
                $this->getRepositories()->store($meta);
            }
        }
        return $this;
    }

    /**
     * shows the differences between the last snapshot and the given entity
     * return Null = there is no snapshot
     * return array() = there is a snapshot but no difference
     *
     * @param $entity
     * @return array|null
     */
    public function diff($entity)
    {
        if ($entity instanceof SnapshotGeneratorProviderInterface) {
            $this->entity = $entity;
            $generator = $this->getGenerator();
            $targetClass = $this->getTarget(false);
            $dataHead = $generator->getSnapshot();
            if (empty($dataHead) || empty($targetClass)) {
                return null;
            }
            $repositorySnapshotMeta = $this->getRepositories()->getRepository($targetClass . "Meta");
            $snapshot = $repositorySnapshotMeta->findSnapshot($this->entity);
            // an snapshot has to be so simple that there is no need for a special hydrator
            $hydrator = new EntityHydrator();
            $dataLast = $hydrator->extract($snapshot);
            if (empty($dataLast)) {
                // there is no Snapshot, but returning an empty array would make a wrong conclusion,
                // that there is a snapshot, and it has no differences.
                // actually, if there is a snapshot, it always differ (dateCreated)
                return null;
            }
            return $this->array_compare($dataLast, $dataHead);
        } else {
            // entity is not an implementation of SnapshotGeneratorProviderInterface
        }
        return $this;
    }

    /**
     * the Target is the snapshotMeta-Class
     *
     * @param bool $generateInstance    most of the time we need an instance of the snapshot
     *                                  but we need sometimes just the repository of the snapshotMeta,
     *                                  and we just want the className.
     *                                  If we make this parameter to False we just get the className
     * @return null|string
     */
    protected function getTarget($generateInstance = true)
    {
        $serviceLocator = $this->getServicelocator();
        // set the actual options
        $this->getGenerator();
        $target = null;
        if (array_key_exists('target', $this->options)) {
            $target = $this->options['target'];
            if (is_string($target)) {
                if ($serviceLocator->has($target)) {
                    $target = $serviceLocator->get($target);
                    if ($generateInstance) {
                        $target = get_class($target);
                    }
                } else {
                    if ($generateInstance) {
                        $target = new $target;
                    }
                }
            }
        }
        return $target;
    }

    /**
     * the generator transforms an entity into an array
     *
     * what a generator ought to do more than an hydrator is to unriddle all related data,
     * which can imply that from other entities there also a snapshot can be created
     * @return SnapshotGenerator|mixed|null
     */
    protected function getGenerator()
    {
        if (isset($this->generator)) {
            return $this->generator;
        }

        if ($this->entity instanceof SnapshotGeneratorProviderInterface) {
            $serviceLocator = $this->getServicelocator();

            // the snapshotgenerator is a service defined by the name of the entity
            // this is the highest means, all subsequent means just add what is not set
            $className = get_class($this->entity);
            if ($serviceLocator->has('snapshotgenerator' . $className)) {
                $generator = $this->serviceLocator->get('snapshotgenerator' . $className);
                if (is_array($generator)) {
                    $this->options = ArrayUtils::merge($generator, $this->options);
                    $generator = null;
                }
            }

            // the snapshotgenerator is provided by the entity
            // this can either be a generator-entity of a array with options
            if (!isset($generator)) {
                $generator = $this->entity->getSnapshotGenerator();
                if (is_array($generator)) {
                    $this->options = ArrayUtils::merge($generator, $this->options);
                    if (array_key_exists('generator', $generator)) {
                        $generator = $this->options['generator'];
                        unset($this->options['generator']);
                    } else {
                        $generator = null;
                    }
                }
                if (is_string($generator)) {
                    $generator = $serviceLocator->get($generator);
                }
            }

            // the last possibility to get a generator
            if (!isset($generator)) {
                // defaultGenerator
                $generator = new SnapshotGenerator();
            }

            // *** filling the options
            // hydrator
            // can be a class, but if it's a string, consider it to be an hydrator in the hydratormanager
            if (array_key_exists('hydrator', $this->options)) {
                $hydrator = $this->options['hydrator'];
                if (is_string($hydrator) && !empty($hydrator)) {
                    $hydrator = $serviceLocator->get('HydratorManager')->get($hydrator);
                }
                $generator->setHydrator($hydrator);
            }

            // exclude
            // add the elements, that should not be transferred
            if (array_key_exists('exclude', $this->options)) {
                // it is very likely that the hydrator is set by the snapshot-class,
                // so we have to asume, that may know the hydrator
                $hydrator = $generator->getHydrator();
                $exclude = $this->options['exclude'];
                if (is_array($exclude)) {
                    $hydrator->setExcludeMethods($exclude);
                }
            }
            $generator->setSource($this->entity);
            $this->generator = $generator;
        }
        return $this->generator;
    }

    /**
     * makes a recursiv difference between array1 and array2
     * found commands like  'array_diff_assoc' wanting
     *
     * the result looks like
     * key => array( old, new)
     * in subarrays it looks like
     * key.subkey = array( old, new)
     *
     * @param $array1
     * @param $array2
     * @param int $maxDepth
     * @return array
     */
    protected function array_compare($array1, $array2, $maxDepth = 2)
    {
        $result = array();
        $arraykeys = array_unique(array_merge(array_keys($array1), array_keys($array2)));
        foreach ($arraykeys as $key) {
            if (!empty($key) && is_string($key) && $key[0] != "\0" && substr($key, 0, 8) != 'Doctrine') {
                if (array_key_exists($key, $array1) && !array_key_exists($key, $array2)) {
                    $result[$key] = array($array1[$key], '');
                }
                if (!array_key_exists($key, $array1) && array_key_exists($key, $array2)) {
                    $result[$key] = array('', $array2[$key]);
                }
                if (array_key_exists($key, $array1) && array_key_exists($key, $array2)) {
                    $subResult = null;
                    if (is_array($array1[$key]) && is_array($array2[$key])) {
                        if (0 < $maxDepth) {
                            $subResult = $this->array_compare($array1[$key], $array2[$key], $maxDepth - 1);
                        }
                    } elseif (is_object($array1[$key]) && is_object($array2[$key])) {
                        if (0 < $maxDepth) {
                            $hydrator = new EntityHydrator();
                            $a1 = $hydrator->extract($array1[$key]);
                            $a2 = $hydrator->extract($array2[$key]);
                            $subResult = $this->array_compare($a1, $a2, $maxDepth - 1);
                        }
                    } else {
                        if ($array1[$key] != $array2[$key]) {
                            $result[$key] = array( $array1[$key], $array2[$key]);
                        }
                    }
                    if (!empty($subResult)) {
                        foreach ($subResult as $subKey => $subValue) {
                            if (!empty($subKey) && is_string($subKey)) {
                                $result[$key . '.' . $subKey] = $subValue;
                            }
                        }
                    }
                }
            }
        }
        return $result;
    }

    /**
     * @param Dispatchable $controller
     */
    public function setController(Dispatchable $controller)
    {
    }

    /**
     * @return null|void|Dispatchable
     */
    public function getController()
    {
    }
}


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

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

use Zend\View\Helper\AbstractHelper;

/**
 * View helper to render Twitter Bootsrtap alert messages.
 * Content to this helper can be provided as string or with its
 * content capture mechanism:
 *
 *      // render string using __invoke
 *      echo $this->alert('info', 'This is an info message');
 *
 *      // pass options
 *      echo $this->alert('info', 'This is an info message', array('id' => 'my_alert'));
 *
 *      // render string using explicit type methods
 *      echo $this->alert()->info('This is an info message');
 *      echo $this->alert()->danger('This is an error message');
 *
 *      echo $this->alert()->success('This is a success message', array('class' => 'my_custom_class'));
 *
 *      // render alert box using content capture
 *      $this->alert()->start('info');
 *      ?> Message HTML whatever.. <?php
 *      echo $this->alert()->end();
 *
 *      echo $this->alert()->start('info', array('dismissable' => true));
 *      // or w/o type (defaults to info)
 *      echo $this->alert()->start(array('dismissable'=> true));
 *
 *      // render alert using content capture with expicit type methods
 *      $this->alert()->warning(); // You may pass in TRUE as argument
 *      ?>
You are about to render an alert box
 <?php
 *      echo $this->alert()->end();
 *
 *      // render alert using content capture with __invoke
 *      $this->alert('danger'); ?>
 *
Conetn of alert box

 *      <?php echo $this->alert()->end();
 *
 * @method info()
 * @method warning()
 * @method success()
 * @method danger()

 *
*@author Mathias Gelhausen <gelhausen@cross-solution.de>
 */
class Alert extends AbstractHelper
{

    /**#@+
     * Type of alert boxes.
     *
     * @var string
     */
    const TYPE_INFO    = 'info';
    const TYPE_SUCCESS = 'success';
    const TYPE_WARNING = 'warning';
    const TYPE_DANGER  = 'danger';
    /**#@-*/

    /**
     * Flag indicating, wether a capture is running at the moment.
     *
     * @var boolean
     */
    protected $captureLock = false;

    /**
     * The type of the alert box which is currently captured.
     *
     * @var string
     */
    protected $captureType;

    protected $captureOptions;

    /**
     * Ends content capturing and returns the captured content.
     *
     * @throws \RuntimeException if there's no capturing process running
     * @return string
     * @uses render()
     */
    public function end()
    {
        if (!$this->captureLock) {
            throw new \RuntimeException('Cannot end capture, there is no capture running.');
        }

        $type                 = $this->captureType;
        $content              = ob_get_clean();
        $options              = $this->captureOptions;
        $this->captureLock    = false;
        $this->captureType    = null;
        $this->captureOptions = null;

        return $this->render($type, $content, $options);
    }

    /**
     * Renders an alert box.
     *
     * if TRUE is passed with $content, a capture process is started.
     * if $type is null, return this instance.
     * if $content is true or not passed, starts a capture process.
     * Following options are recognized:
     *      - "id":           sets an id to the alert div
     *      - "class":        String appended to the class-Attribute
     *      - "dismissable":  Boolean value wether the alert will be dismissable or not.
     *
     * @param array|string|null $type
     * @param array|string|bool $content
     * @param array             $options Additional options array
     *
     * @return string|null
     * @uses start()
     */
    public function render($type = null, $content = true, array $options = array())
    {
        if (is_array($type)) {
            $options = $type;
            $type    = self::TYPE_INFO;
            $content = true;
        } elseif (is_array($content)) {
            $options = $content;
            $content = true;
        }

        if (true === $content) {
            return $this->start($type, $options);
        }

        $id    = isset($options['id']) ? ' id="' . $options['id'] . '"' : '';
        $class = isset($options['class']) ? ' ' . $options['class'] : '';
        if ((isset($options['dismissable']) && $options['dismissable'])
            || !isset($options['dismissable'])
        ) {
            $class .= ' alert-dismissable';
            $content = '<button type="button" class="close" data-dismiss="alert">×</button>'
                     . '' . $content . '';
        }

        $target = array_key_exists('target', $options)?' target="' . $options['target'] . '"':'';
        $markup = '
' . $content . '
' . PHP_EOL;
        return $markup;
    }

    /**
     * Starts content capturing.
     *
     * @param string|array $type
     * @param array        $options see {@łink render()} for information.
     *
     * @return self
     * @throws \RuntimeException if there's already another capturing process running.
     */
    public function start($type = self::TYPE_INFO, array $options = array())
    {
        if ($this->captureLock) {
            throw new \RuntimeException('Cannot start capture, there is already a capture running.');
        }
        $this->captureLock    = true;
        $this->captureType    = $type;
        $this->captureOptions = $options;
        ob_start();

        return $this;
    }

    /**
     * Implement convinient functions for alert types.
     *
     * @param string $method
     * @param array  $args
     *
     * @return self|string
     * @throws \BadMethodCallException
     */
    public function __call($method, $args)
    {
        if (!in_array($method, array(self::TYPE_INFO, self::TYPE_DANGER, self::TYPE_SUCCESS, self::TYPE_WARNING))) {
            throw new \BadMethodCallException('Unknown method: ' . $method);
        }

        // We know that $method is one of the valid types, so we can safely use it as "type"-parameter for the
        // render method.
        array_unshift($args, $method);

        return call_user_func_array(array($this, 'render'), $args);
    }

    /**
     * Entry point, if object is called as function.
     * if $type is null, return this instance.
     * else proxies to {@link render()}.
     *
     * @param array|string|null $type
     * @param array|string|bool $content
     * @param array             $options Additional options array
     *
     * @return \Core\View\Helper\Alert|string
     * @uses render()
     */
    public function __invoke($type = null, $content = true, array $options = array())
    {
        if (null === $type) {
            return $this;
        }

        return $this->render($type, $content, $options);
    }
}


<?php

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

namespace Core;

use Core\Service\ClearCacheService;
use Symfony\Component\Dotenv\Dotenv;
use Zend\Config\Exception\InvalidArgumentException;
use Zend\ModuleManager\Listener\ListenerOptions;
use Zend\Mvc\Application as BaseApplication;
use Zend\Stdlib\ArrayUtils;
use SebastianBergmann\Version;

/**
 * Yawik Custom MVC Application
 *
 * @package Core
 * @author Anthonius Munthi <me@itstoni.com>
 * @since 0.32
 */
class Application extends BaseApplication
{
    /**
     * Current yawik revision
     * @var string
     */
    public static $revision;

    /**
     * A short version of package
     * @var string
     */
    public static $version;

    /**
     * Current yawik environment
     * @var string
     */
    public static $env;

    /**
     * Current yawik config directory
     * @var string
     */
    private static $configDir;

    /**
     * @return string
     */
    public static function getCompleteVersion()
    {
        return sprintf('%s@%s', static::$version, static::$revision);
    }

    /**
     * Get required modules for Yawik
     *
     * @return array
     */
    public static function getRequiredModules()
    {
        return array(
            'Zend\ServiceManager\Di',
            'Zend\Session',
            'Zend\Router',
            'Zend\Navigation',
            'Zend\I18n',
            'Zend\Filter',
            'Zend\InputFilter',
            'Zend\Form',
            'Zend\Validator',
            'Zend\Log',
            'Zend\Mvc\Plugin\Prg',
            'Zend\Mvc\Plugin\Identity',
            'Zend\Mvc\Plugin\FlashMessenger',
            'Zend\Mvc\I18n',
            'Zend\Mvc\Console',
            'Zend\Hydrator',
            'Zend\Serializer',
            'DoctrineModule',
            'DoctrineMongoODMModule',
        );
    }

    /**
     * Generate modules to be loaded for Yawik application
     *
     * @param array $loadModules
     * @return array
     */
    public static function generateModuleConfiguration($loadModules=[])
    {
        $modules = ArrayUtils::merge(
            static::getRequiredModules(),
            $loadModules
        );
        return $modules;
    }

    /**
     * Get config directory location
     *
     * @return string Configuration directory
     */
    public static function getConfigDir()
    {
        if (is_null(static::$configDir)) {
            $configDir = '';
            $dirs = [
                // path/to/module/test/sandbox/config directories
                __DIR__.'/../../../../*/sandbox/config',

                // path/to/yawik-standard/config
                __DIR__.'/../../../config',
            ];
            foreach ($dirs as $dir) {
                foreach (glob($dir) as $testDir) {
                    $configDir = realpath($testDir);
                    break;
                }
                if (is_dir($configDir)) {
                    break;
                }
            }

            if (!is_dir($configDir)) {
                throw new InvalidArgumentException('Can not determine which config directory to be used.');
            }

            static::$configDir = $configDir;
        }
        return static::$configDir;
    }

    /**
     * @inheritdoc
     */
    public static function init($configuration = [])
    {
        // @codeCoverageIgnoreStart
        if (!version_compare(PHP_VERSION, '7.1.0', 'ge')) {
            echo sprintf('
Sorry, YAWIK requires at least PHP 7.1.0 to run, but this server currently provides PHP %s
', PHP_VERSION);
            echo '
Please ask your servers\' administrator to install the proper PHP version.
';
            exit;
        }
        // @codeCoverageIgnoreEnd

        ini_set('display_errors', true);
        ini_set('error_reporting', E_ALL | E_STRICT);

        static::loadDotEnv();

        if (isset($configuration['config_dir'])) {
            static::$configDir = $configuration['config_dir'];
        }
        static::generateVersion();
        $configuration = static::loadConfig($configuration);
        static::checkCache($configuration);
        return parent::init($configuration);
    }

    /**
     * Check current cache status
     * @param array $configuration
     */
    private static function checkCache(array $configuration)
    {
        $config = $configuration['module_listener_options'];
        $options = new ListenerOptions($config);
        $cache = new ClearCacheService($options);
        $cache->checkCache();
    }

    /**
     * Setup php server
     * @return bool
     * @codeCoverageIgnore
     */
    public static function setupCliServerEnv()
    {
        $parseUrl = parse_url(substr($_SERVER["REQUEST_URI"], 1));
        $route = isset($parseUrl['path']) ? $parseUrl['path']:null;
        if (is_file(__DIR__ . '/' . $route)) {
            if (substr($route, -4) == ".php") {
                require __DIR__ . '/' . $route;     // Include requested script files
                exit;
            }
            return false;           // Serve file as is
        } else {                    // Fallback to index.php
            $_GET["q"] = $route;    // Try to emulate the behaviour of a .htaccess here.
        }
        return true;
    }

    /**
     * Load environment variables from .env files
     */
    public static function loadDotEnv()
    {
        $dotenv = new Dotenv();
        if (is_file(getcwd().'/.env.dist')) {
            $dotenv->load(getcwd().'/.env.dist');
        }
        if (is_file($file = getcwd().'/.env')) {
            $dotenv->load($file);
        }

        if (false === getenv('TIMEZONE')) {
            putenv('TIMEZONE=Europe/Berlin');
        }
        date_default_timezone_set(getenv('TIMEZONE'));
    }

    /**
     * Load Application configuration
     * @param array $configuration
     * @return array
     */
    public static function loadConfig($configuration = [])
    {
        $configDir = static::getConfigDir();
        if (empty($configuration)) {
            $configFile = $configDir.'/config.php';
            // @codeCoverageIgnoreStart
            if (!is_file($configFile)) {
                throw new InvalidArgumentException(sprintf(
                    'Can not load config file "%s". Please be sure that this file exists and readable',
                    $configFile
                ));
            }
            // @codeCoverageIgnoreEnd
            $configuration = include $configFile;
        }

        $isCli = php_sapi_name() === 'cli';

        // load modules
        $modules = $configuration['modules'];
        $modules = static::generateModuleConfiguration($modules);

        $yawikConfig = $configDir.'/autoload/yawik.config.global.php';
        $installMode = false;
        if (!$isCli && !file_exists($yawikConfig)) {
            $modules = static::generateModuleConfiguration(['Install']);
            $installMode = true;
        } elseif (in_array('Install', $modules)) {
            $modules = array_diff($modules, ['Install']);
        }

        static::$env = $env = getenv('APPLICATION_ENV') ?: 'production';
        $defaults = [
            'module_listener_options' => [
                'module_paths' => [
                    './module',
                    './vendor',
                    './modules'
                ],
                // What configuration files should be autoloaded
                'config_glob_paths' => [
                    sprintf($configDir.'/autoload/{,*.}{global,%s,local}.php', $env)
                ],

                // Use the $env value to determine the state of the flag
                // caching disabled during install mode
                'config_cache_enabled' => ($env == 'production'),

                // Use the $env value to determine the state of the flag
                'module_map_cache_enabled' => ($env == 'production'),

                'module_map_cache_key' => 'module_map',

                // Use the $env value to determine the state of the flag
                'check_dependencies' => ($env != 'production'),

                'cache_dir' => getcwd()."/var/cache",
            ],
        ];

        $envConfig = [];
        $envConfigFile = $configDir.'/config.'.$env.'.php';
        if (file_exists($envConfigFile)) {
            if (is_readable($envConfigFile)) {
                $envConfig = include $envConfigFile;
            } else {
                \trigger_error(
                    sprintf('Environment config file "%s" is not readable.', $envConfigFile),
                    E_USER_NOTICE
                );
            }
        }

        // configuration file always win
        $configuration = ArrayUtils::merge($defaults, $configuration);
        // environment config always win
        $configuration = ArrayUtils::merge($configuration, $envConfig);

        $configuration['modules'] = $modules;

        // force disabled cache when in install mode
        if ($installMode) {
            $configuration['module_listener_options']['config_cache_enabled'] = false;
            $configuration['module_listener_options']['module_map_cache_enabled'] = false;
        }

        // setup docker environment
        if (getenv('DOCKER_ENV')=='yes') {
            $configuration = ArrayUtils::merge($configuration, static::getDockerEnv($configuration));
        }
        return $configuration;
    }

    /**
     * Override configuration in docker environment
     * This will fix filesystem writing during behat tests
     * @param $configuration
     * @return array
     */
    private static function getDockerEnv($configuration)
    {
        // add doctrine hydrator
        $cacheDir = $configuration['module_listener_options']['cache_dir'].'/docker';
        $configDir = static::getConfigDir();
        $hydratorDir = $cacheDir.'/Doctrine/Hydrator';
        $proxyDir = $cacheDir.'/Doctrine/Proxy';
        if (!is_dir($hydratorDir)) {
            mkdir($hydratorDir, 0777, true);
        }
        if (!is_dir($proxyDir)) {
            mkdir($proxyDir, 0777, true);
        }
        return [
            'module_listener_options' => [
                'cache_dir' => $cacheDir,
                'config_glob_paths' => [
                    $configDir.'/autoload/*.docker.php',
                ]
            ],
            'doctrine' => [
                'configuration' => [
                    'odm_default' => [
                        'hydrator_dir' => $hydratorDir,
                        'proxy_dir' => $proxyDir,
                    ]
                ]
            ]
        ];
    }

    private static function generateVersion()
    {
        if (is_null(static::$revision)) {
            $dirs = [
                // in vendors or modules directory
                __DIR__.'/../.git',

                // in development mode
                __DIR__.'/../../../.git',
            ];

            $path = realpath(dirname(__DIR__));

            foreach ($dirs as $dir) {
                if (is_dir($dir)) {
                    $path = dirname(realpath($dir));
                    break;
                }
            }

            $info = new Version(Module::VERSION, $path);
            $exp  = explode("-g", $info->getVersion(), 2);

            static::$version  = $exp[0];
            static::$revision = isset($exp[1]) ? $exp[1] : '';
        }
    }
}


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

/** */
namespace Core\Factory\Form\Tree;

use Core\Entity\Tree\NodeInterface;
use Core\Form\Hydrator\Strategy\TreeSelectStrategy;
use Core\Form\Tree\Select;
use Interop\Container\ContainerInterface;
use Zend\ServiceManager\Factory\FactoryInterface;
//use Zend\ServiceManager\MutableCreationOptionsInterface;
use Zend\ServiceManager\ServiceLocatorInterface;

/**
 * Factory for a tree select form element.
 *
 * @author  Mathias Gelhausen <gelhausen@cross-solution.de>
 * @author  Anthonius Munthi <me@itstoni.com>
 * @since   0.29
 * @TODO    [ZF3] Check if removed MutableCreationOptionsInterface affecting Yawik
 */
class SelectFactory implements FactoryInterface
{

    /**
     * Creation options.
     *
     * @var array
     */
    protected $options = [];

    /**
     * Creates a tree select form element
     *
     * @param ContainerInterface $container
     * @param string             $requestedName
     * @param array|null         $options
     *
     * @return Select
     * @throws \RuntimeException
     * @throws \DomainException
     */
    public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
    {
        if (!is_array($options)
            || !isset($options['tree']['entity'])
            || (!isset($options['tree']['value']) && !isset($options['tree']['name']))
        ) {
            throw new \DomainException('You must specify ["tree"]["entity"] and either ["tree"]["value"] or ["tree"]["name"]');
        }

        if (isset($options['tree']['value'])) {
            $criteria = ['value' => $options['tree']['value']];
        } else {
            $criteria = ['name' => $options['tree']['name']];
        }

        $root = $container
            ->get('repositories')
            ->get($options['tree']['entity'])
            ->findOneBy($criteria);

        if (!$root) {
            throw new \RuntimeException('Tree root not found');
        }

        $select = new Select();

        if (isset($options['name'])) {
            $select->setName($options['name']);
        }

        if (isset($options['options'])) {
            $select->setOptions($options['options']);
        }

        if (isset($options['attributes'])) {
            $select->setAttributes($options['attributes']);
        }

        $valueOptions = $this->createValueOptions($root, isset($options['allow_select_nodes']) && $options['allow_select_nodes']);
        if (!isset($options['use_root_item']) || !$options['use_root_item']) {
            $valueOptions = array_shift($valueOptions);
            $valueOptions = is_array($valueOptions) ? $valueOptions['options'] : [];
        }
        $select->setValueOptions($valueOptions);

        $strategy = new TreeSelectStrategy();
        $strategy->setTreeRoot($root);
        $strategy->setAllowSelectMultipleItems(function () use ($select) {
            return $select->isMultiple();
        });

        $select->setHydratorStrategy($strategy);

        return $select;
    }

    /**
     * Set creation options
     *
     * @param  array $options
     *
     * @return void
     */
    public function setCreationOptions(array $options)
    {
        $this->options = $options;
    }

    /**
     * Create a tree select form element.
     *
     * @internal
     *      proxies to {@link __invoke}.
     *
     * @param ServiceLocatorInterface $serviceLocator
     * @return Select
     */
    public function createService(ServiceLocatorInterface $serviceLocator)
    {
        /* @var \Zend\ServiceManager\AbstractPluginManager $serviceLocator */
        $select = $this($serviceLocator, self::class, $this->options);
        $this->options = [];

        return $select;
    }

    /**
     * Create value options from a node.
     *
     * @param NodeInterface $node
     * @param bool $allowSelectNodes
     * @param bool $isRoot
     *
     * @return array
     */
    protected function createValueOptions(NodeInterface $node, $allowSelectNodes = false, $isRoot=true)
    {
        $key    = $isRoot ? $node->getValue() : $node->getValueWithParents();
        $name   = $node->getName();

        if ($node->hasChildren()) {
            $leafOptions = [];

            if ($allowSelectNodes && !$isRoot) {
                $leafOptions[$key] = $name;
                $key = "$key-group";
            }

            foreach ($node->getChildren() as $child) {
                $leafOptions += $this->createValueOptions($child, $allowSelectNodes, false);
            }

            $value = [
                'label' => $name,
                'options' => $leafOptions
            ];
        } else {
            $value = $name;
        }

        return [$key => $value];
    }
}


<?php

namespace Core\Service;

use Zend\ServiceManager\ServiceManager;

class Config
{
    protected $serviceManager;
    protected $config;
    protected $map = array();
    protected $applicationMap = array();
    protected $configAccess;
    protected $controller;
    protected $namespace;

    /**
     * @param ServiceManager $serviceManager
     */
    public function __construct(ServiceManager $serviceManager)
    {
        $this->serviceManager = $serviceManager;
    }

    public function setController($controller)
    {
        if ($controller != $this->controller) {
            $this->controller = $controller;
            $controllerClass = $controller;
            if (is_object($controller)) {
                $controllerClass = get_class($controller);
            }
            $this->setNamespace(substr($controllerClass, 0, strpos($controllerClass, '\\')));
        }
        return $this;
    }

    public function setNamespace($name)
    {
        $this->namespace = $name;
        return $this;
    }

    public function getNamespace()
    {
        return $this->namespace;
    }

    public function get($key = null)
    {
        $namespace = $this->getNamespace();
        if (isset($this->map[$key])) {
            return isset($this->map[$key][$module]) ? $this->map[$key][$module] : array();
        }
        $config = $this->getConfig($namespace);
        if (isset($key)) {
            return isset($config[$key]) ? $config[$key] : null;
        }
        return $config;
    }

    /**
     * fetch the settings for a certain key of all Modules
     * @param string $key
     * @return array
     */
    public function getByKey($key = null)
    {
        if (!array_key_exists($key, $this->applicationMap)) {
            $this->applicationMap[$key] = array();
            $config = $this->serviceManager->get('Config');
            $appConfig = $this->serviceManager->get('ApplicationConfig');
            foreach ($appConfig['modules'] as $module) {
                if (array_key_exists($module, $config)) {
                    if (array_key_exists($key, $config[$module])) {
                        // The strtolower is essential for later retrieving
                        // namespaces in the repositories
                        // anyway, it's easier to agree everything should be lowercase
                        $this->applicationMap[$key][strtolower($module)] = $config[$module][$key];
                    }
                }
            }
        }
        return $this->applicationMap[$key];
    }

    protected function getConfig($namespace = null)
    {
        if (!$this->config) {
            $this->config = array();
            $config    = $this->serviceManager->get('Config');
            $appConfig = $this->serviceManager->get('ApplicationConfig');
            foreach ($appConfig['modules'] as $module) {
                $this->config[$module] = array_key_exists($module, $config)?$config[$module]:array();
            }
        }
        if (isset($namespace)) {
            return array_key_exists($namespace, $this->config)?$this->config[$namespace]: array();
        }
        return $this->config;
    }

    protected function getMapConfig($key)
    {
        if (!isset($this->map[$key])) {
            $config          = $this->serviceManager->get('Config');
            $this->map[$key] = isset($config[$key]) ? $config[$key] : array();
        }
        if (!empty($this->map[$key])) {
            $module          = $this->getNamespace();
            return isset($this->map[$key][$module])?$this->map[$key][$module]:array();
        }
        return array();
    }

    /**
     * @param ServiceManager $serviceManager
     * @return Config
     */
    public static function factory(ServiceManager $serviceManager)
    {
        return new static($serviceManager);
    }
}


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

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

use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
use Zend\Http\PhpEnvironment\Request;

/**
 * The Content Controller contains actions for handling static content.
 *
 */
class ContentController extends AbstractActionController
{
    /**
     * Displays a content page
     *
     * @return ViewModel
     */
    public function indexAction()
    {
        $view = $this->params('view');
        $view = 'content/' . $view;

        $viewModel = new ViewModel();
        $viewModel->setTemplate($view);

        /* @var $request Request */
        $request = $this->getRequest();

        if ($request->isXmlHttpRequest()) {
            $viewModel->setTerminal(true);
        }
        return $viewModel;
    }

    /**
     * displays the content of a modal box. This is used e.g. when opening
     * the privacy policies or the terms and conditions in a modal box
     *
     *  @return ViewModel
     */
    public function modalAction()
    {
        $view = $this->params('view');

        $viewModel = new ViewModel();
        $viewModel->setTemplate($view);

        /* @var $request Request */
        $request = $this->getRequest();

        if ($request->isXmlHttpRequest()) {
            $viewModel->setTerminal(true);
        }

        return $viewModel;
    }
}


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

/** */
namespace Core\Listener;

use Core\EventManager\EventManager;
use Core\EventManager\ListenerAggregateTrait;
use Core\Listener\Events\AjaxEvent;
use Zend\EventManager\EventManagerInterface;
use Zend\EventManager\ListenerAggregateInterface;
use Zend\Json\Json;
use Zend\Mvc\MvcEvent;

/**
 * On Route listener which triggers ajax events.
 *
 * If the query param "ajax" is present (and an ajax request is made), it will
 * trigger an AjaxEvent named after the value of the ajax param.
 *
 * The events are triggered on the dedicated event manager
 * "Core/Ajax/Events"
 *
 * @author Mathias Gelhausen <gelhausen@cross-solution.de>
 * @since 0.29
 */
class AjaxRouteListener implements ListenerAggregateInterface
{
    use ListenerAggregateTrait;

    /**
     * The ajax events manager.
     *
     * @var EventManager
     */
    private $ajaxEventManager;

    /**
     * Attach events spec.
     *
     * @see {@ListenerAggregateTrait}
     * @var array
     */
    private $events = [
        [ MvcEvent::EVENT_ROUTE, 'onRoute', 100 ],
    ];

    /**
     * Creates an instance.
     *
     * @param EventManager $ajaxEventManager
     */
    public function __construct(EventManagerInterface $ajaxEventManager)
    {
        $this->ajaxEventManager = $ajaxEventManager;
    }

    /**
     * Handler for onRoute mvc event.
     *
     * @param MvcEvent $event
     *
     * @return null|\Zend\Http\PhpEnvironment\Response
     * @throws \UnexpectedValueException
     */
    public function onRoute(MvcEvent $event)
    {
        /* @var \Zend\Http\PhpEnvironment\Request $request */
        $request = $event->getRequest();
        $ajax = $request->getQuery()->get('ajax');

        if (!$request->isXmlHttpRequest() || !$ajax) {
            /* no ajax request or required parameter not present */
            return;
        }

        /* @var \Zend\Http\PhpEnvironment\Response $response */
        /* @var AjaxEvent $ajaxEvent */
        $response = $event->getResponse();

        $ajaxEvent = $this->ajaxEventManager->getEvent($ajax, $this);
        $ajaxEvent->setRequest($request);
        $ajaxEvent->setResponse($response);

        $results = $this->ajaxEventManager->triggerEventUntil(function ($r) {
            return null !== $r;
        }, $ajaxEvent);
        $result  = $results->last() ?: $ajaxEvent->getResult();

        if (!$result) {
            throw new \UnexpectedValueException('No listener returned anything. Do not know what to do...');
        }

        /* Convert arrays or traversable objects to JSON string. */
        if (is_array($result) || $result instanceof \Traversable) {
            $result = Json::encode($result, true, ['enableJsonExprFinder' => true]);
        }

        $contentType = $ajaxEvent->getContentType();

        $response->getHeaders()->addHeaderLine('Content-Type', $contentType);
        $response->setContent($result);

        return $response;
    }
}


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

namespace Core\Service;

use Zend\Http\Client as ZendClient;
use Zend\Http\Request;
use Zend\Http\Headers;
use \Zend\Stdlib\ArrayUtils;

/**
 * Class RestClient
 * @package Core\Service
 */
class RestClient extends ZendClient
{
    protected $config;

    /**
     * establish all parameters to another YAWIK instance
     * these are quite good default-parameter for all REST-Clients
     *
     * notice: PHP_AUTH_USER and PHP_AUTH_PW are the basic-authentification parameter,
     * they are set by setAuth($user, $pw). It will be replaced by oAuth2.
     * at the client they are with available at the $_SERVER['PHP_AUTH_USER'] and $_SERVER['PHP_AUTH_PW'] again
     * @param null|string $uri
     * @param array $config
     */
    public function __construct($uri, array $config)
    {
        $this->config = $config;
        $config = ArrayUtils::merge(
            array(
                'adapter' => 'Zend\Http\Client\Adapter\Curl',
                'keepalive' => false,
                'encodecookies' => false,
                'outputstream' => false,
                'httpversion' => Request::VERSION_11,
                'storeresponse' => false,
                'maxredirects' => 2
            ),
            $config
        );

        parent::__construct($uri, $config);
        $this->setEncType('application/json');
        $this->authetificate();
    }

    /**
     * @param null $key
     * @param null $module
     * @return mixed
     */
    public function __invoke($key = null, $module = null)
    {
        return $this->get($key, $module);
    }

    /**
     * Get Request
     *
     * @return Request
     */
    public function getRequest()
    {
        if (empty($this->request)) {
            $headers = new Headers();
            $headers->addHeaders(
                array(
                        'Accept' => 'application/json',
                        'Content-Type' => 'application/json'
                    )
            );
            $request = parent::getRequest();
            $request->setHeaders($headers);
            $request->setMethod('POST');
        }
        return $this->request;
    }

    /**
     * @throws \RuntimeException
     * @return mixed
     */
    protected function authetificate()
    {
        $auth = array_key_exists('user', $this->config)?$this->config['user']:'';
        $pass = array_key_exists('pass', $this->config)?$this->config['pass']:'';
        return $this->setAuth($auth, $pass);
    }

    public function getHost()
    {
        if (empty($this->config) || !array_key_exists('host', $this->config)) {
            return null;
        }
        return $this->config['host'];
    }
}


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

/**  */
namespace Core\Form\View\Helper;

use Core\Form\SummaryFormInterface;
use Zend\Form\Element\Hidden;
use Zend\Form\FormInterface;
use Zend\Form\View\Helper\AbstractHelper;
use Zend\Form\ElementInterface;
use Zend\Form\FieldsetInterface;
use Core\Form\ViewPartialProviderInterface;
use Core\Form\DescriptionAwareFormInterface;
use Core\Form\EmptySummaryAwareInterface;

/**
 * Helper to render a summary form container.
 *
 * @author Mathias Gelhausen <gelhausen@cross-solution.de>
 */
class SummaryForm extends AbstractHelper
{

    /**
     * Invoke as function.
     *
     * @param null|SummaryFormInterface $form
     * @param string $layout
     * @param array $parameter
     * @return \Core\Form\View\Helper\SummaryForm|string
     */
    public function __invoke(SummaryFormInterface $form = null, $layout = Form::LAYOUT_HORIZONTAL, $parameter = array())
    {
        if (null === $form) {
            return $this;
        }

        $mode = $form->getRenderMode();
        if (SummaryFormInterface::RENDER_FORM == $mode) {
            return $this->renderForm($form, $layout, $parameter);
        }
        if (SummaryFormInterface::RENDER_SUMMARY == $mode) {
            return $this->renderSummary($form);
        }

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

    /**
     * Renders a summary form container.
     *
     * @param SummaryFormInterface $form
     * @param string $layout
     * @param array $parameter
     * @return string
     */
    public function render(SummaryFormInterface $form, $layout = Form::LAYOUT_HORIZONTAL, $parameter = array())
    {
        $renderer = $this->getView();
        $renderer->headscript()->appendFile($renderer->basepath('modules/Core/js/jquery.summary-form.js'));

        $label = $form->getLabel();
        $labelContent = $label ? '

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

' : '';
        $formContent  = $this->renderForm($form, $layout, $parameter);
        $summaryContent = $this->renderSummary($form);

        $formContent = sprintf(
            '

%s

%s

                ',
            $formContent,
            $summaryContent
        );

        if ($form instanceof DescriptionAwareFormInterface && $form->isDescriptionsEnabled()) {
            $this->getView()->headscript()->appendFile(
                $this->getView()->basepath('modules/Core/js/forms.descriptions.js')
            );

            if ($desc = $form->getOption('description', '')) {
                $translator = $this->getTranslator();
                $textDomain = $this->getTranslatorTextDomain();

                $desc = $translator->translate($desc, $textDomain);
            }

            $formContent = sprintf(
                '

%s

%s

',
                $formContent,
                $desc
            );
        }

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

        $id = str_replace('.', '-', $form->getAttribute('name'));
        $content = sprintf(
            $markup,
            $id,
            $form->getDisplayMode(),
            $labelContent,
            $formContent
        );

        return $content;
    }

    /**
     * Only renders the form representation of a summary form.
     *
     * @param SummaryFormInterface $form
     * @param string $layout
     * @param array $parameter
     * @return string
     */
    public function renderForm(SummaryFormInterface $form, $layout = Form::LAYOUT_HORIZONTAL, $parameter = array())
    {
        /* @var $form SummaryFormInterface|\Core\Form\SummaryForm */
        $renderer     = $this->getView();           /* @var $renderer \Zend\View\Renderer\PhpRenderer */
        $formHelper   = $renderer->plugin('form');  /* @var $formHelper \Core\Form\View\Helper\Form */
        $fieldset     = $form->getBaseFieldset();
        $resetPartial = false;

        if ($fieldset instanceof ViewPartialProviderInterface) {
            $origPartial = $fieldset->getViewPartial();
            $partial     = "$origPartial.form";
            if ($renderer->resolver($partial)) {
                $fieldset->setViewPartial($partial);
                $resetPartial = true;
            }
        }

        $markup = $formHelper->renderBare($form, $layout, $parameter);

        if ($resetPartial) {
            /** @noinspection PhpUndefinedVariableInspection */
            $fieldset->setViewPartial($origPartial);
        }

        return $markup;
    }

    /**
     * Only renders the summary representation of a summary form
     *
     * @param SummaryFormInterface $form
     * @return string
     */
    public function renderSummary(SummaryFormInterface $form)
    {
        $form->prepare();
        $baseFieldset = $form->getBaseFieldset();
        if (!isset($baseFieldset)) {
            throw new \InvalidArgumentException('For the Form ' . get_class($form) . ' there is no Basefieldset');
        }

        $dataAttributesMarkup = '';

        foreach ($form->getAttributes() as $dataKey => $dataValue) {
            if (preg_match('/^data-/', $dataKey)) {
                $dataAttributesMarkup .= sprintf(' %s="%s"', $dataKey, $dataValue);
            }
        }

        $markup = '

%s
%s

';

        $view = $this->getView();
        $buttonMarkup = false === $form->getOption('editable')
                      ? ''
                      : '<button type="button" class="btn btn-default btn-xs sf-edit">'
                        . ' '
                        . $view->translate('Edit')
                        . '</button>';

        if (($controlButtons = $form->getOption('control_buttons')) !== null) {
            $buttonMarkup .= PHP_EOL . implode(PHP_EOL, array_map(function (array $buttonSpec) use ($view) {
                return '<button type="button" class="btn btn-default btn-xs' . (isset($buttonSpec['class']) ? ' ' . $buttonSpec['class'] : '') . '">'
                    . (isset($buttonSpec['icon']) ? ' ' : '')
                    . $view->translate($buttonSpec['label'])
                    . '</button>';
            }, $controlButtons));
        }

        $elementMarkup = $this->renderSummaryElement($baseFieldset);

        return sprintf($markup, $buttonMarkup, $elementMarkup);
    }

    /**
     * Helper function to recurse into form elements when rendering summary.
     *
     * @param ElementInterface $element
     * @return string
     */
    public function renderSummaryElement(ElementInterface $element)
    {
        if ($element instanceof Hidden || false === $element->getOption('render_summary')) {
            return '';
        }

        if ($element instanceof EmptySummaryAwareInterface && $element->isSummaryEmpty()) {
            /* @var $element EmptySummaryAwareInterface|ElementInterface */
            $emptySummaryNotice = $this->getTranslator()->translate(
                $element->getEmptySummaryNotice(),
                $this->getTranslatorTextDomain()
            );

            $markup = sprintf(
                '

%s

',
                $element->getAttribute('id'),
                $emptySummaryNotice
            );
            return $markup;
        }

        if ($element instanceof ViewPartialProviderInterface) {
            $renderer    = $this->getView();                 /* @var $renderer \Zend\View\Renderer\PhpRenderer */
            $origPartial = $element->getViewPartial();
            $partial     = "$origPartial.view";
            $partialParams  = array(
                'element' => $element
            );
            if (!$renderer->resolver($partial)) {
                $partial = $origPartial;
                $partialParams['renderSummary'] = true;
            }

            return $renderer->partial($partial, $partialParams);
        }

        $label  = $this->getTranslator()->translate($element->getLabel());
        $markup = '';

        if ($element instanceof FieldsetInterface) {
            if (!$element instanceof FormInterface && $label) {
                $markup .= '
' . $label . '
';
            }
            foreach ($element as $el) {
                $markup .= $this->renderSummaryElement($el);
            }
            return $markup;
        }

        $elementValue = $element instanceof \Zend\Form\Element\Textarea
                      ? nl2br($element->getValue())
                      : $element->getValue();

        if ('' != $elementValue && $element instanceof \Core\Form\Element\Select) {
            if ($summaryValue = $element->getOption('summary_value')) {
                $elementValue = is_callable($summaryValue) ? $summaryValue() : $summaryValue;
            } else {
                $options = $element->getValueOptions();
                $translator = $this->getTranslator();
                if (true == $element->getAttribute('multiple')) {
                    $multiOptions = [];
                    foreach ($elementValue as $optionKey) {
                        if (isset($options[$optionKey])) {
                            $multiOptions[] = $translator->translate($options[$optionKey]);
                            continue;
                        }

                        foreach ($options as $optKey => $optVal) {
                            if (!is_array($optVal) || !array_key_exists($optionKey, $optVal['options'])) {
                                continue;
                            }

                            $optGroupLabel = isset($optVal['label']) ? $translator->translate($optVal['label']) : $optKey;
                            $multiOptions[] = $optGroupLabel . ' | ' . $translator->translate($optVal['options'][$optionKey]);
                        }
                    }

                    $elementValue = '

' . join('

', $multiOptions) . '

';
                } else {
                    $elementValue = $translator->translate($options[$elementValue]);
                }
            }
        }

        if ('' != $elementValue && $element instanceof \Zend\Form\Element\File) {
            return '';
        }

        $markup .= '
';
        $col = 12;
        if ($label) {
            $markup .= '
' . $label . '
';
            $col = 9;
        }
        $markup .= '
' . $elementValue . '
'
            . '
';
        return $markup;
    }
}


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

/** */
namespace Core\Factory\Navigation;

use Zend\Navigation\Service\DefaultNavigationFactory as ZfDefaultNavigationFactory;
use Zend\Mvc\Router as MvcRouter;
use Zend\Mvc\Router\RouteMatch;

/**
 * Extends the ZF DefaultNavigationFactory to let it set
 * active flags on pages when the route matches an entry
 * in the "active_on" option.
 *
 * @author Mathias Gelhausen <gelhausen@cross-solution.de>
 * @since 0.26
 * @since 0.30 - will do nothing if $routeMatch is null
 *               (prevent fatal error)
 */
class DefaultNavigationFactory extends ZfDefaultNavigationFactory
{

    /**
     * Inject components into the pages.
     *
     * @internal
     *      Parses the pages options for the "active_on" property and
     *      sets the active flag if one of the routes match.
     *
     * {@inheritDoc}
     * @since 0.30 add check, if $routeMatch is null
     */
    protected function injectComponents(
        array $pages,
        $routeMatch = null,
        $router = null,
        $request = null
    ) {
        if ($routeMatch) {
            /* @var RouteMatch|MvcRouter\RouteMatch $routeMatch */
            $routeName = $routeMatch->getMatchedRouteName();

            foreach ($pages as &$page) {
                if (isset($page['active_on']) && in_array($routeName, (array) $page['active_on'])) {
                    $page['active'] = true;
                }
            }
        }

        return parent::injectComponents($pages, $routeMatch, $router, $request);
    }
}


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

namespace Core\Mail;

use Interop\Container\ContainerInterface;
use Zend\Mail\Header;
use Zend\ServiceManager\ServiceLocatorInterface;
use Zend\View\Model\ViewModel;
use Zend\Stdlib\Response;
use Zend\View\Variables as ViewVariables;
use Zend\Stdlib\ArrayUtils;

/**
 * Class HTMLTemplateMessage.
 * uses methods alike ViewModel
 * @package Core\Mail
 */
class HTMLTemplateMessage extends TranslatorAwareMessage
{
    /**
     * @var ServiceLocatorInterface
     */
    protected $serviceManager;

    /**
     * View variables
     * @var array|\ArrayAccess|\Traversable
     */
    protected $variables = array();

    protected $renderedBody;

    /**
     * HTMLTemplateMessage constructor.
     *
     * @param ContainerInterface $serviceManager
     * @param array $options
     */
    public function __construct(
        ContainerInterface $serviceManager,
        array $options = array()
    ) {
        // @TODO make this multipart
        parent::__construct($options);
        $this->serviceManager = $serviceManager;
        $this->getHeaders()->addHeader(Header\ContentType::fromString('Content-Type: text/html; charset=UTF-8'));
        $this->setEncoding('UTF-8');
        $this->variables = new ViewVariables();
    }

    /**
     * Property overloading: set variable value
     *
     * @param  string $name
     * @param  mixed $value
     * @return void
     */
    public function __set($name, $value)
    {
        $this->setVariable($name, $value);
    }

    /**
     * Property overloading: get variable value
     *
     * @param  string $name
     * @return mixed
     */
    public function __get($name)
    {
        if (!$this->__isset($name)) {
            return null;
        }

        $variables = $this->getVariables();
        return $variables[$name];
    }

    /**
     * Property overloading: do we have the requested variable value?
     *
     * @param  string $name
     * @return bool
     */
    public function __isset($name)
    {
        $variables = $this->getVariables();
        return isset($variables[$name]);
    }

    /**
     * Property overloading: unset the requested variable
     *
     * @param  string $name
     * @return void
     */
    public function __unset($name)
    {
        if ($this->__isset($name)) {
            unset($this->variables[$name]);
        }
    }

    /**
     * Get a single view variable
     *
     * @param  string       $name
     * @param  mixed|null   $default (optional) default value if the variable is not present.
     * @return mixed
     */
    public function getVariable($name, $default = null)
    {
        $name = (string) $name;
        if (array_key_exists($name, $this->variables)) {
            return $this->variables[$name];
        }

        return $default;
    }

    /**
     * Set view variable
     *
     * @param  string $name
     * @param  mixed $value
     * @return ViewModel
     */
    public function setVariable($name, $value)
    {
        $this->variables[(string) $name] = $value;
        return $this;
    }

    /**
     * Set view variables en masse
     *
     * Can be an array or a Traversable + ArrayAccess object.
     *
     * @param  array|\ArrayAccess|\Traversable $variables
     * @param  bool $overwrite Whether or not to overwrite the internal container with $variables
     * @throws \InvalidArgumentException
     * @return self
     */
    public function setVariables($variables, $overwrite = false)
    {
        if (!is_array($variables) && !$variables instanceof \Traversable) {
            throw new \InvalidArgumentException(
                sprintf(
                    '%s: expects an array, or Traversable argument; received "%s"',
                    __METHOD__,
                    (is_object($variables) ? get_class($variables) : gettype($variables))
                )
            );
        }

        if ($overwrite) {
            if (is_object($variables) && !$variables instanceof \ArrayAccess) {
                $variables = ArrayUtils::iteratorToArray($variables);
            }

            $this->variables = $variables;
            return $this;
        }

        foreach ($variables as $key => $value) {
            $this->setVariable($key, $value);
        }

        return $this;
    }

    /**
     * Get view variables
     *
     * @return array|\ArrayAccess|\Traversable
     */
    public function getVariables()
    {
        return $this->variables;
    }

    /**
     * Clear all variables
     *
     * Resets the internal variable container to an empty container.
     *
     * @return ViewModel
     */
    public function clearVariables()
    {
        $this->variables = new ViewVariables();
        return $this;
    }

    /**
     *
     * @param $template
     *
     * @return self
     */
    public function setTemplate($template)
    {
        $this->template = $template;
        return $this;
    }

    public function getTemplate()
    {
        return $this->template;
    }

    /**
     * @example /module/Jobs/src/Jobs/Listener/PortalListener.php
     * @return string
     * @throws \InvalidArgumentException the mail body must completely be provided by the template, any other attempt is a misconception that may leave the coder in an quagmire
     */
    public function renderBodyText($force = true, $forceLanguage = null)
    {
        if (!$this->renderedBody || $force) {
            $viewModel    = new ViewModel();
            $response     = new Response();
            $body         = parent::getBodyText();
            if (!empty($body)) {
                throw new \InvalidArgumentException('mail body shall come from Template.');
            }

            /* @var \Zend\Mvc\View\Http\ViewManager $viewManager */
            $viewManager  = $this->serviceManager->get('ViewManager');
            $resolver = $this->serviceManager->get('ViewResolver');

            /* @var \Zend\Mvc\MvcEvent $event */
            $event = $this->serviceManager->get('Application')->getMvcEvent();
            $lang = $forceLanguage ?: $event->getRouteMatch()->getParam('lang');

            if ($resolver->resolve($this->getTemplate() . '.' . $lang)) {
                $viewModel->setTemplate($this->getTemplate() . '.' . $lang);
            } else {
                $viewModel->setTemplate($this->getTemplate());
            }

            $view         = $viewManager->getView();

            $viewModel->setVariables($this->getVariables());
            $viewModel->setVariable('mail', $this);
            $view->setResponse($response);
            $view->render($viewModel);
            $body = $response->getContent();

            $this->renderedBody = $body;
        }
    }

    public function getBodyText()
    {
        $this->renderBodyText();
        return $this->renderedBody;
    }

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


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

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

use Core\Entity\EntityInterface;

/**
 * DependencyResult collection
 *
 * @author Mathias Gelhausen <gelhausen@cross-solution.de>
 * @todo write test
 */
class DependencyResultCollection implements \IteratorAggregate
{

    /**
     * The DependencyResult objects.
     *
     * @var array
     */
    private $results = [];

    /**
     * Add a result in various formats.
     *
     * Possible are
     * - a DependencyResult object
     * - any \Traversable object (in that case, the name is set to the class name of the first item)
     * - an array of DependencyResult objects.
     * - an array in the format
     *   [ name, entities, options]
     * -an array in the format
     *  [
     *      'name' => name,
     *      'entities' => entities,
     *      'options' => [ ... ]
     *  ]
     * - an array of arrays in any of the two formats above or \Traversable objects. Can be mixed.
     *
     * @param DependencyResult|array|\Traversable|string           $name
     * @param null|array|\Traversable       $entities
     * @param array|null $options
     *
     * @return DependencyResultCollection
     */
    public function add($name, $entities = null, array $options = null)
    {
        if ($name instanceof DependencyResult) {
            return $this->addResult($name);
        }

        if ($name instanceof \Traversable) {
            return $this->addTraversable($name);
        }

        if (is_array($name)) {
            return $this->addArray($name);
        }

        if (null === $entities) {
            throw new \UnexpectedValueException('$entities must not be null.');
        }

        return $this->addArray([
            'name' => $name,
            'entities' => $entities,
            'options' => $options,
        ]);
    }

    /**
     * Add a DependencyResult object.
     *
     * @param DependencyResult $result
     *
     * @return self
     */
    private function addResult(DependencyResult $result)
    {
        $this->results[] = $result;

        return $this;
    }

    /**
     * Add a \Traversable object.
     *
     * Sets the name of the result to the class name of the first item in the object collection.
     * Therefor, the \Traversable object must not be empty.
     *
     * @param \Traversable $result
     *
     * @return DependencyResultCollection
     * @throws \InvalidArgumentException
     */
    private function addTraversable(\Traversable $result)
    {
        /*
         * Since we only know, that $result is an instance of \Traversable
         * (and thus, usable in a foreach), we cannot relay on methods like first()
         * which are defined in the \Iterable interface.
         * We must use a foreach to get the first item.
         *
         * Because PHP does not unset the loop variable, this works.
         */
        foreach ($result as $item) {
            break;
        }

        /* @var null|object|mixed $item */
        if (!$item instanceof EntityInterface) {
            throw new \InvalidArgumentException('Traversable objects must be a non-empty collection of Entity instances.');
        }

        $name = get_class($item);

        return $this->addArray([
            'name' => $name,
            'entities' => $result,
        ]);
    }

    /**
     * Add an array.
     *
     * please see {@link add} for a list of possible values.
     *
     * @param array $result
     *
     * @return self
     */
    private function addArray(array $result)
    {
        if (1 < count($result) && !isset($result['name']) && !is_string($result[0])) {
            foreach ($result as $r) {
                if (is_array($r)) {
                    $this->add($r);
                } else {
                    return $this->addTraversable(new \ArrayIterator($result));
                }
            }
            return $this;
        }

        if (is_string($result[0])) {
            $result = [
                'name' => $result[0],
                'entities' => isset($result[1]) ? $result[1] : null,
                'options' => isset($result[2]) && is_array($result[2])
                    ? $result[2]
                    : [
                        'description' => isset($result[2]) ? $result[2] : null,
                        'viewScript' => isset($result[3]) ? $result[3] : null,
                      ],
            ];
        }

        if (!isset($result['name']) || !isset($result['entities'])) {
            throw new \UnexpectedValueException('Array must have the keys "name" and "entities".');
        }

        if (!count($result['entities'])) {
            throw new \UnexpectedValueException('Entities must be non-empty.');
        }

        $result = new DependencyResult($result['name'], $result['entities'], isset($result['options']) ? $result['options'] : null);

        return $this->addResult($result);
    }

    public function getIterator()
    {
        return new \ArrayIterator($this->results);
    }
}


<?php
/**

 */

namespace Core\Form\View\Helper;

use Core\Form\ViewPartialProviderInterface;
use Zend\Form\View\Helper\FormElement as ZendFormElement;
use Zend\Form\ElementInterface;
use Core\Form\Element\ViewHelperProviderInterface as CoreElementInterface;
use Zend\View\Helper\HelperInterface;

class FormElement extends ZendFormElement
{

    /**
     * @param ElementInterface $element
     *
     * @return string
     */
    public function render(ElementInterface $element, $ignoreViewPartial = false)
    {
        $renderer = $this->getView();
        if (!method_exists($renderer, 'plugin')) {
            // Bail early if renderer is not pluggable
            return '';
        }

        if ($element instanceof ViewPartialProviderInterface && !$ignoreViewPartial) {
            $partial = $element->getViewPartial();
            return $renderer->partial($partial, ['element' => $element]);
        }

        if ($element instanceof CoreElementInterface) {
            $helper = $element->getViewHelper();
            if (is_string($helper)) {
                $helper = $renderer->plugin($helper);
            }
            if ($helper instanceof HelperInterface) {
                $helper->setView($renderer);
            }
            return $helper($element);
        }

        return parent::render($element);
    }
}


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

/** */
namespace Core\Entity\Tree;

use Core\Entity\Collection\ArrayCollection;
use Core\Entity\EntityTrait;
use Core\Entity\IdentifiableEntityTrait;
use Doctrine\Common\Collections\Collection;
use \Doctrine\ODM\MongoDB\Mapping\Annotations as ODM;

/**
 * base class for trees.
 *
 * @ODM\MappedSuperclass
 * @author Mathias Gelhausen <gelhausen@cross-solution.de>
 * @since 0.29
 */
class Node implements NodeInterface
{
    use EntityTrait, IdentifiableEntityTrait;

    /**
     * Name of this item.
     *
     * @ODM\Field(type="string")
     * @var string
     */
    protected $name;

    /**
     * Value of this item.
     *
     * Used in select form elements.
     *
     * @ODM\Field(type="string")
     * @var string
     */
    protected $value;

    /**
     * Order priority.
     *
     * @ODM\Field(type="int")
     * @var int
     */
    protected $priority = 0;

    /**
     * Child nodes.
     *
     * @ODM\ReferenceMany(discriminatorField="_entity", storeAs="dbRef", strategy="set", sort={"priority"="asc"}, cascade="all", orphanRemoval="true")
     * @var Collection
     */
    protected $children;

    /**
     * Parent node.
     *
     * @ODM\ReferenceOne(discriminatorField="_entity", storeAs="dbRef", nullable="true")
     * @var
     */
    protected $parent;

    final public static function filterValue($value)
    {
        $value = mb_strtolower($value);
        $value = str_replace(['ä', 'ö', 'ü', 'ß'], ['ae', 'oe', 'ue', 'ss'], $value);
        $value = preg_replace(['~[^a-z0-9]~', '~__+~'], '_', $value);

        return $value;
    }

    /**
     * Creates a new Tree item.
     *
     * @param null|string $name
     * @param null|string $value
     * @param int  $priority
     */
    public function __construct($name = null, $value = null, $priority = 0)
    {
        if (null !== $name) {
            $this->setName($name);
            $this->setValue($value);
            $this->setPriority($priority);
        }
    }

    /**
     * Set the name.
     *
     * @param string $name
     *
     * @return self
     * @throws \InvalidArgumentException if $name is empty.
     */
    public function setName($name)
    {
        if (!$name) {
            throw new \InvalidArgumentException('Name must not be empty.');
        }

        $this->name = (string) $name;

        return $this;
    }

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

    /**
     * Set the value.
     *
     * Used in form selects.
     *
     * @param string $value
     *
     * @return self
     * @throws \InvalidArgumentException if $value AND {@link name} are empty.
     */
    public function setValue($value)
    {
        if (!$value) {
            if (!$this->getName()) {
                throw new \InvalidArgumentException('Value must not be empty.');
            }
            $value = self::filterValue($this->getName());
        }

        $this->value = (string) $value;

        return $this;
    }

    public function getValue()
    {
        if (!$this->value) {
            $this->setValue(null);
        }

        return $this->value;
    }

    public function getValueWithParents($withRoot = false, $useNames = false)
    {
        $parts = [ ($useNames ? $this->getName() : $this->getValue()) ];
        $item = $this;

        while ($item = $item->getParent()) {
            $parts[] = $useNames ? $item->getName() : $item->getValue();
        }

        if (!$withRoot) {
            array_pop($parts); // No root node.
        }

        $parts = array_reverse($parts);
        $value = join(($useNames ? ' | ' : '-'), $parts);

        return $value;
    }

    public function getNameWithParents($withRoot = false)
    {
        return $this->getValueWithParents($withRoot, true);
    }

    public function setPriority($priority)
    {
        $this->priority = (int) $priority;

        return $this;
    }

    public function getPriority()
    {
        return $this->priority;
    }

    public function setChildren(Collection $children)
    {
        $this->children = $children;

        /* @var NodeInterface $child */
        foreach ($children as $child) {
            $child->setParent($this);
        }

        return $this;
    }

    public function getChildren()
    {
        if (!$this->children) {
            $this->setChildren(new ArrayCollection());
        }

        return $this->children;
    }

    public function hasChildren()
    {
        return (bool) $this->getChildren()->count();
    }

    public function addChild(NodeInterface $child)
    {
        $this->getChildren()->add($child);
        $child->setParent($this);

        return $this;
    }

    public function removeChild(NodeInterface $child)
    {
        $this->getChildren()->removeElement($child);

        return $this;
    }

    public function clearChildren()
    {
        $this->getChildren()->clear();

        return $this;
    }

    public function setParent(NodeInterface $parent)
    {
        $this->parent = $parent;

        return $this;
    }

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


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

namespace Core\Form;

use Core\Form\Hydrator\HydratorStrategyProviderInterface;
use Zend\Form\Form as ZendForm;
use Zend\Form\FieldsetInterface;
use Core\Entity\Hydrator\EntityHydrator;
use Zend\Hydrator\HydratorInterface;
use Zend\Hydrator\StrategyEnabledInterface;
use Zend\InputFilter\InputFilterInterface;
use Zend\EventManager\EventManagerAwareTrait;

/**
 * Core form.
 *
 * @author Mathias Gelhausen <gelhausen@cross-solution.de>
 */
class Form extends ZendForm implements
    DescriptionAwareFormInterface,
                                       DisableElementsCapableInterface,
                                       FormParentInterface
{
    use EventManagerAwareTrait, HydratorStrategyAwareTrait;

    const EVENT_IS_VALID = 'validate';
    const EVENT_PREPARE = 'prepare';

    /**
     * Form parameters.
     * An array of key  => value pairs which are rendered as hidden fields.
     *
     * @var array
     */
    protected $params;

    /**
     * @var ZendForm
     */
    protected $parent;

    /**
     * Flag, if descriptions handling is enabled or not.
     *
     * @var bool
     */
    protected $isDescriptionsEnabled = false;

    /**
     * @param array|\Traversable|\Zend\Form\ElementInterface $elementOrFieldset
     * @param array                                          $flags
     *
     * @return $this
     */
    public function add($elementOrFieldset, array $flags = array())
    {
        parent::add($elementOrFieldset, $flags);
        if ($elementOrFieldset instanceof FormParentInterface) {
            $elementOrFieldset->setParent($this);
        }
        return $this;
    }

    /**
     * @param bool $flag
     *
     * @return $this
     */
    public function setIsDescriptionsEnabled($flag)
    {
        $this->isDescriptionsEnabled = (bool) $flag;
        return $this;
    }

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

    /**
     * @param string $description
     *
     * @return $this
     */
    public function setDescription($description, $params = null)
    {
        $this->options['description'] = $description;
        $this->options['description_params'] = $params;
        return $this;
    }

    /**
     * @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
     *
     * @return $this
     */
    public function disableElements(array $map)
    {
        if (!$this->isDisableElementsCapable()) {
            return $this;
        }

        foreach ($map as $key => $name) {
            if (is_numeric($key)) {
                $key = $name;
                $name = null;
            }

            if (!$this->has($key)) {
                continue;
            }

            $element = $this->get($key);

            if (null === $name) {
                if (($element instanceof DisableCapableInterface && $element->isDisableCapable())
                    || false !== $element->getOption('is_disable_capable')) {
                    $this->remove($element);
                }
                continue;
            }

            if ($element instanceof FieldsetInterface
                && $element instanceof DisableElementsCapableInterface
                && $element->isDisableElementsCapable()
            ) {
                $element->disableElements($name);
            }
        }
        return $this;
    }

    /**
     * @return \Zend\Hydrator\HydratorInterface
     */
    public function getHydrator()
    {
        if (!$this->hydrator) {
            $hydrator = new EntityHydrator();
            $this->addHydratorStrategies($hydrator);
            $this->setHydrator($hydrator);
        }
        return $this->hydrator;
    }

    /**
     * @param array|\Traversable $options
     *
     * @return $this
     */
    public function setOptions($options)
    {
        $desc = isset($this->options['description']) ? $this->options['description'] : null;

        parent::setOptions($options);

        if (isset($options['enable_descriptions'])) {
            $this->setIsDescriptionsEnabled($options['enable_descriptions']);
        }

        if (!isset($options['description']) && null !== $desc) {
            $this->options['description'] = $desc;
        }
        return $this;
    }

    /**
     * Sets many form parameters at once.
     *
     * @param array $params
     *
     * @return self
     */
    public function setParams(array $params)
    {
        foreach ($params as $key => $value) {
            $this->setParam($key, $value);
        }
        return $this;
    }

    /**
     * Sets a form parameter.
     *
     * @param string $key
     * @param string $value
     *
     * @return self
     */
    public function setParam($key, $value)
    {
        if ($this->has($key)) {
            $this->get($key)->setValue($value);
        } else {
            $this->add(
                [
                    'type'       => 'hidden',
                    'name'       => $key,
                    'attributes' => [
                        'value' => $value
                    ]
                ]
            );
        }
        return $this;
    }

    /**
     * Adds hydrator strategies to the default hydrator upon instanciation.
     *
     * @param \Zend\Hydrator\HydratorInterface $hydrator
     */
    protected function addHydratorStrategies($hydrator)
    {
    }

    /**
     * @param $spec
     *
     * @return $this
     */
    public function addClass($spec)
    {
        $class = array();
        if ($this->hasAttribute('class')) {
            $class = $this->getAttribute('class');
        }
        if (!is_array($class)) {
            $class = explode(' ', $class);
        }
        if (!in_array($spec, $class)) {
            $class[] = $spec;
        }
        $this->setAttribute('class', implode(' ', $class));
        return $this;
    }

    /**
     * @return Form
     */
    public function setValidate()
    {
        return $this->addClass('validate');
    }

    /**
     * {@inheritDoc}
     * Rebinds the bound object or sets data to the filtered values.
     */
    public function isValid()
    {
        $isValid = parent::isValid();
        if ($isValid) {
            if (is_object($this->object)) {
                $this->bind($this->object);
            } else {
                $filter = $this->getInputFilter();
                $this->setData($filter->getValues());
            }
        }

        $this->getEventManager()->trigger(static::EVENT_IS_VALID, $this, [
            'isValid' => $isValid
        ]);

        return $isValid;
    }

    public function getFormName()
    {
        $name = $this->getBaseFieldset()->getAttribute('name');
        if (empty($name)) {
            throw new \RuntimeException('missing name for form');
        }
        return $name;
    }

    public function setParent($parent)
    {
        $this->parent = $parent;
        return $this;
    }

    public function getParent()
    {
        return $this->parent;
    }

    public function hasParent()
    {
        return isset($this->parent);
    }

    /**
     * reassurance, that no required inputFilter is set on a non-existing field, this mistake is otherwise hard to detect
     * there is still a lot to do on this issue
     * @param InputFilterInterface $inputFilter
     * @param FieldsetInterface $fieldset
     * @throws \RuntimeException
     */
    public function attachInputFilterDefaults(InputFilterInterface $inputFilter, FieldsetInterface $fieldset)
    {
        parent::attachInputFilterDefaults($inputFilter, $fieldset);
        /* @var $inputFilter \Zend\InputFilter\InputFilter */
        foreach ($inputFilter->getInputs() as $name => $input) {
            if (!$input instanceof InputFilterInterface) {
                /* @var $input \Zend\InputFilter\Input */
                $required = $input->isRequired();
                $inputExists = $fieldset->has($name);
                if (!$inputExists && $required) {
                    $fieldsetName = '';
                    if ($fieldset->hasAttribute('name')) {
                        $fieldsetName = 'in Fieldset "' . $fieldset->getAttribute('name') . '" ';
                    }
                    throw new \RuntimeException('input for "' . $name . '" ' . $fieldsetName . 'is required but a input-field with this name is not defined');
                }
            }
        }
    }

    /**
     * @see \Zend\Form\Form::prepare()
     */
    public function prepare()
    {
        if ($this->isPrepared) {
            return $this;
        }

        parent::prepare();
        $this->getEventManager()->trigger(static::EVENT_PREPARE, $this);

        return $this;
    }
}


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

/** EagerCursor.php */
namespace Core\Repository\DoctrineMongoODM\PaginatorAdapter;

use Doctrine\ODM\MongoDB\EagerCursor as DoctrineEagerCursor;

class EagerCursor extends \DoctrineMongoODMModule\Paginator\Adapter\DoctrinePaginator
{
    public function __construct(DoctrineEagerCursor $cursor)
    {
        $this->cursor = $cursor;
    }

    /**
     * {@inheritDoc}
     */
    public function getItems($offset, $itemCountPerPage)
    {
        $cursor = clone $this->cursor;

        //$cursor->recreate();
        $cursor->skip($offset);
        $cursor->limit($itemCountPerPage);

        return $cursor;
    }
}


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

/** */
namespace Core\Form;

use Zend\Form\Element;

/**
 * A wizard style form container.
 *
 * Holds instances of form containers which each represent a "tab" of an wizard.
 *
 * @author Mathias Gelhausen <gelhausen@cross-solution.de>
 * @since  0.22
 */
class WizardContainer extends Container implements HeadscriptProviderInterface, \IteratorAggregate
{
    /**
     * Headscripts.
     *
     * @var array
     */
    protected $scripts = [
        //'/assets/twitter-bootstrap-wizard/jquery.bootstrap.wizard.js',
    ];

    public function setHeadscripts(array $scripts)
    {
        $this->scripts = $scripts;

        return $this;
    }

    public function getHeadscripts()
    {
        return $this->scripts;
    }

    /**
     * Sets a form container.
     *
     * Either pass in an object of type \Core\Form\Container or provide a $spec array.
     * Only instances of \Core\Form\Container which have a label are allowed.
     *
     * @see \Core\Form\Container::setForm
     *
     * @param string                            $key
     * @param array|string|\Core\Form\Container $spec
     * @param bool                              $enabled
     *
     * @return self
     * @throws \InvalidArgumentException
     */
    public function setForm($key, $spec, $enabled = true)
    {
        if (is_object($spec)) {
            if (!$spec instanceof Container) {
                throw new \InvalidArgumentException('Tab container must be of the type \Core\Form\Container');
            }

            if (!$spec->getLabel()) {
                throw new \InvalidArgumentException('Container instances must have a label.');
            }
        }

        if (is_array($spec)) {
            if (!isset($spec['type'])) {
                $spec['type'] = 'Core/Container';
            }

            /*
             * For convenience, forms may be specified outside the options array.
             * But in order to be passed through to the form element manager,
             * we must move it to the options.
             */
            if (!isset($spec['options']['forms']) && isset($spec['forms'])) {
                $spec['options']['forms'] = $spec['forms'];
                unset($spec['forms']);
            }
        }

        return parent::setForm($key, $spec, $enabled);
    }

    /**
     * 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.
     *
     * @see Container::getForm
     *
     * @param string $key
     * @param bool   $asInstance if false, the specification array is returned.
     *
     * @return Container|null|\Zend\Form\FormInterface|array
     * @throws \UnexpectedValueException
     */
    public function getForm($key, $asInstance = true)
    {
        $form = parent::getForm($key, $asInstance);

        /*
         * We must check here, if a lazy loaded top level form is an
         * instance of Container.
         */
        if ($asInstance && false === strpos($key, '.') && (!$form instanceof Container || !$form->getLabel())) {
            throw new \UnexpectedValueException(sprintf(
                                                    'The registered form with key "%s" is not an instance of \Core\Form\Container or does not have a label.',
                                                    $key
                                                ));
        }

        return $form;
    }
}


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

namespace Zicht\Bundle\PageBundle\Model;

/**
 * Helper class to configure the contentitem region / type matrix.
 *
 * Usage:
 *
 * function getContentItemMatrix() {
 *     return ContentItemMatrix::create()
 *         ->region('left')
 *             ->type(Text::class)
 *             ->type(Embed::class)
 *         ->region('right')
 *             ->type(Text::class)
 *     ;
 * }
 * return
 */
final class ContentItemMatrix
{
    /**
     * Points to the current region being configured.
     *
     * @var string
     */
    private $currentRegion;

    /**
     * Contains the matrix
     *
     * @var array
     */
    private $matrix;

    /**
     * Stubbed constructor.
     */
    public function __construct()
    {
        $this->currentRegion = 'left';
        $this->matrix = [];
    }

    /**
     * Provides fluent interface for building the matrix.
     *
     * @return ContentItemMatrix
     */
    public static function create()
    {
        return new self();
    }

    /**
     * Select a region to configure.
     *
     * @param string $region
     * @param bool $reset
     *
     * @return ContentItemMatrix
     */
    public function region($region, $reset = false)
    {
        $this->currentRegion = $region;
        if ($reset) {
            $this->matrix[$this->currentRegion] = [];
        }

        return $this;
    }

    /**
     * Remove a region
     *
     * @param string $region
     *
     * @return $this
     */
    public function removeRegion($region)
    {
        if (array_key_exists($region, $this->matrix)) {
            unset($this->matrix[$region]);
        }

        return $this;
    }

    /**
     * Remove a type from a region
     *
     * @param string $type
     * @param string $region
     *
     * @return $this
     */
    public function removeTypeFromRegion($type, $region)
    {
        if (array_key_exists($region, $this->matrix)) {
            array_walk(
                $this->matrix[ $region ],
                function ($value, $idx, $matrix) use ($type, $region) {
                    $class = explode('\\', $value);
                    $className = array_pop($class);
                    if ($className === $type) {
                        unset($matrix[ $region ][ $idx ]);
                    }
                },
                $this->matrix
            );
        }

        return $this;
    }

    /**
     * Adds the type to the currently selected region.
     *
     * @param string $className
     *
     * @return ContentItemMatrix
     */
    public function type($className)
    {
        if (!class_exists($className)) {
            throw new \InvalidArgumentException(
                sprintf(
                    'Class %s is non-existent or could not be loaded',
                    $className
                )
            );
        }
        $this->matrix[$this->currentRegion][] = $className;

        return $this;
    }

    /**
     * Returns the available types for a specified region.
     * If not specified, returns all types configured.
     *
     * @param string $region
     *
     * @return array
     */
    public function getTypes($region = null)
    {
        if (null === $region) {
            $ret = [];
            foreach ($this->matrix as $types) {
                $ret = array_merge($ret, $types);
            }

            return array_values(array_unique($ret));
        }

        return $this->matrix[$region];
    }

    /**
     * Returns the available regions for a specified type.
     * If not specified, all regions are returned.
     *
     * @param null $type
     *
     * @return array
     */
    public function getRegions($type = null)
    {
        if (null === $type) {
            return array_keys($this->matrix);
        }

        $regions = [];
        foreach ($this->matrix as $region => $types) {
            if (in_array($type, $types)) {
                $regions[] = $region;
            }
        }

        return $regions;
    }

    /**
     * @return array
     */
    public function getMatrix()
    {
        return $this->matrix;
    }
}