<?php declare(strict_types=1);
namespace Imatic\Bundle\ViewBundle\Templating\Helper\Format;

use DateTime;
use IntlDateFormatter;
use Locale;
use NumberFormatter;

class IntlFormatter implements FormatterInterface
{
    /** @var int[] */
    protected static $dateFormatTypes = [
        'none' => IntlDateFormatter::NONE,
        'short' => IntlDateFormatter::SHORT,
        'medium' => IntlDateFormatter::MEDIUM,
        'long' => IntlDateFormatter::LONG,
        'full' => IntlDateFormatter::FULL,
    ];
    /** @var int[] */
    protected static $numberFormatTypes = [
        'default' => NumberFormatter::DEFAULT_STYLE,
        'decimal' => NumberFormatter::DECIMAL,
        'currency' => NumberFormatter::CURRENCY,
        'percent' => NumberFormatter::PERCENT,
        'scientific' => NumberFormatter::SCIENTIFIC,
        'spellout' => NumberFormatter::SPELLOUT,
        'ordinal' => NumberFormatter::ORDINAL,
        'duration' => NumberFormatter::DURATION,
    ];
    /** @var array */
    protected $datePatternOverrides = [
        'cs.date.short' => 'dd.MM.y',
        'cs.datetime.short:short' => 'dd.MM.y H:mm',
        'sk.date.short' => 'dd.MM.y',
        'sk.datetime.short:short' => 'dd.MM.y H:mm',
    ];

    public function addDatePatternOverrides(array $overrides)
    {
        $this->datePatternOverrides = $overrides + $this->datePatternOverrides;
    }

    public function format($value, $format, array $options = [])
    {
        if (null !== $value) {
            return $this->{"format{$format}"}($value, $options);
        }
    }

    protected function formatDate($value, array $options)
    {
        if (!$value instanceof \DateTimeInterface) {
            $value = new DateTime($value);
        }

        if (isset($options['format'])) {
            // explicit format given
            return $value->format($options['format']);
        }
        // use intl
        return $this->intlDateTimeFormat(
            $value,
            isset($options['type']) ? $options['type'] : 'short',
            'none',
            isset($options['timezone']) ? $options['timezone'] : null,
            isset($options['locale']) ? $options['locale'] : null
        );
    }

    protected function formatDateTime($value, array $options)
    {
        if (!$value instanceof \DateTimeInterface) {
            $value = new DateTime($value);
        }

        if (isset($options['format'])) {
            // explicit format given
            return $value->format($options['format']);
        }
        // use intl
        return $this->intlDateTimeFormat(
            $value,
            isset($options['date_type']) ? $options['date_type'] : 'short',
            isset($options['time_type']) ? $options['time_type'] : 'short',
            isset($options['timezone']) ? $options['timezone'] : null,
            isset($options['locale']) ? $options['locale'] : null
        );
    }

    protected function formatTime($value, array $options)
    {
        if (!$value instanceof \DateTimeInterface) {
            $value = new DateTime($value);
        }

        if (isset($options['format'])) {
            // explicit format given
            return $value->format($options['format']);
        }
        // use intl
        return $this->intlDateTimeFormat(
            $value,
            'none',
            isset($options['type']) ? $options['type'] : 'short',
            isset($options['timezone']) ? $options['timezone'] : null,
            isset($options['locale']) ? $options['locale'] : null
        );
    }

    protected function formatNumber($value, array $options)
    {
        if (isset($options['decimal']) || isset($options['decimalPoint']) || isset($options['thousandSep'])) {
            // use number_format()
            return \number_format(
                $value,
                isset($options['decimal']) ? $options['decimal'] : 0,
                isset($options['decimalPoint']) ? $options['decimalPoint'] : '.',
                isset($options['thousandSep']) ? $options['thousandSep'] : ','
            );
        }
        // use number formatter
        if (isset($options['type'])) {
            if (!isset(static::$numberFormatTypes[$options['type']])) {
                throw new \InvalidArgumentException(\sprintf('Invalid number type "%s", valid types are: %s', $options['type'], \implode(', ', \array_keys(static::$numberFormatTypes))));
            }

            $type = static::$numberFormatTypes[$options['type']];
        } else {
            $type = static::$numberFormatTypes['default'];
        }

        $formatter = new NumberFormatter(
            isset($options['locale']) ? $options['locale'] : Locale::getDefault(),
            $type
        );

        if (NumberFormatter::PERCENT === $type) {
            $formatter->setAttribute(NumberFormatter::MULTIPLIER, isset($options['multiplier']) ? $options['multiplier'] : 1);
            $formatter->setTextAttribute(NumberFormatter::POSITIVE_SUFFIX, '%');
            $formatter->setTextAttribute(NumberFormatter::NEGATIVE_SUFFIX, '%');
        }

        if (NumberFormatter::CURRENCY === $type) {
            return $formatter->formatCurrency($value, $options['currency']);
        }
        return $formatter->format($value);
    }

    /**
     * @param \DateTimeInterface $dateTime
     * @param string $dateType
     * @param string $timeType
     * @param mixed $timezone
     * @param string|null $locale
     *
     * @return string|bool
     */
    protected function intlDateTimeFormat(\DateTimeInterface $dateTime, $dateType, $timeType, $timezone, $locale)
    {
        if (!isset(static::$dateFormatTypes[$dateType])) {
            throw new \InvalidArgumentException(\sprintf('Invalid date type "%s", valid types are: %s', $dateType, \implode(', ', \array_keys(static::$dateFormatTypes))));
        }
        if (!isset(static::$dateFormatTypes[$dateType])) {
            throw new \InvalidArgumentException(\sprintf('Invalid time type "%s", valid types are: %s', $timeType, \implode(', ', \array_keys(static::$dateFormatTypes))));
        }
        if (!$locale) {
            $locale = Locale::getDefault();
        }

        $formatter = new IntlDateFormatter(
            $locale,
            static::$dateFormatTypes[$dateType],
            static::$dateFormatTypes[$timeType],
            $timezone ?: $dateTime->getTimezone()
        );

        if ($pattern = $this->getIntlDatePattern($locale, $dateType, $timeType)) {
            $formatter->setPattern($pattern);
        }

        return $formatter->format($dateTime);
    }

