<?php

/*
 * This file is part of the Typhoon package.
 *
 * Copyright © 2013 Erin Millard
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Eloquent\Typhoon\Generator;

use Eloquent\Cosmos\ClassName;
use Eloquent\Typhoon\Configuration\RuntimeConfiguration;
use Eloquent\Typhoon\TypeCheck\TypeCheck;
use Icecave\Pasta\AST\Expr\ArrayLiteral;
use Icecave\Pasta\AST\Expr\Assign;
use Icecave\Pasta\AST\Expr\Call;
use Icecave\Pasta\AST\Expr\Concat;
use Icecave\Pasta\AST\Expr\Constant;
use Icecave\Pasta\AST\Expr\Literal;
use Icecave\Pasta\AST\Expr\LogicalAnd;
use Icecave\Pasta\AST\Expr\LogicalNot;
use Icecave\Pasta\AST\Expr\Member;
use Icecave\Pasta\AST\Expr\NewOperator;
use Icecave\Pasta\AST\Expr\QualifiedIdentifier;
use Icecave\Pasta\AST\Expr\StaticMember;
use Icecave\Pasta\AST\Expr\StrictEquals;
use Icecave\Pasta\AST\Expr\StrictNotEquals;
use Icecave\Pasta\AST\Expr\Subscript;
use Icecave\Pasta\AST\Expr\Variable;
use Icecave\Pasta\AST\Func\ArrayTypeHint;
use Icecave\Pasta\AST\Func\ObjectTypeHint;
use Icecave\Pasta\AST\Func\Parameter;
use Icecave\Pasta\AST\Identifier;
use Icecave\Pasta\AST\PhpBlock;
use Icecave\Pasta\AST\Stmt\ExpressionStatement;
use Icecave\Pasta\AST\Stmt\IfStatement;
use Icecave\Pasta\AST\Stmt\NamespaceStatement;
use Icecave\Pasta\AST\Stmt\ReturnStatement;
use Icecave\Pasta\AST\SyntaxTree;
use Icecave\Pasta\AST\Type\AccessModifier;
use Icecave\Pasta\AST\Type\ClassDefinition;
use Icecave\Pasta\AST\Type\ClassModifier;
use Icecave\Pasta\AST\Type\ConcreteMethod;
use Icecave\Pasta\AST\Type\Property;
use Icecave\Rasta\Renderer;

class FacadeGenerator implements StaticClassGenerator
{
    /**
     * @param Renderer|null                      $renderer
     * @param RuntimeConfigurationGenerator|null $configurationGenerator
     */
    public function __construct(
        Renderer $renderer = null,
        RuntimeConfigurationGenerator $configurationGenerator = null
    ) {
        $this->typeCheck = TypeCheck::get(__CLASS__, func_get_args());

        if (null === $renderer) {
            $renderer = new Renderer;
        }
        if (null === $configurationGenerator) {
            $configurationGenerator = new RuntimeConfigurationGenerator;
        }

        $this->renderer = $renderer;
        $this->configurationGenerator = $configurationGenerator;
    }

    /**
     * @return Renderer
     */
    public function renderer()
    {
        $this->typeCheck->renderer(func_get_args());

        return $this->renderer;
    }

    /**
     * @return RuntimeConfigurationGenerator
     */
    public function configurationGenerator()
    {
        $this->typeCheck->configurationGenerator(func_get_args());

        return $this->configurationGenerator;
    }

    /**
     * @param RuntimeConfiguration $configuration
     * @param null                 &$className
     *
     * @return string
     */
    public function generate(
        RuntimeConfiguration $configuration,
        &$className = null
    ) {
        $this->typeCheck->generate(func_get_args());

        return $this->generateSyntaxTree(
            $configuration,
            $className
        )->accept($this->renderer());
    }

    /**
     * @param RuntimeConfiguration $configuration
     * @param null                 &$className
     *
     * @return SyntaxTree
     */
    public function generateSyntaxTree(
        RuntimeConfiguration $configuration,
        &$className = null
    ) {
        $this->typeCheck->generateSyntaxTree(func_get_args());

        $className = $configuration
            ->validatorNamespace()
            ->joinAtoms('TypeCheck')
        ;

        $classDefinition = new ClassDefinition(
            new Identifier($className->shortName()->string()),
            ClassModifier::ABSTRACT_()
        );
        $classDefinition->add($this->generateGetMethod());
        $classDefinition->add($this->generateInstallMethod());
        $classDefinition->add($this->generateSetDummyModeMethod());
        $classDefinition->add($this->generateDummyModeMethod());
        $classDefinition->add($this->generateSetRuntimeGenerationMethod());
        $classDefinition->add($this->generateRuntimeGenerationMethod());
        $classDefinition->add($this->generateCreateValidatorMethod(
            $configuration
        ));
        $classDefinition->add($this->generateDefineValidatorMethod(
            $configuration
        ));
        $classDefinition->add($this->generateConfigurationMethod(
            $configuration
        ));

        $instancesProperty = new Property(
            new Identifier('instances'),
            AccessModifier::PRIVATE_(),
            true
        );
        $instancesProperty->setDefaultValue(
            new ArrayLiteral
        );
        $classDefinition->add($instancesProperty);

        $dummyModeProperty = new Property(
            new Identifier('dummyMode'),
            AccessModifier::PRIVATE_(),
            true
        );
        $dummyModeProperty->setDefaultValue(new Literal(false));
        $classDefinition->add($dummyModeProperty);

        $runtimeGenerationProperty = new Property(
            new Identifier('runtimeGeneration'),
            AccessModifier::PRIVATE_(),
            true
        );
        $runtimeGenerationProperty->setDefaultValue(new Literal(false));
        $classDefinition->add($runtimeGenerationProperty);

        $primaryBlock = new PhpBlock;
        $primaryBlock->add(new NamespaceStatement(QualifiedIdentifier::fromString(
            $className->parent()->toRelative()->string()
        )));
        $primaryBlock->add($classDefinition);

        $syntaxTree = new SyntaxTree;
        $syntaxTree->add($primaryBlock);

        return $syntaxTree;
    }

    /**
     * @return ConcreteMethod
     */
    protected function generateGetMethod()
    {
        $this->typeCheck->generateGetMethod(func_get_args());

        $staticConstant = new Constant(new Identifier('static'));
        $classNameIdentifier = new Identifier('className');
        $classNameVariable = new Variable($classNameIdentifier);
        $argumentsIdentifier = new Identifier('arguments');
        $argumentsVariable = new Variable($argumentsIdentifier);
        $staticInstances = new StaticMember(
            $staticConstant,
            new Variable(new Identifier('instances'))
        );

        $method = new ConcreteMethod(
            new Identifier('get'),
            AccessModifier::PUBLIC_(),
            true
        );
        $method->addParameter(new Parameter($classNameIdentifier));
        $argumentsParameter = new Parameter(
            $argumentsIdentifier,
            new ArrayTypeHint
        );
        $argumentsParameter->setDefaultValue(new Literal(null));
        $method->addParameter($argumentsParameter);

        $dummyModeIf = new IfStatement(
            new Call(new StaticMember(
                $staticConstant,
                new Constant(new Identifier('dummyMode'))
            ))
        );
        $newDummyCall = new Call(QualifiedIdentifier::fromString('DummyValidator'));
        $newDummy = new NewOperator($newDummyCall);
        $dummyModeIf->trueBranch()->add(new ReturnStatement($newDummy));
        $method->statementBlock()->add($dummyModeIf);

        $existsCall = new Call(QualifiedIdentifier::fromString('\array_key_exists'));
        $existsCall->addMany(array(
            $classNameVariable,
            $staticInstances,
        ));
        $nonExistantIf = new IfStatement(new LogicalNot($existsCall));
        $installCall = new Call(new StaticMember(
            $staticConstant,
            new Constant(new Identifier('install'))
        ));
        $installCall->add($classNameVariable);
        $createValidatorCall = new Call(new StaticMember(
            $staticConstant,
            new Constant(new Identifier('createValidator'))
        ));
        $createValidatorCall->add($classNameVariable);
        $installCall->add($createValidatorCall);
        $nonExistantIf->trueBranch()->add(new ExpressionStatement($installCall));
        $method->statementBlock()->add($nonExistantIf);

        $validatorVariable = new Variable(new Identifier('validator'));
        $method->statementBlock()->add(new ExpressionStatement(new Assign(
            $validatorVariable,
            new Subscript(
                $staticInstances,
                $classNameVariable
            )
        )));

        $nonNullArgumentsIf = new IfStatement(new StrictNotEquals(
            new Literal(null),
            $argumentsVariable
        ));
        $validateConstructCall = new Call(new Member(
            $validatorVariable,
            new Constant(new Identifier('validateConstruct'))
        ));
        $validateConstructCall->add($argumentsVariable);
        $nonNullArgumentsIf->trueBranch()->add(new ExpressionStatement(
            $validateConstructCall
        ));
        $method->statementBlock()->add($nonNullArgumentsIf);

        $method->statementBlock()->add(new ReturnStatement($validatorVariable));

        return $method;
    }

    /**
     * @return ConcreteMethod
     */
    protected function generateInstallMethod()
    {
        $this->typeCheck->generateInstallMethod(func_get_args());

        $classNameIdentifier = new Identifier('className');
        $validatorIdentifier = new Identifier('validator');

        $method = new ConcreteMethod(
            new Identifier('install'),
            AccessModifier::PUBLIC_(),
            true
        );
        $method->addParameter(new Parameter($classNameIdentifier));
        $method->addParameter(new Parameter($validatorIdentifier));

        $method->statementBlock()->add(new ExpressionStatement(
            new Assign(
                new Subscript(
                    new StaticMember(
                        new Constant(new Identifier('static')),
                        new Variable(new Identifier('instances'))
                    ),
                    new Variable($classNameIdentifier)
                ),
                new Variable($validatorIdentifier)
            )
        ));

        return $method;
    }

    /**
     * @return ConcreteMethod
     */
    protected function generateSetDummyModeMethod()
    {
        $this->typeCheck->generateSetDummyModeMethod(func_get_args());

        $dummyModeIdentifier = new Identifier('dummyMode');
        $dummyModeVariable = new Variable($dummyModeIdentifier);

        $method = new ConcreteMethod(
            new Identifier('setDummyMode'),
            AccessModifier::PUBLIC_(),
            true
        );
        $method->addParameter(new Parameter($dummyModeIdentifier));

        $method->statementBlock()->add(new ExpressionStatement(
            new Assign(
                new StaticMember(
                    new Constant(new Identifier('static')),
                    $dummyModeVariable
                ),
                $dummyModeVariable
            )
        ));

        return $method;
    }

    /**
     * @return ConcreteMethod
     */
    protected function generateDummyModeMethod()
    {
        $this->typeCheck->generateDummyModeMethod(func_get_args());

        $method = new ConcreteMethod(
            new Identifier('dummyMode'),
            AccessModifier::PUBLIC_(),
            true
        );

        $method->statementBlock()->add(new ReturnStatement(
            new StaticMember(
                new Constant(new Identifier('static')),
                new Variable(new Identifier('dummyMode'))
            )
        ));

        return $method;
    }

    /**
     * @return ConcreteMethod
     */
    protected function generateSetRuntimeGenerationMethod()
    {
        $this->typeCheck->generateSetRuntimeGenerationMethod(func_get_args());

        $runtimeGenerationIdentifier = new Identifier('runtimeGeneration');
        $runtimeGenerationVariable = new Variable($runtimeGenerationIdentifier);

        $method = new ConcreteMethod(
            new Identifier('setRuntimeGeneration'),
            AccessModifier::PUBLIC_(),
            true
        );
        $method->addParameter(new Parameter($runtimeGenerationIdentifier));

        $method->statementBlock()->add(new ExpressionStatement(
            new Assign(
                new StaticMember(
                    new Constant(new Identifier('static')),
                    $runtimeGenerationVariable
                ),
                $runtimeGenerationVariable
            )
        ));

        return $method;
    }

    /**
     * @return ConcreteMethod
     */
    protected function generateRuntimeGenerationMethod()
    {
        $this->typeCheck->generateRuntimeGenerationMethod(func_get_args());

        $method = new ConcreteMethod(
            new Identifier('runtimeGeneration'),
            AccessModifier::PUBLIC_(),
            true
        );

        $method->statementBlock()->add(new ReturnStatement(
            new StaticMember(
                new Constant(new Identifier('static')),
                new Variable(new Identifier('runtimeGeneration'))
            )
        ));

        return $method;
    }

    /**
     * @param RuntimeConfiguration $configuration
     *
     * @return ConcreteMethod
     */
    protected function generateCreateValidatorMethod(
        RuntimeConfiguration $configuration
    ) {
        $this->typeCheck->generateCreateValidatorMethod(func_get_args());

        $classNameIdentifier = new Identifier('className');
        $classNameVariable = new Variable($classNameIdentifier);
        $validatorClassNameVariable = new Variable(new Identifier('validatorClassName'));

        $method = new ConcreteMethod(
            new Identifier('createValidator'),
            AccessModifier::PROTECTED_(),
            true
        );
        $method->addParameter(new Parameter($classNameIdentifier));

        $validatorClassNameConcatenation = new Concat(
            new Literal(sprintf(
                '%s\\',
                $configuration
                    ->validatorNamespace()
                    ->joinAtoms('Validator')
                    ->string()
            )),
            $classNameVariable
        );
        $validatorClassNameConcatenation->add(new Literal('TypeCheck'));
        $method->statementBlock()->add(new ExpressionStatement(new Assign(
            $validatorClassNameVariable,
            $validatorClassNameConcatenation
        )));

        $staticConstant = new Constant(new Identifier('static'));
        $runtimeGenerationCall = new Call(new StaticMember(
            $staticConstant,
            new Constant(new Identifier('runtimeGeneration'))
        ));
        $classExistsCall = new Call(QualifiedIdentifier::fromString('\class_exists'));
        $classExistsCall->add($validatorClassNameVariable);
        $runtimeGenerationIf = new IfStatement(new LogicalAnd(
            $runtimeGenerationCall,
            new LogicalNot($classExistsCall)
        ));
        $dummyModeVariable = new Variable(new Identifier('dummyMode'));
        $dummyModeCall = new Call(new StaticMember(
            new Constant(new Identifier('static')),
            new Constant(new Identifier('dummyMode'))
        ));
        $runtimeGenerationIf->trueBranch()->add(
            new ExpressionStatement(new Assign(
                $dummyModeVariable,
                $dummyModeCall
            ))
        );
        $setDummyModeTrueCall = new Call(new StaticMember(
            new Constant(new Identifier('static')),
            new Constant(new Identifier('setDummyMode'))
        ));
        $setDummyModeTrueCall->add(new Literal(true));
        $runtimeGenerationIf->trueBranch()->add(new ExpressionStatement(
            $setDummyModeTrueCall
        ));
        $defineValidatorCall = new Call(new StaticMember(
            $staticConstant,
            new Constant(new Identifier('defineValidator'))
        ));
        $defineValidatorCall->add($classNameVariable);
        $runtimeGenerationIf->trueBranch()->add(
            new ExpressionStatement($defineValidatorCall)
        );
        $resetDummyModeCall = new Call(new StaticMember(
            new Constant(new Identifier('static')),
            new Constant(new Identifier('setDummyMode'))
        ));
        $resetDummyModeCall->add($dummyModeVariable);
        $runtimeGenerationIf->trueBranch()->add(new ExpressionStatement(
            $resetDummyModeCall
        ));
        $method->statementBlock()->add($runtimeGenerationIf);

        $method->statementBlock()->add(new ReturnStatement(
            new NewOperator($validatorClassNameVariable)
        ));

        return $method;
    }

    /**
     * @param RuntimeConfiguration $configuration
     *
     * @return ConcreteMethod
     */
    protected function generateDefineValidatorMethod(
        RuntimeConfiguration $configuration
    ) {
        $this->typeCheck->generateDefineValidatorMethod(func_get_args());

        $classNameIdentifier = new Identifier('className');
        $classNameVariable = new Variable($classNameIdentifier);
        $classGeneratorIdentifier = new Identifier('classGenerator');
        $classGeneratorVariable = new Variable($classGeneratorIdentifier);
        $classGeneratorClassIdentifier = QualifiedIdentifier::fromString(
            '\Eloquent\Typhoon\Generator\ValidatorClassGenerator'
        );

        $method = new ConcreteMethod(
            new Identifier('defineValidator'),
            AccessModifier::PROTECTED_(),
            true
        );
        $method->addParameter(new Parameter($classNameIdentifier));
        $classGeneratorParameter = new Parameter(
            $classGeneratorIdentifier,
            new ObjectTypeHint($classGeneratorClassIdentifier)
        );
        $classGeneratorParameter->setDefaultValue(new Literal(null));
        $method->addParameter($classGeneratorParameter);

        $nullClassGeneratorIf = new IfStatement(new StrictEquals(
            new Literal(null),
            $classGeneratorVariable
        ));
        $nullClassGeneratorIf->trueBranch()->add(new ExpressionStatement(
            new Assign(
                $classGeneratorVariable,
                new NewOperator($classGeneratorClassIdentifier)
            )
        ));
        $method->statementBlock()->add($nullClassGeneratorIf);

        $evalCall = new Call(QualifiedIdentifier::fromString('eval'));
        $generateFromClassCall = new Call(new Member(
            $classGeneratorVariable,
            new Constant(new Identifier('generateFromClass'))
        ));
        $generateFromClassCall->add(new Call(new StaticMember(
            new Constant(new Identifier('static')),
            new Constant(new Identifier('configuration'))
        )));
        $newReflectorCall = new Call(
            QualifiedIdentifier::fromString('\ReflectionClass')
        );
        $newReflectorCall->add($classNameVariable);
        $newReflector = new NewOperator($newReflectorCall);
        $generateFromClassCall->add($newReflector);
        $evalCall->add(new Concat(
            new Literal('?>'),
            $generateFromClassCall
        ));
        $method->statementBlock()->add(new ExpressionStatement($evalCall));

        return $method;
    }

    /**
     * @param RuntimeConfiguration $configuration
     *
     * @return ConcreteMethod
     */
    protected function generateConfigurationMethod(
        RuntimeConfiguration $configuration
    ) {
        $this->typeCheck->generateConfigurationMethod(func_get_args());

        $method = new ConcreteMethod(
            new Identifier('configuration'),
            AccessModifier::PROTECTED_(),
            true
        );

        $method->statementBlock()->add(new ReturnStatement(
            $this->configurationGenerator()->generate($configuration)
        ));

        return $method;
    }

    private $renderer;
    private $configurationGenerator;
    private $typeCheck;
}


