<?php
/**
 * @link http://www.linchpinstudios.com/
 * @copyright Copyright (c) 2014 Linchpin Studios LLC
 * @license http://opensource.org/licenses/MIT
 */

namespace linchpinstudios\datetimepicker;

use Yii;
use yii\helpers\Html;
use yii\helpers\Json;
use yii\widgets\InputWidget;

/**
 * Use this plugin to unobtrusively add a datetimepicker, datepicker or
 * timepicker dropdown to your forms. It's easy to customize options.
 *
 * For example,
 *
 * ```php
 * // a button group using Dropdown widget
 * $form->field($model, 'body')->widget(DateTime::className(), [
 *      'options' => ['rows' => 10],
 *      'clientOptions' => [
 *          'datepicker' => false,
 *          'format' => 'H:i',
 *      ]
 *  ]);
 * ```
 * @see http://xdsoft.net/jqplugins/datetimepicker/
 * @author Josh Hagel <joshhagel@linchpinstudios.com>
 * @since 0.1
 */

 class DateTime extends InputWidget
 {
    /**
     * @var array the options for the DateTime JS plugin.
     * Please refer to the DateTime JS plugin Web page for possible options.
     * @see http://xdsoft.net/jqplugins/datetimepicker/
     */
    public $clientOptions = [];

    /**
     * run function.
     *
     * @access public
     * @return void
     */
    public function run()
    {
        if ($this->hasModel()) {
            echo Html::activeTextInput($this->model, $this->attribute, $this->options);
        } else {
            echo Html::textInput($this->name, $this->value, $this->options);
        }
        $this->registerClientScript();
    }

    /**
     * Registers CSS and Scripts
     */
    protected function registerClientScript()
    {
        $view = $this->getView();

        DateTimePickerAssets::register($view);

        $id = $this->options['id'];

        $options = Json::encode($this->clientOptions);

        $view->registerJs("jQuery('#$id').datetimepicker($options);");
    }

 }


<?php

namespace Peyote;

/**
 * Building a SELECT query.
 *
 * The join(), select(), and limit() functions should just be passthrus, but I
 * was getting an error when naming a function the same as the class (php4 FTW!)
 * so I had to just move the methods here and call back. Lame I know, but the
 * only other choice was to go back down to 5.2 and name everything with
 * underscores, and I didn't want to do that, so here we are...
 *
 * @package    Peyote
 * @author     Dave Widmer <dave@davewidmer.net>
 */
class Select extends \Peyote\Query
{
	/**
	 * @var \Peyote\Join  The join object
	 */
	protected $join = null;

	/**
	 * @var \Peyote\Where  The where object
	 */
	protected $where = null;

	/**
	 * @var \Peyote\Group  The group object
	 */
	protected $group_by = null;

	/**
	 * @var \Peyote\Order  The order object
	 */
	protected $order_by = null;

	/**
	 * @var \Peyote\Limit  The limit object
	 */
	protected $limit = null;

	/**
	 * @var array  A list of mixins that the query can passthru
	 */
	protected $mixins = array('join', 'where', 'group_by', 'order_by', 'limit', 'having');

	/**
	 * @var int  The number to offset by.
	 */
	private $offset_num = null;

	/**
	 * @var boolean  Run a distinct query?
	 */
	private $is_distinct = false;

	/**
	 * @var array  A list of columns to search for
	 */
	private $columns = array();

	/**
	 * Optionally sets the table name and initializes the internal class
	 * properties.
	 *
	 * @param string $table  The name of the table
	 */
	public function __construct($table = null)
	{
		$this->join = new \Peyote\Join;
		$this->where = new \Peyote\Where;
		$this->group_by = new \Peyote\Group;
		$this->order_by = new \Peyote\Order;
		$this->limit = new \Peyote\Limit;
		$this->having = new \Peyote\Having;

		parent::__construct($table);
	}

	/**
	 * Run a SELECT DISTINCT query.
	 *
	 * @return \Peyote\Select
	 */
	public function distinct()
	{
		$this->is_distinct = true;
		return $this;
	}

	/**
	 * Specify the columns to select.
	 *
	 * @param  string ...  Any number of string column names
	 * @return \Peyote\Select
	 */
	public function columns()
	{
		return $this->columnsArray(func_get_args());
	}

	/**
	 * Specify the columns to select as an array.
	 *
	 * @param  array $columns  The columns to select
	 * @return \Peyote\Select
	 */
	public function columnsArray(array $columns)
	{
		$this->columns = $columns;
		return $this;
	}

	/**
	 * Add a join.
	 *
	 * @param  string $table  The table name
	 * @param  string $type   The type of join
	 * @return \Peyote\Select
	 */
	public function join($table, $type = null)
	{
		$this->join->addJoin($table, $type);
		return $this;
	}

	/**
	 * Adds a WHERE clause.
	 *
	 * @param  string  $column  The column name
	 * @param  string  $op      The comparison operator
	 * @param  mixed   $value   The value to bind
	 * @param  boolean $isParam Is this a parameter (replace value with ? if true)
	 * @return \Peyote\Select
	 */
	public function where($column, $op, $value, $isParam = true)
	{
		$this->where->andWhere($column, $op, $value, $isParam);
		return $this;
	}

	/**
	 * Adds a HAVING clause.
	 *
	 * @param  string  $column  The column name
	 * @param  string  $op      The comparison operator
	 * @param  mixed   $value   The value to bind
	 * @param  boolean $isParam Is this a parameter (replace value with ? if true)
	 * @return \Peyote\Select
	 */
	public function having($column, $op, $value, $isParam = true)
	{
		$this->having->andHaving($column, $op, $value, $isParam);
		return $this;
	}

	/**
	 * Sets the limit.
	 *
	 * @param  int $num  The number to limit the queries to
	 * @return \Peyote\Select
	 */
	public function limit($num, $offset = 0)
	{
		$this->limit->setLimit($num, $offset);
		return $this;
	}

	/**
	 * The offset number.
	 *
	 * @param  int $num The number of rows to offset by
	 * @return \Peyote\Select
	 */
	public function offset($num)
	{
		$this->offset_num = (int) $num;
		return $this;
	}

	/**
	 * Gets all of the bound parameters for this query.
	 *
	 * @return array
	 */
	public function getParams()
	{
		return array_merge($this->where->getParams(), $this->having->getParams());
	}

	/**
	 * Compiles the query into raw SQL
	 *
	 * @return  string
	 */
	public function compile()
	{
		$sql = array("SELECT");

		if ($this->is_distinct)
		{
			$sql[] = "DISTINCT";
		}

		if (empty($this->columns))
		{
			$sql[] = "*";
		}
		else
		{
			$sql[] = join(', ', $this->columns);
		}

		$sql[] = "FROM";
		$sql[] = $this->table;

		$sql = \array_merge($sql, $this->compileMixins());

		if ($this->offset_num !== null)
		{
			$sql[] = "OFFSET {$this->offset_num}";
		}

		return join(' ', $sql);
	}

}


<?php

namespace Nkstamina\Framework\Provider;

use Nkstamina\Framework\ServiceProviderInterface;
use Pimple\Container;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\Finder\Finder;
use Symfony\Component\Routing\Loader\YamlFileLoader;
use Symfony\Component\Yaml\Parser;

/**
 * Class ConfigServiceProvider
 * @package Nkstamina\Framework\Provider
 */
class ConfigServiceProvider implements ServiceProviderInterface
{
    /**
     * {@inheritdoc}
     */
    public function register(Container $app)
    {
        $configDirectories = [$app['app.config.dir']];
        $locator = new FileLocator($configDirectories);

        // Loads routes files
        $app['config.loader'] = function ($app) use ($locator) {
            // load only *.yml files?
            $loader =  new YamlFileLoader($locator);
            return $loader;
        };

        // Finds files or directories
        $app['config.finder'] = function () {
            return new Finder();
        };

        // Parses yaml files
        $app['config.parser'] = function () {
            return new Parser();
        };
    }

    /**
     * {@inheritdoc}
     */
    public function boot(Container $app)
    {
    }

    /**
     * Returns the name of the service
     *
     * @return mixed
     */
    public function getName()
    {
        return 'config_service_provider';
    }
}


<?php
namespace LunixREST\Server\Throttle;

use LunixREST\Server\APIRequest\APIRequest;
use Psr\Cache\CacheItemPoolInterface;

/**
 * A Throttle implementation that relies on an underlying CacheItemPool, and allows a certain number requests in a certain number of seconds.
 * Class CachePoolThrottle
 * @package LunixREST\Server\Throttle
 */
abstract class CachePoolThrottle implements Throttle
{
    /**
     * @var CacheItemPoolInterface
     */
    private $cacheItemPool;
    /**
     * @var int
     */
    private $limit;
    /**
     * @var int
     */
    private $perXSeconds;

    /**
     * CachePoolThrottle constructor.
     * @param CacheItemPoolInterface $cacheItemPool
     * @param int $limit
     * @param int $perXSeconds
     */
    public function __construct(CacheItemPoolInterface $cacheItemPool, int $limit = 60, int $perXSeconds = 60)
    {
        $this->cacheItemPool = $cacheItemPool;
        $this->limit = $limit;
        $this->perXSeconds = $perXSeconds;
    }

    /**
     * Returns true if the given request should be throttled in our implementation
     * @param \LunixREST\Server\APIRequest\APIRequest $request
     * @return bool
     */
    public function shouldThrottle(APIRequest $request): bool
    {
        $item = $this->cacheItemPool->getItem($this->deriveCacheKey($request));

        return $item->get() >= $this->limit;
    }