    /**
     * @param string $locale
     * @param int    $dateType
     * @param int    $timeType
     *
     * @return string|null
     */
    protected function getIntlDatePattern($locale, $dateType, $timeType)
    {
        $hasDate = 'none' !== $dateType;
        $hasTime = 'none' !== $timeType;

        if ($hasDate && $hasTime) {
            $overrideKey = "{$locale}.datetime.{$dateType}:{$timeType}";
        } elseif ($hasDate) {
            $overrideKey = "{$locale}.date.{$dateType}";
        } elseif ($hasTime) {
            $overrideKey = "{$locale}.time.{$timeType}";
        } else {
            $overrideKey = null;
        }

        if ($overrideKey && isset($this->datePatternOverrides[$overrideKey])) {
            return $this->datePatternOverrides[$overrideKey];
        }
    }
}


<?php

namespace ArneGroskurth\Url;

class Url {

    /*
     * The following values can be subtracted or added together to get a mask identifying all parts that has to be included.
     */
    const NONE = 0;

    const SCHEME = 1;
    const USER = 2;
    const PASS = 4;
    const CREDENTIALS = 6;
    const PORT = 8;
    const PATH = 16;
    const QUERY = 32;
    const FRAGMENT = 64;

    const ALL = 127;

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

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

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

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

    /**
     * @var int
     */
    protected $port;

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

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

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

    /**
     * @return string
     */
    public function getScheme() {

        return $this->scheme;
    }

    /**
     * @param string $scheme
     *
     * @return Url
     */
    public function setScheme($scheme) {

        $this->scheme = $scheme;

        return $this;
    }

    /**
     * @return string
     */
    public function getUser() {

        return $this->user;
    }

    /**
     * @param string $user
     *
     * @return Url
     */
    public function setUser($user) {

        $this->user = $user;

        return $this;
    }

    /**
     * @return string
     */
    public function getPass() {

        return $this->pass;
    }

    /**
     * @param string $pass
     *
     * @return Url
     */
    public function setPass($pass) {

        $this->pass = $pass;

        return $this;
    }

    /**
     * @return string
     */
    public function getHost() {

        return $this->host;
    }

    /**
     * @param string $host
     *
     * @return Url
     */
    public function setHost($host) {

        $this->host = $host;

        return $this;
    }

    /**
     * @param bool $canonicalized
     *
     * @return string
     */
    public function getPath($canonicalized = false) {

        return $canonicalized ? ('/' . $this->getCanonicalizedPath($this->path)) : $this->path;
    }

    /**
     * @param string $path
     *
     * @return $this
     */
    public function setPath($path) {

        $path = $path ?: '/';

        if($path[0] !== '/') {

            $path = '/' . $path;
        }

        $this->path = $path;

        return $this;
    }

    /**
     * @return int
     */
    public function getPort() {

        return $this->port;
    }

    /**
     * @param int $port
     *
     * @return Url
     * @throws UrlException
     */
    public function setPort($port) {

        if(!is_int($port) || $port < 1 || $port > 65535) {

            throw new UrlException('Invalid port given.');
        }

        $this->port = $port;

        return $this;
    }

    /**
     * @return array
     */
    public function getQuery() {

        return $this->query;
    }

    /**
     * @param array $query
     *
     * @return Url
     */
    public function setQuery(array $query) {

        $this->query = $query;

        return $this;
    }

    /**
     * @param string $name
     *
     * @return bool
     */
    public function hasQueryParameter($name) {

        return isset($this->query[$name]);
    }

    /**
     * @param string $name
     *
     * @return string
     */
    public function getQueryParameter($name) {

        return isset($this->query[$name]) ? $this->query[$name] : null;
    }

    /**
     * @param string $name
     * @param string $value
     *
     * @return $this
     */
    public function setQueryParameter($name, $value) {

        $this->query[$name] = $value;

        return $this;
    }

    /**
     * @param string $name
     *
     * @return $this
     */
    public function removeQueryParameter($name) {

        if(isset($this->query[$name])) {

            unset($this->query[$name]);
        }

        return $this;
    }

    /**
     * @return string
     */
    public function getQueryString() {

        $return = array();

        foreach($this->query as $name => $value) {

            $return[] = $name . '=' . urlencode($value);
        }

        return implode('&', $return);
    }

    /**
     * @param string $queryString
     *
     * @return $this
     */
    public function setQueryString($queryString) {

        foreach(explode('&', $queryString) as $parameter) {

            list($name, $value) = explode('=', $parameter);

            $this->query[$name] = urldecode($value);
        }

        return $this;
    }

    /**
     * @return string
     */
    public function getFragment() {

        return $this->fragment;
    }

    /**
     * @param string $fragment
     *
     * @return Url
     */
    public function setFragment($fragment) {

        $this->fragment = $fragment;

        return $this;
    }

    /**
     * @param string $url
     *
     * @throws UrlException
     */
    public function __construct($url = null) {

        if($url === null) {
            return;
        }

        // http://php.net/manual/de/function.parse-url.php#114817
        $encodedUrl = preg_replace_callback('%[^:/@?&=#]+%usD', function ($matches) {

            return urlencode($matches[0]);

        }, $url);

        $parts = parse_url($encodedUrl);

        if($parts === false) {

            throw new UrlException('Invalid Url given.');
        }

        foreach($parts as $name => $value) {

            $parts[$name] = urldecode($value);
        }

        if(!isset($parts['host'])) {

            throw new UrlException('Invalid Url given.');
        }

        $this->scheme = isset($parts['scheme']) ? $parts['scheme'] : null;
        $this->user = isset($parts['user']) ? $parts['user'] : null;
        $this->pass = isset($parts['pass']) ? $parts['pass'] : null;
        $this->host = $parts['host'];
        $this->port = isset($parts['port']) ? (int)$parts['port'] : null;
        $this->path = isset($parts['path']) ? $parts['path'] : null;
        $this->fragment = isset($parts['fragment']) ? $parts['fragment'] : null;

        if(isset($parts['query'])) {

            $this->setQueryString($parts['query']);
        }
    }