<?php

/*
 * This file is part of the andreas-weber/php-runner library.
 *
 * (c) Andreas Weber <code@andreas-weber.me>
 *
 * This source file is subject to the MIT license that is bundled
 * with this source code in the file LICENSE.
 */

namespace AndreasWeber\Runner\Event;

use AndreasWeber\Runner\Payload\PayloadInterface;
use AndreasWeber\Runner\Runner;
use AndreasWeber\Runner\Task\TaskInterface;
use Symfony\Component\EventDispatcher\Event as BaseEvent;

class Event extends BaseEvent implements EventInterface
{
    /**
     * @var Runner
     */
    private $runner;

    /**
     * @var TaskInterface
     */
    private $task;

    /**
     * @var PayloadInterface
     */
    private $payload;

    /**
     * @var int Exit code
     */
    private $exitCode;

    /**
     * @var \Exception
     */
    private $exception;

    /**
     * Sets the runner.
     *
     * @param Runner $runner
     *
     * @return $this
     */
    public function setRunner(Runner $runner)
    {
        $this->runner = $runner;

        return $this;
    }

    /**
     * Returns the runner.
     *
     * @return Runner
     */
    public function getRunner()
    {
        return $this->runner;
    }

    /**
     * Sets the task.
     *
     * @param TaskInterface $task
     *
     * @return $this
     */
    public function setTask(TaskInterface $task)
    {
        $this->task = $task;

        return $this;
    }

    /**
     * Returns the task
     *
     * @return TaskInterface
     */
    public function getTask()
    {
        return $this->task;
    }