    /**
     * Log that a request took place
     * @param \LunixREST\Server\APIRequest\APIRequest $request
     */
    public function logRequest(APIRequest $request): void
    {
        $item = $this->cacheItemPool->getItem($this->deriveCacheKey($request));

        if($requestCount = $item->get()) {
            $item->set($requestCount + 1);
        } else {
            $item->set(1)->expiresAfter($this->perXSeconds);
        }

        $this->cacheItemPool->save($item);
    }

    /**
     * @param APIRequest $request
     * @return string
     */
    protected abstract function deriveCacheKey(APIRequest $request): string;

    /**
     * @return CacheItemPoolInterface
     */
    public function getCacheItemPool(): CacheItemPoolInterface
    {
        return $this->cacheItemPool;
    }
}


<?php
/*
 * Copyright (c) 2015 @trashtoy
 * https://github.com/trashtoy/
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
 * Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
/**
 * PHP class file.
 * @auhtor trashtoy
 * @since  2.0.1
 */
namespace Peach\DT\SimpleFormat;

use Peach\Util\ArrayMap;
use Peach\Util\Strings;

/**
 * 文字列の先頭が指定された文字列に合致するか調べる Pattern です.
 *
 * @ignore
 */
class Raw implements Pattern
{
    /**
     * 候補の一覧です.
     * @var array
     */
    private $candidates;

    /**
     * 文字列の候補を指定して新しい Raw オブジェクトを生成します.
     * @param array $candidates 候補の一覧
     */
    public function __construct(array $candidates)
    {
        $this->candidates = $candidates;
    }

    /**
     * このメソッドは何も行いません.
     *
     * @param ArrayMap $fields  適用対象のフィールド
     * @param string   $matched マッチした文字列
     */
    public function apply(ArrayMap $fields, $matched)
    {
        // noop
    }

    /**
     * 文字列の先頭が, このオブジェクトにセットされている候補一覧の中のいずれかに合致するかどうかを調べます.
     * 合致した候補文字列を返します.
     *
     * @param  string $input 検査対象の文字列
     * @return string        合致した候補文字列
     */
    public function match($input)
    {
        foreach ($this->candidates as $candidate) {
            if (Strings::startsWith($input, $candidate)) {
                return $candidate;
            }
        }
        return null;
    }
}


<?php

namespace Nkstamina\Framework\Provider;

use Nkstamina\Framework\Common\Utils;
use Nkstamina\Framework\ServiceProviderInterface;
use Nkstamina\Framework\Provider\Exception\InvalidConfigurationException;
use Pimple\Container;
use Symfony\Component\Finder\Finder;
use Symfony\Component\Yaml\Exception\ParseException;
use Symfony\Component\Yaml\Yaml;

/**
 * Class ExtensionServiceProvider
 * @package Nkstamina\Framework\Provider
 */
class ExtensionServiceProvider implements ServiceProviderInterface
{
    protected static $expectedDirectories = ['Config, Controller, Model, Resources, Views'];
    protected $extensions = [];

    /**
     * {@inheritdoc}
     */
    public function register(Container $app)
    {
        $app['extensions'] = function () use ($app) {
            // Get extensions directories
            return $this->getExtensions($app);
        };
    }

    /**
     * {@inheritdoc}
     */
    public function boot(Container $app)
    {
    }

    /**
     * {@inheritdoc}
     */
    public function getName()
    {
        return 'extension_service_provider';
    }

    /**
     * Return an array of extensions
     *
     * @param Container $app
     *
     * @return array
     */
    public function getExtensions(Container $app)
    {
        $directories = $this->findExtensionsDirectories($app);

        foreach ($directories as $directory) {
            $extensionName                                  = $directory->getRelativePathname();
            $this->extensions[$extensionName]['name']       = $extensionName;
            $this->extensions[$extensionName]['pathName']   = $directory->getPathName();
        }

        return $this->extensions;
    }

    /**
     * Returns all valid extensions folders
     *
     * @param Container $app
     *
     * @return Finder
     */
    private function findExtensionsDirectories(Container $app)
    {
        $directories = $app['config.finder']
            ->ignoreUnreadableDirs()
            ->directories()
            ->name('*Extension')
            ->in($app['app.extensions.dir'])
            ->depth('< 3')
            ->sortByName()
        ;

        return $directories;
    }
}


<?php
namespace Cyberhouse\Phpstyle\Fixer;

/*
 * This file is (c) 2017 by Cyberhouse GmbH
 *
 * It is free software; you can redistribute it and/or
 * modify it under the terms of the MIT License (MIT)
 *
 * For the full copyright and license information see
 * <https://opensource.org/licenses/MIT>
 */

use PhpCsFixer\Tokenizer\Token;
use PhpCsFixer\Tokenizer\Tokens;

/**
 * A php-cs-fixer fixer implementation that uses a slightly
 * different layout than the default header comment fixer
 *
 * @author Georg Großberger <georg.grossberger@cyberhouse.at>
 * @copyright (c) 2016 by Cyberhouse GmbH <www.cyberhouse.at>
 */
class LowerHeaderCommentFixer extends BaseFixer
{
    private static $headerComment = '';

    public static function setHeader($header)
    {
        $header = trim((string) $header);

        if (!empty($header)) {
            self::$headerComment = "/*\n";

            foreach (explode("\n", $header) as $line) {
                self::$headerComment .= rtrim(' * ' . trim($line)) . "\n";
            }

            self::$headerComment .= ' */';
        }
    }

    /**
     * {@inheritdoc}
     */
    public function isCandidate(Tokens $tokens)
    {
        return self::$headerComment !== '' && $tokens->isMonolithicPhp();
    }

    /**
     * {@inheritdoc}
     */
    public function fix(\SplFileInfo $file, Tokens $tokens)
    {
        $index = 1;
        $hasNs = false;

        for ($i = 1; $i < $tokens->count(); $i++) {
            if ($tokens[$i]->isGivenKind(T_NAMESPACE)) {
                $hasNs = true;

                while ($tokens[$i]->getContent() !== ';') {
                    $i++;
                }
                $i++;
                $index = $i + 1;
            } elseif (!$tokens[$i]->isWhitespace() && !$tokens[$i]->isGivenKind(T_COMMENT)) {
                break;
            }
            $tokens[$i]->clear();
        }

        $tokens->insertAt($index, [
            new Token([T_WHITESPACE, "\n" . ($hasNs ? "\n" : '')]),
            new Token([T_COMMENT, self::$headerComment]),
            new Token([T_WHITESPACE, "\n\n"]),
        ]);

        $tokens->clearEmptyTokens();
    }
}


<?php declare(strict_types=1);

namespace Roquie\Database\Migration;

use League\Flysystem\FilesystemInterface;
use Roquie\Database\Notify\NotifyInterface;
use Roquie\Database\Migration\Creator\MigrationCreatorInterface as M;
use Roquie\Database\Migration\Repository\MigrationRepositoryInterface;
use Roquie\Database\Migration\Repository\SqlMigrationRepository;

class Migrator
{
    /**
     * @var \Roquie\Database\Migration\Repository\MigrationRepositoryInterface
     */
    private $repository;

    /**
     * @var \League\Flysystem\FilesystemInterface
     */
    private $filesystem;

    /**
     * @var \Roquie\Database\Notify\NotifyInterface
     */
    private $notify;

    /**
     * Migrator constructor.
     *
     * @param \Roquie\Database\Migration\Repository\MigrationRepositoryInterface $repository
     * @param \League\Flysystem\FilesystemInterface $filesystem
     * @param \Roquie\Database\Notify\NotifyInterface $notify
     */
    public function __construct(
        MigrationRepositoryInterface $repository,
        FilesystemInterface $filesystem,
        NotifyInterface $notify
    )
    {
        $this->repository = $repository;
        $this->filesystem = $filesystem;
        $this->notify = $notify;
    }

    /**
     * Run the pending migrations.
     *
     * @param  array  $options
     * @return void
     */
    public function migrate(array $options = []): void
    {
        // Once we grab all of the migration files for the path, we will compare them
        // against the migrations that have already been run for this package then
        // run each of the outstanding migrations against a database connection.
        $files = $this->getMigrationFiles(M::TYPE_UP);

        $migrations = $this->pendingMigrations(
            $files, $this->repository->getRan()
        );

        // Once we have all these migrations that are outstanding we are ready to run
        // we will go ahead and run them "up". This will execute each migration as
        // an operation against a database. Then we'll return this list of them.
        $this->runPending($migrations, $options);
    }

    /**
     * Get all of the migration files in a given path.
     *
     * @param string $type
     * @return array
     */
    public function getMigrationFiles(string $type): array
    {
        $array = [];
        foreach ($this->filesystem->listContents() as $file) {
            if ($type === pathinfo($file['filename'], PATHINFO_EXTENSION)) {
                $array[] = $file;
            }
        }

        return $array;
    }

    /**
     * Run an array of migrations.
     *
     * @param  array  $migrations
     * @param  array  $options
     * @return void
     */
    public function runPending(array $migrations, array $options = [])
    {
        // First we will just make sure that there are any migrations to run. If there
        // aren't, we will just make a note of it to the developer so they're aware
        // that all of the migrations have been run against this database system.
        if (count($migrations) === 0) {
            $this->notify->note('<info>Nothing to migrate.</info>');

            return;
        }

        // Next, we will get the next batch number for the migrations so we can insert
        // correct batch number in the database migrations repository when we store
        // each migration's execution. We will also extract a few of the options.
        $batch = $this->repository->getNextBatchNumber();

        $step = $options['step'] ?? false;

        // A blank line before top output.
        $this->notify->note('');

        // Once we have the array of migrations, we will spin through them and run the
        // migrations "up" so the changes are made to the databases. We'll then log
        // that the migration was run so we don't repeat it next time we execute.
        foreach ($migrations as $file) {
            $this->runUp($file, $batch);

            if ($step) {
                $batch++;
            }
        }
    }