    /**
     * @param int $includeParts
     * @param bool $skipDefaultPort
     * @param bool $canonicalizePath
     *
     * @return string
     * @throws UrlException
     */
    public function getUrl($includeParts = self::ALL, $skipDefaultPort = true, $canonicalizePath = true) {

        if(!is_int($includeParts) || $includeParts < static::NONE || $includeParts > static::ALL) {

            throw new UrlException('Invalid part inclusion mask given.');
        }

        $return = '';

        if($includeParts & self::SCHEME && $this->scheme) {

            $return .= $this->scheme . ':';
        }

        $return .= '//';

        if($includeParts & self::USER && $this->user) {

            $return .= $this->user;

            if($includeParts & self::PASS && $this->pass) {

                $return .= ':' . $this->pass;
            }

            $return .= '@';
        }

        $return .= $this->host;

        if($includeParts & self::PORT && $this->port) {

            $defaultPort = $this->scheme ? static::getDefaultPort($this->scheme) : null;

            if($this->port !== $defaultPort || !$skipDefaultPort) {

                $return .= ':' . $this->port;
            }
        }

        if($includeParts & self::PATH && $this->path) {

            $return .= $this->getPath($canonicalizePath);
        }

        else {

            $return .= '/';
        }

        if($includeParts & self::QUERY && $this->query) {

            $return .= '?' . $this->getQueryString();
        }

        if($includeParts & self::FRAGMENT && $this->fragment) {

            $return .= '#' . $this->fragment;
        }

        return $return;
    }

    /**
     * Build absolute url of given path in given context
     *
     * @param string $url
     *
     * @return Url
     */
    public function resolveRelativeUrl($url) {

        try {

            // return absolute url
            return new static($url);
        }
        catch(UrlException $exception) {}

        // anchor
        if($url[0] === '#') {

            return new static($this->getUrl(self::ALL - self::FRAGMENT) . $url);
        }

        // query
        if($url[0] === '?') {

            return new static($this->getUrl(self::ALL - self::FRAGMENT - self::QUERY) . $url);
        }

        // relative path from domain root
        if($url[0] === '/') {

            return new static($this->getUrl(self::ALL - self::FRAGMENT - self::QUERY - self::PATH) . substr($url, 1));
        }

        // relative path from current path
        else {

            $currentPath = $this->path ?: '/';

            // cut last path fragment
            if(substr($currentPath, -1) !== '/') {

                $currentPath = substr($currentPath, 0, strrpos($currentPath, '/') + 1);
            }

            return new static($this->getUrl(self::ALL - self::FRAGMENT - self::QUERY - self::PATH) . $this->getCanonicalizedPath($currentPath . $url));
        }
    }

    /**
     * @return string
     */
    public function __toString() {

        return $this->getUrl();
    }

    /**
     * @param string $path
     *
     * @return string
     */
    protected function getCanonicalizedPath($path) {

        $newPath = array();
        foreach(explode('/', $path) as $segment) {

            if($segment === '' || $segment === '.') {

                continue;
            }

            elseif($segment === '..') {

                array_pop($newPath);
            }

            else {

                array_push($newPath, $segment);
            }
        }

        return implode('/', $newPath);
    }

    /**
     * Returns true if the given Url is valid.
     *
     * @param string $url
     *
     * @return bool
     */
    public static function validate($url) {

        try {

            new self($url);

            return true;
        }
        catch(UrlException $exception) {

            return false;
        }
    }

    /**
     * Returns the default port the given scheme usually can be contacted on.
     *
     * @param string $scheme
     *
     * @return int
     */
    public static function getDefaultPort($scheme) {

        switch(strtolower($scheme)) {

            case 'dav': return 9800;
            case 'ftp': return 21;
            case 'ftps': return 990;
            case 'git': return 9418;
            case 'http': return 80;
            case 'https': return 443;
            case 'svn': return 3690;

            // sub-protocol of http
            case 'ws': return 80;
            case 'wss': return 443;

            default: return null;
        }
    }
}


<?php

/**
 * Routines to assist in the installation of various parts of QCubed with composer.
 *
 */

namespace QCubed\Composer;

use Composer\Package\PackageInterface;
use Composer\Installer\LibraryInstaller;
use Composer\Repository\InstalledRepositoryInterface;

$__CONFIG_ONLY__ = true;

class Installer extends LibraryInstaller
{
	/** Overrides **/
	/**
	 * Return the types of packages that this installer is responsible for installing.
	 *
	 * @param $packageType
	 * @return bool
	 */
	public function supports($packageType)
	{
		return ('qcubed-plugin' === $packageType ||
			'qcubed-framework' === $packageType);
	}

	public function getInstallPath(PackageInterface $package) {
		$strDest = parent::getInstallPath($package);
		$parts = explode('_', $package->getName());

		if ('qcubed/plugin' === $parts[0]) {
			$strDest = ($this->vendorDir ? $this->vendorDir . '/' : '') . 'qcubed/plugin/' . $parts[1];
		}
		return $strDest;
	}

	/**
	 * Respond to the install command.
	 *
	 * @param InstalledRepositoryInterface $repo
	 * @param PackageInterface $package
	 */
	public function install(InstalledRepositoryInterface $repo, PackageInterface $package) {
		parent::install($repo, $package);

		$strPackageName = $package->getName();

		if (self::startsWith($strPackageName, 'qcubed/plugin')) {
			$this->composerPluginInstall($package);
		}
		elseif (self::startsWith($strPackageName, 'qcubed/qcubed')) {
			// updating the framework
			$this->composerFrameworkInstall($package);
		}

	}

	/**
	 * Move files out of the vendor directory and into the project directory that are in the plugin's install directory.
	 * @param $strPackageName
	 */
	protected function composerPluginInstall ($package) {
		require_once(($this->vendorDir ? $this->vendorDir . '/' : '') . 'qcubed/qcubed/qcubed.inc.php');	// get the configuration options so we can know where to put the plugin files

		// recursively copy the contents of the install subdirectory in the plugin.
		$strPluginDir = $this->getPackageBasePath($package);
		$strInstallDir = $strPluginDir . '/install';
		$strDestDir = __INCLUDES__ . '/plugins';

		$this->filesystem->ensureDirectoryExists($strDestDir);
		$this->io->write('Copying files from ' . $strInstallDir . ' to ' . $strDestDir);
		self::copy_dir($strInstallDir, $strDestDir);
	}