    /**
     * Sets the payload.
     *
     * @param PayloadInterface $payload
     *
     * @return $this
     */
    public function setPayload(PayloadInterface $payload)
    {
        $this->payload = $payload;

        return $this;
    }

    /**
     * Returns the payload.
     *
     * @return PayloadInterface
     */
    public function getPayload()
    {
        return $this->payload;
    }

    /**
     * Sets the exit code.
     *
     * @param int $exitCode
     *
     * @return $this
     */
    public function setExitCode($exitCode)
    {
        \Assert\that($exitCode)->integer()->min(0);

        $this->exitCode = $exitCode;

        return $this;
    }

    /**
     * Returns the exit code.
     *
     * @return int
     */
    public function getExitCode()
    {
        return $this->exitCode;
    }

    /**
     * Sets the exception.
     *
     * @param \Exception $exception
     *
     * @return $this
     */
    public function setException(\Exception $exception)
    {
        $this->exception = $exception;

        return $this;
    }

    /**
     * Returns the exception.
     *
     * @return \Exception
     */
    public function getException()
    {
        return $this->exception;
    }
}


<?php

/*
 * This file is part of the Typhoon package.
 *
 * Copyright © 2013 Erin Millard
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Eloquent\Typhoon\Generator\ExceptionGenerator;

use Eloquent\Cosmos\ClassName;
use Eloquent\Typhoon\Configuration\RuntimeConfiguration;
use Eloquent\Typhoon\Generator\StaticClassGenerator;
use Eloquent\Typhoon\TypeCheck\TypeCheck;
use Icecave\Pasta\AST\Expr\Assign;
use Icecave\Pasta\AST\Expr\Call;
use Icecave\Pasta\AST\Expr\Constant;
use Icecave\Pasta\AST\Expr\Literal;
use Icecave\Pasta\AST\Expr\Member;
use Icecave\Pasta\AST\Expr\QualifiedIdentifier;
use Icecave\Pasta\AST\Expr\StaticMember;
use Icecave\Pasta\AST\Expr\Variable;
use Icecave\Pasta\AST\Func\ObjectTypeHint;
use Icecave\Pasta\AST\Func\Parameter;
use Icecave\Pasta\AST\Identifier;
use Icecave\Pasta\AST\PhpBlock;
use Icecave\Pasta\AST\Stmt\ExpressionStatement;
use Icecave\Pasta\AST\Stmt\NamespaceStatement;
use Icecave\Pasta\AST\Stmt\ReturnStatement;
use Icecave\Pasta\AST\Stmt\StatementBlock;
use Icecave\Pasta\AST\SyntaxTree;
use Icecave\Pasta\AST\Type\AccessModifier;
use Icecave\Pasta\AST\Type\ClassDefinition;
use Icecave\Pasta\AST\Type\ClassModifier;
use Icecave\Pasta\AST\Type\ConcreteMethod;
use Icecave\Pasta\AST\Type\Property;
use Icecave\Rasta\Renderer;

class MissingArgumentExceptionGenerator implements StaticClassGenerator
{
    /**
     * @param Renderer|null $renderer
     */
    public function __construct(Renderer $renderer = null)
    {
        $this->typeCheck = TypeCheck::get(__CLASS__, func_get_args());

        if (null === $renderer) {
            $renderer = new Renderer;
        }

        $this->renderer = $renderer;
    }

    /**
     * @return Renderer
     */
    public function renderer()
    {
        $this->typeCheck->renderer(func_get_args());

        return $this->renderer;
    }

    /**
     * @param RuntimeConfiguration $configuration
     * @param null                 &$className
     *
     * @return string
     */
    public function generate(
        RuntimeConfiguration $configuration,
        &$className = null
    ) {
        $this->typeCheck->generate(func_get_args());

        return $this->generateSyntaxTree(
            $configuration,
            $className
        )->accept($this->renderer());
    }

    /**
     * @param RuntimeConfiguration $configuration
     * @param null                 &$className
     *
     * @return SyntaxTree
     */
    public function generateSyntaxTree(
        RuntimeConfiguration $configuration,
        &$className = null
    ) {
        $this->typeCheck->generateSyntaxTree(func_get_args());

        $className = $configuration
            ->validatorNamespace()
            ->joinAtoms('Exception', 'MissingArgumentException')
        ;

        $classDefinition = new ClassDefinition(
            new Identifier($className->shortName()->string()),
            ClassModifier::FINAL_()
        );
        $classDefinition->setParentName(
            QualifiedIdentifier::fromString('UnexpectedInputException')
        );
        $classDefinition->add($this->generateConstructor());
        $classDefinition->add($this->generateParameterNameMethod());
        $classDefinition->add($this->generateIndexMethod());
        $classDefinition->add($this->generateExpectedTypeMethod());

        $classDefinition->add(new Property(
            new Identifier('parameterName'),
            AccessModifier::PRIVATE_()
        ));
        $classDefinition->add(new Property(
            new Identifier('index'),
            AccessModifier::PRIVATE_()
        ));
        $classDefinition->add(new Property(
            new Identifier('expectedType'),
            AccessModifier::PRIVATE_()
        ));

        $primaryBlock = new PhpBlock;
        $primaryBlock->add(new NamespaceStatement(QualifiedIdentifier::fromString(
            $className->parent()->toRelative()->string()
        )));
        $primaryBlock->add($classDefinition);

        $syntaxTree = new SyntaxTree;
        $syntaxTree->add($primaryBlock);

        return $syntaxTree;
    }

    /**
     * @return ConcreteMethod
     */
    protected function generateConstructor()
    {
        $this->typeCheck->generateConstructor(func_get_args());

        $parameterNameIdentifier = new Identifier('parameterName');
        $parameterNameVariable = new Variable($parameterNameIdentifier);
        $indexIdentifier = new Identifier('index');
        $indexVariable = new Variable($indexIdentifier);
        $expectedTypeIdentifier = new Identifier('expectedType');
        $expectedTypeVariable = new Variable($expectedTypeIdentifier);
        $previousIdentifier = new Identifier('previous');
        $thisVariable = new Variable(new Identifier('this'));
        $thisParameterNameMember = new Member(
            $thisVariable,
            new Constant($parameterNameIdentifier)
        );
        $thisIndexMember = new Member(
            $thisVariable,
            new Constant($indexIdentifier)
        );
        $thisExpectedTypeMember = new Member(
            $thisVariable,
            new Constant($expectedTypeIdentifier)
        );

        $method = new ConcreteMethod(
            new Identifier('__construct'),
            AccessModifier::PUBLIC_()
        );
        $method->addParameter(new Parameter($parameterNameIdentifier));
        $method->addParameter(new Parameter($indexIdentifier));
        $method->addParameter(new Parameter($expectedTypeIdentifier));
        $previousParameter = new Parameter(
            $previousIdentifier,
            new ObjectTypeHint(QualifiedIdentifier::fromString('\Exception'))
        );
        $previousParameter->setDefaultValue(new Literal(null));
        $method->addParameter($previousParameter);

        $method->statementBlock()->add(new ExpressionStatement(new Assign(
            $thisParameterNameMember,
            $parameterNameVariable
        )));
        $method->statementBlock()->add(new ExpressionStatement(new Assign(
            $thisIndexMember,
            $indexVariable
        )));
        $method->statementBlock()->add(new ExpressionStatement(new Assign(
            $thisExpectedTypeMember,
            $expectedTypeVariable
        )));

        $sprintfCall = new Call(QualifiedIdentifier::fromString('\sprintf'));
        $sprintfCall->add(
            new Literal("Missing argument for parameter '%s' at index %d. Expected '%s'.")
        );
        $sprintfCall->add($parameterNameVariable);
        $sprintfCall->add($indexVariable);
        $sprintfCall->add($expectedTypeVariable);
        $parentConstructCall = new Call(new StaticMember(
            new Constant(new Identifier('parent')),
            new Constant(new Identifier('__construct'))
        ));
        $parentConstructCall->add($sprintfCall);
        $parentConstructCall->add(new Variable($previousIdentifier));
        $method->statementBlock()->add(new ExpressionStatement(
            $parentConstructCall
        ));

        return $method;
    }

    /**
     * @return ConcreteMethod
     */
    protected function generateParameterNameMethod()
    {
        $this->typeCheck->generateParameterNameMethod(func_get_args());

        $parameterNameIdentifier = new Identifier('parameterName');
        $method = new ConcreteMethod(
            $parameterNameIdentifier,
            AccessModifier::PUBLIC_()
        );
        $method->statementBlock()->add(new ReturnStatement(new Member(
            new Variable(new Identifier('this')),
            new Constant($parameterNameIdentifier)
        )));

        return $method;
    }

    /**
     * @return ConcreteMethod
     */
    protected function generateIndexMethod()
    {
        $this->typeCheck->generateIndexMethod(func_get_args());

        $indexIdentifier = new Identifier('index');
        $method = new ConcreteMethod(
            $indexIdentifier,
            AccessModifier::PUBLIC_()
        );
        $method->statementBlock()->add(new ReturnStatement(new Member(
            new Variable(new Identifier('this')),
            new Constant($indexIdentifier)
        )));

        return $method;
    }

    /**
     * @return ConcreteMethod
     */
    protected function generateExpectedTypeMethod()
    {
        $this->typeCheck->generateExpectedTypeMethod(func_get_args());

        $expectedTypeIdentifier = new Identifier('expectedType');
        $method = new ConcreteMethod(
            $expectedTypeIdentifier,
            AccessModifier::PUBLIC_()
        );
        $method->statementBlock()->add(new ReturnStatement(new Member(
            new Variable(new Identifier('this')),
            new Constant($expectedTypeIdentifier)
        )));

        return $method;
    }

    private $renderer;
    private $typeCheck;
}


<?php

namespace Harmony\Bundle\ThemeBundle\Twig\Loader;

use Harmony\Bundle\CoreBundle\Component\HttpKernel\AbstractKernel;
use Harmony\Bundle\SettingsManagerBundle\Settings\SettingsRouter;
use Liip\ThemeBundle\Twig\Loader\FilesystemLoader as BaseFilesystemLoader;
use Symfony\Component\Config\FileLocatorInterface;
use Symfony\Component\HttpKernel\KernelInterface;
use Symfony\Component\Templating\TemplateNameParserInterface;
use Symfony\Component\Templating\TemplateReferenceInterface;