    /**
     * Rollback the last migration operation.
     *
     * @param  array $options
     * @return void
     */
    public function rollback(array $options = []): void
    {
        // We want to pull in the last batch of migrations that ran on the previous
        // migration operation. We'll then reverse those migrations and run each
        // of them "down" to reverse the last migration "operation" which ran.
        $migrations = $this->getMigrationsForRollback($options);

        if (count($migrations) === 0) {
            $this->notify->note('<info>Nothing to rollback.</info>');

            return;
        }

        $this->rollbackMigrations($migrations);
    }

    /**
     * Rolls all of the currently applied migrations back.
     *
     * @return void
     */
    public function reset(): void
    {
        // Next, we will reverse the migration list so we can run them back in the
        // correct order for resetting this database. This will allow us to get
        // the database back into its "empty" state ready for the migrations.
        $migrations = array_reverse($this->repository->getRan());

        if (count($migrations) === 0) {
            $this->notify->note('<info>Nothing to rollback.</info>');

            return;
        }

        $this->rollbackMigrations($migrations);
    }

    /**
     * Drops all of tables and views in the database.
     *
     * @return void
     */
    public function drop(): void
    {
        $dropped = $this->repository->drop();

        if (count($dropped) === 0) {
            return;
        }

        $this->notify->note('');

        foreach ($dropped as [$type, $value]) {
            $type = ucfirst($type);
            $this->notify->note("<comment>{$type}</comment> \"{$value}\" <comment>dropped</comment>");
        }
    }

    /**
     * Migration name for database.
     *
     * @param array $file
     * @return string
     */
    public function getMigrationName(array $file): string
    {
        return pathinfo($file['filename'], PATHINFO_FILENAME);
    }

    /**
     * Get the migrations for a rollback operation.
     *
     * @param  array  $options
     * @return array
     */
    protected function getMigrationsForRollback(array $options)
    {
        if (($steps = $options['step'] ?? 0) > 0) {
            return $this->repository->getMigrations($steps);
        }

        return $this->repository->getLast();
    }

    /**
     * Rollback the given migrations.
     *
     * @param  array  $migrations
     * @return void
     */
    protected function rollbackMigrations(array $migrations): void
    {
        // A blank line before top output.
        $this->notify->note('');

        foreach ($this->getMigrationFiles(M::TYPE_DOWN) as $file) {
            if (in_array($name = $this->getMigrationName($file), $migrations, true)) {
                $this->runDown($file);
                continue;
            }

            $this->notify->note("<fg=red>Migrate not found (in database table):</> {$name}");
        }
    }

    /**
     * Run "down" a migration instance.
     *
     * @param  array $file
     * @return void
     */
    protected function runDown(array $file): void
    {
        $this->notify->note("<comment>Rolling back:</comment> {$file['basename']}");

        $this->runMigration($file);

        // Once we have successfully run the migration "down" we will remove it from
        // the migration repository so it will be considered to have not been run
        // by the application then will be able to fire by any later operation.
        $this->repository->delete($this->getMigrationName($file));

        $this->notify->note("<info>Rolled back:</info>  {$file['basename']}");
    }

    /**
     * Run "up" a migration instance.
     *
     * @param array  $file
     * @param int   $batch
     *
     * @return void
     */
    protected function runUp(array $file, int $batch): void
    {
        $this->notify->note("<comment>Migrating:</comment> {$file['basename']}");

        $this->runMigration($file);

        // Once we have run a migrations class, we will log that it was run in this
        // repository so that we don't try to run it next time we do a migration
        // in the application. A migration repository keeps the migrate order.
        $this->repository->log($this->getMigrationName($file), $batch);

        $this->notify->note("<info>Migrated:</info>  {$file['basename']}");
    }

    /**
     * Run a migration inside a transaction if the database supports it.
     *
     * @param array $file
     * @return void
     */
    protected function runMigration(array $file)
    {
        $this->repository->transaction(function (SqlMigrationRepository $repo) use ($file) {
            $contents = (string) $this->filesystem->read($file['path']);
            $repo->execute($contents);
        });
    }

    /**
     * Get the migration files that have not yet run.
     *
     * @param  array  $files
     * @param  array  $ran
     *
     * @return array
     */
    protected function pendingMigrations(array $files, array $ran): array
    {
        $array = [];
        foreach ($files as $file) {
            if (! in_array($this->getMigrationName($file), $ran, true)) {
                $array[] = $file;
            }
        }

        return $array;
    }
}


<?php
/**
 *  Dolumar engine, php/html MMORTS engine
 *  Copyright (C) 2009 Thijs Van der Schaeghe
 *  CatLab Interactive bvba, Gent, Belgium
 *  http://www.catlab.eu/
 *  http://www.dolumar.com/
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License along
 *  with this program; if not, write to the Free Software Foundation, Inc.,
 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

abstract class Neuron_GameServer_Map_MapObject
{
	/**
	*	Return a displayobject reprecenting this object
	*/
	public abstract function getDisplayObject ();

	public abstract function getName ();

	private $location;
	private $status;
	private $events = array ();
	private $movements = array ();

	public function getId ()
	{
		return $this->getLocation ()->toString ();
	}

	public function getUOID ()
	{
		return $this->getId ();
	}

	public function setLocation (Neuron_GameServer_Map_Location $location)
	{
		$this->location = $location;
	}

	public function getLocation ($time = NOW)
	{
		// Go trough the paths to update
		foreach ($this->movements as $v)
		{
			if ($v->isActive ($time))
			{
				return $v->getCurrentLocation ($time);
			}
		}

		return $this->location;
	}

	/**
	* Goes true all paths and checks the final location
	*/
	public function getEndLocation ()
	{
		$lastLocation = $this->getLocation ();
		$lastDate = NOW;

		foreach ($this->movements as $v)
		{
			if ($v->getEndTime () > $lastDate)
			{
				$lastDate = $v->getEndTime ();
				$lastLocation = $v->getEndLocation ();
			}
		}

		return $lastLocation;
	}

	public function getEndUp ()
	{
		$lastUp = $this->getLocation ();
		$lastDate = NOW;

		foreach ($this->movements as $v)
		{
			if ($v->getEndTime () > $lastDate)
			{
				$lastDate = $v->getEndTime ();
				$lastUp = $v->getEndUp ();
			}
		}

		return $lastUp;
	}

	public function setMapObjectStatus (Neuron_GameServer_Map_MapObjectStatus $status)
	{
		$this->status = $status;
	}

	public function getMapObjectStatus ()
	{
		if ($this->status == null)
		{
			$this->setMapObjectStatus (new Neuron_GameServer_Map_MapObjectStatus ());
		}

		return $this->status;
	}

	/**
	*	Events
	*/
	private function checkValidEvent ($method)
	{
		switch ($method)
		{
			case 'click':

			break;

			default:
				throw new Neuron_Exceptions_InvalidParameter ("method not suitable for observation: " . $method);
			break;
		}
	}

	public function observe ($method, $action)
	{
		$this->checkValidEvent ($method);

		if (!isset ($this->events[$method]))
		{
			$this->events[$method] = array ();
		}

		$this->events[$method][] = $action;
	}

	public function getEvents ($method)
	{
		$this->checkValidEvent ($method);

		if (isset ($this->events[$method]))
		{
			return $this->events[$method];
		}

		return array ();
	}

	public function move (Neuron_GameServer_Map_Movement $movement)
	{
		// To be defined by clients
	}

	public function addMovement (Neuron_GameServer_Map_Movement $movement)
	{
		$this->movements[] = $movement;
	}

	/**
	* The up vector can be manipulated by the movements.
	*/
	public function getUp ($time = NOW)
	{
		// Go trough the paths to update
		foreach ($this->movements as $v)
		{
			if ($v->isActive ($time))
			{
				$up = $v->getCurrentUp ($time);
				if (isset ($up))
				{
					return $v->getCurrentUp ($time);
				}
			}
		}

		return new Neuron_GameServer_Map_Vector3 (0, 1, 0);
	}

	/**
	* Rotation can also be manipulated by the movement.
	* By default, an object always "looks" in the direction of the movement
	*/
	public function getDirection ()
	{
		return new Neuron_GameServer_Map_Vector3 (0, 0, 0);
	}

	/**
	* Return the default rotation (use this to turn your object around)
	*/
	public function getDefaultRotation ()
	{
		return new Neuron_GameServer_Map_Vector3 (0, 0, 0);
	}

	public function getExportData ()
	{
		$location = $this->getLocation ();

		$path = array ();
		foreach ($this->movements as $v)
		{
			$path[] = $v->getData ();
		}

		$displayobject = $this->getDisplayObject ();

		$out = array
		(
			'attributes' => array
			(
				'x' => $location->x (),
				'y' => $location->y (),
				'z' => $location->z (),
				'id' => $this->getUOID (),
				'name' => $this->getName ()
			),
			'up' => array ('attributes' => $this->getUp ()->getData ()),
			'model' => $displayobject->getDisplayData (),
			'defaultRotation' => array ('attributes' => $this->getDefaultRotation ()->getData ()),
			'direction' => array ('attributes' => $this->getDirection ()->getData ()),
			'paths' => $path
		);

		return $out;
	}
}


<?php declare(strict_types=1);

namespace Roquie\Database\Notify;

use Psr\Log\LoggerInterface;
use Roquie\Database\Exception\InvalidArgumentException;
use Roquie\Database\PrettyLogger;
use Symfony\Component\Console\Output\Output;