	protected function NormalizeNonPosixPath($s){
		return str_replace('\\', '/', $s);
	}

	/**
	 * First time installation of framework. For first-time installation, we create the project directory and modify
	 * the configuration file.
	 *
	 * @param $strPackageName
	 */
	protected function composerFrameworkInstall ($package) {
		$extra = $package->getExtra();

		// recursively copy the contents of the install directory, providing each file is not there.
		$strInstallDir = self::NormalizeNonPosixPath($this->getPackageBasePath($package)) . '/install/project';
		$strDestDir = ($this->vendorDir ? $this->vendorDir . '/' : '') . '../project'; // try to find the default project location
		$strDestDir = self::NormalizeNonPosixPath($strDestDir);

		$this->io->write('Copying files from ' . $strInstallDir . ' to ' . $strDestDir);
		self::copy_dir($strInstallDir, $strDestDir);

		// Make sure particular directories are writable by the web server. These are listed in the extra section of the composer.json file.
		// We are assuming that the first time installation is installed in a subdirectory of docroot.
		$strInstallDir = self::NormalizeNonPosixPath(realpath(dirname($strDestDir)));
		$strSubDirectory = '/' . basename($strInstallDir);
		$strDocRoot = self::NormalizeNonPosixPath(realpath($strInstallDir . '/../'));
		$strConfigDirectory = $strDestDir . '/includes/configuration';

		$this->io->write('Updating permissions');
		foreach ($extra['writePermission'] as $strDir) {
			$strTargetDir = $strInstallDir . '/' . $strDir;
			if(!file_exists($strTargetDir)){
				mkdir($strTargetDir, 0777, true);
			}
			chmod ($strTargetDir, 0777);
		}

		// write configuration.inc.php only if it does not exists
		if (!file_exists($strConfigDirectory . '/configuration.inc.php')) {
			// fix up the configuration file
			$strFile = file_get_contents($strConfigDirectory . '/configuration.inc.sample.php');
			if ($strFile) {
				$strFile = str_replace (['{docroot}', '{vd}', '{subdir}'], [$strDocRoot, '', $strSubDirectory], $strFile);
				file_put_contents($strConfigDirectory . '/configuration.inc.php', $strFile);
			}
		}
	}

	/**
	 * Respond to an update command.
	 *
	 * @param InstalledRepositoryInterface $repo
	 * @param PackageInterface $initial
	 * @param PackageInterface $target
	 */
	public function update(InstalledRepositoryInterface $repo, PackageInterface $initial, PackageInterface $target) {
		parent::install($repo, $initial, $target);

		$strPackageName = $target->getName();
		if (self::startsWith($strPackageName, 'qcubed/plugin')) {
			$this->composerPluginInstall($target);
		}
		elseif (self::startsWith($strPackageName, 'qcubed/qcubed')) {
			// updating the framework
			$this->composerFrameworkUpdate($target);
		}

	}

	/**
	 * Return true if the needle starts with the haystack.
	 *
	 * @param string $haystack
	 * @param string $needle
	 * @return bool
	 */
	protected static function startsWith($haystack, $needle) {
		// search backwards starting from haystack length characters from the end
		return $needle === "" || strrpos($haystack, $needle, -strlen($haystack)) !== FALSE;
	}

	/**
	 * Update a package. In particular, new install files will be moved to the correct location.
	 *
	 * @param $package
	 */
	protected function composerFrameworkUpdate ($package) {
		require_once(($this->vendorDir ? $this->vendorDir . '/' : '') . 'qcubed/qcubed/qcubed.inc.php');	// get the configuration options so we can know where to put the plugin files

		// recursively copy the contents of the install directory, providing each file is not there.
		$strInstallDir = $this->getPackageBasePath($package) . '/install/project';
		$strDestDir = __PROJECT__;

		// copy_dir will not overwrite files, but will add any new stub files
		$this->io->write('Copying files from ' . $strInstallDir . ' to ' . $strDestDir);
		self::copy_dir($strInstallDir, $strDestDir);
	}

	/**
	 * Uninstalls a plugin if requested.
	 *
	 * @param InstalledRepositoryInterface $repo
	 * @param PackageInterface $package
	 */
	public function uninstall(InstalledRepositoryInterface $repo, PackageInterface $package)
	{
		$strPackageName = $package->getName();
		if (self::startsWith($strPackageName, 'qcubed/plugin')) {
			$this->composerPluginUninstall($package);
		}
		parent::uninstall ($repo, $package);
	}

	/**
	 * Delete the given plugin.
	 *
	 * @param PackageInterface $package
	 */
	public function composerPluginUninstall (PackageInterface $package) {
		require_once(($this->vendorDir ? $this->vendorDir . '/' : '') . 'qcubed/qcubed/qcubed.inc.php');	// get the configuration options so we can know where the plugin files are

		// recursively delete the contents of the install directory, providing each file is there.
		$strPluginDir = $this->getPackageBasePath($package) . '/install';
		$strDestDir = __INCLUDES__ . '/plugins';

		$this->io->write('Removing files from ' . $strPluginDir);
		self::remove_matching_dir($strPluginDir, $strDestDir);
	}

	/**
	 * Copy the contents of the source directory into the destination directory, creating the destination directory
	 * if it does not exist. If the destination file exists, it will NOT overwrite the file.
	 *
	 * @param string $src	source directory
	 * @param string $dst	destination directory
	 */
	protected static function copy_dir($src,$dst) {
		if (!$src || !is_dir($src)) {
			return;
		}
		$dir = opendir($src);

		if (!file_exists($dst)) {
			mkdir($dst);
		}
		while(false !== ( $file = readdir($dir)) ) {
			if (( $file != '.' ) && ( $file != '..' )) {
				if ( is_dir($src . '/' . $file) ) {
					self::copy_dir($src . '/' . $file,$dst . '/' . $file);
				}
				else {
					if (!file_exists($dst . '/' . $file)) {
						copy($src . '/' . $file,$dst . '/' . $file);
					}
				}
			}
		}
		closedir($dir);
	}