/**
 * Class FilesystemLoader
 *
 * @package Harmony\Bundle\ThemeBundle\Twig\Loader
 */
class FilesystemLoader extends BaseFilesystemLoader
{

    /** @var KernelInterface $kernel */
    protected $kernel;

    /** @var SettingsRouter $settingsRouter */
    protected $settingsRouter;

    /**
     * Constructor.
     *
     * @see TwigBundle own FilesystemLoader
     *
     * @param FileLocatorInterface           $locator  A FileLocatorInterface instance
     * @param TemplateNameParserInterface    $parser   A TemplateNameParserInterface instance
     * @param KernelInterface|AbstractKernel $kernel
     * @param SettingsRouter                 $settingsRouter
     * @param string|null                    $rootPath The root path common to all relative paths (null for getcwd())
     */
    public function __construct(FileLocatorInterface $locator, TemplateNameParserInterface $parser,
                                KernelInterface $kernel, SettingsRouter $settingsRouter, ?string $rootPath = null)
    {
        parent::__construct($locator, $parser, $rootPath);
        $this->kernel         = $kernel;
        $this->settingsRouter = $settingsRouter;
    }

    /**
     * Returns the path to the template file.
     * The file locator is used to locate the template when the naming convention
     * is the symfony one (i.e. the name can be parsed).
     * Otherwise the template is located using the locator from the twig library.
     *
     * @param string|TemplateReferenceInterface $template The template
     * @param bool                              $throw    When true, a \Twig_Error_Loader exception will be thrown if a
     *                                                    template could not be found
     *
     * @return string The path to the template file
     * @throws \Twig_Error_Loader if the template could not be found
     */
    protected function findTemplate($template, $throw = true)
    {
        // Set list of themes, otherwise generate error when clearing cache warmup
        $this->activeTheme->setThemes(array_keys($this->kernel->getThemes()));

        // Set active theme from database/settings
        if ($name = $this->settingsRouter->get('theme')) {
            $this->activeTheme->setName($name);
        }

        return parent::findTemplate($template, $throw);
    }
}


<?php

namespace Harmony\Bundle\ThemeBundle\DependencyInjection\Compiler;

use Harmony\Bundle\SettingsManagerBundle\Provider\DoctrineOdmSettingsProvider;
use Harmony\Bundle\SettingsManagerBundle\Provider\DoctrineOrmSettingsProvider;
use Harmony\Bundle\ThemeBundle\Provider\ThemeProviderFactory;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;

/**
 * Class ThemeProviderPass
 *
 * @package Harmony\Bundle\ThemeBundle\DependencyInjection\Compiler
 */
class ThemeProviderPass implements CompilerPassInterface
{

    /**
     * You can modify the container here before it is dumped to PHP code.
     *
     * @param ContainerBuilder $container
     */
    public function process(ContainerBuilder $container)
    {
        // Register $provider for Doctrine ORM or ODM, fallback to lazy provider otherwise
        $themeProviderFactoryDefinition = $container->findDefinition(ThemeProviderFactory::class);

        if ($container->hasDefinition(DoctrineOrmSettingsProvider::class)) {
            $themeProviderFactoryDefinition->setArgument('$provider',
                new Reference(DoctrineOrmSettingsProvider::class));
        } elseif ($container->hasDefinition(DoctrineOdmSettingsProvider::class)) {
            $themeProviderFactoryDefinition->setArgument('$provider',
                new Reference(DoctrineOdmSettingsProvider::class));
        } else {
            $themeProviderFactoryDefinition->setArgument('$provider',
                new Reference('settings_manager.provider.config'));
        }
    }
}


<?php

declare(strict_types=1);

namespace Harmony\Bundle\ThemeBundle\EventListener;

use Exception;
use Harmony\Bundle\CoreBundle\Component\HttpKernel\AbstractKernel;
use Harmony\Bundle\CoreBundle\Component\Routing\RouteCollectionBuilder;
use Harmony\Bundle\SettingsManagerBundle\Settings\SettingsRouter;
use Harmony\Bundle\ThemeBundle\Exception\NoActiveThemeException;
use LogicException;
use ReflectionException;
use SplFileInfo;
use Symfony\Component\Finder\Finder;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\HttpKernel\KernelInterface;
use Symfony\Component\Translation\DataCollectorTranslator;
use Symfony\Component\Translation\Translator;
use Symfony\Contracts\Translation\TranslatorInterface;
use function explode;
use function is_dir;

/**
 * Class ThemeRequestListener
 *
 * @package Harmony\Bundle\ThemeBundle\EventListener
 */
class ThemeRequestListener
{

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

    /** @var SettingsRouter $settingsRouter */
    protected $settingsRouter;

    /** @var KernelInterface $kernel */
    protected $kernel;

    /** @var TranslatorInterface|DataCollectorTranslator|Translator $translator */
    protected $translator;

    /** @var RouteCollectionBuilder $builder */
    protected $builder;

    /**
     * @param KernelInterface|AbstractKernel              $kernel
     * @param SettingsRouter                              $settingsRouter
     * @param TranslatorInterface|DataCollectorTranslator $translator
     * @param RouteCollectionBuilder                      $builder
     */
    public function __construct(KernelInterface $kernel, SettingsRouter $settingsRouter,
                                TranslatorInterface $translator, RouteCollectionBuilder $builder)
    {
        $this->kernel         = $kernel;
        $this->settingsRouter = $settingsRouter;
        $this->translator     = $translator;
        $this->builder        = $builder;
    }

    /**
     * @param GetResponseEvent $event
     *
     * @throws ReflectionException
     * @throws Exception
     */
    public function onKernelRequest(GetResponseEvent $event)
    {
        if (HttpKernelInterface::MASTER_REQUEST === $event->getRequestType()) {
            $value = $this->settingsRouter->get('theme', null);

            /**
             * Throw exception if no theme set by default.
             * This can occur only for routes inside the `main` slot.
             * In that case, exception will not be throw in the admin area.
             */
            if (null === $value && $this->builder->hasRoute($event->getRequest()->get('_route'))) {
                throw new NoActiveThemeException('You must enable a theme to be set has an active theme.');
            }

            if ((null !== $theme = $this->kernel->getThemes()[$value] ?? null) &&
                $this->translator instanceof DataCollectorTranslator) {

                $finder = (new Finder())->files();
                // Parent need to be loaded first
                if (null !== $theme->getParent() &&
                    is_dir($parentTransPath = $theme->getParent()->getPath() . '/translations')) {
                    $finder->in($parentTransPath);
                }
                // Child (current) theme, will override translations
                if (is_dir($transPath = $theme->getPath() . '/translations')) {
                    $finder->in($transPath);
                }

                try {
                    /** @var SplFileInfo $file */
                    foreach ($finder as $file) {
                        [$domain, $locale] = explode('.', $file->getBasename(), 3);
                        switch ($file->getExtension()) {
                            case 'php':
                                $this->translator->addResource('php', (string)$file, $locale, $domain);
                                break;
                            case 'xlf':
                            case 'xliff':
                                $this->translator->addResource('xlf', (string)$file, $locale, $domain);
                                break;
                            case 'yaml':
                                $this->translator->addResource('yaml', (string)$file, $locale, $domain);
                                break;
                        }
                    }
                }
                catch (LogicException $e) {
                }
            }
        }
    }
}


<?php

/**
 * Adds URLSegment functionality to Tags & Categories
 *
 * @package silverstripe
 * @subpackage blog
 *
 * @author Michael Strong <github@michaelstrong.co.uk>
**/
class URLSegmentExtension extends DataExtension {

	private static $db = array(
		"URLSegment" => "Varchar(255)"
	);

	public function onBeforeWrite() {
		$this->owner->generateURLSegment();
	}

	/**
	 * Generates a unique URLSegment from the title.
	 *
	 * @param $increment
	 *
	 * @return string URLSegment
	**/
	public function generateURLSegment($increment = null) {
		$filter = new URLSegmentFilter();
		$this->owner->URLSegment = $filter->filter($this->owner->Title);
		if(is_int($increment)) $this->owner->URLSegment .= '-' . $increment;

		// Check to see if the URLSegment already exists
		$duplicate = DataList::create($this->owner->ClassName)->filter(array(
			"URLSegment" => $this->owner->URLSegment,
			"BlogID" => $this->owner->BlogID
		));
		if($this->owner->ID) $duplicate = $duplicate->exclude("ID", $this->owner->ID);
		if($duplicate->count() > 0) {
			$increment = is_int($increment) ? $increment + 1 : 0;
			$this->owner->generateURLSegment((int) $increment);
		}
		return $this->owner->URLSegment;
	}

}


<?php

/*
 * This file is part of the Typhoon package.
 *
 * Copyright © 2013 Erin Millard
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Eloquent\Typhoon\CodeAnalysis\Issue\ParameterIssue;

use Eloquent\Typhoon\ClassMapper\ClassDefinition;
use Eloquent\Typhoon\ClassMapper\MethodDefinition;
use Eloquent\Typhoon\CodeAnalysis\Issue\AbstractParameterRelatedIssue;
use Eloquent\Typhoon\CodeAnalysis\Issue\IssueSeverity;
use Eloquent\Typhoon\CodeAnalysis\Issue\IssueVisitorInterface;
use Eloquent\Typhoon\CodeAnalysis\Issue\ParameterIssueInterface;
use Eloquent\Typhoon\TypeCheck\TypeCheck;

class DocumentedParameterNameMismatch extends AbstractParameterRelatedIssue implements ParameterIssueInterface
{
    /**
     * @param ClassDefinition    $classDefinition
     * @param MethodDefinition   $methodDefinition
     * @param string             $parameterName
     * @param string             $documentedParameterName
     * @param IssueSeverity|null $severity
     */
    public function __construct(
        ClassDefinition $classDefinition,
        MethodDefinition $methodDefinition,
        $parameterName,
        $documentedParameterName,
        IssueSeverity $severity = null
    ) {
        $this->typeCheck = TypeCheck::get(__CLASS__, func_get_args());
        parent::__construct(
            $classDefinition,
            $methodDefinition,
            $parameterName,
            $severity
        );

        $this->documentedParameterName = $documentedParameterName;
    }

    /**
     * @return string
     */
    public function documentedParameterName()
    {
        $this->typeCheck->documentedParameterName(func_get_args());

        return $this->documentedParameterName;
    }

    /**
     * @param IssueVisitorInterface $visitor
     *
     * @return mixed
     */
    public function accept(IssueVisitorInterface $visitor)
    {
        $this->typeCheck->accept(func_get_args());

        return $visitor->visitDocumentedParameterNameMismatch($this);
    }

    private $documentedParameterName;
    private $typeCheck;
}


