<?php
/**
 * Zend Framework
 *
 * LICENSE
 *
 * This source file is subject to the new BSD license that is bundled
 * with this package in the file LICENSE.txt.
 * It is also available through the world-wide-web at this URL:
 * http://framework.zend.com/license/new-bsd
 * If you did not receive a copy of the license and are unable to
 * obtain it through the world-wide-web, please send an email
 * to license@zend.com so we can send you a copy immediately.
 *
 * @category   Zend
 * @package    Zend_Filter
 * @copyright  Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
 * @license    http://framework.zend.com/license/new-bsd     New BSD License
 * @version    $Id: Alpha.php 24593 2012-01-05 20:35:02Z matthew $
 */

/**
 * @see Zend_Filter_Interface
 */

/**
 * @see Zend_Locale
 */

/**
 * @category   Zend
 * @package    Zend_Filter
 * @copyright  Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
 * @license    http://framework.zend.com/license/new-bsd     New BSD License
 */
class Zend_Filter_Alpha implements Zend_Filter_Interface
{
    /**
     * Whether to allow white space characters; off by default
     *
     * @var boolean
     * @deprecated
     */
    public $allowWhiteSpace;

    /**
     * Is PCRE is compiled with UTF-8 and Unicode support
     *
     * @var mixed
     **/
    protected static $_unicodeEnabled;

    /**
     * Locale in browser.
     *
     * @var Zend_Locale object
     */
    protected $_locale;

    /**
     * The Alphabet means english alphabet.
     *
     * @var boolean
     */
    protected static $_meansEnglishAlphabet;

    /**
     * Sets default option values for this instance
     *
     * @param  boolean $allowWhiteSpace
     * @return void
     */
    public function __construct($allowWhiteSpace = false)
    {
        if ($allowWhiteSpace instanceof Zend_Config) {
            $allowWhiteSpace = $allowWhiteSpace->toArray();
        } else if (is_array($allowWhiteSpace)) {
            if (array_key_exists('allowwhitespace', $allowWhiteSpace)) {
                $allowWhiteSpace = $allowWhiteSpace['allowwhitespace'];
            } else {
                $allowWhiteSpace = false;
            }
        }

        $this->allowWhiteSpace = (boolean) $allowWhiteSpace;
        if (null === self::$_unicodeEnabled) {
            self::$_unicodeEnabled = (@preg_match('/\pL/u', 'a')) ? true : false;
        }

        if (null === self::$_meansEnglishAlphabet) {
            $this->_locale = new Zend_Locale('auto');
            self::$_meansEnglishAlphabet = in_array($this->_locale->getLanguage(),
                                                    array('ja', 'ko', 'zh')
                                                    );
        }

    }

    /**
     * Returns the allowWhiteSpace option
     *
     * @return boolean
     */
    public function getAllowWhiteSpace()
    {
        return $this->allowWhiteSpace;
    }

    /**
     * Sets the allowWhiteSpace option
     *
     * @param boolean $allowWhiteSpace
     * @return Zend_Filter_Alpha Provides a fluent interface
     */
    public function setAllowWhiteSpace($allowWhiteSpace)
    {
        $this->allowWhiteSpace = (boolean) $allowWhiteSpace;
        return $this;
    }

    /**
     * Defined by Zend_Filter_Interface
     *
     * Returns the string $value, removing all but alphabetic characters
     *
     * @param  string $value
     * @return string
     */
    public function filter($value)
    {
        $whiteSpace = $this->allowWhiteSpace ? '\s' : '';
        if (!self::$_unicodeEnabled) {
            // POSIX named classes are not supported, use alternative a-zA-Z match
            $pattern = '/[^a-zA-Z' . $whiteSpace . ']/';
        } else if (self::$_meansEnglishAlphabet) {
            //The Alphabet means english alphabet.
            $pattern = '/[^a-zA-Z'  . $whiteSpace . ']/u';
        } else {
            //The Alphabet means each language's alphabet.
            $pattern = '/[^\p{L}' . $whiteSpace . ']/u';
        }

        return preg_replace($pattern, '', (string) $value);
    }
}


<?php namespace Ordercloud\Entities\Orders;

use JsonSerializable;
use Ordercloud\Entities\Organisations\OrganisationAddress;
use Ordercloud\Entities\Organisations\OrganisationShort;

class OrderItemMerchant extends OrganisationShort implements JsonSerializable
{
    /**
     * @var OrganisationAddress
     */
    private $address;
    /** @var string */
    private $contactNumber;

    public function __construct($id, $name, $code, OrganisationAddress $address = null, $contactNumber)
    {
        parent::__construct($id, $name, $code);
        $this->address = $address;
        $this->contactNumber = $contactNumber;
    }

    /**
     * @return OrganisationAddress|null
     */
    public function getAddress()
    {
        return $this->address;
    }

    /**
     * @return string
     */
    public function getContactNumber()
    {
        return $this->contactNumber;
    }

    /**
     * Specify data which should be serialized to JSON
     */
    public function jsonSerialize()
    {
        $json = parent::jsonSerialize();

        $json['address'] = $this->getAddress();
        $json['contactNumber'] = $this->getContactNumber();

        return $json;
    }
}


<?php

/**
 * Jin Framework
 * Diatem
 */

namespace Jin2\Form\Validators;

use Jin2\Language\Translation;

/**
 * Validateur : teste si une valeur est un email valide
 */
class IsDate extends AbstractValidator
{

  /**
   * Constructeur
   *
   * @param  array $args          Tableau d'arguments array('arg1'=>'val1','arg2'=>'val2)
   * @throws \Exception
   */
  public function __construct($args)
  {
    return parent::__construct($args, array('format'));
  }

  /**
   * Implémente la fonction AbstractValidator::getType()
   *
   * @return string
   */
  public static function getType()
  {
    return 'isdate';
  }

  /**
   * Teste la validité
   *
   * @param mixed $value Valeur à tester
   * @return boolean
   */
  public function isValid($value)
  {
    parent::resetErrors();
    if (empty($value)) {
      return true;
    }

    $format = $this->getArgValue('format');
    $date = \DateTime::createFromFormat($format, $value);
    $res = $date && $date->format($format) == $value;

    if (!$res) {
      $eMsg = Translation::get('validatorerror_isdate');
      $eMsg = str_replace('%format%', parent::getArgValue('format'), $eMsg);
      parent::addError($eMsg);
    }
    return $res;
  }

}


<?php

namespace Bcismariu\Commons\Descendable;

/**
 * handles multidimensional arrays, chained object properties
 * or a mix of the two
 */
class Descendable
{

    protected $separator = '.';
    protected $container = '';

    public function __construct($container)
    {
        $this->container = $container;
    }

    public function setKeySeparator($separator)
    {
        $this->separator = $separator;
    }

    /**
     * Get multidimenional array value
     * @param string $composite_key concatenated keys with key separator
     * @param string $default_value to return in case that one key from chain is undefined
     */
    public function get($composite_key, $default_value = null)
    {
        $array_keys = explode($this->separator, $composite_key);
        $container = $this->container;

        foreach ($array_keys as $key) {
            if (!$this->hasChild($container, $key)) {
                return $default_value;
            }
            $container = $this->getChild($container, $key);
        }
        return $container;
    }

    /**
     * Check if the last key from chain is defined
     * @param string $composite_key concatenated keys with key separator
     * @return Boolean
     */
    public function has($composite_key)
    {
        $array_keys = explode($this->separator, $composite_key);
        $container = $this->container;

        foreach ($array_keys as $key) {
            if (!$this->hasChild($container, $key)) {
                return false;
            }
            $container = $this->getChild($container, $key);
        }
        return true;
    }

    protected function hasChild($container, $key)
    {
        if (is_array($container) && (array_key_exists($key, $container))) {
            return true;
        }
        if (is_object($container) && (property_exists($container, $key))) {
            return true;
        }
        return false;
    }

    protected function getChild($container, $key)
    {
        if (is_array($container) && (array_key_exists($key, $container))) {
            return $container[$key];
        }
        if (is_object($container) && (property_exists($container, $key))) {
            return $container->$key;
        }
        return null;
    }
}


<?php
/**
 * Modify artisan to seed after refresh in tests
 */
declare(strict_types=1);

namespace AaronSaray\LaravelTestHelpers;

/**
 * Trait SeedAfterRefresh
 * @package AaronSaray\LaravelTestHelpers
 */
trait SeedAfterRefresh
{
    /**
     * Overwriting the artisan command for a specific reason:
     *
     * When we use the database command, it tries to run migrate fresh - but it gives no option to seed
     * I want mine to seed as well before we start transactions
     *
     * @param string $command
     * @param array $parameters
     * @return \Illuminate\Foundation\Testing\PendingCommand|int
     */
    public function artisan($command, $parameters = [])
    {
        if ($command === 'migrate:fresh') {
            $parameters['--seed'] = true;
        }

        return parent::artisan($command, $parameters);
    }
}


<?php

/*
 * This file is part of the Snide monitoring package.
 *
 * (c) Pascal DENIS <pascal.denis.75@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Snide\Monitoring\Manager;

use Snide\Monitoring\Loader\TestLoaderInterface;
use Snide\Monitoring\Model\Application;
use Snide\Monitoring\Repository\ApplicationRepositoryInterface;

/**
 * Class ApplicationManager
 *
 * @author Pascal DENIS <pascal.denis.75@gmail.com>
 */
class ApplicationManager implements ApplicationManagerInterface
{
    /**
     * Application repository
     *
     * @var ApplicationRepositoryInterface
     */
    protected $repository;
    /**
     * Application class
     *
     * @var string
     */
    protected $class;
    /**
     * Test loader (Loader for application tests)
     *
     * @var TestLoaderInterface
     */
    protected $testLoader;