	/**
	 * Remove the files in the destination directory whose names match the files in the source directory.
	 *
	 * @param string $src	Source directory
	 * @param string $dst	Destination directory
	 */
	protected static function remove_matching_dir($src,$dst) {
		if (!$dst || !$src || !is_dir($src) || !is_dir($dst)) return;	// prevent deleting an entire disk by accidentally calling this with an empty string!
		$dir = opendir($src);

		while(false !== ( $file = readdir($dir)) ) {
			if (( $file != '.' ) && ( $file != '..' )) {
				if ( is_dir($src . '/' . $file) ) {
					self::remove_dir($dst . '/' . $file);
				}
				else {
					if (file_exists($dst . '/' . $file)) {
						unlink($dst . '/' . $file);
					}
				}
			}
		}
		closedir($dir);
	}

	/**
	 * Delete a directory and all of its contents.
	 *
	 * @param string $dst Directory to delete
	 */
	protected static function remove_dir($dst) {
		if (!$dst || !is_dir($dst)) return;	// prevent deleting an entire disk by accidentally calling this with an empty string!
		$dir = opendir($dst);

		while(false !== ( $file = readdir($dir)) ) {
			if (( $file != '.' ) && ( $file != '..' )) {
				if ( is_dir($dst . '/' . $file) ) {
					self::remove_dir($dst . '/' . $file);
				}
				else {
					unlink($dst . '/' . $file);
				}
			}
		}
		closedir($dir);
		rmdir($dst);
	}

}


<?php

namespace DDDominio\EventSourcing\Snapshotting\Vendor;

use DDDominio\EventSourcing\EventStore\InitializableInterface;
use DDDominio\EventSourcing\Snapshotting\SnapshotInterface;
use DDDominio\EventSourcing\Snapshotting\SnapshotStoreInterface;
use DDDominio\EventSourcing\Serialization\SerializerInterface;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Schema\Schema;

class DoctrineDbalSnapshotStore implements SnapshotStoreInterface, InitializableInterface
{
    const SNAPSHOTS_TABLE = 'snapshots';

    /**
     * @var Connection
     */
    private $connection;

    /**
     * @var SerializerInterface
     */
    private $serializer;

    /**
     * @param Connection $connection
     * @param SerializerInterface $serializer
     */
    public function __construct(Connection $connection, SerializerInterface $serializer)
    {
        $this->connection = $connection;
        $this->serializer = $serializer;
    }

    /**
     * @param SnapshotInterface $snapshot
     */
    public function addSnapshot($snapshot)
    {
        $stmt = $this->connection
            ->prepare('INSERT INTO snapshots (aggregate_type, aggregate_id, type, version, snapshot) VALUES (:aggregateType, :aggregateId, :type, :version, :snapshot)');
        $stmt->bindValue(':aggregateType', $snapshot->aggregateClass());
        $stmt->bindValue(':aggregateId', $snapshot->aggregateId());
        $stmt->bindValue(':type', get_class($snapshot));
        $stmt->bindValue(':version', $snapshot->version());
        $stmt->bindValue(':snapshot', $this->serializer->serialize($snapshot));
        $stmt->execute();
    }

    /**
     * @param string $aggregateClass
     * @param string $aggregateId
     * @return SnapshotInterface|null
     */
    public function findLastSnapshot($aggregateClass, $aggregateId)
    {
        $stmt = $this->connection
            ->prepare('SELECT type, snapshot FROM snapshots WHERE aggregate_type = :aggregateType AND aggregate_id = :aggregateId ORDER BY id DESC LIMIT 1');
        $stmt->bindValue(':aggregateType', $aggregateClass);
        $stmt->bindValue(':aggregateId', $aggregateId);
        $stmt->execute();
        $snapshot = $stmt->fetch();
        return $snapshot ? $this->serializer->deserialize($snapshot['snapshot'], $snapshot['type']) : null;
    }

    /**
     * @param string $aggregateClass
     * @param string $aggregateId
     * @param int $version
     * @return SnapshotInterface|null
     */
    public function findNearestSnapshotToVersion($aggregateClass, $aggregateId, $version)
    {
        $stmt = $this->connection
            ->prepare('SELECT type, snapshot FROM snapshots WHERE aggregate_type = :aggregateType AND aggregate_id = :aggregateId AND version <= :version ORDER BY version DESC LIMIT 1');
        $stmt->bindValue(':aggregateType', $aggregateClass);
        $stmt->bindValue(':aggregateId', $aggregateId);
        $stmt->bindValue(':version', $version);
        $stmt->execute();
        $snapshot = $stmt->fetch();
        return $snapshot ? $this->serializer->deserialize($snapshot['snapshot'], $snapshot['type']) : null;
    }

    /**
     * Initialize the Event Store
     */
    public function initialize()
    {
        $schema = new Schema();

        $snapshotsTable = $schema->createTable(self::SNAPSHOTS_TABLE);
        $snapshotsTable->addColumn('id', 'integer', ['autoincrement' => true]);
        $snapshotsTable->addColumn('aggregate_type', 'string');
        $snapshotsTable->addColumn('aggregate_id', 'string');
        $snapshotsTable->addColumn('type', 'string');
        $snapshotsTable->addColumn('version', 'integer');
        $snapshotsTable->addColumn('snapshot', 'text');
        $snapshotsTable->setPrimaryKey(['id']);

        $queries = $schema->toSql($this->connection->getDatabasePlatform());
        $this->connection->transactional(function(Connection $connection) use ($queries) {
            foreach ($queries as $query) {
                $connection->exec($query);
            }
        });
    }

    /**
     * Check if the Event Store has been initialized
     *
     * @return bool
     */
    public function initialized()
    {
        return $this->connection->getSchemaManager()->tablesExist([self::SNAPSHOTS_TABLE]);
    }
}


<?php

namespace Clio\Widgets\Tables;