class NotifyFactory
{
    /**
     * Create a notify object.
     *
     * @param $notify
     * @return NotifyConsole|NotifyLogger|NotifyStdout|NotifyBlackhole
     * @throws \Roquie\Database\Exception\InvalidArgumentException
     */
    public static function create($notify)
    {
        switch (true) {
            case $notify === NotifyInterface::STDOUT:
                return new NotifyStdout();
            case $notify === NotifyInterface::LOGGER:
                return new NotifyLogger(PrettyLogger::create());
            case $notify === NotifyInterface::BLACKHOLE:
                return new NotifyBlackhole();
            case $notify instanceof Output:
                return new NotifyConsole($notify);
            case $notify instanceof LoggerInterface:
                return new NotifyLogger($notify);
            default:
                throw InvalidArgumentException::forNotSupportedNotifier();
        }
    }
}


<?php

namespace L5Starter\Setting\Http\Controllers\Admin;

use App\Http\Controllers\Controller;
use L5Starter\Setting\Repositories\SettingRepository;
use L5Starter\Core\Support\DateFormatter;
use Illuminate\Http\Request;
use Flash;
use Prettus\Repository\Criteria\RequestCriteria;
use Response;

class SettingController extends Controller
{
    /** @var SettingRepository */
    private $settingRepository;

    public function __construct(SettingRepository $settingRepo)
    {
        $this->settingRepository = $settingRepo;
    }

    /**
     * Display a listing of the Setting.
     *
     * @param Request $request
     * @return Response
     */
    public function index(Request $request)
    {
        $this->settingRepository->pushCriteria(new RequestCriteria($request));
        $settings = $this->settingRepository->all();
        $dateFormats = DateFormatter::dropdownArray();

        return view('l5starter::admin.settings.index')->with([
            'dateFormats' => $dateFormats,
            'settings' => $settings,
        ]);
    }

    /**
     * Update the specified Setting in storage.
     *
     * @param Request $request
     * @return Response
     */
    public function update(Request $request)
    {
        foreach ($request->all() as $key => $value) {
            if (substr($key, 0, 8) == 'setting_') {
                $skipSave = false;
                $key = substr($key, 8);
                if (! $skipSave) {
                    $this->settingRepository->save($key, $value);
                }
            }
        }

        Flash::success(trans('l5starter::messages.update.success'));

        return redirect(route('admin.settings.index'));
    }
}


<?php
namespace DreamFactory\Core\Email\Components;

class Mailer extends \Illuminate\Mail\Mailer
{
    use EmailUtilities;

    /**
     * Render the given view.
     *
     * @param  string $view
     * @param  array  $data
     *
     * @return mixed
     */
    protected function renderView($view, $data)
    {
        try {
            return parent::renderView($view, $data);
        } catch (\InvalidArgumentException $e) {
            return static::applyDataToView($view, $data);
        }
    }
}


<?php
namespace Cora;

class DatabaseBuilder extends Framework
{
    protected $modelPath;
    public $displayOutput;
    public $newline = "\n";

    public function __construct($displayOutput = true)
    {
        parent::__construct();

        $this->modelPath = realpath($this->config['pathToModels']);
        $this->displayOutput = $displayOutput;
    }

    public function reset($connection = false)
    {
        $this->dbEmpty($connection);
        $this->dbBuild();
    }

    public function dbEmpty($connection = false)
    {
        if ($this->config['mode'] == 'development') {
            $db = false;
            if ($connection == false) {
                $db = \Cora\Database::getDefaultDb();
            }
            else {
                $db = \Cora\Database::getDb($connection);
            }
            $db->emptyDatabase();
        }
        else {
            echo 'Database manipulation is turned off for projects not in "development" mode. If you want to use the Database Builder on this project, edit the config "mode" setting and change it to "development"';
        }
    }

    public function dbBuild($data = '')
    {
        if ($this->config['mode'] == 'development') {
            // Call recursive processing of models to build DB.
            $this->examine('');

            // If no datafile name was passed in, set default.
            if ($data == '') {
                $data = 'data.php';
            }

            // Determine path
            $path = $this->config['basedir'].'includes/'.$data;

            // If a data PHP file to include exists, include it.
            if (file_exists($path)) {
                include($path);
            }
        }
        else {
            echo 'Database manipulation is turned off for projects not in "development" mode. If you want to use the Database Builder on this project, edit the config "mode" setting and change it to "development"';
        }
    }

    protected function examine($partialPath)
    {
        $path = $this->modelPath.'/'.$partialPath;

        // Grab list of files and subfolders in Models directory.
        $files = array_diff(scandir($path), array('..', '.'));

        foreach ($files as $file) {
            $fullPath = $path.'/'.$file;
            $relPath = $partialPath.$file;
            if (is_dir($fullPath)) {
                $this->examine($relPath.'/');
            }
            else {
                $fileinfo = pathinfo($fullPath);
                if ($fileinfo['extension'] == 'php') {

                    $model = $this->getModel($relPath);
                    $refModel = new \ReflectionClass($model);
                    $this->output("//////////////////////");
                    $this->output('MODEL: '.$model);
                    $this->output("//////////////////////");

                    // Only build a table for this model if extends Cora's Model class.
                    if (is_subclass_of($model, '\\Cora\\Model') && $refModel->isAbstract() == false) {
                        $object = new $model();

                        $db         = $object->getDbAdaptor();
                        $tableName  = $object->getTableName();

                        // It's possible for models to have nothing but references (no actual table data of their own)
                        // In that case, we don't want to issue a CREATE table statement.
                        $nonEmptyModel = false;

                        // For tracking fields that have already been set for creation on this model
                        $modelFields = new \Cora\Collection();

                        foreach ($object->model_attributes as $key => $props) {
                            //echo $key."\n";
                            $rmodel = isset($props['model']);
                            $rmodels = isset($props['models']);
                            $fieldName = $object->getFieldName($key);

                            // Check if current attribute is a model reference.
                            if ($rmodel || $rmodels) {

                                // Grab related object.
                                if ($rmodel) {
                                    $relatedObj = $object->fetchRelatedObj($props['model']);
                                }
                                else {
                                    $relatedObj = $object->fetchRelatedObj($props['models']);
                                }

                                // Check if uses a relation table.
                                $rTable = $object->usesRelationTable($relatedObj, $key);
                                if ($rTable) {
                                    if (!isset($props['passive'])) {
                                        $this->output("Creating Relation Table: ".$rTable);

                                        // Checking dominance
                                        $rdb = $object->getDbAdaptor(true);

                                        // Determine relation table field names.
                                        // Set to default to start.
                                        $className = $object->getClassName();
                                        $relClassName = $relatedObj->getClassName();

                                        // Check if custom field names were set for relation.
                                        if (isset($props['relThis']) && isset($props['relThat'])) {
                                            $className = $props['relThis'];
                                            $relClassName = $props['relThat'];
                                        }

                                        // EDGE CASE - if a relation is being created between the same model.
                                        // If no custom names were set, check for this edge case.
                                        else if ($className == $relClassName) {
                                            $relClassName = $relClassName.'2';
                                        }

                                        // Build relation table.
                                        $rdb->create($rTable)
                                            ->field('id', 'int', 'NOT NULL AUTO_INCREMENT')
                                            ->field($className, 'int')
                                            ->field($relClassName, 'int')
                                            ->primaryKey('id');
                                        $this->output($rdb->getQuery(), 2);
                                        //$rdb->reset();
                                        $rdb->exec();
                                    }
                                }

                                // Model either is a direct reference to a single object,
                                // or else an abstract reference that uses an 'owner' type column on
                                // the other object's table.
                                // If abstract reference (via keyword is set), then we don't want to do anything
                                // here. The ownership column will be handled when the other object is processed.
                                else {
                                    if (!isset($props['via']) && !isset($props['using'])) {
                                        if (!$modelFields->{$fieldName}) {
                                            $db ->field($fieldName, 'int');
                                            $modelFields->$fieldName = true;
                                        }
                                    }
                                }
                            }

                            // If not a model reference, then just add column to this models table.
                            else {
                                // There's at least one attribute on this model which isn't a reference
                                $nonEmptyModel = true;

                                // Set primary key if applicable
                                if (isset($props['primaryKey'])) {
                                    $db ->primaryKey($fieldName);
                                }

                                // Grab column type and then set it.
                                //$attr = $this->getAttributes($props);
                                if (!$modelFields->{$fieldName}) {
                                    $attr = $db->getAttributes($props);
                                    $type = $db->getType($props);
                                    $def = $type.' '.$attr;
                                    $db ->field($fieldName, $def);
                                    $modelFields->$fieldName = true;
                                }

                                // If the column is defined to have an index, create one.
                                $db->setIndex($fieldName, $props);
                            }
                        }

                        if ($nonEmptyModel) {
                            $this->output("Creating Table: ".$tableName);
                            $db ->create($tableName);
                            $this->output($db->getQuery(), 2);
                            //echo $db->reset();
                            $db->exec();
                        }
                    }
                    else {
                        $this->output('NOTICE: '.$model." is not a Cora Model. Ignoring for DB creation", 2);
                    }
                }
                else {
                    $this->output('NOTICE: '.$relPath." is not a PHP file. Ignoring for DB creation", 2);
                }
            }
        }
        //print_r($files);
    }

    protected function output($string, $newlines = 1)
    {
        if ($this->displayOutput) {
            echo $string;
            for($i = 0; $i < $newlines; $i++) {
                echo $this->newline;
            }
        }
    }

    /**
     *  Given a model's attributes, return it's
     */
    protected function getAttributes($props)
    {
        $attr = '';
        if (isset($props['primaryKey'])) {
            $attr .= 'NOT NULL AUTO_INCREMENT';
        }
        return $attr;
    }