    /**
     * Constructor
     *
     * @param ApplicationRepositoryInterface $repository Application repository
     * @param $class
     * @param \Snide\Monitoring\Loader\TestLoaderInterface $testLoader Application test loader
     */
    public function __construct(ApplicationRepositoryInterface $repository, $class, TestLoaderInterface $testLoader)
    {
        $this->repository = $repository;
        $this->class = $class;
        $this->testLoader = $testLoader;
    }

    /**
     * Create and save an application
     *
     * @param Application $application
     */
    public function create(Application $application)
    {
        $this->repository->create($application);
    }

    /**
     * Delete an application
     *
     * @param \Snide\Monitoring\Model\Application $application
     */
    public function delete(Application $application)
    {
        $this->repository->delete($application);
    }

    /**
     * Find an application
     *
     * @param string $id App ID
     * @return Application
     */
    public function find($id)
    {
        $application = $this->repository->find($id);
        if (null == $application) {
            return null;
        }
        // Load tests
        $this->testLoader->loadByApplication($application);

        return $application;
    }

    /**
     * Find all applications
     *
     * @return array
     */
    public function findAll()
    {
        $applications = array();
        foreach ($this->repository->findAll() as $application) {
            // Load tests
            $this->testLoader->loadByApplication($application);
            $applications[] = $application;
        }

        return $applications;
    }

    /**
     * Update an application
     *
     * @param \Snide\Monitoring\Model\Application $application
     */
    public function update(Application $application)
    {
        $this->repository->update($application);
    }

    /**
     * Create an application instance
     *
     * @return Application
     */
    public function createNew()
    {
        $class = $this->class;

        return new $class;
    }

    /**
     * Getter testLoader
     *
     * @return \Snide\Monitoring\Loader\TestLoaderInterface
     */
    public function getTestLoader()
    {
        return $this->testLoader;
    }

    /**
     * Getter repository
     *
     * @return ApplicationRepositoryInterface
     */
    public function getRepository()
    {
        return $this->repository;
    }
}


<?php

namespace gries\NumberSystem;

use gries\NumberSystem\Exception\NumberParseException;

/**
 * Class NumberSystem
 *
 * This class represents a number system.
 * A number-system consist of a number-index and a base.
 *
 * For example the decimal number-system is base 10 with symbols ranging from 0 to 10
 *
 * You can use this class to represent "abstract" number systems such as ["tree", "stone", "water"]
 * which is a system base 3.
 *
 *
 * @package gries\NumberSystem
 */
class NumberSystem
{
    /**
     * The symbols used by this system.
     *
     * @var array
     */
    protected $symbolIndex;

    /**
     * The numeric base of this system.
     *
     * @var int
     */
    protected $base;

    /**
     * Defines which string is used to split numbers.
     *
     * @var string
     */
    protected $delimiter;

    /**
     * @param array $symbolIndex
     * @param null  $delimiter
     */
    public function __construct(array $symbolIndex = null, $delimiter = null)
    {
        if (null === $symbolIndex) {
            $symbolIndex = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9' ]; // dont use range() here because we dont want integers
        }

        $this->delimiter = $delimiter;
        $this->symbolIndex = $symbolIndex;
        $this->base = count($symbolIndex);
    }

    /**
     * Get the symbol index of this system.
     *
     * @return array
     */
    public function getSymbolIndex()
    {
        return $this->symbolIndex;
    }

    /**
     * Get the base of this NumberSystem.
     *
     * @return int
     */
    public function getBase()
    {
        return $this->base;
    }

    /**
     * Get the delimiter used by this system.
     *
     * @return string
     */
    public function getDelimiter()
    {

    }

    /**
     * Compare two number systems.
     *
     * @param NumberSystem $comparedNumberSystem
     *
     * @return bool
     */
    public function equals(NumberSystem $comparedNumberSystem)
    {
        if ($this->getBase() !== $comparedNumberSystem->getBase() ||
            $this->getSymbolIndex() !== $comparedNumberSystem->getSymbolIndex()
        ) {
            return false;
        }

        return true;
    }

    /**
     * Get the position of a symbol in this system.
     *
     * @param $symbol
     *
     * @return int
     */
    public function getSymbolPosition($symbol)
    {
        return array_search($symbol,  $this->getSymbolIndex(), true);
    }

    /**
     * Get the symbol that lays on a given position of this system.
     *
     * @param $position
     *
     * @return mixed
     */
    public function getSymbolForPosition($position)
    {
        return $this->getSymbolIndex()[$position];
    }

    /**
     * Get all digits of a given number according to
     * this number-system.
     *
     * @param Number $number
     *
     * @return array
     */
    public function getDigits(Number $number)
    {
        if (null === $this->delimiter) {
            return str_split($number->value());
        }

        return explode($this->delimiter, $number->value());
    }

    /**
     * Build a number based on given digits.
     *
     * @param array $digits
     *
     * @return Number
     */
    public function buildNumber(array $digits)
    {
        $newNumberString = implode($this->delimiter, $digits);

        return new Number($newNumberString, $this);
    }

    /**
     * Check if a given symbol exists in this NumberSystem.
     *
     * @param $symbol
     *
     * @return bool
     */
    protected function containsSymbol($symbol)
    {
        return false !== $this->getSymbolPosition($symbol);
    }

    /**
     * Check if a string value is a valid number of this system.
     *
     * @param string $value
     * @throws NumberParseException
     *
     * @return bool
     */
    public function validateNumberValue($value)
    {
        if (null === $this->delimiter) {
            $parts = str_split($value);
        } else {
            $parts = explode($this->delimiter, $value);
        }

        foreach ($parts as $numberSymbol) {
            if (!$this->containsSymbol($numberSymbol)) {
                throw new NumberParseException($value, $numberSymbol);
            }
        }

        return true;
    }
}


<?php
namespace Gosyl\CommonBundle\Security;

use Symfony\Component\Security\Core\User\UserChecker as BaseUserChecker;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;

class UserChecker extends BaseUserChecker {
	/**
	 * {@inheritdoc}
	 */
	public function checkPreAuth(UserInterface $user) {

		if (!$user->isAccountDeleted()) {
			$ex = new UsernameNotFoundException('User account is deleted.');
			$ex->setUsername($user->getUsername());
			throw $ex;
		}

		parent::checkPreAuth($user);
	}
}


<?php

namespace Ekyna\Bundle\CoreBundle\Form\Type;

use Ekyna\Bundle\CoreBundle\Form\DataTransformer\UploadableToNullTransformer;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormView;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\PropertyAccess\PropertyAccess;

/**
 * Class UploadType
 * @package Ekyna\Bundle\CoreBundle\Form\Type
 * @author Étienne Dauvergne <contact@ekyna.com>
 */
class UploadType extends AbstractType
{
    /**
     * {@inheritdoc}
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        if ($options['js_upload']) {
            $builder->add('key', 'hidden');
        }

        if ($options['rename_field']) {
            $builder->add('rename', 'text', [
                'label' => 'ekyna_core.field.rename',
                'required' => $options['required'],
                'sizing' => 'sm',
                'admin_helper' => 'FILE_RENAME',
                'attr' => [
                    'class' => 'file-rename',
                    'label_col' => 2,
                    'widget_col' => 10
                ],
            ]);
        }

        $builder->addEventListener(
            FormEvents::PRE_SET_DATA,
            function(FormEvent $event) use ($options) {
                $form = $event->getForm();
                /** @var \Ekyna\Bundle\CoreBundle\Model\UploadableInterface $uploadable */
                $uploadable = $event->getData();

                if (null !== $uploadable && null !== $uploadable->getPath()) {
                    $form->add('file', 'file', [
                        'label' => 'ekyna_core.field.file',
                        'required' => false,
                        'sizing' => 'sm',
                        'admin_helper' => 'FILE_UPLOAD',
                        'attr' => [
                            'label_col' => 2,
                            'widget_col' => 10
                        ]
                    ]);
                    if ($options['unlink_field']) {
                        $form->add('unlink', 'checkbox', [
                            'label' => 'ekyna_core.field.unlink',
                            'required' => false,
                            'sizing' => 'sm',
                            'admin_helper' => 'FILE_UNLINK',
                            'attr' => [
                                'label_col' => 2,
                                'widget_col' => 10,
                                'align_with_widget' => true,
                            ]
                        ]);
                    }
                } else {
                    $form->add('file', 'file', [
                        'label' => 'ekyna_core.field.file',
                        'required' => true,
                        'sizing' => 'sm',
                        'admin_helper' => 'FILE_UPLOAD',
                        'attr' => [
                            'label_col' => 2,
                            'widget_col' => 10
                        ]
                    ]);
                }
            }
        );

        $builder->addModelTransformer(new UploadableToNullTransformer());
    }

    /**
     * {@inheritdoc}
     */
    public function buildView(FormView $view, FormInterface $form, array $options)
    {
        if (array_key_exists('file_path', $options) && 0 < strlen($filePath = $options['file_path'])) {
            $data = $form->getData();
            $currentPath = null;
            $currentName = null;
            if (null !== $data) {
                $accessor = PropertyAccess::createPropertyAccessor();
                $currentPath = $accessor->getValue($data, $filePath);
                $currentName = pathinfo($currentPath, PATHINFO_BASENAME);
            }
            $view->vars['current_file_path'] = $currentPath;
            $view->vars['current_file_name'] = $currentName;
        }
    }

    /**
     * {@inheritdoc}
     */
    public function finishView(FormView $view, FormInterface $form, array $options)
    {
        if ($options['js_upload']) {
            $view->children['key']->vars['attr']['data-target'] = $view->children['file']->vars['id'];
        }
    }

    /**
     * {@inheritdoc}
     */
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver
            ->setDefaults([
                'label'        => 'ekyna_core.field.file',
                'data_class'   => 'Ekyna\Bundle\CoreBundle\Entity\AbstractUpload',
                'file_path'    => 'path',
                'rename_field' => true,
                'unlink_field' => false,
                'js_upload'    => true,
                'error_bubbling' => false,
            ])
            ->setAllowedTypes('file_path',    ['null', 'string'])
            ->setAllowedTypes('rename_field', 'bool')
            ->setAllowedTypes('unlink_field', 'bool')
            ->setAllowedTypes('js_upload',    'bool')
        ;
    }

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