use ANSI\Color\Color;
use ANSI\Color\ColorInterface;
use Clio\Styling\Markup\Definition;
use Clio\Styling\Markup\Justification;

/**
 * This class is part of the Clio Open Source project, Clio.1happyplace.com
 * Copyright, Katie Ayres, katie@1happyplace.com
 *
 * Available through the MIT license
 * @license MIT
 *
 * The Column class represents one column in a table.  It keeps track of whether
 * the width is static or calculated (and the corresponding max width), left
 * and right padding, justification and colors.
 *
 */

class Column
{

    /**
     * The text for the first line with headers
     * @var string | null
     */
    protected $headerText = null;

    /**
     * Whether the width is based on the widest data
     * @var bool
     */
    private $calculateWidth = true;

    /**
     * The width (in characters) of the column, including any padding
     *
     * @var integer | null - null indicates it should be calculated based on the data
     */
    protected $width = null;

    /**
     * If the width is calculated, then optional value to ensure the calculated width
     * never goes wider than this
     *
     * @var integer | null
     */
    protected $maximumWidth = null;

    /**
     * The left padding (if desired), this will be subtracted from the width
     *
     * @var int
     */
    protected $leftPadding = 0;

    /**
     * The right padding for the table (number of empty spaces), this will be subtracted
     * from the $width
     *
     * @var int
     */
    protected $rightPadding = 3;

    /**
     * The justification of the column
     * @var int - Justification::LEFT, ::RIGHT, ::CENTER
     */
    protected $justification = Justification::LEFT;

    /**
     * The text color of the column
     *
     * @var Color | null
     */
    protected $textColor = null;

    /**
     * The fill color of the column
     *
     * @var Color | null
     */
    protected $fillColor = null;

    /**
     * Column constructor.
     *
     * @param string|null $headerText
     * @param int|null $width - set to null if it should be based on the widest text in the column, or set it to
     * an integer to set a static width.  This width will include the left and right padding as well. So if
     * width is set to 10 and right padding is at the default 3, the text will have 7 spaces of space.
     */
    public function __construct($headerText = null, $width = null)
    {
        // save the header Text
        $this->headerText = $headerText;

        // if the width is defined, then it will not be calculated
        if ($width) {

            // save the width
            $this->width = $width;

            // indicate the width is not calculated
            $this->calculateWidth = false;
        }

    }

    /////////////////////////////////////////////////////////////////////////////////////
    //                               Setters and Getters                               //
    /////////////////////////////////////////////////////////////////////////////////////

    /**
     * Setter for the header text
     *
     * @param null|string $headerText
     */
    public function setHeaderText($headerText)
    {
        $this->headerText = $headerText;
    }

    /**
     * Getter for the header text
     * @return null|string
     */
    public function getHeaderText()
    {
        return $this->headerText;
    }

    /**
     * Whether the header text was defined
     *
     * @return bool
     */
    public function hasHeaderText() {

        // return true if it is not null
        return !is_null($this->headerText);
    }

    /**
     * Setter for width
     * @param int|null $width
     *
     * @return $this
     */
    public function setWidth($width)
    {
        // if the width was set
        if ($width) {

            // turn off the calculated width flag
            $this->calculateWidth = false;

            // save the desired static width
            $this->width = $width;

        // width is not specified
        } else {

            // turn on the calculated with flag
            $this->calculateWidth = true;

            // clear out the width
            $this->width = null;

        }

        // chaining
        return $this;
    }

    /**
     * Getter for width
     *
     * @return int|null
     */
    public function getWidth()
    {
        return $this->width;
    }

    /**
     * Getter for calculated width flag
     *
     * @return boolean
     */
    public function isCalculateWidth()
    {
        return $this->calculateWidth;
    }

    /**
     * Setter for maximum width (used with calculated fields)
     *
     * @param null $maximumWidth
     *
     * @return $this
     */
    public function setMaximumWidth($maximumWidth)
    {
        $this->maximumWidth = $maximumWidth;

        // chaining
        return $this;
    }

    /**
     * Getter for maximum width
     *
     * @return int|null
     */
    public function getMaximumWidth()
    {
        return $this->maximumWidth;
    }

    /**
     * Setter for left padding
     *
     * @param int $leftPadding
     * @return $this
     */
    public function setLeftPadding($leftPadding)
    {
        $this->leftPadding = $leftPadding;

        // chaining
        return $this;
    }

    /**
     * Getter for left padding
     *
     * @return int
     */
    public function getLeftPadding()
    {
        return $this->leftPadding;
    }

    /**
     * Setter for right padding
     *
     * @param int $rightPadding
     * @return $this
     */
    public function setRightPadding($rightPadding)
    {
        $this->rightPadding = $rightPadding;

        // chaining
        return $this;
    }

    /**
     * Getter for right padding
     *
     * @return int
     */
    public function getRightPadding()
    {
        return $this->rightPadding;
    }

    /**
     * Setter for justification
     * @param int $justification
     *
     * @return $this
     */
    public function setJustification($justification)
    {
        $this->justification = $justification;

        // chaining
        return $this;
    }

    /**
     * Getter for justification
     *
     * @return int - Justification::LEFT, ::CENTER, ::RIGHT
     */
    public function getJustification()
    {
        return $this->justification;
    }

    /**
     * Set the colors of a column
     *
     * @param null | int | string | ColorInterface $textColor - any valid setting for the Color constructor
     * @param null | int | string | ColorInterface $fillColor
     * @return $this
     */
    public function setColors($textColor = null, $fillColor = null) {

        // if the text color was specified
        if ($textColor) {

            // store it
            $this->textColor = new Color($textColor);

        // not set
        } else {

            // clear out the text color
            $this->textColor = null;
        }

        // if the fill color was specified
        if ($fillColor) {

            // store it
            $this->fillColor = new Color($fillColor);

        // not set
        } else {

            // clear out the text color
            $this->fillColor = null;
        }

        // chaining
        return $this;

    }

    /**
     * Getter for text color
     *
     * @return Color|null
     */
    public function getTextColor()
    {
        return $this->textColor;
    }