    /**
     *  Returns a model in string form such that we could do
     *  'new $fullClassName()' to get an instance of it.
     */
    protected function getModel($filepath)
    {
        ////////////////////////////////////////////
        // If file path is /task/class.note.inc.php
        ////////////////////////////////////////////

        // Get 'class.note.inc.php'
        $nameFull = $this->getName($filepath);

        // Get '/task'
        $path = $this->getPath($filepath);

        // Remove prefix and postfix and .php to get classname.
        // gives 'note'
        $className = $this->getClassName($nameFull);

        // Get '\task\note'
        $fullClassName = CORA_MODEL_NAMESPACE.$this->getClassPath($path).$className;

        return $fullClassName;
    }

    /**
     *  Changes '/path/name' to '\path\name'
     */
    protected function getClassPath($path)
    {
        $path = str_replace('/', '\\', $path);

        return $path;
    }

    /**
     *  Removes prefix, postfix, and .php from class filename.
     */
    protected function getClassName($fileName)
    {
        // Get rid of prefix
        $namePiece = @explode($this->config['modelsPrefix'], $fileName);
        $name = isset($namePiece[1]) ? $namePiece[1] : $fileName;

        // Get rid of postfix
        $namePiece = @explode($this->config['modelsPostfix'], $name);
        $name = isset($namePiece[1]) ? $namePiece[0] : $name;

        // Get rid of .php
        $namePiece = explode('.php', $name);
        $name = isset($namePiece[1]) ? $namePiece[0] : $name;

        return $name;
    }
}


<?php
namespace Cora;

class Autoload extends Framework
{
    public function __construct()
    {
        parent::__construct(); // Call parent constructor too so we don't lose functionality.

        // Register autoloader functions. Are called when an unloaded class is invoked.
        // These should only end up getting called if Composer doesn't work first.
        spl_autoload_register(array($this, 'autoLoader'));
        spl_autoload_register(array($this, 'coraLoader'));
        spl_autoload_register(array($this, 'coraLegacyLoader'));
    }

    /************************************************
     *  PSR-4 Autoloaders.
     ***********************************************/

    protected function autoLoader($className)
    {
        $path = $this->getPathBackslash($className);
        $name = $this->getNameBackslash($className);
        $root = strToLower(self::getRootBackslash($className));
        $prefix = isset($this->config[$root.'Prefix']) ? $this->config[$root.'Prefix'] : '';
        $postfix = isset($this->config[$root.'Postfix']) ? $this->config[$root.'Postfix'] : '';

        $fullPath = $this->config['basedir'].$path.$prefix.$name.$postfix.'.php';
        //echo 'Trying to load ', $className, '
     from file ', $fullPath, "
     via ", __METHOD__, "
";

        if (file_exists($fullPath)) {
            include($fullPath);
        }
    }

    protected function coraLoader($className)
    {
        $fullPath = dirname(__FILE__) . '/' .
                    $this->getPathBackslash($className, true) .
                    $this->getNameBackslash($className) .
                    '.php';
        //echo 'Trying to load ', $className, '
     from file ', $fullPath, "
     via ", __METHOD__, "
";
        if (file_exists($fullPath)) {
            include($fullPath);
        }
    }

    protected function coraLegacyLoader($className)
    {
        $fullPath = dirname(__FILE__) . '/' .
                    //$this->getPathBackslash($className) .
                    $this->getNameBackslash($className) .
                    '.php';
        //echo 'Trying to load ', $className, '
     from file ', $fullPath, "
     via ", __METHOD__, "
";
        if (file_exists($fullPath)) {
            include($fullPath);
        }
    }
}


<?php
/**
 * Phossa Project
 *
 * PHP version 5.4
 *
 * @category  Library
 * @package   Phossa2\Shared
 * @copyright Copyright (c) 2016 phossa.com
 * @license   http://mit-license.org/ MIT License
 * @link      http://www.phossa.com/
 */
/*# declare(strict_types=1); */

namespace Phossa2\Shared\Message;

use Phossa2\Shared\Base\StaticAbstract;
use Phossa2\Shared\Message\Mapping\MappingTrait;
use Phossa2\Shared\Message\Mapping\MappingInterface;
use Phossa2\Shared\Message\Loader\LoaderAwareInterface;
use Phossa2\Shared\Message\Formatter\FormatterAwareTrait;
use Phossa2\Shared\Message\Formatter\FormatterAwareInterface;

/**
 * MessageAbstract
 *
 * - Used to convert message code into human-readable messages.
 *
 * - Subclass *MUST* define its own property `$messages`
 *
 * - Message loader maybe used to load different message mapping such as
 *   language files.
 *
 * - Message formatter maybe used to output message in different format.
 *
 * - Once loader set for parent class, it will affect all the descendant
 *   classes unless they have own loader set.
 *
 * - extending `MessageAbstract`
 *
 *   ```php
 *   use Phossa2\Shared\Message\MessageAbstract
 *
 *   // define own message class
 *   class MyMessage extends MessageAbstract
 *   {
 *       // define unique message codes, usually YearMonthDateMinute
 *       const MSG_HELLO = 1606151214;
 *
 *       // MUST define message template mappings
 *       protected static $messages = [
 *           self::MSG_HELLO => 'Hello %s'
 *       ];
 *   }
 *   ```
 *
 * - usage
 *
 *   ```php
 *   // print 'Hello World'
 *   echo MyMessage::get(MyMessage::MSG_HELLO, 'World');
 *
 *   // used in exception
 *   throw new \Exception(MyMessage::get(MyMessage::MSG_HELLO, 'John'));
 *   ```
 *
 * @package Phossa2\Shared
 * @author  Hong Zhang <phossa@126.com>
 * @see     StaticAbstract
 * @see     MessageInterface
 * @see     LoaderAwareInterface
 * @see     FormatterAwareInterface
 * @version 2.0.0
 * @since   2.0.0 added
 */
abstract class MessageAbstract extends StaticAbstract implements MessageInterface, MappingInterface, LoaderAwareInterface, FormatterAwareInterface
{
    use MappingTrait, FormatterAwareTrait;

    /**
     * {@inheritDoc}
     */
    public static function get(/*# int */ $code)/*# : string */
    {
        // process code
        if (!is_numeric($code)) {
            return is_scalar($code) ? (string) $code : print_r($code, true);
        } else {
            $code = (int) $code;
        }

        // get remaining arguments if any
        $arguments = func_get_args();
        array_shift($arguments);

        // build message and return it
        return self::getFormatter()->formatMessage(
            self::getTemplateByCode($code, get_called_class()),
            $arguments
        );
    }
}


<?php
/**
 * Copyright (c) 2018 Wakers.cz
 *
 * @author Jiří Zapletal (http://www.wakers.cz, zapletal@wakers.cz)
 *
 */

namespace Wakers\StructureModule\Component\Frontend\StructureModal;

use Nette\Application\UI\Form;
use Nette\Application\UI\Multiplier;
use Nette\Forms\Controls\UploadControl;
use Nette\Http\FileUpload;
use Nette\Utils\DateTime;
use Propel\Runtime\Collection\ObjectCollection;
use Wakers\BaseModule\Component\Frontend\BaseControl;
use Wakers\BaseModule\Util\AjaxValidate;
use Wakers\BaseModule\Util\SetDisabledForm;
use Wakers\CategoryModule\Repository\CategoryRepository;
use Wakers\PageModule\Database\Page;
use Wakers\PageModule\Repository\PageRepository;
use Wakers\StructureModule\Builder\IVariableFormBuilder;
use Wakers\StructureModule\Database\RecipeSlug;
use Wakers\StructureModule\Database\RecipeVariable;
use Wakers\StructureModule\Database\Structure;
use Wakers\StructureModule\Database\StructureValueFile;
use Wakers\StructureModule\Manager\StructureInCategoryManager;
use Wakers\StructureModule\Manager\StructureInPageManager;
use Wakers\StructureModule\Manager\StructureManager;
use Wakers\StructureModule\Manager\StructureValueFileManager;
use Wakers\StructureModule\Manager\StructureValueManager;
use Wakers\StructureModule\Repository\RecipeSlugRepository;
use Wakers\StructureModule\Repository\StructureInCategoryRepository;
use Wakers\StructureModule\Repository\StructureRepository;
use Wakers\StructureModule\Repository\StructureValueFileRepository;
use Wakers\StructureModule\Repository\StructureValueRepository;
use Wakers\StructureModule\Repository\RecipeVariableRepository;
use Wakers\StructureModule\Security\StructureAuthorizator;
use Wakers\UserModule\Database\User;

class StructureModal extends BaseControl
{
    use AjaxValidate;
    use SetDisabledForm;

    /**
     *  Regulární výraz pro formát: 21.3.2018 05:31:01
     */
    const REGEX_DATETIME = '([1-9]|1[0-9]|2[0-9]|3[0-1])\.([1-9]|1[0-2])\.([0-2]{1}[0-9]{3})\040(0[0-9]|1[0-9]|2[0-3])(\:(0[0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-9]|5[0-9])){2}';

    /**
     * Formát data
     */
    const FORMAT_DATETIME = 'j.n.Y H:i:s';

    /**
     * @var RecipeSlugRepository
     */
    protected $recipeSlugRepository;

    /**
     * @var RecipeVariableRepository
     */
    protected $recipeVariableRepository;

    /**
     * @var StructureRepository
     */
    protected $structureRepository;

    /**
     * @var StructureValueRepository
     */
    protected $structureValueRepository;

    /**
     * @var StructureValueFileRepository
     */
    protected $structureValueFileRepository;

    /**
     * @var StructureInCategoryRepository
     */
    protected $structureInCategoryRepository;