<?php declare(strict_types=1);

/**
 * @copyright (c) 2015-present brian ridley
 * @author brian ridley <ptlis@ptlis.net>
 * @license http://opensource.org/licenses/MIT MIT
 */

namespace ptlis\ShellCommand;

use ptlis\ShellCommand\Interfaces\ProcessOutputInterface;

/**
 * Stores the output of a terminated process.
 */
final class ProcessOutput implements ProcessOutputInterface
{
    /** @var int */
    private $exitCode;

    /** @var string */
    private $stdOut;

    /** @var string */
    private $stdErr;

    public function __construct(
        int $exitCode,
        string $stdOut,
        string $stdErr
    ) {
        $this->exitCode = $exitCode;
        $this->stdOut = $stdOut;
        $this->stdErr = $stdErr;
    }

    public function getStdOut(): string
    {
        return $this->stdOut;
    }

    public function getStdOutLines(): array
    {
        return $this->stringToArray($this->stdOut);
    }

    public function getStdErr(): string
    {
        return $this->stdErr;
    }

    public function getStdErrLines(): array
    {
        return $this->stringToArray($this->stdErr);
    }

    public function getExitCode(): int
    {
        return $this->exitCode;
    }

    /**
     * Accepts console output as a string and returns an array of it split by newlines.
     */
    private function stringToArray(string $string): array
    {
        $lines = preg_split('/\R/', $string);
        if (1 === count($lines) && '' === $lines[0]) {
            $lines = [];
        }

        return $lines;
    }
}


<?php

/*
 * This file is part of the Typhoon package.
 *
 * Copyright © 2013 Erin Millard
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Eloquent\Typhoon\Configuration;

use Eloquent\Enumeration\Enumeration;
use Eloquent\Typhoon\TypeCheck\TypeCheck;
use Exception as NativeException;

final class ConfigurationOption extends Enumeration
{
    const LOADER_PATHS = 'loader-paths';
    const OUTPUT_PATH = 'output-path';
    const SOURCE_PATHS = 'source-paths';
    const USE_NATIVE_CALLABLE = 'use-native-callable';
    const VALIDATOR_NAMESPACE = 'validator-namespace';

    /**
     * @param string               $className
     * @param string               $property
     * @param mixed                $value
     * @param NativeException|null $previous
     *
     * @return Exception\UndefinedConfigurationOptionException
     */
    protected static function createUndefinedInstanceException(
        $className,
        $property,
        $value,
        NativeException $previous = null
    ) {
        TypeCheck::get(__CLASS__)->createUndefinedInstanceException(func_get_args());

        return new Exception\UndefinedConfigurationOptionException($value, $previous);
    }
}


<?php

/**
 * This class is responsible for filtering the SiteTree when necessary and also
 * overlaps into filtering only published posts.
 *
 * @package silverstripe
 * @subpackage blog
 *
 * @author Michael Strong <github@michaelstrong.co.uk>
 *
 **/
class BlogFilter extends Lumberjack {

	/**
	 * Augments (@link Hierarchy::stageChildren()}
	 *
	 * @param $staged DataList
	 * @param $showAll boolean
	**/
	public function stageChildren($showAll = false) {
		$staged = parent::stageChildren($showAll);

		if(!$this->shouldFilter()
			&& in_array(get_class($this->owner), ClassInfo::subClassesFor("Blog"))
			&& !Permission::check("VIEW_DRAFT_CONTENT")
		) {

			// Get the current stage.
			$stage = Versioned::current_stage();
			if($stage == "Stage") $stage = "";
			else $stage = "_" . Convert::raw2sql($stage);

			// Filter published posts
			$dataQuery = $staged->dataQuery()
				->innerJoin("BlogPost", '"BlogPost' . $stage . '"."ID" = "SiteTree' . $stage . '"."ID"')
				->where('"PublishDate" < \'' . Convert::raw2sql(SS_Datetime::now()) . '\'');
			$staged = $staged->setDataQuery($dataQuery);
		}
		return $staged;
	}

	/**
	 * Augments (@link Hierarchy::liveChildren()}
	 *
	 * @param $staged DataList
	 * @param $showAll boolean
	**/
	public function liveChildren($showAll = false, $onlyDeletedFromStage = false) {
		$staged = parent::liveChildren($showAll, $onlyDeletedFromStage);

		if(!$this->shouldFilter()
			&& in_array(get_class($this->owner), ClassInfo::subClassesFor("Blog"))
			&& !Permission::check("VIEW_DRAFT_CONTENT")
		) {
			// Filter publish posts
			$dataQuery = $staged->dataQuery()
				->innerJoin("BlogPost", '"BlogPost_Live"."ID" = "SiteTree"_"Live"."ID"')
				->where('"PublishDate" < \'' . Convert::raw2sql(SS_Datetime::now()) . '\'');
			$staged = $staged->setDataQuery($dataQuery);
		}
		return $staged;
	}

}


<?php

/*
 * This file is part of the Typhoon package.
 *
 * Copyright © 2013 Erin Millard
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Eloquent\Typhoon\CodeAnalysis;

use Eloquent\Cosmos\ClassName;
use Eloquent\Typhoon\TypeCheck\TypeCheck;

class AnalysisResult
{
    /**
     * @param array<Issue\IssueInterface> $issues
     */
    public function __construct(array $issues = array())
    {
        $this->typeCheck = TypeCheck::get(__CLASS__, func_get_args());
        $this->issues = $issues;
    }

    /**
     * @return array<Issue\IssueInterface>
     */
    public function issues()
    {
        $this->typeCheck->issues(func_get_args());

        return $this->issues;
    }

    /**
     * @param Issue\IssueSeverity $severity
     *
     * @return array<Issue\IssueInterface>
     */
    public function issuesBySeverity(Issue\IssueSeverity $severity)
    {
        $this->typeCheck->issuesBySeverity(func_get_args());

        $issues = array();
        foreach ($this->issues() as $issue) {
            if ($issue->severity() === $severity) {
                $issues[] = $issue;
            }
        }

        return $issues;
    }

    /**
     * @param Issue\IssueSeverity $severity
     *
     * @return array<ClassName>
     */
    public function classNamesBySeverity(Issue\IssueSeverity $severity)
    {
        $this->typeCheck->classNamesBySeverity(func_get_args());

        $classNames = array();
        foreach ($this->issuesBySeverity($severity) as $issue) {
            if (
                $issue instanceof Issue\ClassRelatedIssueInterface &&
                !in_array(
                    $issue->classDefinition()->className(),
                    $classNames
                )
            ) {
                $classNames[] = $issue->classDefinition()->className();
            }
        }
        sort($classNames, SORT_STRING);

        return $classNames;
    }

    /**
     * @param Issue\IssueSeverity $severity
     * @param ClassName           $className
     *
     * @return array<Issue\IssueInterface>
     */
    public function classIssuesBySeverityAndClass(
        Issue\IssueSeverity $severity,
        ClassName $className
    ) {
        $this->typeCheck->classIssuesBySeverityAndClass(func_get_args());

        $issues = array();
        foreach ($this->issuesBySeverity($severity) as $issue) {
            if (
                $issue instanceof Issue\ClassIssueInterface &&
                $issue->classDefinition()->className()->isEqualTo($className)
            ) {
                $issues[] = $issue;
            }
        }

        return $issues;
    }

    /**
     * @param Issue\IssueSeverity $severity
     * @param ClassName           $className
     *
     * @return array<Issue\IssueInterface>
     */
    public function methodRelatedIssuesBySeverityAndClass(
        Issue\IssueSeverity $severity,
        ClassName $className
    ) {
        $this->typeCheck->methodRelatedIssuesBySeverityAndClass(func_get_args());

        $issues = array();
        foreach ($this->issuesBySeverity($severity) as $issue) {
            if (
                $issue instanceof Issue\MethodRelatedIssueInterface &&
                $issue->classDefinition()->className()->isEqualTo($className)
            ) {
                $issues[$issue->methodDefinition()->name()][] = $issue;
            }
        }

        return $issues;
    }

    /**
     * @return boolean
     */
    public function isError()
    {
        $this->typeCheck->isError(func_get_args());

        return count($this->issuesBySeverity(Issue\IssueSeverity::ERROR())) > 0;
    }

    private $issues;
    private $typeCheck;
}


<?php namespace uMailPHP\Entities;

/**
 * Rendition class.
 *
 * @license https://www.apache.org/licenses/LICENSE-2.0
 * @author Hunter Perrin <hperrin@gmail.com>
 * @copyright SciActive.com
 * @link http://umailphp.org/
 */
class Rendition extends \Nymph\Entity {
  const ETYPE = 'umailphp_rendition';

  public function __construct($id = 0) {
    if (parent::__construct($id) !== null) {
      return;
    }
    // Defaults.
    $this->enabled = true;
    $this->acOther = 1;
  }

  /**
   * Save the rendition.
   * @return bool True on success, false on failure.
   */
  public function save() {
    if (!isset($this->name)) {
      return false;
    }
    if (
        class_exists('\Tilmeld\Tilmeld')
        && !\Tilmeld\Tilmeld::gatekeeper('umailphp/admin')
      ) {
      return false;
    }
    return parent::save();
  }
}


<?php

namespace Harmony\Bundle\ThemeBundle\Provider;