<?php

namespace Pompdelux\PHPRedisBundle\Client;

use Pompdelux\PHPRedisBundle\Logger\Logger;

/**
 * Class Redis
 *
 * This Resis class extends \Resis to allow us extra control over the object.
 * Adds logging and DataCollector to the mix.
 *
 * @package Hanzo\Bundle\RedisBundle\Client
 */
class PHPRedis extends \Redis
{
    /**
     * Logger
     * @var Logger
     */
    private $logger = null;

    /**
     * Whether or not we are connected to the redis server
     * @var boolean
     */
    private $connected = false;

    /**
     * Redis connection parameters
     * @var array
     */
    private $parameters = [];

    /**
     * Name/label of the connection, used for logging
     * @var string
     */
    private $name;

    /**
     * constructor method
     *
     * @param string $name        Name of the connection
     * @param string $environment The kernel environment variable
     * @param array  $parameters  Configuration parameters
     */
    public function __construct($name, $environment, array $parameters = [])
    {
        parent::__construct();

        if ($parameters['skip_env']) {
            $prefix = $name.':';
        } else {
            $prefix = $name.'.'.$environment.':';
        }

        if (empty($parameters['prefix'])) {
            $parameters['prefix'] = $prefix;
        } else {
            $parameters['prefix'] .= '.'.$prefix;
        }

        $this->name = $name;
        $this->parameters = $parameters;
    }

    /**
     * Get the current prefix
     *
     * @return mixed
     */
    public function getPrefix()
    {
        return $this->parameters['prefix'];
    }

    /**
     * Set prefix
     *
     * @param string $s
     */
    public function setPrefix($s)
    {
        $this->parameters['prefix'] = $s;

        if ($this->connected) {
            $this->setOption(\Redis::OPT_PREFIX, $this->parameters['prefix']);
        }
    }

    /**
     * setup logging
     *
     * @param Logger $logger
     */
    public function setLogger(Logger $logger)
    {
        $this->logger = $logger;
    }

    /**
     * wrap all redis calls to handle profiling
     *
     * @param string $name      Redis method
     * @param array  $arguments Arguments to parse on the real method
     *
     * @return boolean
     * @throws \InvalidArgumentException    If the command called does not exist
     * @throws PHPRedisCommunicationException If the call to redis fails
     */
    public function makeCall($name, array $arguments = [])
    {
        if (!$this->connected) {
            $this->_connect();
        }

        // ignore connect commands
        if (in_array($name, ['connect', 'pconnect'])) {
            return;
        }

        $log = true;
        switch (strtolower($name)) {
            case 'open':
            case 'popen':
            case 'close':
            case 'setoption':
            case 'getoption':
            case 'auth':
            case 'select':
                $log = false;
                break;
        }

        $ts     = microtime(true);
        $result = call_user_func_array('parent::'.$name, $arguments);
        $ts     = (microtime(true) - $ts) * 1000;

        $isError = false;
        if ($error = $this->getLastError()) {
            $this->clearLastError();
            $isError = true;
        }

        if ($log && null !== $this->logger) {
            $this->logger->logCommand($this->getCommandString($name, $arguments), $ts, $this->name, $isError);
        }

        if ($isError) {
            throw new PHPRedisCommunicationException('Redis command failed: '.$error);
        }

        return $result;
    }

    /**
     * Generate cache key from method arguments.
     *
     * Example:
     * <code>
     * // string arguments
     * $key = $redis->generateKey('some', 'part', 'of', 'key'); // returns: "some:part:of:key"
     *
     * // array argument
     * $key = $redis->generateKey(['some', 'part', 'of', 'key']); // returns: "some:part:of:key"
     * </code>
     *
     * @param string|array $kp,... List of parameters to use in key generation
     *
     * @return string
     */
    public function generateKey($kp)
    {
        $arguments = func_get_args();

        if (is_array($arguments[0])) {
            $arguments = $arguments[0];
        }

        return implode(':', $arguments);
    }

    /**
     * handle connection management
     *
     * @param boolean $bailOnError keeps track on connection retry
     *
     * @return boolean
     * @throws PHPRedisCommunicationException If connection fails
     */
    private function _connect($bailOnError = false)
    {
        $this->connected = $this->connect(
            $this->parameters['host'],
            $this->parameters['port'],
            ($this->parameters['timeout'] ?: 0)
        );

        if ($this->connected) {
            if ($this->parameters['auth']) {
                $this->auth($this->parameters['auth']);
            }

            if ($this->select($this->parameters['database'])) {
                // setup default options
                $this->setOption(\Redis::OPT_PREFIX, $this->parameters['prefix']);
                $this->setOption(\Redis::OPT_SERIALIZER, \Redis::SERIALIZER_PHP);

                return true;
            }
        } elseif (!$bailOnError) {
            // try to re-connect, but only once.
            usleep(1000);
            $this->_connect(true);
        }

        $error = $this->getLastError();
        $this->clearLastError();

        if ($this->logger) {
            $this->logger->err('Could not connect to redis server (' . $error . ')');
        }

        throw new PHPRedisCommunicationException('Could not connect to Redis: '.$error);
    }

    /**
     * Returns a string representation of the given command including arguments
     *
     * @param string $command   A command name
     * @param array  $arguments An array of command arguments
     *
     * @return string
     */
    private function getCommandString($command, array $arguments)
    {
        $list = [];
        foreach ($arguments as $argument) {
            $list[] = is_scalar($argument) ? $argument : '[.. complex type ..]';
        }

        return mb_substr(trim(strtoupper($command) . ' ' . $this->getPrefix() . implode(' ', $list)), 0, 256);
    }

    // the rest is all wrapper calls to allow us to time and log calls.