    /**
     * @var CategoryRepository
     */
    protected $categoryRepository;

    /**
     * @var StructureManager
     */
    protected $structureManager;

    /**
     * @var StructureValueManager
     */
    protected $structureValueManager;

    /**
     * @var StructureValueFileManager
     */
    protected $structureValueFileManager;

    /**
     * @var StructureInPageManager
     */
    protected $structureInPageManager;

    /**
     * @var StructureInCategoryManager
     */
    protected $structureInCategoryManager;

    /**
     * @var IVariableFormBuilder
     */
    protected $IVariableFormBuilder;

    /**
     * Aktuální stránka
     * @var Page
     */
    protected $page;

    /**
     * Aktuální uživatel
     * @var User
     */
    protected $user;

    /**
     * Entita
     * @var RecipeSlug
     */
    protected $recipeSlug;

    /**
     * Entita
     * @var Structure
     */
    protected $structure;

    /**
     * Entity
     * @var ObjectCollection|RecipeVariable[]
     */
    protected $fileVariables;

    /**
     * Entity
     * @var ObjectCollection|RecipeVariable[]
     */
    protected $noFileVariables;

    /**
     * @var callable
     */
    public $onOpen = [];

    /**
     * @var callable
     */
    public $onSaveNoFile = [];

    /**
     * @var callable
     */
    public $onSaveFile = [];

    /**
     * @var callable
     */
    public $onSaveMain = [];

    /**
     * @var string
     * @persistent
     */
    public $recipeSlugString;

    /**
     * @var int $structureId
     * @persistent
     */
    public $structureId;

    /**
     * StructureModal constructor.
     * @param RecipeSlugRepository $recipeSlugRepository
     * @param RecipeVariableRepository $recipeVariableRepository
     * @param StructureRepository $structureRepository
     * @param StructureValueRepository $structureValueRepository
     * @param StructureValueFileRepository $valueFileRepository
     * @param StructureInCategoryRepository $structureInCategoryRepository
     * @param CategoryRepository $categoryRepository
     * @param StructureManager $structureManager
     * @param StructureValueManager $structureValueManager
     * @param StructureInPageManager $structureInPageManager
     * @param StructureValueFileManager $structureValueFileManager
     * @param StructureInCategoryManager $structureInCategoryManager
     * @param IVariableFormBuilder $IValueFormBuilder
     * @param PageRepository $pageRepository
     * @param \Nette\Security\User $user
     */
    public function __construct(
        RecipeSlugRepository $recipeSlugRepository,
        RecipeVariableRepository $recipeVariableRepository,

        StructureRepository $structureRepository,
        StructureValueRepository $structureValueRepository,
        StructureValueFileRepository $valueFileRepository,
        StructureInCategoryRepository $structureInCategoryRepository,
        CategoryRepository $categoryRepository,

        StructureManager $structureManager,
        StructureValueManager $structureValueManager,
        StructureInPageManager $structureInPageManager,
        StructureValueFileManager $structureValueFileManager,
        StructureInCategoryManager $structureInCategoryManager,

        IVariableFormBuilder $IValueFormBuilder,

        PageRepository $pageRepository,
        \Nette\Security\User $user
    ) {
        $this->recipeSlugRepository = $recipeSlugRepository;
        $this->recipeVariableRepository = $recipeVariableRepository;

        $this->structureRepository = $structureRepository;
        $this->structureValueRepository = $structureValueRepository;
        $this->structureValueFileRepository = $valueFileRepository;
        $this->structureInCategoryRepository = $structureInCategoryRepository;
        $this->categoryRepository = $categoryRepository;

        $this->structureManager = $structureManager;
        $this->structureValueManager = $structureValueManager;
        $this->structureInPageManager = $structureInPageManager;
        $this->structureValueFileManager = $structureValueFileManager;
        $this->structureInCategoryManager = $structureInCategoryManager;

        $this->IVariableFormBuilder = $IValueFormBuilder;

        $this->page = $pageRepository->getActivePage();
        $this->user = $user->getIdentity()->getData()['userEntity'];
    }

    /**
     * @throws \Propel\Runtime\Exception\PropelException
     */
    public function render() : void
    {
        $recipeSlug = $this->getRecipeSlug();

        $this->template->recipe = $recipeSlug ? $recipeSlug->getRecipe() : NULL;
        $this->template->structure =  $this->getStructure();
        $this->template->fileVariables = $this->getFileVariables();
        $this->template->setFile(__DIR__.'/templates/modal.latte');
        $this->template->render();
    }

    /**
     * Variables form
     * @return Form
     * @throws \Propel\Runtime\Exception\PropelException
     */
    protected function createComponentFormNoFile() : Form
    {
        $variables = $this->getNoFileVariables();
        $recipeSlug = $this->getRecipeSlug();
        $structure = $this->getStructure();
        $recipeVariables = [];

        if ($structure)
        {
            $structureValues = $this->structureValueRepository->findByStructure($structure);

            foreach ($structureValues as $structureValue)
            {
                $recipeVariableSlug = $structureValue->getRecipeVariable()->getSlug();
                $recipeVariables[$recipeVariableSlug] = $structureValue;
            }
        }

        $form = new Form;

        /**
         * @var string $variableSlug
         * @var RecipeVariable $recipeVariable
         */
        foreach ($variables->toKeyIndex('Slug') as $variableSlug => $recipeVariable)
        {
            $value = key_exists($variableSlug, $recipeVariables) ? $recipeVariables[$variableSlug] : NULL;

            $component = $this->IVariableFormBuilder->buildComponent($recipeSlug->getRecipe(), $recipeVariable, $structure, $value);
            $form->addComponent($component, $recipeVariable->getSlug());
        }

        $form->addSubmit('save');

        $form->onValidate[] = function (Form $form) { $this->validate($form); };
        $form->onSuccess[] = function (Form $form) { $this->successNoFile($form); };

        if (!$this->presenter->user->isAllowed(StructureAuthorizator::RES_STRUCTURE_MODAL))
        {
            $this->setDisabledForm($form, TRUE);
        }

        return $form;
    }

    /**
     * Success - non-file inputs form
     * @param Form $form
     * @throws \Propel\Runtime\Exception\PropelException
     * @throws \Exception
     */
    public function successNoFile(Form $form) : void
    {
        if ($this->presenter->isAjax() && $this->presenter->user->isAllowed(StructureAuthorizator::RES_STRUCTURE_MODAL))
        {
            $recipeSlug = $this->getRecipeSlug();
            $structure = $this->getStructure();
            $noFileVariables = $this->getNoFileVariables();

            $this->structureManager->getConnection()->beginTransaction();

            try
            {
                $structure = $this->structureManager->save(
                    $structure,
                    $recipeSlug,
                    $this->user
                );

                $this->structureValueManager->saveNoFileFields(
                    $structure,
                    $noFileVariables,
                    $form->getValues()
                );

                if ($recipeSlug->getRecipe()->isDynamic() && !$this->structure)
                {
                    $this->structureInPageManager->add($this->page, $structure);
                    $this->presenter->notificationAjax('Nezapomeňte', 'Nezapomeňte položku zařadit do příslušných kategorií.', 'warning', FALSE);
                }

                $this->structureManager->getConnection()->commit();
            }
            catch (\Exception $exception)
            {
                $this->structureManager->getConnection()->rollBack();
                throw $exception;
            }

            $this->structure = $structure;
            $this->structureId = $structure->getId();

            $this->presenter->notificationAjax(
                "{$recipeSlug->getRecipe()->getName()} uložena",
                "{$recipeSlug->getRecipe()->getName()} byla úspěšně uložena.",
                'success',
                FALSE
            );

            $this->onSaveNoFile();
        }
    }

    /**
     * File Forms
     * @return Multiplier
     * @throws \Propel\Runtime\Exception\PropelException
     */
    protected function createComponentFormFile() : Multiplier
    {
        $recipeSlug = $this->getRecipeSlug();
        $structure = $this->getStructure();
        $recipeVariables = $this->getFileVariables()->toKeyIndex('Slug');

        return new Multiplier(function ($variableSlug) use ($recipeVariables, $recipeSlug, $structure)
        {
            /** @var RecipeVariable $recipeVariable */
            $recipeVariable = $recipeVariables[$variableSlug];

            $component = $this->IVariableFormBuilder->buildComponent($recipeSlug->getRecipe(), $recipeVariable, $structure,NULL);

            $form = new Form;
            $form->addComponent($component, $recipeVariable->getSlug());
            $form->addSubmit('save');

            if (!$this->getStructure())
            {
                foreach ($form->getComponents() as $component)
                {
                    $component->setDisabled(TRUE);
                }
            }

            $form->onValidate[] = function (Form $form) { $this->validate($form); };
            $form->onSuccess[] = function (Form $form) { $this->successFile($form); };

            if (!$this->presenter->user->isAllowed(StructureAuthorizator::RES_STRUCTURE_MODAL))
            {
                $this->setDisabledForm($form, TRUE);
            }

            return $form;

        });
    }