use Harmony\Bundle\CoreBundle\Component\HttpKernel\AbstractKernel;
use Harmony\Bundle\ThemeBundle\DependencyInjection\SettingsConfiguration;
use Harmony\Sdk\Theme\ThemeInterface;
use Harmony\Bundle\SettingsManagerBundle\Model\SettingDomain;
use Harmony\Bundle\SettingsManagerBundle\Model\Setting;
use Harmony\Bundle\SettingsManagerBundle\Model\SettingTag;
use Harmony\Bundle\SettingsManagerBundle\Provider\Factory\ProviderFactoryInterface;
use Harmony\Bundle\SettingsManagerBundle\Provider\ReadableSimpleSettingsProvider;
use Harmony\Bundle\SettingsManagerBundle\Provider\SettingsProviderInterface;
use Harmony\Bundle\SettingsManagerBundle\Provider\Traits\ReadOnlyProviderTrait;
use Symfony\Component\Config\Definition\ConfigurationInterface;
use Symfony\Component\Config\Definition\Processor;
use Symfony\Component\HttpKernel\KernelInterface;
use Symfony\Component\Serializer\Exception\ExceptionInterface;
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
use Symfony\Component\Yaml\Yaml;

/**
 * Class ThemeProviderFactory
 *
 * @package Harmony\Bundle\ThemeBundle\Provider
 */
class ThemeProviderFactory implements ProviderFactoryInterface
{

    use ReadOnlyProviderTrait;

    /** @var DenormalizerInterface $serializer */
    protected $serializer;

    /** @var KernelInterface|AbstractKernel $kernel */
    protected $kernel;

    /** @var null|Setting $theme */
    protected $theme;

    /**
     * ThemeProviderFactory constructor.
     *
     * @param DenormalizerInterface     $serializer
     * @param SettingsProviderInterface $provider
     * @param KernelInterface           $kernel
     */
    public function __construct(DenormalizerInterface $serializer, SettingsProviderInterface $provider,
                                KernelInterface $kernel)
    {
        $this->serializer = $serializer;
        $theme            = $provider->getSettingsByName(['default'], ['theme']);
        $this->theme      = array_shift($theme);
        $this->kernel     = $kernel;
    }

    /**
     * @return SettingsProviderInterface
     * @throws ExceptionInterface
     */
    public function get(): SettingsProviderInterface
    {
        $data  = [];
        $theme = null;
        if (null !== $this->theme && $this->kernel instanceof AbstractKernel) {
            if ((null !== $theme = $this->kernel->getThemes()[$this->theme->getData()] ?? null) &&
                ($theme->hasSettings() ||
                    (null !== $parentTheme = $theme->getParent()) && $parentTheme->hasSettings())) {
                $settingPath = $theme->getSettingPath();
                if (isset($parentTheme) && $parentTheme->hasSettings()) {
                    $settingPath = $parentTheme->getSettingPath();
                }

                $configuration = new SettingsConfiguration();
                $data          = $this->processConfiguration($configuration, Yaml::parseFile($settingPath));
            }
        }
        /** @var Setting[] $settings */
        $settings = $this->serializer->denormalize($data, Setting::class . '[]');
        if (!empty($settings)) {
            $this->_updateSettingsForTheme($settings, $theme);
        }

        return new ReadableSimpleSettingsProvider($settings);
    }

    /**
     * @param ConfigurationInterface $configuration
     * @param array                  $configs
     *
     * @return array
     */
    protected function processConfiguration(ConfigurationInterface $configuration, array $configs)
    {
        $processor = new Processor();

        return $processor->processConfiguration($configuration, $configs);
    }

    /**
     * Override SettingModel values to be matched as a theme settings.
     * A theme setting is defined by:
     * - domain = theme
     * - tags contain the theme name
     *
     * @param array               $settings
     * @param ThemeInterface|null $theme
     *
     * @return void
     */
    private function _updateSettingsForTheme(array &$settings, ?ThemeInterface $theme): void
    {
        $themeDomain = (new SettingDomain())->setName('theme')->setEnabled(true)->setReadOnly(true);
        $themeIdTag  = (new SettingTag())->setName($theme->getIdentifier());

        /** @var Setting $setting */
        foreach ($settings as $setting) {
            // Set default domain to `theme`
            $setting->setDomain($themeDomain);
            if ($theme instanceof ThemeInterface) {
                $setting->getTags()->add($themeIdTag);
            }
        }
    }
}


<?php