    /**
     * Getter for fill color
     *
     * @return Color|null
     */
    public function getFillColor()
    {
        return $this->fillColor;
    }

    /**
     * Calculate the text area by taking the width and subtracting any padding
     * @return int
     */
    protected function getTextArea() {

        // initialize the return value
        $textArea = 0;

        // if the width has a value (if it is calculated, it may not)
        if ($this->width) {
            // subtract the padding from the width
            $textArea = $this->width - $this->rightPadding - $this->leftPadding;
        }

        // if it goes below zero
        if ($textArea < 0) {

            // make it zero
            $textArea = 0;
        }

        return $textArea;
    }

    /////////////////////////////////////////////////////////////////////////////////////////
    //                                Public functions                                     //
    /////////////////////////////////////////////////////////////////////////////////////////

    /**
     * Run the data through and make the width as wide as the widest text
     *
     * @param array $data
     * @param Definition $markupDefinition
     */
    public function calculateWidth($data, $markupDefinition = null) {

        // if the width is not calculated, or the data is invalid
        if (($this->calculateWidth === false) || !is_array($data) || (count($data) === 0)) {

            // nothing to do, it is not a calculated width
            return;
        }

        // initialize the array of sizes of each string
        $sizes = [];

        // reset the width
        $this->width = null;

        // if the header text was specified
        if ($this->headerText) {

            // add the length to the array of string lengths
            $sizes[] = strlen($this->headerText);
        }

        // go through and create an array sizes
        for ($i=0; $i<count($data); ++$i) {

            // get the text (make it into a string)
            $text = strval($data[$i]);

            // if the markup definition was sent in
            if ($markupDefinition) {

                // strip out any markup symbols
                $text = $markupDefinition->stripMarkupSymbols($text);
            }

            // add the size of this text to the array of sizes
            $sizes[] = strlen($text);
        }

        // now get the highest value in the array of sizes and add the padding
        $widestText = max($sizes) + $this->rightPadding + $this->leftPadding;

        // if the maximum width is defined and the width hasn't already maxed out
        if ($this->maximumWidth) {

            // check to ensure the text length is less than or equal to the maximum width
            if ($widestText <= $this->maximumWidth) {

                // the width is now the newest text length
                $this->width = $widestText;

            } else {
                // set the width to the maximum width (text will be truncated)
                $this->width = $this->maximumWidth;
            }

        // there is no maximum width
        } else {

            // just set the width to that widest text
            $this->width = $widestText;
        }

    }

    /**
     * Justify text
     *
     * @param string $text - the text to justify
     * @param Definition $markupDefinition
     *
     * @return string
     */
    public function justify($text, $markupDefinition) {

        // if the width is null
        if ((is_null($this->width)) || ($this->getTextArea() === 0)) {

            // just return the text, something was wrong
            return "";

        }

        // ask the markup definition object to do the justification so all
        // the markup text does not affect the justification
        $justifiedText = $markupDefinition->justify($text, $this->justification, $this->getTextArea());

        // put the left pad and right padding around the justified text
        return $markupDefinition->pad($justifiedText, $this->leftPadding, $this->rightPadding);

    }

}


<?php namespace Kharanenka\Scope;

use Carbon\Carbon;

/**
 * Class DateField
 * @package Kharanenka\Scope
 * @author Andrey Kharanenka, kharanenka@gmail.com
 *
 *  @method static $this getByDateValue(string $sFieldName, string $sDate, string $sCondition)
 */
trait DateField {

    /**
     * Get by date
     * @param \Illuminate\Database\Eloquent\Builder|\October\Rain\Database\Builder $obQuery
     * @param string $sDate
     * @param string $sField
     * @param string $sCondition
     * @return \Illuminate\Database\Eloquent\Builder|\October\Rain\Database\Builder;
     */
    public function scopeGetByDateValue($obQuery, $sField, $sDate, $sCondition = '=')
    {

        if(empty($sDate) || empty($sCondition) || empty($sField)) {
            return $obQuery;
        }

        return $obQuery->where($sField, $sCondition, $sDate);
    }

    /**
     * Get date value
     * @param string $sFieldName
     * @param string $sFormat
     * @return null|string
     */
    public function getDateValue($sFieldName, $sFormat = 'd.m.Y')
    {
        if(empty($sFieldName) || empty($sFormat)) {
            return null;
        }

        /** @var Carbon $obDate */
        $obDate = $this->$sFieldName;
        if(empty($obDate) || !$obDate instanceof Carbon) {
            return $obDate;
        }

        return $obDate->format($sFormat);
    }
}


<?php

namespace Addons\Core\Models;

use Illuminate\Support\Str;

trait PolyfillTrait{

	protected $originalCastTypes = ['int','integer','real','float','double','string','bool','boolean','object','array','json','collection','date','datetime','timestamp', 'custom_datetime'];

	public static function insertUpdate(array $attributes)
	{
		$model = new static;
		$model->fill($attributes);

		if ($model->usesTimestamps())
			$model->updateTimestamps();

		$attributes = $model->getAttributes();

		$query = $model->newBaseQueryBuilder();
		$processor = $query->getProcessor();
		$grammar = $query->getGrammar();

		$table = $grammar->wrapTable($model->getTable());
		$keyName = $model->getKeyName();
		$columns = $grammar->columnize(array_keys($attributes));
		$insertValues = $grammar->parameterize($attributes);

		$updateValues = [];

		if ($model->getKeyName() !== null)
			$updateValues[] = "{$grammar->wrap($keyName)} = LAST_INSERT_ID({$keyName})";

		foreach ($attributes as $k => $v)
			$updateValues[] = sprintf("%s = '%s'", $grammar->wrap($k), $v);

		$updateValues = join(',', $updateValues);

		$sql = "insert into {$table} ({$columns}) values ({$insertValues}) on duplicate key update {$updateValues}";

		$id = $processor->processInsertGetId($query, $sql, array_values($attributes));

		$model->setAttribute($keyName, $id);

		return $model;
	}