    /**
     * Success - file input form
     * @param Form $form
     * @throws \Propel\Runtime\Exception\PropelException
     */
    public function successFile(Form $form) : void
    {
        if ($this->presenter->isAjax() && $this->presenter->user->isAllowed(StructureAuthorizator::RES_STRUCTURE_MODAL))
        {
            $recipeSlug = $this->getRecipeSlug();
            $structure = $this->getStructure();

            foreach ($form->getValues() as $recipeVariableSlug => $files)
            {
                $recipeVariable = $this->recipeVariableRepository->findOneByRecipeSlug($recipeSlug->getRecipe(), $recipeVariableSlug);
                $structureValue = $this->structureValueRepository->findOneByStructureAndVariableSlug($structure, $recipeVariableSlug);

                try
                {
                    if (!$structureValue)
                    {
                        $structureValue = $this->structureValueManager->createEmptyVariable($structure, $recipeVariable);
                    }

                    /** @var FileUpload $file */
                    foreach ($files as $file)
                    {
                        $this->structureValueFileManager->add($structureValue, $file);

                        $this->presenter->notificationAjax(
                            'Soubor nahrán',
                            "Soubor '{$file->getName()}' byl úspěšně nahrán.",
                            'success',
                            FALSE
                        );
                    }

                    // Reset rules
                    $component = $this->IVariableFormBuilder->buildComponent($recipeSlug->getRecipe(), $recipeVariable, $structure, $structureValue);
                    /** @var UploadControl $component */
                    $form->removeComponent($form->getComponent($recipeVariableSlug));
                    $form->addComponent($component, $recipeVariableSlug);

                }
                catch (\Exception $exception)
                {
                    $this->presenter->notificationAjax(
                        'Chyba při nahrávání',
                        "Soubor '{$file->getName()}' se nepodařilo nahrát. Chyba: {$exception->getMessage()}",
                        'error',
                        FALSE
                    );
                }
            }

            $this->onSaveFile();
        }
    }

    /**
     * File property forms
     * @return Multiplier
     * @throws \Propel\Runtime\Exception\PropelException
     */
    protected function createComponentFormFileProperty() : Multiplier
    {
        $structureValueFiles = [];

        // TODO: Vyřešit přes SQL i když to nějak moc nezpomaluje :-D

        /** @var RecipeVariable $recipeVariable */
        foreach ($this->getFileVariables()->toKeyIndex('Slug') as $recipeVariable)
        {
            foreach ($recipeVariable->getStructureValues() as $structureValue)
            {
                foreach ($structureValue->getStructureValueFiles() as $structureValueFile)
                {
                    $structureValueFiles[$structureValueFile->getId()] = $structureValueFile;
                }
            }
        }

        return new Multiplier(function ($structureValueFileId) use ($structureValueFiles)
        {
            /** @var StructureValueFile $structureValueFile */
            $structureValueFile = $structureValueFiles[$structureValueFileId];

            $form = new Form;

            $form->addText('title')
                ->setRequired('Titulek je povinný.')
                ->addRule(Form::MAX_LENGTH, 'Maximální délka titulku je %d znaků.', 128);

            $form->addText('uploadedAt')
                ->setRequired('Datum nahrání je povinný.')
                ->addRule(Form::PATTERN, "Datum vytvoření musí být ve formátu: 24.8.2018 08:59:01.", self::REGEX_DATETIME);

            $form->addHidden('structureValueFileId', $structureValueFileId);

            $form->addSubmit('save');

            if (!$this->getStructure())
            {
                foreach ($form->getComponents() as $component)
                {
                    $component->setDisabled(TRUE);
                }
            }

            $form->setDefaults([
                'title' => $structureValueFile->getTitle(),
                'uploadedAt' => $structureValueFile->getUploadedAt()->format(self::FORMAT_DATETIME),
            ]);

            $form->onValidate[] = function (Form $form) { $this->validate($form); };
            $form->onSuccess[] = function (Form $form) { $this->successFileProperty($form); };

            if (!$this->presenter->user->isAllowed(StructureAuthorizator::RES_STRUCTURE_MODAL))
            {
                $this->setDisabledForm($form, TRUE);
            }

            return $form;
        });
    }

    /**
     * Success - file property
     * @param Form $form
     * @throws \Exception
     */
    public function successFileProperty(Form $form) : void
    {
        if ($this->presenter->isAjax() && $this->presenter->user->isAllowed(StructureAuthorizator::RES_STRUCTURE_MODAL))
        {
            $values = $form->getValues();

            $uploadedAt = new DateTime($values->uploadedAt);

            $this->structureValueFileManager->update(
                $values->structureValueFileId,
                $uploadedAt,
                $values->title
            );

            $this->presenter->notificationAjax(
                'Atributy aktualizovány',
                'Dodatečné atributy souboru byly aktualizovány.',
                'success',
                FALSE
            );

            $this->onSaveFile();
        }
    }

    /**
     * Main form
     * @return Form
     * @throws \Propel\Runtime\Exception\PropelException
     */
    protected function createComponentFormMain() : Form
    {
        $recipeSlug = $this->getRecipeSlug();
        $structure = $this->getStructure();
        $parents = $this->getParentsExceptSubParents();

        $categories = $this->getCategories();

        $form = new Form;

        $form->addText('createdAt')
            ->setRequired('Datum vytvoření je povinný.')
            ->addRule(Form::PATTERN, "Datum vytvoření musí být ve formátu: 24.8.2018 08:59:01.", self::REGEX_DATETIME);

        $form->addText('updatedAt')
            ->setDisabled(TRUE);

        $form->addCheckboxList('categories', NULL, $categories)
            ->setRequired(FALSE);
            //->setRequired('Minimálně jedna kategorie je povinná.');

        if ($recipeSlug->getRecipe()->getMaxCategories() > 0)
        {
            $form->getComponent('categories')
                ->addRule(Form::MAX_LENGTH, 'Maximální počet kategorií je %d.', $recipeSlug->getRecipe()->getMaxCategories());
        }

        $form->addSelect('parent', NULL, $parents)
            ->setRequired(FALSE);

        $form->addSubmit('save');

        if (!$this->getStructure())
        {
            foreach ($form->getComponents() as $component)
            {
                $component->setDisabled(TRUE);
            }
        }

        if ($structure)
        {
            $parent = $structure->getParent();

            $parentId = $parent && !$parent->isRoot() ? $parent->getId() : -1;

            //$parentId = key_exists($parentId, $parents) ? $parentId : -1;

            $form->setDefaults([
                'createdAt' => $structure->getCreatedAt()->format(self::FORMAT_DATETIME),
                'updatedAt' => $structure->getUpdatedAt()->format(self::FORMAT_DATETIME),
                'categories' => array_keys(
                    $this->structureInCategoryRepository
                        ->findByStructure($structure)
                        ->toKeyIndex('CategoryId')
                ),
                'parent' => $parentId,
            ]);
        }

        $form->onValidate[] = function (Form $form) { $this->validate($form); };
        $form->onSuccess[] = function (Form $form) { $this->successMain($form); };

        if (!$this->presenter->user->isAllowed(StructureAuthorizator::RES_STRUCTURE_MODAL))
        {
            $this->setDisabledForm($form, TRUE);
        }

        return $form;
    }

    /**
     * Success - main form
     * @param Form $form
     * @throws \Exception
     */
    public function successMain(Form $form) : void
    {
        if ($this->presenter->isAjax() && $this->presenter->user->isAllowed(StructureAuthorizator::RES_STRUCTURE_MODAL))
        {
            $recipeSlug = $this->getRecipeSlug();
            $structure = $this->getStructure();
            $values = $form->getValues();

            $createdAt = new DateTime($values->createdAt);
            $parent = ($values->parent > 0) ? $this->structureRepository->findOneById($values->parent) : NULL;

            $this->structureManager->getConnection()->beginTransaction();

            try
            {
                $structure = $this->structureManager->save(
                    $structure,
                    $recipeSlug,
                    $this->user,
                    $parent,
                    $createdAt
                );

                $diffCategories = $this->structureInCategoryManager->makeDiff($structure, $values->categories);
                $this->structureManager->saveCategories($structure, $diffCategories);

                $this->structureManager->getConnection()->commit();

                $parents = $this->getParentsExceptSubParents();

                $form->getComponent('parent')->setItems($parents);
                $form->getComponent('updatedAt')->setValue($structure->getUpdatedAt()->format(self::FORMAT_DATETIME));

                $this->presenter->notificationAjax(
                    'Nastavení aktualizováno',
                    'Další nastavení bylo aktualizováno.',
                    'success',
                    FALSE
                );

                $this->onSaveMain();
            }
            catch (\Exception $exception)
            {
                $this->structureManager->getConnection()->rollBack();
                throw $exception;
            }
        }
    }

    /**
     * @param int $structureValueFileId
     * @throws \Exception
     */
    public function handleRemoveFile(int $structureValueFileId) : void
    {
        if ($this->presenter->isAjax() && $this->presenter->user->isAllowed(StructureAuthorizator::RES_STRUCTURE_MODAL))
        {
            $this->structureValueFileManager->remove($structureValueFileId);
            $this->presenter->notificationAjax('Soubor odstraněn', 'Soubor byl úspěšně odstraněn.', 'info', FALSE);
            $this->onSaveFile();
        }
    }