/*
 * This file is part of the Typhoon package.
 *
 * Copyright © 2013 Erin Millard
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Eloquent\Typhoon\Configuration;

use Eloquent\Composer\Configuration\ConfigurationReader as ComposerReader;
use Eloquent\Cosmos\ClassName;
use Eloquent\Typhoon\TypeCheck\TypeCheck;
use ErrorException;
use Icecave\Isolator\Isolator;
use Symfony\Component\Filesystem\Filesystem;
use stdClass;

class ConfigurationReader
{
    /**
     * @param Filesystem|null     $filesystemHelper
     * @param ComposerReader|null $composerReader
     * @param Isolator|null       $isolator
     */
    public function __construct(
        Filesystem $filesystemHelper = null,
        ComposerReader $composerReader = null,
        Isolator $isolator = null
    ) {
        $this->typeCheck = TypeCheck::get(__CLASS__, func_get_args());
        if (null === $filesystemHelper) {
            $filesystemHelper = new Filesystem;
        }
        if (null === $composerReader) {
            $composerReader = new ComposerReader;
        }

        $this->filesystemHelper = $filesystemHelper;
        $this->composerReader = $composerReader;
        $this->isolator = Isolator::get($isolator);
    }

    /**
     * @return Filesystem
     */
    public function filesystemHelper()
    {
        $this->typeCheck->filesystemHelper(func_get_args());

        return $this->filesystemHelper;
    }

    /**
     * @return ComposerReader
     */
    public function composerReader()
    {
        $this->typeCheck->composerReader(func_get_args());

        return $this->composerReader;
    }

    /**
     * @param string|null $path
     * @param boolean     $throwOnFailure
     *
     * @return Configuration|null
     */
    public function read($path = null, $throwOnFailure = false)
    {
        $this->typeCheck->read(func_get_args());
        if (null === $path) {
            $path = $this->isolator->getcwd();
        }

        if ($configuration = $this->readTyphoon($path)) {
            return $configuration;
        }
        if ($configuration = $this->readComposer($path)) {
            return $configuration;
        }

        if ($throwOnFailure) {
            throw new Exception\ConfigurationReadException($this->typhoonPath($path));
        }

        return null;
    }

    /**
     * @param string $path
     *
     * @return string
     */
    protected function typhoonPath($path)
    {
        $this->typeCheck->typhoonPath(func_get_args());

        return sprintf(
            '%s/typhoon.json',
            $path
        );
    }

    /**
     * @param string $path
     *
     * @return string
     */
    protected function composerPath($path)
    {
        $this->typeCheck->composerPath(func_get_args());

        return sprintf(
            '%s/composer.json',
            $path
        );
    }

    /**
     * @param string $path
     *
     * @return Configuration|null
     */
    protected function readTyphoon($path)
    {
        $this->typeCheck->readTyphoon(func_get_args());

        $typhoonPath = $this->typhoonPath($path);
        if (!$this->isolator->is_file($typhoonPath)) {
            return null;
        }

        return $this->buildConfiguration(
            $this->loadJSON($typhoonPath)
        );
    }

    /**
     * @param string $path
     *
     * @return Configuration|null
     */
    protected function readComposer($path)
    {
        $this->typeCheck->readComposer(func_get_args());

        $composerPath = $this->composerPath($path);
        if (!$this->isolator->is_file($composerPath)) {
            return null;
        }

        $composerData = $this->composerReader()->read($composerPath);
        if (
            $composerData->extra() instanceof stdClass &&
            property_exists($composerData->extra(), 'typhoon') &&
            $composerData->extra()->typhoon instanceof stdClass
        ) {
            $typhoonData = $composerData->extra()->typhoon;
        } else {
            $typhoonData = new stdClass;
        }

        if (!property_exists($typhoonData, ConfigurationOption::SOURCE_PATHS()->value())) {
            $sourcePaths = $composerData->allSourcePaths();

            if (!property_exists($typhoonData, ConfigurationOption::OUTPUT_PATH()->value())) {
                $typhoonData->{ConfigurationOption::OUTPUT_PATH()->value()} = $this->inferOutputPath(
                    $sourcePaths
                );
            }

            $typhoonData->{ConfigurationOption::SOURCE_PATHS()->value()} = array();
            foreach ($sourcePaths as $sourcePath) {
                if (!$this->pathIsDescandantOrEqual(
                    $path,
                    $typhoonData->{ConfigurationOption::OUTPUT_PATH()->value()},
                    $sourcePath
                )) {
                    $typhoonData->{ConfigurationOption::SOURCE_PATHS()->value()}[] = $sourcePath;
                }
            }
        } elseif (!property_exists($typhoonData, ConfigurationOption::OUTPUT_PATH()->value())) {
            $typhoonData->{ConfigurationOption::OUTPUT_PATH()->value()} = $this->inferOutputPath(
                $typhoonData->{ConfigurationOption::SOURCE_PATHS()->value()}
            );
        }

        if (!property_exists($typhoonData, ConfigurationOption::VALIDATOR_NAMESPACE()->value())) {
            $validatorNamespace = array_search(
                array($typhoonData->{ConfigurationOption::OUTPUT_PATH()->value()}),
                $composerData->autoloadPSR0(),
                true
            );

            if (false === $validatorNamespace) {
                $mainNamespace = null;
                $mainNamespaceLength = null;
                foreach ($composerData->autoloadPSR0() as $namespace => $paths) {
                    $namespaceLength = count(explode('\\', $namespace));
                    if (
                        null === $mainNamespace ||
                        $namespace < $mainNamespaceLength
                    ) {
                        $mainNamespace = $namespace;
                        $mainNamespaceLength = $namespaceLength;
                    }
                }

                if (null !== $mainNamespace) {
                    $typhoonData->{ConfigurationOption::VALIDATOR_NAMESPACE()->value()} =
                        sprintf('%s\\TypeCheck', $mainNamespace)
                    ;
                }
            } else {
                $typhoonData->{ConfigurationOption::VALIDATOR_NAMESPACE()->value()} =
                    $validatorNamespace
                ;
            }
        }

        if (!property_exists($typhoonData, ConfigurationOption::USE_NATIVE_CALLABLE()->value())) {
            $composerDependencies = $composerData->dependencies();
            $phpConstraint = null;
            if (array_key_exists('php', $composerDependencies)) {
                $phpConstraint = $composerDependencies['php'];
            } elseif (array_key_exists('php-64bit', $composerDependencies)) {
                $phpConstraint = $composerDependencies['php-64bit'];
            }

            $useNativeCallable = false;
            if (null !== $phpConstraint) {
                foreach (explode(',', $phpConstraint) as $constraint) {
                    if (
                        preg_match('/>=?\s*(\d+(?:\.\d+)?(?:\.\d+)?)/', $constraint, $matches) &&
                        version_compare($matches[1], '5.4', '>=')
                    ) {
                        $useNativeCallable = true;
                    }
                }
            }

            $typhoonData->{ConfigurationOption::USE_NATIVE_CALLABLE()->value()} =
                $useNativeCallable
            ;
        }

        return $this->buildConfiguration($typhoonData);
    }

    /**
     * @param mixed $data
     *
     * @return Configuration
     */
    protected function buildConfiguration($data)
    {
        $this->typeCheck->buildConfiguration(func_get_args());

        $this->validateData($data);

        if (property_exists($data, ConfigurationOption::OUTPUT_PATH()->value())) {
            $outputPath = $data->{ConfigurationOption::OUTPUT_PATH()->value()};
        } else {
            $outputPath = $this->inferOutputPath(
                $data->{ConfigurationOption::SOURCE_PATHS()->value()}
            );
        }

        $configuration = new Configuration(
            $outputPath,
            $data->{ConfigurationOption::SOURCE_PATHS()->value()}
        );

        if (property_exists($data, ConfigurationOption::LOADER_PATHS()->value())) {
            $configuration->setLoaderPaths(
                $data->{ConfigurationOption::LOADER_PATHS()->value()}
            );
        }
        if (property_exists($data, ConfigurationOption::VALIDATOR_NAMESPACE()->value())) {
            $configuration->setValidatorNamespace(
                ClassName::fromString(
                    $data->{ConfigurationOption::VALIDATOR_NAMESPACE()->value()}
                )
            );
        }
        if (property_exists($data, ConfigurationOption::USE_NATIVE_CALLABLE()->value())) {
            $configuration->setUseNativeCallable(
                $data->{ConfigurationOption::USE_NATIVE_CALLABLE()->value()}
            );
        }

        return $configuration;
    }

    /**
     * @param string $path
     *
     * @return mixed
     */
    protected function loadJSON($path)
    {
        $this->typeCheck->loadJSON(func_get_args());

        $data = json_decode($this->load($path));
        $lastJSONError = json_last_error();
        if (JSON_ERROR_NONE !== $lastJSONError) {
            throw new Exception\InvalidJSONException($lastJSONError, $path);
        }

        return $data;
    }

    /**
     * @param string $path
     *
     * @return string
     */
    protected function load($path)
    {
        $this->typeCheck->load(func_get_args());

        try {
            $data = $this->isolator->file_get_contents($path);
        } catch (ErrorException $e) {
            throw new Exception\ConfigurationReadException($path, $e);
        }

        return $data;
    }

    /**
     * @param mixed $data
     */
    protected function validateData($data)
    {
        $this->typeCheck->validateData(func_get_args());

        if (!$data instanceof stdClass) {
            throw new Exception\InvalidConfigurationException(
                'Typhoon configuration data must be an object.'
            );
        }
        foreach ($data as $optionName => $value) {
            ConfigurationOption::instanceByValue($optionName);
        }

        // output path
        if (property_exists($data, ConfigurationOption::OUTPUT_PATH()->value())) {
            if (!is_string($data->{ConfigurationOption::OUTPUT_PATH()->value()})) {
                throw new Exception\InvalidConfigurationException(
                    "Output path must be a string."
                );
            }
        }

        // source paths
        if (!property_exists($data, ConfigurationOption::SOURCE_PATHS()->value())) {
            throw new Exception\InvalidConfigurationException(
                "At least one source path is required."
            );
        }
        if (!is_array($data->{ConfigurationOption::SOURCE_PATHS()->value()})) {
            throw new Exception\InvalidConfigurationException(
                "Source paths must be an array."
            );
        }
        foreach ($data->{ConfigurationOption::SOURCE_PATHS()->value()} as $sourcePath) {
            if (!is_string($sourcePath)) {
                throw new Exception\InvalidConfigurationException(
                    "Entries in source paths must be strings."
                );
            }
        }

        // loader paths
        if (property_exists($data, ConfigurationOption::LOADER_PATHS()->value())) {
            if (!is_array($data->{ConfigurationOption::LOADER_PATHS()->value()})) {
                throw new Exception\InvalidConfigurationException(
                    "Loader paths must be an array."
                );
            }
            foreach ($data->{ConfigurationOption::LOADER_PATHS()->value()} as $loaderPath) {
                if (!is_string($loaderPath)) {
                    throw new Exception\InvalidConfigurationException(
                        "Entries in loader paths must be strings."
                    );
                }
            }
        }

        // validator namespace
        if (property_exists($data, ConfigurationOption::VALIDATOR_NAMESPACE()->value())) {
            if (!is_string($data->{ConfigurationOption::VALIDATOR_NAMESPACE()->value()})) {
                throw new Exception\InvalidConfigurationException(
                    "Validator namespace must be a string."
                );
            }
        }

        // use native callable
        if (property_exists($data, ConfigurationOption::USE_NATIVE_CALLABLE()->value())) {
            if (!is_bool($data->{ConfigurationOption::USE_NATIVE_CALLABLE()->value()})) {
                throw new Exception\InvalidConfigurationException(
                    "Use native callable option must be a boolean."
                );
            }
        }
    }

    /**
     * @param array<string> $sourcePaths
     *
     * @return string
     */
    protected function inferOutputPath(array $sourcePaths)
    {
        $this->typeCheck->inferOutputPath(func_get_args());

        if (in_array('src', $sourcePaths, true)) {
            return 'src-typhoon';
        }
        if (in_array('lib', $sourcePaths, true)) {
            return 'lib-typhoon';
        }

        return 'src-typhoon';
    }

    /**
     * @param string $workingPath
     * @param string $ancestor
     * @param string $descendant
     *
     * @return boolean
     */
    protected function pathIsDescandantOrEqual(
        $workingPath,
        $ancestor,
        $descendant
    ) {
        $this->typeCheck->pathIsDescandantOrEqual(func_get_args());

        $ancestor = $this->normalizePath($workingPath, $ancestor);
        $descendant = $this->normalizePath($workingPath, $descendant);

        return 0 === strpos($descendant, $ancestor);
    }

    /**
     * @param string $workingPath
     * @param string $path
     *
     * @return string
     */
    protected function normalizePath($workingPath, $path)
    {
        $this->typeCheck->normalizePath(func_get_args());

        if ($this->filesystemHelper->isAbsolutePath($path)) {
            $path = $this->filesystemHelper->makePathRelative(
                $path,
                $workingPath
            );
        }

        return implode(
            '/',
            array_filter(
                explode('/', str_replace('\\', '/', $path)),
                function ($atom) {
                    return '.' !== $atom;
                }
            )
        );
    }

    private $filesystemHelper;
    private $composerReader;
    private $isolator;
    private $typeCheck;
}


<?php