	/**
	 * Cast an attribute to a native PHP type.
	 *
	 * @param  string  $key
	 * @param  mixed  $value
	 * @return mixed
	 */
	protected function castAttribute($key, $value)
	{
		$type = $this->getCastType($key);
		if (!empty($type) && !in_array($type, $this->originalCastTypes))
		{
			$method = 'as'.Str::studly($type);
			if (method_exists($this, $method))
				return call_user_func([$this, $method], $value, $key, $type);
		}
		return parent::castAttribute($key, $value);
	}

	/**
	 * Convert the model's attributes to an array.
	 *
	 * @return array
	 */
	public function attributesToArray()
	{
		$data = parent::attributesToArray();
		foreach ($this->getCasts() as $key => $type)
		{
			if (!empty($type) && !in_array($type, $this->originalCastTypes) && isset($data[$key]))
			{
				$method = Str::camel($type).'ToArray';
				if (method_exists($this, $method))
					$data[$key] = call_user_func([$this, $method], $data[$key], $key, $type);
			}
		}
		return $data;
	}

	/**
	 * Set a given attribute on the model.
	 *
	 * @param  string  $key
	 * @param  mixed  $value
	 * @return $this
	 */
	public function setAttribute($key, $value)
	{
		$type = $this->hasCast($key) ? $this->getCastType($key) : null;
		if (!empty($type) && !$this->hasSetMutator($key)  && !in_array($type, $this->originalCastTypes))
		{
			$method = 'from'.Str::studly($type);
			if (method_exists($this, $method))
				$value = call_user_func([$this, $method], $value, $key, $type);
		}
		return parent::setAttribute($key, $value);
	}

}


<?php

namespace Addons\Core\Tools;

use Addons\Core\Tools\TreeNode;
use Illuminate\Support\Collection;

class TreeCollection extends Collection {

	protected $root;

	public function search($key, $defaultValue = null, $searchField = 'name')
	{
		return $this->offsetExists($key) ? $this->offsetGet($key) :
			(empty($this->root) ? value($defaultValue) : $this->root->search($key, $defaultValue, $searchField));
	}

	public static function make($tree = [])
	{
		$self = new static();

		$node = new TreeNode();
		$self->setRoot($node);
		$self->makeNodes($tree, $node);

		return $self;
	}

	public function makeNodes(array $tree, TreeNode $node)
	{
		$prev = null;
		foreach($tree as $key => $value)
		{
			$children = $value['children'] ?? [];

			$n = $node->childSet($key, $value);
			$n->parent($node)->prev($prev);

			$this[$key] = $n;
			!empty($prev) && $prev->next($n);
			$prev = $n;

			if (!empty($children))
				$this->makeNodes($children, $node->childGet($key));
		}
	}

	public function setRoot(TreeNode $node)
	{
		$this->root = $node;
	}

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

	/**
	 * Set the item at a given offset.
	 *
	 * @param  mixed  $key
	 * @param  mixed  $value
	 * @return void
	 */
	public function offsetSet($key, $value)
	{
		$value = $value instanceof TreeNode ? $value : new TreeNode($value);

		if (is_null($key)) {
			$this->items[] = $value;
		} else {
			$this->items[$key] = $value;
		}
	}

}


<?php declare(strict_types=1);
namespace Imatic\Bundle\ViewBundle\Templating\Helper\Action;

use Imatic\Bundle\ViewBundle\Templating\Helper\Html\HtmlElement;
use Symfony\Component\PropertyAccess\PropertyAccess;
use Symfony\Component\PropertyAccess\PropertyAccessor;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;

class ActionHelper
{
    /**
     * @var UrlGeneratorInterface
     */
    private $urlGenerator;

    /**
     * @var PropertyAccessor
     */
    private $accessor;

    public function __construct(UrlGeneratorInterface $urlGenerator)
    {
        $this->urlGenerator = $urlGenerator;
        $this->accessor = PropertyAccess::createPropertyAccessor();
    }

    /**
     * @param ActionOptions|array $actionOptions
     * @param array|null          $contextOptions
     *
     * @return HtmlElement
     */
    public function create($actionOptions, $contextOptions = null)
    {
        if (!($actionOptions instanceof ActionOptions)) {
            $actionOptions = new ActionOptions($actionOptions);
        }
        if (\is_null($contextOptions) || !\is_array($contextOptions)) {
            $contextOptions = [];
        }

        $url = $this->getActionUrl($actionOptions, $contextOptions);

        if ('input' === $actionOptions->tag) {
            $element = new HtmlElement('input', null, $actionOptions->attrs + [
                'type' => 'submit',
                'formaction' => $url ? $url : null,
                'value' => $actionOptions->label,
                'name' => $actionOptions->name,
            ]);
        } else {
            $element = new HtmlElement('a', $actionOptions->label, $actionOptions->attrs + ['href' => $url]);
        }

        foreach ($actionOptions->data as $dataKey => $dataValue) {
            $element->data()->set($dataKey, $dataValue);
        }
        $element->classes()->add($actionOptions->class);

        return $element;
    }

    /**
     * @param object|array $object
     * @param array        $parameters
     *
     * @return array
     */
    public function applyParameters($object, array $parameters)
    {
        foreach ($parameters as $name => $value) {
            if (0 === \strpos($value, '#')) {
                $key = \substr($value, 1);
                $value = $this->accessor->getValue($object, $key);
                $parameters[$name] = $value;
            }
        }

        return $parameters;
    }

    /**
     * @param ActionOptions|array $action
     *
     * @return ActionOptions
     */
    public function getActionOptions($action)
    {
        if (!($action instanceof ActionOptions)) {
            return new ActionOptions($action);
        }

        return $action;
    }

    /**
     * @param ActionOptions $actionOptions
     * @param array         $contextOptions
     *
     * @return string
     */
    public function getActionUrl(ActionOptions $actionOptions, array $contextOptions)
    {
        $url = $actionOptions->url;
        if (!$url && $actionOptions->route) {
            $routeParameters = $actionOptions->routeParams;
            if (\array_key_exists('item', $contextOptions)) {
                $routeParameters = $this->applyParameters($contextOptions['item'], $routeParameters);
            }
            $url = $this->urlGenerator->generate($actionOptions->route, $routeParameters);
        }

        return $url;
    }
}