    /**
     * Open add modal (edit existing structure)
     * @param string $recipeSlug
     * @param int $structureId
     * @param bool $isNew
     * @throws \Propel\Runtime\Exception\PropelException
     */
    public function handleOpen(string $recipeSlug, int $structureId = NULL, bool $isNew = FALSE) : void
    {
        if ($this->presenter->isAjax() && $this->presenter->user->isAllowed(StructureAuthorizator::RES_STRUCTURE_MODAL))
        {
            $recipeSlugString = $recipeSlug;
            $this->recipeSlugString = $recipeSlugString;

            $recipeSlug = $this->getRecipeSlug();

            if ($recipeSlug)
            {
                if ($isNew)
                {
                    if ($recipeSlug->getRecipe()->isDynamic())
                    {
                        $count = $this->structureRepository->countByRecipeSlugAndPage($recipeSlugString, $this->page);
                    }
                    else
                    {
                        $count = $this->structureRepository->countByRecipeSlug($recipeSlugString);
                    }

                    if ($count >= $recipeSlug->getRecipe()->getMaxInstances() && $recipeSlug->getRecipe()->getMaxInstances() !== 0)
                    {
                        $message = $recipeSlug->getRecipe()->isDynamic() ? 'na této stránce' : '';

                        $this->presenter->notificationAjax(
                            'Dosažení limitu',
                            "Pro položku '{$recipeSlug->getRecipe()->getName()} [slug: {$recipeSlugString}]' byl {$message} dosažen limit. Maximální počet položek: {$recipeSlug->getRecipe()->getMaxInstances()}.",
                            'error',
                            TRUE
                        );
                    }
                }

                if ($structureId !== NULL)
                {
                    $structure = $this->getStructure();

                    if (!$structure)
                    {
                        $this->presenter->notificationAjax(
                            'Položka neexistuje',
                            "Položka s id '{$structureId}' neexistuje.",
                            'error',
                            TRUE
                        );
                    }
                }

                $this->presenter->handleModalToggle('show', '#wakers_structure_structure_modal', FALSE);
                $this->onOpen();
            }
            else
            {
                $this->presenter->notificationAjax('Chyba', "Předpis se slugem '{$recipeSlugString}' neexistuje", 'error', TRUE);
            }
        }
    }

    /**
     * @return ObjectCollection|RecipeVariable[]
     * @throws \Propel\Runtime\Exception\PropelException
     */
    protected function getFileVariables() : ObjectCollection
    {
        $recipeSlug = $this->getRecipeSlug();

        if (!$this->fileVariables && $recipeSlug)
        {
            $this->fileVariables = $this->recipeVariableRepository->findFileVariables($recipeSlug->getRecipe());
        }

        if (!$this->fileVariables instanceof ObjectCollection)
        {
            $this->fileVariables = new ObjectCollection;
        }

        $structure = $this->getStructure();

        if ($structure)
        {
            $structureValueFileArray = $this->structureValueRepository->findStructureVariableFilesByStructure($structure);

            foreach ($this->fileVariables as $fileVariable)
            {
                $collection = [];

                $slug = $fileVariable->getSlug();

                if (key_exists($slug, $structureValueFileArray))
                {
                    $collection = $structureValueFileArray[$slug];
                }

                $fileVariable->setVirtualColumn('Files', $collection);
            }
        }

        return $this->fileVariables;
    }

    /**
     * @return ObjectCollection|RecipeVariable[]
     * @throws \Propel\Runtime\Exception\PropelException
     */
    protected function getNoFileVariables() : ObjectCollection
    {
        $recipeSlug = $this->getRecipeSlug();

        if (!$this->noFileVariables && $recipeSlug)
        {
            $this->noFileVariables = $this->recipeVariableRepository->findNoFileVariables($recipeSlug->getRecipe());
        }

        if (!$this->noFileVariables instanceof ObjectCollection)
        {
            $this->noFileVariables = new ObjectCollection;
        }

        return $this->noFileVariables;
    }

    /**
     * @return array
     * @throws \Propel\Runtime\Exception\PropelException
     */
    protected function getCategories() : array
    {
        $recipeSlug = $this->getRecipeSlug();
        $categories = [];

        foreach($this->categoryRepository->findByRecipe($recipeSlug->getRecipe()) as $category)
        {
            $level = $category->getLevel() - 2;
            $categories[$category->getId()] = $level . '|' .  str_repeat('––', $level) . ' ' . $category->getName();
        }

        return $categories;
    }

    /**
     * @return array
     * @throws \Propel\Runtime\Exception\PropelException
     */
    protected function getParentsExceptSubParents() : array
    {
        $recipeSlug = $this->getRecipeSlug();
        $structure = $this->getStructure();
        $recipeId = $recipeSlug->getRecipe()->getAllowedParentId();

        $parents = [-1 => 'Bez nadřazené položky'];

        if ($recipeId && $structure)
        {
            $recipeSlugs = $this->recipeSlugRepository->findByRecipeId($recipeId)->toKeyIndex('Slug');
            $dbParents = $this->structureRepository->findParentsExceptSubParents(array_keys($recipeSlugs), $structure);
            $currentSubLevels = $this->structureRepository->countSubLevels($structure);

            foreach ($dbParents as $parent)
            {
                // TODO: načítat sub-levels count již v hlavním dotazu (zde se opakuje SQL v cyklu)
                $targetSubLevels = $this->structureRepository->countSubLevels($parent);

                if ($currentSubLevels <= $targetSubLevels && $parent->getLevel() + $currentSubLevels <= $recipeSlug->getRecipe()->getMaxDepth())
                {
                    $parents[$parent->getId()] = str_repeat('––', $parent->getLevel() - 1) .
                        "{$parent->getRecipeSlug()->getRecipe()->getName()} (# {$parent->getId()})";
                }
            }
        }

        return $parents;
    }

    /**
     * Optimalizace SQL
     * @return RecipeSlug|NULL
     */
    protected function getRecipeSlug() : ?RecipeSlug
    {
        if (!$this->recipeSlug && $this->recipeSlugString)
        {
            $this->recipeSlug = $this->recipeSlugRepository->findOneBySlug($this->recipeSlugString);
        }

        return $this->recipeSlug;
    }

    /**
     * Optimalizace SQL
     * @return Structure|NULL
     */
    protected function getStructure() : ?Structure
    {
        if (!$this->structure && $this->structureId)
        {
            $this->structure = $this->structureRepository->findOneById($this->structureId);
        }

        return $this->structure;
    }
}


<?php declare(strict_types=1);

namespace Roquie\Database\Connection\Wait;

use PDO;
use Psr\Log\LoggerInterface;
use Roquie\Database\Connection\Exception\NotConnectedException;
use Roquie\Database\PrettyLogger;

final class Wait
{
    private const CHANNEL = 'WaitDB';
    private const DEFAULT_ATTEMPTS = 10;
    private const DEFAULT_EVERY_SECOND = 3;

    /**
     * @var \Psr\Log\LoggerInterface
     */
    private $logger;

    /**
     * @var \Roquie\Database\Connection\Wait\WaitInterface
     */
    private $connection;

    /**
     * @var integer
     */
    private $attempt = self::DEFAULT_ATTEMPTS;

    /**
     * @var integer
     */
    private $every = self::DEFAULT_EVERY_SECOND;

    /**
     * @var bool
     */
    private static $disableExit = false;

    /**
     * Database options.
     *
     * @var array
     */
    private $options;

    /**
     * Wait constructor.
     *
     * @param array $options
     * @param \Psr\Log\LoggerInterface|null $logger
     */
    public function __construct(array $options = [], LoggerInterface $logger = null)
    {
        $this->options = $options;
        $this->logger = $logger ?: PrettyLogger::create(self::CHANNEL);
        $this->logger->info('Wait connection to database...');
    }

    /**
     * @param \Roquie\Database\Connection\Wait\WaitInterface $connection
     * @return \Roquie\Database\Connection\Wait\Wait
     */
    public function with(WaitInterface $connection): Wait
    {
        $this->connection = $connection;

        return $this;
    }

    /**
     * @param array $options
     * @return \Roquie\Database\Connection\Wait\Wait
     */
    public function options(array $options): Wait
    {
        $this->options = $options;

        return $this;
    }

    /**
     * @param int $count
     * @return \Roquie\Database\Connection\Wait\Wait
     */
    public function attempts(int $count)
    {
        $this->attempt = $count;

        return $this;
    }

    /**
     * @param int $second
     * @return \Roquie\Database\Connection\Wait\Wait
     */
    public function every(int $second)
    {
        $this->every = $second;

        return $this;
    }

    /**
     * @return \Roquie\Database\Connection\Wait\Wait
     */
    public static function new()
    {
        return new static();
    }

    public static function disableExitOnFail()
    {
        static::$disableExit = true;
    }

    /**
     * @param string $dsn
     * @param array $params
     */
    public static function connection(string $dsn, ...$params)
    {
        if (count($params) === 1) {
            $callback = $params[0];
        } else {
            [$attempts, $callback] = $params;
        }

        $wait = new static();
        $wait->with(new PdoWait());
        $wait->attempts($attempts ?? self::DEFAULT_ATTEMPTS);
        $wait->start($dsn, $callback);

        return;
    }

    /**
     * TODO refactor Connection Waiter.
     *
     * @param string $dsn
     * @param array $params
     */
    public static function persistent(string $dsn, ...$params)
    {
        if (count($params) === 1) {
            $callback = $params[0];
        } else {
            [$attempts, $callback] = $params;
        }

        $wait = new static();
        $wait->with(new PdoWait());
        $wait->attempts($attempts ?? self::DEFAULT_ATTEMPTS);
        $wait->options([
            PDO::ATTR_PERSISTENT => true
        ]);

        $wait->start($dsn, $callback);

        return;
    }

    /**
     * @param string $dsn
     * @param callable $callback
     */
    public function start(string $dsn, callable $callback)
    {
        $completed = 0;
        while ($completed < $this->attempt) {
            try {
                $database = $this->connection->alive($dsn, $this->options);
            } catch (NotConnectedException $e) {
                $completed++;
                $this->logger->warn(sprintf('%s Attempt no. %d', $e->getMessage(), $completed));
                sleep($this->every);

                if ($this->toBeOrNotToBe($completed)) {
                    $this->logger->info('Exit from application because connection not established.');
                    exit(1);
                }

                continue;
            }

            if (is_object($database)) {
                $this->logger->info('Connected successfully.');
                $callback($database);
                break;
            }

            $completed++;
        }
    }

    /**
     * Exit from application if connection does not successful or not.
     *
     * @param $completed
     * @return bool
     */
    private function toBeOrNotToBe($completed): bool
    {
        return $completed === $this->attempt && !static::$disableExit;
    }
}