/*
 * This file is part of the Typhoon package.
 *
 * Copyright © 2013 Erin Millard
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Eloquent\Typhoon\Generator\ExceptionGenerator;

use Eloquent\Cosmos\ClassName;
use Eloquent\Typhoon\Configuration\RuntimeConfiguration;
use Eloquent\Typhoon\Generator\StaticClassGenerator;
use Eloquent\Typhoon\TypeCheck\TypeCheck;
use Icecave\Pasta\AST\Expr\Assign;
use Icecave\Pasta\AST\Expr\Call;
use Icecave\Pasta\AST\Expr\Constant;
use Icecave\Pasta\AST\Expr\Literal;
use Icecave\Pasta\AST\Expr\Member;
use Icecave\Pasta\AST\Expr\NewOperator;
use Icecave\Pasta\AST\Expr\QualifiedIdentifier;
use Icecave\Pasta\AST\Expr\StaticMember;
use Icecave\Pasta\AST\Expr\StrictEquals;
use Icecave\Pasta\AST\Expr\Variable;
use Icecave\Pasta\AST\Func\ObjectTypeHint;
use Icecave\Pasta\AST\Func\Parameter;
use Icecave\Pasta\AST\Identifier;
use Icecave\Pasta\AST\PhpBlock;
use Icecave\Pasta\AST\Stmt\ExpressionStatement;
use Icecave\Pasta\AST\Stmt\IfStatement;
use Icecave\Pasta\AST\Stmt\NamespaceStatement;
use Icecave\Pasta\AST\Stmt\ReturnStatement;
use Icecave\Pasta\AST\Stmt\StatementBlock;
use Icecave\Pasta\AST\SyntaxTree;
use Icecave\Pasta\AST\Type\AccessModifier;
use Icecave\Pasta\AST\Type\ClassDefinition;
use Icecave\Pasta\AST\Type\ClassModifier;
use Icecave\Pasta\AST\Type\ConcreteMethod;
use Icecave\Pasta\AST\Type\Property;
use Icecave\Rasta\Renderer;

class UnexpectedArgumentValueExceptionGenerator implements StaticClassGenerator
{
    /**
     * @param Renderer|null $renderer
     */
    public function __construct(Renderer $renderer = null)
    {
        $this->typeCheck = TypeCheck::get(__CLASS__, func_get_args());

        if (null === $renderer) {
            $renderer = new Renderer;
        }

        $this->renderer = $renderer;
    }

    /**
     * @return Renderer
     */
    public function renderer()
    {
        $this->typeCheck->renderer(func_get_args());

        return $this->renderer;
    }

    /**
     * @param RuntimeConfiguration $configuration
     * @param null                 &$className
     *
     * @return string
     */
    public function generate(
        RuntimeConfiguration $configuration,
        &$className = null
    ) {
        $this->typeCheck->generate(func_get_args());

        return $this->generateSyntaxTree(
            $configuration,
            $className
        )->accept($this->renderer());
    }

    /**
     * @param RuntimeConfiguration $configuration
     * @param null                 &$className
     *
     * @return SyntaxTree
     */
    public function generateSyntaxTree(
        RuntimeConfiguration $configuration,
        &$className = null
    ) {
        $this->typeCheck->generateSyntaxTree(func_get_args());

        $className = $configuration
            ->validatorNamespace()
            ->joinAtoms('Exception', 'UnexpectedArgumentValueException')
        ;

        $classDefinition = new ClassDefinition(
            new Identifier($className->shortName()->string()),
            ClassModifier::FINAL_()
        );
        $classDefinition->setParentName(
            QualifiedIdentifier::fromString('UnexpectedInputException')
        );
        $classDefinition->add($this->generateConstructor($configuration));
        $classDefinition->add($this->generateParameterNameMethod());
        $classDefinition->add($this->generateIndexMethod());
        $classDefinition->add($this->generateValueMethod());
        $classDefinition->add($this->generateExpectedTypeMethod());
        $classDefinition->add($this->generateTypeInspectorMethod());
        $classDefinition->add($this->generateUnexpectedTypeMethod());

        $classDefinition->add(new Property(
            new Identifier('parameterName'),
            AccessModifier::PRIVATE_()
        ));
        $classDefinition->add(new Property(
            new Identifier('index'),
            AccessModifier::PRIVATE_()
        ));
        $classDefinition->add(new Property(
            new Identifier('value'),
            AccessModifier::PRIVATE_()
        ));
        $classDefinition->add(new Property(
            new Identifier('expectedValue'),
            AccessModifier::PRIVATE_()
        ));
        $classDefinition->add(new Property(
            new Identifier('typeInspector'),
            AccessModifier::PRIVATE_()
        ));
        $classDefinition->add(new Property(
            new Identifier('unexpectedValue'),
            AccessModifier::PRIVATE_()
        ));

        $primaryBlock = new PhpBlock;
        $primaryBlock->add(new NamespaceStatement(QualifiedIdentifier::fromString(
            $className->parent()->toRelative()->string()
        )));
        $primaryBlock->add($classDefinition);

        $syntaxTree = new SyntaxTree;
        $syntaxTree->add($primaryBlock);

        return $syntaxTree;
    }

    /**
     * @param RuntimeConfiguration $configuration
     *
     * @return ConcreteMethod
     */
    protected function generateConstructor(RuntimeConfiguration $configuration)
    {
        $this->typeCheck->generateConstructor(func_get_args());

        $parameterNameIdentifier = new Identifier('parameterName');
        $parameterNameVariable = new Variable($parameterNameIdentifier);
        $indexIdentifier = new Identifier('index');
        $indexVariable = new Variable($indexIdentifier);
        $valueIdentifier = new Identifier('value');
        $valueVariable = new Variable($valueIdentifier);
        $expectedTypeIdentifier = new Identifier('expectedType');
        $expectedTypeVariable = new Variable($expectedTypeIdentifier);
        $previousIdentifier = new Identifier('previous');
        $previousVariable = new Variable($previousIdentifier);
        $typeInspectorIdentifier = new Identifier('typeInspector');
        $typeInspectorVariable = new Variable($typeInspectorIdentifier);
        $thisVariable = new Variable(new Identifier('this'));
        $thisParameterNameMember = new Member(
            $thisVariable,
            new Constant($parameterNameIdentifier)
        );
        $thisIndexMember = new Member(
            $thisVariable,
            new Constant($indexIdentifier)
        );
        $thisValueMember = new Member(
            $thisVariable,
            new Constant($valueIdentifier)
        );
        $thisExpectedTypeMember = new Member(
            $thisVariable,
            new Constant($expectedTypeIdentifier)
        );
        $thisTypeInspectorMember = new Member(
            $thisVariable,
            new Constant($typeInspectorIdentifier)
        );
        $thisUnexpectedTypeMember = new Member(
            $thisVariable,
            new Constant(new Identifier('unexpectedType'))
        );
        $typeInspectorClassName = QualifiedIdentifier::fromString(
            $configuration
                ->validatorNamespace()
                ->joinAtoms('TypeInspector')
                ->string()
        );

        $method = new ConcreteMethod(
            new Identifier('__construct'),
            AccessModifier::PUBLIC_()
        );
        $method->addParameter(new Parameter($parameterNameIdentifier));
        $method->addParameter(new Parameter($indexIdentifier));
        $method->addParameter(new Parameter($valueIdentifier));
        $method->addParameter(new Parameter($expectedTypeIdentifier));
        $previousParameter = new Parameter(
            $previousIdentifier,
            new ObjectTypeHint(QualifiedIdentifier::fromString('\Exception'))
        );
        $previousParameter->setDefaultValue(new Literal(null));
        $method->addParameter($previousParameter);
        $typeInspectorParameter = new Parameter(
            $typeInspectorIdentifier,
            new ObjectTypeHint($typeInspectorClassName)
        );
        $typeInspectorParameter->setDefaultValue(new Literal(null));
        $method->addParameter($typeInspectorParameter);

        $nullTypeInspectorIf = new IfStatement(new StrictEquals(
            new Literal(null),
            $typeInspectorVariable
        ));
        $nullTypeInspectorIf->trueBranch()->add(new ExpressionStatement(
            new Assign(
                $typeInspectorVariable,
                new NewOperator(new Call($typeInspectorClassName))
            )
        ));
        $method->statementBlock()->add($nullTypeInspectorIf);

        $method->statementBlock()->add(new ExpressionStatement(new Assign(
            $thisParameterNameMember,
            $parameterNameVariable
        )));
        $method->statementBlock()->add(new ExpressionStatement(new Assign(
            $thisIndexMember,
            $indexVariable
        )));
        $method->statementBlock()->add(new ExpressionStatement(new Assign(
            $thisValueMember,
            $valueVariable
        )));
        $method->statementBlock()->add(new ExpressionStatement(new Assign(
            $thisExpectedTypeMember,
            $expectedTypeVariable
        )));
        $method->statementBlock()->add(new ExpressionStatement(new Assign(
            $thisTypeInspectorMember,
            $typeInspectorVariable
        )));

        $typeInspectorTypeCall = new Call(new Member(
            $typeInspectorVariable,
            new Constant(new Identifier('type'))
        ));
        $typeInspectorTypeCall->add($thisValueMember);
        $method->statementBlock()->add(new ExpressionStatement(new Assign(
            $thisUnexpectedTypeMember,
            $typeInspectorTypeCall
        )));

        $sprintfCall = new Call(QualifiedIdentifier::fromString('\sprintf'));
        $sprintfCall->add(new Literal(
            "Unexpected argument of type '%s' for parameter '%s' at index %d. Expected '%s'."
        ));
        $sprintfCall->add($thisUnexpectedTypeMember);
        $sprintfCall->add($parameterNameVariable);
        $sprintfCall->add($indexVariable);
        $sprintfCall->add($expectedTypeVariable);
        $parentConstructCall = new Call(new StaticMember(
            new Constant(new Identifier('parent')),
            new Constant(new Identifier('__construct'))
        ));
        $parentConstructCall->add($sprintfCall);
        $parentConstructCall->add(new Variable($previousIdentifier));
        $method->statementBlock()->add(new ExpressionStatement(
            $parentConstructCall
        ));

        return $method;
    }

    /**
     * @return ConcreteMethod
     */
    protected function generateParameterNameMethod()
    {
        $this->typeCheck->generateParameterNameMethod(func_get_args());

        $parameterNameIdentifier = new Identifier('parameterName');
        $method = new ConcreteMethod(
            $parameterNameIdentifier,
            AccessModifier::PUBLIC_()
        );
        $method->statementBlock()->add(new ReturnStatement(new Member(
            new Variable(new Identifier('this')),
            new Constant($parameterNameIdentifier)
        )));

        return $method;
    }

    /**
     * @return ConcreteMethod
     */
    protected function generateIndexMethod()
    {
        $this->typeCheck->generateIndexMethod(func_get_args());

        $indexIdentifier = new Identifier('index');
        $method = new ConcreteMethod(
            $indexIdentifier,
            AccessModifier::PUBLIC_()
        );
        $method->statementBlock()->add(new ReturnStatement(new Member(
            new Variable(new Identifier('this')),
            new Constant($indexIdentifier)
        )));

        return $method;
    }

    /**
     * @return ConcreteMethod
     */
    protected function generateValueMethod()
    {
        $this->typeCheck->generateValueMethod(func_get_args());

        $valueIdentifier = new Identifier('value');
        $method = new ConcreteMethod(
            $valueIdentifier,
            AccessModifier::PUBLIC_()
        );
        $method->statementBlock()->add(new ReturnStatement(new Member(
            new Variable(new Identifier('this')),
            new Constant($valueIdentifier)
        )));

        return $method;
    }

    /**
     * @return ConcreteMethod
     */
    protected function generateExpectedTypeMethod()
    {
        $this->typeCheck->generateExpectedTypeMethod(func_get_args());

        $expectedTypeIdentifier = new Identifier('expectedType');
        $method = new ConcreteMethod(
            $expectedTypeIdentifier,
            AccessModifier::PUBLIC_()
        );
        $method->statementBlock()->add(new ReturnStatement(new Member(
            new Variable(new Identifier('this')),
            new Constant($expectedTypeIdentifier)
        )));

        return $method;
    }

    /**
     * @return ConcreteMethod
     */
    protected function generateTypeInspectorMethod()
    {
        $this->typeCheck->generateTypeInspectorMethod(func_get_args());

        $typeInspectorIdentifier = new Identifier('typeInspector');
        $method = new ConcreteMethod(
            $typeInspectorIdentifier,
            AccessModifier::PUBLIC_()
        );
        $method->statementBlock()->add(new ReturnStatement(new Member(
            new Variable(new Identifier('this')),
            new Constant($typeInspectorIdentifier)
        )));

        return $method;
    }

    /**
     * @return ConcreteMethod
     */
    protected function generateUnexpectedTypeMethod()
    {
        $this->typeCheck->generateUnexpectedTypeMethod(func_get_args());

        $unexpectedTypeIdentifier = new Identifier('unexpectedType');
        $method = new ConcreteMethod(
            $unexpectedTypeIdentifier,
            AccessModifier::PUBLIC_()
        );
        $method->statementBlock()->add(new ReturnStatement(new Member(
            new Variable(new Identifier('this')),
            new Constant($unexpectedTypeIdentifier)
        )));

        return $method;
    }

    private $renderer;
    private $typeCheck;
}