    /**
     * {@inheritDoc}
     */
    public function close()
    {
        return $this->makeCall('close', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function ping()
    {
        return $this->makeCall('ping', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function get($key)
    {
        return $this->makeCall('get', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function set($key, $value, $timeout = 0.0)
    {
        return $this->makeCall('set', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function setex($key, $ttl, $value)
    {
        return $this->makeCall('setex', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function psetex($key, $ttl, $value)
    {
        return $this->makeCall('psetex', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function setnx($key, $value)
    {
        return $this->makeCall('setnx', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function getSet($key, $value)
    {
        return $this->makeCall('getSet', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function randomKey()
    {
        return $this->makeCall('randomKey', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function renameKey($srcKey, $dstKey)
    {
        return $this->makeCall('renameKey', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function renameNx($srcKey, $dstKey)
    {
        return $this->makeCall('renameNx', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function getMultiple(array $keys)
    {
        return $this->makeCall('getMultiple', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function exists($key)
    {
        return $this->makeCall('exists', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function delete($key1)
    {
        return $this->makeCall('delete', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function incr($key)
    {
        return $this->makeCall('incr', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function incrBy($key, $value)
    {
        return $this->makeCall('incrBy', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function incrByFloat($key, $increment)
    {
        return $this->makeCall('incrByFloat', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function decr($key)
    {
        return $this->makeCall('decr', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function decrBy($key, $value)
    {
        return $this->makeCall('decrBy', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function type($key)
    {
        return $this->makeCall('type', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function append($key, $value)
    {
        return $this->makeCall('append', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function getRange($key, $start, $end)
    {
        return $this->makeCall('getRange', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function setRange($key, $offset, $value)
    {
        return $this->makeCall('setRange', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function getBit($key, $offset)
    {
        return $this->makeCall('getBit', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function setBit($key, $offset, $value)
    {
        return $this->makeCall('setBit', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function strlen($key)
    {
        return $this->makeCall('strlen', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function getKeys($pattern)
    {
        return $this->makeCall('getKeys', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function sort($key, $option = null)
    {
        return $this->makeCall('sort', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function sortAsc()
    {
        return $this->makeCall('sortAsc', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function sortAscAlpha()
    {
        return $this->makeCall('sortAscAlpha', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function sortDesc()
    {
        return $this->makeCall('sortDesc', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function sortDescAlpha()
    {
        return $this->makeCall('sortDescAlpha', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function lPush($key, $value1, $value2 = null, $valueN = null)
    {
        return $this->makeCall('lPush', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function rPush($key, $value1, $value2 = null, $valueN = null)
    {
        return $this->makeCall('rPush', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function lPushx($key, $value)
    {
        return $this->makeCall('lPushx', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function rPushx($key, $value)
    {
        return $this->makeCall('rPushx', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function lPop($key)
    {
        return $this->makeCall('lPop', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function rPop($key)
    {
        return $this->makeCall('rPop', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function blPop(array $keys)
    {
        return $this->makeCall('blPop', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function brPop(array $keys)
    {
        return $this->makeCall('brPop', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function lSize($key)
    {
        return $this->makeCall('lSize', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function lRemove($key, $value, $count)
    {
        return $this->makeCall('lRemove', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function listTrim($key, $start, $stop)
    {
        return $this->makeCall('listTrim', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function lGet($key, $index)
    {
        return $this->makeCall('lGet', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function lGetRange($key, $start, $end)
    {
        return $this->makeCall('lGetRange', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function lSet($key, $index, $value)
    {
        return $this->makeCall('lSet', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function lInsert($key, $position, $pivot, $value)
    {
        return $this->makeCall('lInsert', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function sAdd($key, $value1, $value2 = null, $valueN = null)
    {
        return $this->makeCall('sAdd', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function sSize()
    {
        return $this->makeCall('sSize', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function sRemove($key, $member1, $member2 = null, $memberN = null)
    {
        return $this->makeCall('sRemove', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function sMove($srcKey, $dstKey, $member)
    {
        return $this->makeCall('sMove', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function sPop($key)
    {
        return $this->makeCall('sPop', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function sRandMember($key)
    {
        return $this->makeCall('sRandMember', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function sContains($key, $value)
    {
        return $this->makeCall('sContains', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function sMembers($key)
    {
        return $this->makeCall('sMembers', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function sInter($key1, $key2, $keyN = null)
    {
        return $this->makeCall('sInter', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function sInterStore($dstKey, $key1, $key2, $keyN = null)
    {
        return $this->makeCall('sInterStore', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function sUnion($key1, $key2, $keyN = null)
    {
        return $this->makeCall('sUnion', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function sUnionStore($dstKey, $key1, $key2, $keyN = null)
    {
        return $this->makeCall('sUnionStore', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function sDiff($key1, $key2, $keyN = null)
    {
        return $this->makeCall('sDiff', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function sDiffStore($dstKey, $key1, $key2, $keyN = null)
    {
        return $this->makeCall('sDiffStore', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function setTimeout($key, $ttl)
    {
        return $this->makeCall('setTimeout', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function save()
    {
        return $this->makeCall('save', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function bgSave()
    {
        return $this->makeCall('bgSave', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function lastSave()
    {
        return $this->makeCall('lastSave', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function flushDB()
    {
        return $this->makeCall('flushDB', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function flushAll()
    {
        return $this->makeCall('flushAll', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function dbSize()
    {
        return $this->makeCall('dbSize', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function auth($password)
    {
        return $this->makeCall('auth', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function ttl($key)
    {
        return $this->makeCall('ttl', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function pttl($key)
    {
        return $this->makeCall('pttl', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function persist($key)
    {
        return $this->makeCall('persist', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function info($option = null)
    {
        return $this->makeCall('info', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function resetStat()
    {
        return $this->makeCall('resetStat', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function select($dbindex)
    {
        return $this->makeCall('select', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function move($key, $dbindex)
    {
        return $this->makeCall('move', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function bgrewriteaof()
    {
        return $this->makeCall('bgrewriteaof', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function slaveof($host = '127.0.0.1', $port = 6379)
    {
        return $this->makeCall('slaveof', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function object($string = '', $key = '')
    {
        return $this->makeCall('object', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function bitop($operation, $retKey, $key1, $key2, $key3 = null)
    {
        return $this->makeCall('bitop', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function bitcount($key)
    {
        return $this->makeCall('bitcount', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function bitpos()
    {
        return $this->makeCall('bitpos', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function mset(array $array)
    {
        return $this->makeCall('mset', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function msetnx(array $array)
    {
        return $this->makeCall('msetnx', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function rpoplpush($srcKey, $dstKey)
    {
        return $this->makeCall('rpoplpush', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function brpoplpush($srcKey, $dstKey, $timeout)
    {
        return $this->makeCall('brpoplpush', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function zAdd($key, $score1, $value1, $score2 = null, $value2 = null, $scoreN = null, $valueN = null)
    {
        return $this->makeCall('zAdd', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function zDelete($key, $member1, $member2 = null, $memberN = null)
    {
        return $this->makeCall('zDelete', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function zRange($key, $start, $end, $withscores = null)
    {
        return $this->makeCall('zRange', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function zReverseRange()
    {
        return $this->makeCall('zReverseRange', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function zRangeByScore($key, $start, $end, array $options = [])
    {
        return $this->makeCall('zRangeByScore', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function zRevRangeByScore($key, $start, $end, array $options = [])
    {
        return $this->makeCall('zRevRangeByScore', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function zCount($key, $start, $end)
    {
        return $this->makeCall('zCount', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function zDeleteRangeByScore($key, $start, $end)
    {
        return $this->makeCall('zDeleteRangeByScore', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function zDeleteRangeByRank($key, $start, $end)
    {
        return $this->makeCall('zDeleteRangeByRank', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function zCard($key)
    {
        return $this->makeCall('zCard', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function zScore($key, $member)
    {
        return $this->makeCall('zScore', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function zRank($key, $member)
    {
        return $this->makeCall('zRank', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function zRevRank($key, $member)
    {
        return $this->makeCall('zRevRank', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function zInter($Output, $ZSetKeys, array $Weights = null, $aggregateFunction = 'SUM')
    {
        return $this->makeCall('zInter', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function zUnion($Output, $ZSetKeys, array $Weights = null, $aggregateFunction = 'SUM')
    {
        return $this->makeCall('zUnion', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function zIncrBy($key, $value, $member)
    {
        return $this->makeCall('zIncrBy', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function expireAt($key, $timestamp)
    {
        return $this->makeCall('expireAt', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function pExpire($key, $ttl)
    {
        return $this->makeCall('pExpire', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function pExpireAt($key, $timestamp)
    {
        return $this->makeCall('pExpireAt', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function hGet($key, $hashKey)
    {
        return $this->makeCall('hGet', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function hSet($key, $hashKey, $value)
    {
        return $this->makeCall('hSet', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function hSetNx($key, $hashKey, $value)
    {
        return $this->makeCall('hSetNx', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function hDel($key, $hashKey1, $hashKey2 = null, $hashKeyN = null)
    {
        return $this->makeCall('hDel', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function hLen($key)
    {
        return $this->makeCall('hLen', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function hKeys($key)
    {
        return $this->makeCall('hKeys', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function hVals($key)
    {
        return $this->makeCall('hVals', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function hGetAll($key)
    {
        return $this->makeCall('hGetAll', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function hExists($key, $hashKey)
    {
        return $this->makeCall('hExists', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function hIncrBy($key, $hashKey, $value)
    {
        return $this->makeCall('hIncrBy', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function hIncrByFloat($key, $field, $increment)
    {
        return $this->makeCall('hIncrByFloat', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function hMset($key, $hashKeys)
    {
        return $this->makeCall('hMset', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function hMget($key, $hashKeys)
    {
        return $this->makeCall('hMget', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function multi()
    {
        return $this->makeCall('multi', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function discard()
    {
        return $this->makeCall('discard', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function exec()
    {
        return $this->makeCall('exec', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function pipeline()
    {
        return $this->makeCall('pipeline', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function watch($key)
    {
        return $this->makeCall('watch', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function unwatch()
    {
        return $this->makeCall('unwatch', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function publish($channel, $message)
    {
        return $this->makeCall('publish', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function subscribe($channels, $callback)
    {
        return $this->makeCall('subscribe', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function psubscribe($patterns, $callback)
    {
        return $this->makeCall('psubscribe', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function unsubscribe()
    {
        return $this->makeCall('unsubscribe', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function punsubscribe()
    {
        return $this->makeCall('punsubscribe', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function time()
    {
        return $this->makeCall('time', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function evalSha($scriptSha, $args = array(), $numKeys = 0)
    {
        return $this->makeCall('evalSha', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function script($command, $script)
    {
        return $this->makeCall('script', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function dump($key)
    {
        return $this->makeCall('dump', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function restore($key, $ttl, $value)
    {
        return $this->makeCall('restore', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function migrate($host, $port, $key, $db, $timeout)
    {
        return $this->makeCall('migrate', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function _prefix($value)
    {
        return $this->makeCall('prefix', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function _serialize()
    {
        return $this->makeCall('serialize', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function _unserialize($value)
    {
        return $this->makeCall('unserialize', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function client()
    {
        return $this->makeCall('client', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function scan(&$i_iterator, $str_pattern = null, $i_count = null)
    {
        return $this->makeCall('scan', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function hscan($str_key, &$i_iterator, $str_pattern = null, $i_count = null)
    {
        return $this->makeCall('hscan', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function zscan($str_key, &$i_iterator, $str_pattern = null, $i_count = null)
    {
        return $this->makeCall('zscan', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function sscan($str_key, &$i_iterator, $str_pattern = null, $i_count = null)
    {
        return $this->makeCall('sscan', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function getOption($name)
    {
        return $this->makeCall('getOption', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function setOption($name, $value)
    {
        return $this->makeCall('setOption', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function config($operation, $key, $value)
    {
        return $this->makeCall('config', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function slowlog()
    {
        return $this->makeCall('slowlog', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function getHost()
    {
        return $this->makeCall('getHost', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function getPort()
    {
        return $this->makeCall('getPort', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function getDBNum()
    {
        return $this->makeCall('getDBNum', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function getTimeout()
    {
        return $this->makeCall('getTimeout', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function getReadTimeout()
    {
        return $this->makeCall('getReadTimeout', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function getPersistentID()
    {
        return $this->makeCall('getPersistentID', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function getAuth()
    {
        return $this->makeCall('getAuth', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function isConnected()
    {
        return $this->makeCall('isConnected', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function wait()
    {
        return $this->makeCall('wait', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function pubsub()
    {
        return $this->makeCall('pubsub', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function open($host, $port = 6379, $timeout = 0.0)
    {
        return $this->makeCall('open', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function popen($host, $port = 6379, $timeout = 0.0)
    {
        return $this->makeCall('popen', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function lLen($key)
    {
        return $this->makeCall('lLen', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function sGetMembers($key)
    {
        return $this->makeCall('sGetMembers', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function mget(array $array)
    {
        return $this->makeCall('mget', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function expire($key, $ttl)
    {
        return $this->makeCall('expire', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function zunionstore()
    {
        return $this->makeCall('zunionstore', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function zinterstore()
    {
        return $this->makeCall('zinterstore', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function zRemove()
    {
        return $this->makeCall('zRemove', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function zRem($key, $member1, $member2 = null, $memberN = null)
    {
        return $this->makeCall('zRem', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function zRemoveRangeByScore()
    {
        return $this->makeCall('zRemoveRangeByScore', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function zRemRangeByScore($key, $start, $end)
    {
        return $this->makeCall('zRemRangeByScore', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function zRemRangeByRank($key, $start, $end)
    {
        return $this->makeCall('zRemRangeByRank', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function zSize($key)
    {
        return $this->makeCall('zSize', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function substr($key, $start, $end)
    {
        return $this->makeCall('substr', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function rename($srcKey, $dstKey)
    {
        return $this->makeCall('rename', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function del($key1, $key2 = null, $key3 = null)
    {
        return $this->makeCall('del', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function keys($pattern)
    {
        return $this->makeCall('keys', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function lRem($key, $value, $count)
    {
        return $this->makeCall('lRem', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function lTrim($key, $start, $stop)
    {
        return $this->makeCall('lTrim', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function lIndex($key, $index)
    {
        return $this->makeCall('lIndex', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function lRange($key, $start, $end)
    {
        return $this->makeCall('lRange', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function sCard($key)
    {
        return $this->makeCall('sCard', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function sRem($key, $member1, $member2 = null, $memberN = null)
    {
        return $this->makeCall('sRem', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function sIsMember($key, $value)
    {
        return $this->makeCall('sIsMember', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function zRevRange($key, $start, $end, $withscore = null)
    {
        return $this->makeCall('zRevRange', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function sendEcho()
    {
        return $this->makeCall('sendEcho', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function evaluate($script, $args = array(), $numKeys = 0)
    {
        return $this->makeCall('evaluate', func_get_args());
    }

    /**
     * {@inheritDoc}
     */
    public function evaluateSha($scriptSha, $args = array(), $numKeys = 0)
    {
        return $this->makeCall('evaluateSha', func_get_args());
    }
}


<?php
/**
 * Абстрактное поле
 *
 * @version ${product.version}
 *
 * @copyright 2013, Михаил Красильников <m.krasilnikov@yandex.ru>
 * @license http://www.gnu.org/licenses/gpl.txt	GPL License 3
 * @author Михаил Красильников <m.krasilnikov@yandex.ru>
 *
 * Данная программа является свободным программным обеспечением. Вы
 * вправе распространять ее и/или модифицировать в соответствии с
 * условиями версии 3 либо (по вашему выбору) с условиями более поздней
 * версии Стандартной Общественной Лицензии GNU, опубликованной Free
 * Software Foundation.
 *
 * Мы распространяем эту программу в надежде на то, что она будет вам
 * полезной, однако НЕ ПРЕДОСТАВЛЯЕМ НА НЕЕ НИКАКИХ ГАРАНТИЙ, в том
 * числе ГАРАНТИИ ТОВАРНОГО СОСТОЯНИЯ ПРИ ПРОДАЖЕ и ПРИГОДНОСТИ ДЛЯ
 * ИСПОЛЬЗОВАНИЯ В КОНКРЕТНЫХ ЦЕЛЯХ. Для получения более подробной
 * информации ознакомьтесь со Стандартной Общественной Лицензией GNU.
 *
 * Вы должны были получить копию Стандартной Общественной Лицензии
 * GNU с этой программой. Если Вы ее не получили, смотрите документ на
 * <http://www.gnu.org/licenses/>
 *
 * @package ORM
 */

/**
 * Абстрактное поле
 *
 * @package ORM
 * @since 3.00
 */
abstract class ORM_Field_Abstract
{
    /**
     * Имя поля
     *
     * @var string
     */
    protected $name;

    /**
     * Параметры поля
     *
     * @var array
     */
    protected $params;

    /**
     * Таблица, которой принадлежит поле
     * @var ORM_Table
     * @since 3.00
     */
    protected $table;

    /**
     * Параметры поля
     *
     * @param ORM_Table $table
     * @param string    $name
     * @param array     $params
     */
    public function __construct(ORM_Table $table, $name, array $params)
    {
        assert('is_string($name)');
        assert('"" != $name');
        $this->table = $table;
        $this->name = $name;
        $this->checkParams($params);
        $this->params = $params;
    }

    /**
     * Возвращает имя поля
     *
     * @return string
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * Возвращает имя типа
     *
     * @return string
     *
     * @since 3.00
     */
    abstract public function getTypeName();

    /**
     * Возвращает true если это виртуальный тип (т. е. для него не надо создавать поле в таблице)
     *
     * @return bool
     *
     * @see evaluateVirtualValue()
     * @since 3.00
     */
    public function isVirtual()
    {
        return false;
    }

    /**
     * Вычисляет и возвращает значение виртуального поля
     *
     * @param ORM_Entity $entity
     *
     * @return mixed
     *
     * @see isVirtual()
     * @since 3.00
     */
    public function evaluateVirtualValue(ORM_Entity $entity)
    {
        return null;
    }

    /**
     * Возвращает соответствующий тип PDO (PDO::PARAM_…) или null
     *
     * @return null|int
     *
     * @since 3.00
     */
    public function getPdoType()
    {
        return null;
    }

    /**
     * Преобразует значение ORM в значение PDO
     *
     * @param mixed $ormValue
     *
     * @return mixed
     *
     * @since 3.00
     */
    public function orm2pdo($ormValue)
    {
        return $ormValue;
    }

    /**
     * Преобразует значение PDO в значение ORM
     *
     * @param mixed $pdoValue
     *
     * @return mixed
     *
     * @since 3.00
     */
    public function pdo2orm($pdoValue)
    {
        return $pdoValue;
    }

    /**
     * Возвращает true если указанный параметр задан
     *
     * @param string $name
     *
     * @return bool
     *
     * @since 3.00
     */
    public function hasParam($name)
    {
        assert('is_string($name)');
        return array_key_exists($name, $this->params);
    }

    /**
     * Возвращает значение параметра поля
     *
     * @param string $name
     * @param mixed  $default  значение по умолчанию, если параметр не задан
     *
     * @return mixed
     *
     * @since 3.00
     */
    public function getParam($name, $default = null)
    {
        return $this->hasParam($name) ? $this->params[$name] : $default;
    }

    /**
     * Может ли это поле участвовать в разделе WHERE запросов SQL
     *
     * @return bool
     *
     * @since 3.00
     */
    public function canBeUsedInWhere()
    {
        return !$this->isVirtual();
    }

    /**
     * Возвращает true если поле автоинкрементируемое
     *
     * @return bool
     */
    public function isAutoIncrementing()
    {
        return array_key_exists('autoincrement', $this->params) && $this->params['autoincrement'];
    }

    /**
     * Дополнительные действия при формировании раздела SELECT
     *
     * @param ezcQuerySelect $query
     * @param array          $currentSelects  уже сформированные части SELECT
     *
     * @return array  изменённый $currentSelects
     */
    public function onSelect(ezcQuerySelect $query, array $currentSelects)
    {
        return $currentSelects;
    }

    /**
     * Дополнительные действия при формировании раздела FROM
     *
     * @param ezcQuerySelect $query
     */
    public function onFrom(ezcQuerySelect $query)
    {
    }

    /**
     * Действия, выполняемые после создания таблицы
     */
    public function afterTableCreate()
    {
    }

    /**
     * Действия, выполняемые после удаления таблицы
     */
    public function afterTableDrop()
    {
    }

    /**
     * Действия, выполняемые после сохранения сущности
     *
     * @param ORM_Entity $entity
     */
    public function afterEntitySave(ORM_Entity $entity)
    {
    }

    /**
     * Действия, выполняемые после удаления сущности
     *
     * @param ORM_Entity $entity
     */
    public function afterEntityDelete(ORM_Entity $entity)
    {
    }

    /**
     * Возвращает выражение SQL для описания поля при создании таблицы
     *
     * @throws LogicException
     *
     * @return string
     */
    public function getSqlFieldDefinition()
    {
        if (!$this->isVirtual())
        {
            throw new LogicException(get_class($this)
                . ' should override method "getSqlFieldDefinition"');
        }
        return '';
    }

    /**
     * Проверяет параметры в описании поля
     *
     * @param array $params
     *
     * @throws InvalidArgumentException
     *
     * @uses getValidParams()
     */
    protected function checkParams(array $params)
    {
        $unknown = array_diff(array_keys($params),
            $this->getRequiredParams(), $this->getOptionalParams(), array('default', 'comment'));
        if (count($unknown) > 0)
        {
            throw new InvalidArgumentException(
                sprintf('Unknown option(s) "%s" in field "%s" definition',
                    implode(',', $unknown), $this->getName()));
        }

        $missed = array_diff($this->getRequiredParams(), array_keys($params));
        if (count($missed) > 0)
        {
            throw new InvalidArgumentException(
                sprintf('Missed required option(s) "%s" in field "%s" definition',
                    implode(',', $missed), $this->getName()));
        }
    }

    /**
     * Возвращает список обязательных параметров
     *
     * @return string[]
     *
     * @since 3.00
     */
    protected function getRequiredParams()
    {
        return array();
    }

    /**
     * Возвращает список возможных необязательных параметров
     *
     * @return string[]
     *
     * @since 3.00
     */
    protected function getOptionalParams()
    {
        return array();
    }
}


<?php

declare(strict_types=1);

namespace Ruwork\PaginatorBundle\DependencyInjection;

use Ruwork\PaginatorBundle\EventListener\PageOutOfRangeExceptionListener;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;

class RuworkPaginatorExtension extends Extension
{
    /**
     * {@inheritdoc}
     */
    public function load(array $configs, ContainerBuilder $container): void
    {
        $container->register(PageOutOfRangeExceptionListener::class)
            ->setPublic(false)
            ->addTag('kernel.event_subscriber');
    }
}


<?php
namespace FzyCommon\Service\Update;

use FzyCommon\Entity\BaseInterface;
use FzyCommon\Exception\Search\NotFound;
use FzyCommon\Exception\Update\FailedLookup;
use FzyCommon\Service\Search\Base as SearchService;
use FzyCommon\Util\Params;
use Zend\EventManager\EventManagerInterface;
use Zend\EventManager\EventManager;
use Zend\EventManager\EventManagerAwareInterface;
use Zend\Form\Form;
use Zend\EventManager\Event;
use FzyCommon\Service\Base as UpdateService;

/**
 * Class Update
 * @package FzyCommon\Service
 */
class Base extends UpdateService implements EventManagerAwareInterface
{
    const EVENT_CONFIGURE_ENTITY = 'configure';

    const EVENT_CONFIGURE_FORM = 'configure_form';

    const EVENT_FORM_DATA = 'formdata';

    const MAIN_ENTITY_CLASS = 'FzyCommon\Entity\Base';

    const MAIN_ENTITY_ID_PARAM = 'id';

    // OPERATIONAL CONSTANTS
    const OPERATION_CREATE = 'created';
    const OPERATION_UPDATE = 'updated';
    const OPERATION_DELETE = 'deleted';
    const OPERATION_NONE   = 'none';

    /**
     * Option during update. If this is set to true,
     * the form validation loop is stopped at the first
     * invalid result (rather than running through all forms)
     */
    const OPTION_SHORT_CIRCUIT = 'short_circuit';

    /**
     * Set this option if you don't want the update service to
     * flush on the entity manager automatically. To persist
     * changes, you will need to manually flush the entity manager.
     */
    const OPTION_NO_FLUSH = 'no_flush';

    const MAIN_TAG = 'entity';

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

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

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

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

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

    /**
     * @var bool
     */
    protected $valid;

    /**
     * @var bool
     */
    protected $useSessionMessage = true;

    /**
     * @var string
     */
    protected $operation = self::OPERATION_NONE;

    /**
     * Array of form validator callables
     *
     * The default behavior is to simply return the result of '$form->isValid()'
     * however some further validation may be necessary (or $form->isValid() may not apply)
     * so this array allows you to specify a $tag => $callable associative array
     * where $callable accepts 2 params: (Params $params, Form $form)
     * and should return a boolean $isValid
     *
     * @var array
     */
    protected $formValidators;

    /**
     * Reset state of service
     * @return $this
     */
    public function reset()
    {
        unset($this->entity);
        unset($this->entities);
        unset($this->forms);
        unset($this->valid);
        unset($this->params);
        $this->setOperation(self::OPERATION_NONE);
        unset($this->formValidators);
        $this->errorMessages = array();
        $this->useSessionMessage = true;

        return $this;
    }

    /**
     * Creates a new instance of the entity this service updates
     * @param Params $params
     *
     * @return mixed
     */
    public function createNewEntity(Params $params)
    {
        $class = '\\'.static::MAIN_ENTITY_CLASS;
        $mainEntity = new $class();

        return $mainEntity;
    }

    /**
     * @param  Param                                    $params
     * @param  bool                                     $readonly
     * @return $this
     * @throws \FzyCommon\Exception\Update\FailedLookup
     */
    public function setMainEntityFromParam(Params $params, SearchService $search)
    {
        $mainEntity = null;
        try {
            $mainEntity = $search->identitySearch($params);
            $this->setOperation(self::OPERATION_UPDATE);
        } catch (NotFound $e) {
            $mainEntity = $this->createNewEntity($params);
            $this->setOperation(self::OPERATION_CREATE);
        }
        $this->setEntity($mainEntity);

        return $this;
    }

    /**
     * @param  Params $params
     * @param  array  $options
     * @return $this
     */
    public function update(Params $params, $options = array())
    {
        $valid = true;
        $this->setUpFormDataEventListeners();
        /* @var $form \Zend\Form\Form */
        foreach ($this->getForms() as $tag => $form) {
            if (!$this->updateIteration($tag, $form, $params)) {
                $valid = false;
                // optional to stop at the first failed validation or keep validating the rest of the forms
                if (isset($options[self::OPTION_SHORT_CIRCUIT]) && $options[self::OPTION_SHORT_CIRCUIT]) {
                    break;
                }
            }
        }

        $this->valid = $valid;
        $this->postValidate($valid, $params, $options);

        return $this;
    }

    /**
     * @param $tag
     * @param  Form   $form
     * @param  Params $params
     * @return bool
     */
    public function updateIteration($tag, Form $form, Params $params)
    {
        $valid = true;
        $this->getEventManager()->trigger(self::EVENT_FORM_DATA.$tag, $this, array('form' => $form, 'data' => $params));
        if (!$this->call($this->getFormValidators(), $tag, array($params, $form), function (Params $params, Form $form) {return $form->isValid();})) {
            $valid = false;
            $this->errorMessages[$tag] = $this->normalizeMessages($form->getMessages());
        }

        return $valid;
    }

    /**
     * This is here to format standard form validation errors, so that
     * we can use customized error messaging instead of the 1 message only
     * practice from using annotations.
     *
     * @param $messages
     * @return array
     */
    protected function normalizeMessages($messages)
    {
        $queue = array();

        foreach ($messages as $key => $value) {
            if (is_array($value) && count($value)) {
                $queue[$key] = (array) array_pop($value);
            } else {
                $queue[$key] = (array) $value;
            }
        }

        return $queue;
    }

    /**
     * Abstract utility method for calling a callable in an array of tagged callables, passing it the specified params array
     * If the $tag key exists, that callable is invoked, otherwise the default callable is invoked.
     *
     * @param $callableArray
     * @param $tag
     * @param $params
     * @param $defaultCallable
     * @return mixed
     */
    protected function call(array $callableArray, $tag, array $params, $defaultCallable)
    {
        $callable = isset($callableArray[$tag]) ? $callableArray[$tag] : $defaultCallable;

        return call_user_func_array($callable, $params);
    }

    /**
     * Method to get form validators (triggering generateFormValidators once)
     * @return array
     */
    final protected function getFormValidators()
    {
        // Not sure how form validators wouldn't be set, but leaving in place for now
        if (!isset($this->formValidators)) {
            $this->formValidators = $this->generateFormValidators();
        }

        return $this->formValidators;
    }

    /**
     * Array of form validator callables
     *
     * The default behavior is to simply return the result of '$form->isValid()'
     * however some further validation may be necessary (or $form->isValid() may not apply)
     * so this array allows you to specify a $tag => $callable associative array
     * where $callable accepts 2 params: (Params $params, Form $form)
     * and should return a boolean $isValid
     *
     * @return array
     */
    protected function generateFormValidators()
    {
        return array();
    }

    /**
     * Called after all forms have been validated.
     * Passed the validation result
     * @param boolean $valid
     * @param Param   $params
     */
    protected function postValidate($valid, Params $params, $options = array())
    {
        if ($valid) {
            foreach ($this->getEntities() as $tag => $entity) {
                $this->em()->persist($entity);
            }
            if (!isset($options[static::OPTION_NO_FLUSH]) || !$options[static::OPTION_NO_FLUSH]) {
                $this->em()->flush();
            }
        }
    }

    /**
     * Function which attaches any data events to the
     * forms relevant to this update.
     * @return $this
     */
    protected function setUpFormDataEventListeners()
    {
        $this->formDataEvent(static::MAIN_TAG);

        return $this;
    }

    /**
     * Utility method for attaching a form data event listener
     * Utility method for attaching a form data event listener
     * for a form by a given tag. The optional 'callable' method
     * should accept and return a Param object.
     * @param $tag
     * @param null $callable
     */
    protected function formDataEvent($tag, $callable = null)
    {
        $this->getEventManager()->attach(self::EVENT_FORM_DATA.$tag, function ($event) use ($callable) {
            $eventParams = $event->getParams();
            /* @var $form \Zend\Form\Form */
            $form = $eventParams['form'];
            /* @var $data Param */
            $data = $eventParams['data'];
            if (!empty($callable) && is_callable($callable)) {
                $data = call_user_func($callable, $data);
            }
            $form->setData($data->get());
        });
    }

    /**
     * @param  BaseInterface $entity
     * @return Update
     */
    public function setEntity(BaseInterface $entity)
    {
        $this->setOperation($entity->id() ? static::OPERATION_UPDATE : static::OPERATION_CREATE);
        $this->entity = $this->preSetEntity($entity);

        return $this;
    }

    /**
     * @param  BaseInterface $entity
     * @return BaseInterface
     */
    protected function preSetEntity(BaseInterface $entity)
    {
        return $entity;
    }

    /**
     * @return BaseInterface
     */
    public function getEntity()
    {
        return $this->entity;
    }

    /**
     * Generate forms from entities
     * @return array
     */
    public function getForms()
    {
        if (!isset($this->forms)) {
            $forms = array();
            $entities = $this->getEntities();
            // set up any connections
            $this->beforeFormGeneration($entities);
            foreach ($entities as $tag => $entity) {
                /* @var $form \Zend\Form\Form */
                $form = $this->entityToForm($entity);
                $this->getEventManager()
                    ->trigger(self::EVENT_CONFIGURE_FORM.$tag, $this, array(
                        'tag' => $tag,
                        'entity' => $entity,
                        'form' => $form,
                        'entities' => $entities,
                    ));
                $forms[$tag] = $form;
            }
            $this->forms = $forms;
        }

        return $this->forms;
    }

    /**
     * Modify array to remove the specified value
     * @param $list
     * @param $value
     * @return $this
     */
    protected function removeStringFromArray(&$list, $value)
    {
        $index = array_search($value, $list);
        if ($index !== false) {
            unset($list[$index]);
        }

        return $this;
    }

    /**
     * Hook to allow setup of forms
     * @param array $entities
     */
    protected function beforeFormGeneration(array $entities)
    {
    }

    /**
     * Attaches a subentity to the main entity in several ways:
     *
     *  During form generation, some subentities may be null on the main entity, the form
     *  will create a new doctrine entity to represent its data, the main entity needs to use
     *  the specified 'setter' to set the main entity's relation to this newly generated entity
     *  additionally, the entry for this new entity at 'tag' in the Update service's '$entities' array
     *  will be modified.
     *
     *  Finally, the main entity will have a mapping set to this configured form so- on render- your configured
     *  subform will be used
     *
     * @param $tag
     * @param $entities
     * @param $mainEntitySetter
     * @param  null  $afterAttachCallable
     * @param  null  $mainEntityGetter
     * @return $this
     */
    protected function attachToMainEntity($tag, $entities, $mainEntitySetter, $afterAttachCallable = null, $mainEntityGetter = null)
    {
        $mainEntity = $entities[static::MAIN_TAG];
        $self = $this;
        $this->getEventManager()
            ->attach(self::EVENT_CONFIGURE_FORM.$tag, function (Event $e) use ($tag, $mainEntity, $mainEntitySetter, $afterAttachCallable, $self, $mainEntityGetter) {
                /* @var $form \Zend\Form\Form */
                $form = $e->getParam('form');
                // attach main entity to the entity generated by the form for this tag
                /**
                 * IMPORTANT: can't use the address entity as this may be a null object. Once it has been
                 * run through entity-to-form, the form generates a non-null entity it will save to. The
                 * office entity will need to attach to that
                 */
                $mainEntity->$mainEntitySetter($form->getObject());
                // if this entity changed, update the entities array on this service
                $self->swapEntity($tag, $form->getObject());
                if (empty($mainEntityGetter)) {
                    $mainEntityGetter = 'g'.substr($mainEntitySetter, 1);
                }
                // map this generated form in the main entity form
                // so any configuration changes are reflected when rendered
                $self->setFormMapEntry($mainEntityGetter, $form);

                if (is_callable($afterAttachCallable)) {
                    call_user_func($afterAttachCallable, $form->getObject(), $form, $mainEntity, $tag);
                }
            });

        return $this;
    }

    /**
     * Utility method to convert entity to form.
     * @param  BaseInterface   $entity
     * @return \Zend\Form\Form
     */
    protected function entityToForm(BaseInterface $entity)
    {
        return $this->getServiceLocator()->get('FzyCommon\Service\EntityToForm')->convertEntity($entity);
    }

    /**
     * Returns any side entities as a tag/entity associative array
     * @return array
     */
    protected function generateEntities()
    {
        return array();
    }

    /**
     * Ensures 'generateEntities' is only ever invoked once.
     * Fires the EVENT_CONFIGURE_ENTITY event on each entity
     * to allow for any configuration.
     *
     * TODO: test that this even actually gets fired and provides
     * access/configuration to the entity
     *
     * @return array
     */
    final public function getEntities()
    {
        if (!isset($this->entities)) {
            $this->entities = array();
            $entities = $this->generateEntities();
            $entities[static::MAIN_TAG] = $this->getEntity();
            /* @var $entity \FzyCommon\Entity\BaseInterface */
            foreach ($entities as $tag => $entity) {
                $this->getEventManager()
                    ->trigger(self::EVENT_CONFIGURE_ENTITY.$tag, $this, array(
                        'tag' => $tag,
                        'entity' => $entity,
                        'entities' => $entities,
                    ));
                $this->entities[$tag] = $entity;
                $entity->setFormTag($tag);
            }
        }

        return $this->entities;
    }

    /**
     * Utility to replace an entity at a tag
     * @param $tag
     * @param  BaseInterface     $entity
     * @return $this
     * @throws \RuntimeException
     */
    final public function swapEntity($tag, BaseInterface $entity)
    {
        if (!isset($this->entities[$tag])) {
            throw new \RuntimeException("Unable to swap entity that does not exist");
        }
        $this->entities[$tag] = $entity;
        $entity->setFormTag($tag);
        $this->getEventManager()
            ->trigger(self::EVENT_CONFIGURE_ENTITY.$tag, $this, array(
                'tag' => $tag,
                'entity' => $entity,
                'entities' => $this->getEntities(),
            ));

        return $this;
    }

    public function getEntitiesAsJson()
    {
        $result = array();
        $entities = $this->getEntities();
        /* @var $entity \FzyCommon\Entity\BaseInterface */
        foreach ($entities as $tag => $entity) {
            $result[$tag] = $entity->flatten();
        }

        return $result;
    }

    /**
     * Public getter for an entity associated with the given tag
     * @param null $tag
     */
    public function entity($tag = null)
    {
        return $this->getEntryForTag($this->getEntities(), $tag);
    }

    public function form($tag = null)
    {
        return $this->getEntryForTag($this->getForms(), $tag);
    }

    protected function getEntryForTag(array $arr, $tag = null)
    {
        if ($tag === null) {
            $tag = static::MAIN_TAG;
        }
        if (!isset($arr[$tag])) {
            throw new \InvalidArgumentException("No entry associated with tag ".$tag);
        }

        return $arr[$tag];
    }

    /**
     * @param  boolean $valid
     * @return Update
     */
    public function setValid($valid)
    {
        $this->valid = $valid;

        return $this;
    }

    /**
     * @return boolean
     */
    public function getValid()
    {
        return $this->valid;
    }

    /**
     * @param  array  $errorMessages
     * @return Update
     */
    public function setErrorMessages($errorMessages)
    {
        $this->errorMessages = $errorMessages;

        return $this;
    }

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

    /**
     * @return string
     */
    public function getGenericSuccessMessage()
    {
        return 'Success';
    }

    /**
     * @return string
     */
    public function getEntityDisplayName()
    {
        return ucwords(static::MAIN_TAG);
    }

    protected function getEntityEditUrl(BaseInterface $entity)
    {
        return $this->url()->fromRoute($this->getSuccessRedirectRouteName(), array(static::MAIN_ENTITY_ID_PARAM => $entity->id(), 'action' => 'edit'));
    }

    /**
     * @return string
     */
    public function getUpdateSuccessMessage()
    {
        return $this->getEntityDisplayName().' was updated. getEntityEditUrl($this->entity()).'">Click here to edit.';
    }

    public function getCreateSuccessMessage()
    {
        return $this->getEntityDisplayName().' was created. getEntityEditUrl($this->entity()).'">Click here to edit.';
    }

    /**
     * @return string
     */
    public function getDeleteSuccessMessage()
    {
        return $this->getEntityDisplayName().' was deleted';
    }

    /**
     * Returns message based on whether the main entity was created or updated
     * @return string
     */
    public function getFormattedSuccessMessage()
    {
        return $this->getSuccessMessage($this->getOperation());
    }

    /**
     * @return Params
     */
    protected function getSuccessMessages()
    {
        return Params::create(array(
                self::OPERATION_CREATE => $this->getCreateSuccessMessage(),
                self::OPERATION_UPDATE => $this->getUpdateSuccessMessage(),
                self::OPERATION_DELETE => $this->getDeleteSuccessMessage(),
            ));
    }

    /**
     * @return array
     */
    public function getSuccessMessage($key)
    {
        return $this->getSuccessMessages()->get($key, $this->getGenericSuccessMessage());
    }

    /**
     * Returns the route name to redirect to on successful update
     * @return string
     */
    public function getSuccessRedirectRouteName()
    {
        return 'home';
    }

    /**
     * Returns any param values for the success redirect route
     * @return array
     */
    public function getSuccessRedirectRouteParams()
    {
        return array();
    }

    /**
     * Returns any option values for the success redirect route
     * @return array
     */
    public function getSuccessRedirectRouteOptions()
    {
        return array();
    }

    /**
     * Inject an EventManager instance
     *
     * @param  EventManagerInterface $eventManager
     * @return void
     */
    public function setEventManager(EventManagerInterface $events)
    {
        $events->setIdentifiers(array(
            __CLASS__,
            get_called_class(),
        ));
        $this->events = $events;

        return $this;
    }

    /**
     * Retrieve the event manager
     *
     * Lazy-loads an EventManager instance if none registered.
     *
     * @return EventManagerInterface
     */
    public function getEventManager()
    {
        if (null === $this->events) {
            $this->setEventManager(new EventManager());
        }

        return $this->events;
    }

    /**
     * Removes some elements from being validated; best used for subforms
     * @param $tag
     * @param array $elementNames
     */
    public function configureFormToExcludeData($tag, array $elementNames)
    {
        $removeCallable = array($this, 'removeStringFromArray');
        $self = $this;
        $this->getEventManager()->attach(self::EVENT_CONFIGURE_FORM.$tag, function (Event $event) use ($elementNames, $self) {
            /* @var $form \Zend\Form\Form */
            $form = $event->getParam('form');
            $fieldsToValidate = array_keys($form->getElements());
            foreach ($elementNames as $elementToRemove) {
                $self->removeStringFromArray($fieldsToValidate, $elementToRemove);
            }
            $form->setValidationGroup($fieldsToValidate);
        });
    }

    /**
     * Handler for subform data
     * @param $tag
     * @param $paramName
     * @return $this
     */
    public function setSubFormDataHandler($tag, $paramName)
    {
        $this->formDataEvent($tag, function (Params $params) use ($paramName) {return Params::create($params->get($paramName));});

        return $this;
    }

    public function setFormMapEntry($getterString, $configuredForm)
    {
        return $this;
    }

    /**
     * Function meant to be run as a callback for attacheToMainEntity.
     *
     * In this case, it's being used to filter form fields from the sub
     * forms and entities.
     *
     * @param $formObject
     * @param $form
     * @param $mainEntity
     * @param $tag
     */
    public function afterAttach($formObject, $form, $mainEntity, $tag)
    {
        foreach ($this->getExcludedFieldsForEntityTag($tag) as $fieldName) {
            /* @var \Zend\Form\Form $form */
            $form->remove($fieldName);
        }
    }

    /**
     * Given a tag (like contact) get a list of fields that need
     * to be excluded from the form.
     *
     * @param  string $entityTag
     * @return null   | array
     */
    protected function getExcludedFieldsForEntityTag($entityTag)
    {
        $excludedFields = $this->getExcludedFields();

        return
            isset($excludedFields[$entityTag]) ?
                $excludedFields[$entityTag] :
                array();
    }

    /**
     * Maintains a list of fields to exclude for this entity and
     * its subentities.
     *
     * @return array
     */
    protected function getExcludedFields()
    {
        return array();
    }

    /**
     * @param string $operation
     */
    public function setOperation($operation)
    {
        $this->operation = $operation;
    }

    /**
     * @return string
     */
    public function getOperation()
    {
        return $this->operation;
    }

    /**
     * @return boolean
     */
    public function getUseSessionMessage()
    {
        return $this->useSessionMessage;
    }

    /**
     * @param  boolean $useSessionMessage
     * @return $this
     */
    public function setUseSessionMessage($useSessionMessage)
    {
        $this->useSessionMessage = $useSessionMessage;

        return $this;
    }
}


<?php
/**
 * Mock adapter intended for testing
 *
 * PHP version 5
 *
 * LICENSE
 *
 * This source file is subject to BSD 3-Clause License that is bundled
 * with this package in the file LICENSE and available at the URL
 * https://raw.github.com/pear/HTTP_Request2/trunk/docs/LICENSE
 *
 * @category  HTTP
 * @package   HTTP_Request2
 * @author    Alexey Borzov <avb@php.net>
 * @copyright 2008-2014 Alexey Borzov <avb@php.net>
 * @license   http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License
 * @link      http://pear.php.net/package/HTTP_Request2
 */

/**
 * Base class for HTTP_Request2 adapters
 */
require_once 'HTTP/Request2/Adapter.php';

/**
 * Mock adapter intended for testing
 *
 * Can be used to test applications depending on HTTP_Request2 package without
 * actually performing any HTTP requests. This adapter will return responses
 * previously added via addResponse()
 * <code>
 * $mock = new HTTP_Request2_Adapter_Mock();
 * $mock->addResponse("HTTP/1.1 ... ");
 *
 * $request = new HTTP_Request2();
 * $request->setAdapter($mock);
 *
 * // This will return the response set above
 * $response = $req->send();
 * </code>
 *
 * @category HTTP
 * @package  HTTP_Request2
 * @author   Alexey Borzov <avb@php.net>
 * @license  http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License
 * @version  Release: 2.2.1
 * @link     http://pear.php.net/package/HTTP_Request2
 */
class HTTP_Request2_Adapter_Mock extends HTTP_Request2_Adapter
{
    /**
     * A queue of responses to be returned by sendRequest()
     * @var  array
     */
    protected $responses = array();

    /**
     * Returns the next response from the queue built by addResponse()
     *
     * Only responses without explicit URLs or with URLs equal to request URL
     * will be considered. If matching response is not found or the queue is
     * empty then default empty response with status 400 will be returned,
     * if an Exception object was added to the queue it will be thrown.
     *
     * @param HTTP_Request2 $request HTTP request message
     *
     * @return   HTTP_Request2_Response
     * @throws   Exception
     */
    public function sendRequest(HTTP_Request2 $request)
    {
        $requestUrl = (string)$request->getUrl();
        $response   = null;
        foreach ($this->responses as $k => $v) {
            if (!$v[1] || $requestUrl == $v[1]) {
                $response = $v[0];
                array_splice($this->responses, $k, 1);
                break;
            }
        }
        if (!$response) {
            return self::createResponseFromString("HTTP/1.1 400 Bad Request\r\n\r\n");

        } elseif ($response instanceof HTTP_Request2_Response) {
            return $response;

        } else {
            // rethrow the exception
            $class   = get_class($response);
            $message = $response->getMessage();
            $code    = $response->getCode();
            throw new $class($message, $code);
        }
    }

    /**
     * Adds response to the queue
     *
     * @param mixed  $response either a string, a pointer to an open file,
     *                         an instance of HTTP_Request2_Response or Exception
     * @param string $url      A request URL this response should be valid for
     *                         (see {@link http://pear.php.net/bugs/bug.php?id=19276})
     *
     * @throws   HTTP_Request2_Exception
     */
    public function addResponse($response, $url = null)
    {
        if (is_string($response)) {
            $response = self::createResponseFromString($response);
        } elseif (is_resource($response)) {
            $response = self::createResponseFromFile($response);
        } elseif (!$response instanceof HTTP_Request2_Response &&
                  !$response instanceof Exception
        ) {
            throw new HTTP_Request2_Exception('Parameter is not a valid response');
        }
        $this->responses[] = array($response, $url);
    }

    /**
     * Creates a new HTTP_Request2_Response object from a string
     *
     * @param string $str string containing HTTP response message
     *
     * @return   HTTP_Request2_Response
     * @throws   HTTP_Request2_Exception
     */
    public static function createResponseFromString($str)
    {
        $parts       = preg_split('!(\r?\n){2}!m', $str, 2);
        $headerLines = explode("\n", $parts[0]);
        $response    = new HTTP_Request2_Response(array_shift($headerLines));
        foreach ($headerLines as $headerLine) {
            $response->parseHeaderLine($headerLine);
        }
        $response->parseHeaderLine('');
        if (isset($parts[1])) {
            $response->appendBody($parts[1]);
        }
        return $response;
    }

    /**
     * Creates a new HTTP_Request2_Response object from a file
     *
     * @param resource $fp file pointer returned by fopen()
     *
     * @return   HTTP_Request2_Response
     * @throws   HTTP_Request2_Exception
     */
    public static function createResponseFromFile($fp)
    {
        $response = new HTTP_Request2_Response(fgets($fp));
        do {
            $headerLine = fgets($fp);
            $response->parseHeaderLine($headerLine);
        } while ('' != trim($headerLine));

        while (!feof($fp)) {
            $response->appendBody(fread($fp, 8192));
        }
        return $response;
    }
}
?>


<?php

namespace Oxygen\Data\Repository\Doctrine;

use Carbon\Carbon;
use Doctrine\ORM\QueryBuilder;

trait Versions {

    /**
     * Makes a new version of the given entity.
     *
     * @param  object  $entity the entity
     * @param  boolean $flush
     * @return object  The new version
     */
    public function makeNewVersion($entity, $flush = true) {
        $new = clone $entity;
        $new->setHead($entity->getHead());
        $this->entities->persist($new);
        if($flush) {
            $this->entities->flush();
        }
        return $new;
    }

    /**
     * Makes an entity the head version.
     *
     * @param object $entity
     * @return boolean
     */
    public function makeHeadVersion($entity) {
        if($entity->isHead()) {
            return false;
        }

        $oldHead = $entity->getHead();

        // update references on all old versions
        $this->entities->createQueryBuilder()
            ->update($this->entityName, 'o')
            ->set('o.headVersion', ':newHead')
            ->where('o.headVersion = :oldHead')
            ->setParameter('newHead', $entity)
            ->setParameter('oldHead', $oldHead)
            ->getQuery()
            ->execute();

        // make the old head now just a sub-version
        $oldHead->setHead($entity);
        $this->persist($oldHead, false);

        // make this entity the head
        $entity->setHead(null);
        $this->persist($entity, false);

        $this->entities->flush();
        return true;
    }

    /**
     * Determines if the entity needs a new version created.
     *
     * @param $entity
     * @return boolean
     */

    protected function needsNewVersion($entity) {
        if(!$entity->isHead()) {
            return false;
        }

        if(!$entity->hasVersions()) {
            return true;
        }

        $oldTimestamp = $entity->getVersions()->first()->getUpdatedAt();
        $newTimestamp = Carbon::now();
        $diff = $newTimestamp->diffInHours($oldTimestamp);

        if($diff >= 24) {
            return true;
        }
    }

    /**
     * Persists an entity. Creating a new version of it if needed.
     *
     * @param object $entity
     * @param string $version
     * @return boolean true if a new version was created
     */
    public function persist($entity, $version = 'guess') {
        $this->entities->persist($entity);

        if($version === 'new' || ($version === 'guess' && $this->needsNewVersion($entity))) {
            $this->makeNewVersion($entity, false);
            $return = true;
        } else {
            $return = false;
        }

        $this->entities->flush();

        return $return;
    }

    /**
     * Clears old versions of an entity.
     *
     * @param object $entity
     * @return object
     */
    public function clearVersions($entity) {
        $entity = $entity->getHead();
        $versions = $entity->getVersions();

        foreach($versions as $version) {
            $this->delete($version, false);
        }
        $versions->clear();
        $this->persist($entity, 'overwrite');

        return $entity;
    }

    /**
     * Filters out non-head versions.
     *
     * @param QueryBuilder $query
     * @return QueryBuilder
     */

    protected function scopeExcludeVersions(QueryBuilder $query) {
        return $query->andWhere('o.headVersion is NULL');
    }

    /**
     * Filters everything except non-head versions.
     *
     * @param QueryBuilder $query
     * @return QueryBuilder
     */

    protected function scopeOnlyVersions(QueryBuilder $query) {
        return $query->andWhere('o.headVersion is NOT NULL');
    }

}