<?php

namespace Burrow\CLI;

use Burrow\Driver;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Console\Exception\LogicException;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

/**
 * @codeCoverageIgnore
 */
class DeleteExchangeCommand extends Command
{
    /** @var Driver */
    private $driver;

    /**
     * DeclareQueueCommand constructor.
     *
     * @param Driver $driver
     *
     * @throws LogicException
     */
    public function __construct(Driver $driver)
    {
        parent::__construct();

        $this->driver = $driver;
    }

    protected function configure()
    {
        $this->setName('admin:delete:exchange')
            ->setDescription('Deletes an exchange in RabbitMQ.')
            ->addArgument(
                'name',
                InputArgument::REQUIRED,
                'The name of the exchange to delete.'
            );
    }

    /**
     * @param InputInterface  $input
     * @param OutputInterface $output
     *
     * @return int|null|void
     *
     * @throws InvalidArgumentException
     */
    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $name = $input->getArgument('name');

        $this->driver->deleteExchange($name);
        $output->writeln(sprintf('<info>Delete exchange <comment>%s</comment></info>', $name));
    }
}


<?php

namespace Burrow;

use Assert\Assertion;
use Assert\AssertionFailedException;

class Message
{
    /** @var string */
    private $body;

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

    /** @var string[] */
    private $headers;

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

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

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

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

    /**
     * Message constructor.
     *
     * @param string   $body
     * @param string   $routingKey
     * @param string[] $headers
     * @param string   $correlationId
     * @param string   $replyTo
     *
     * @throws AssertionFailedException
     * @throws \InvalidArgumentException
     */
    public function __construct($body, $routingKey = '', array $headers = [], $correlationId = '', $replyTo = '')
    {
        Assertion::string($body, 'Message body must be a string');
        Assertion::string($routingKey, 'Routing key must be a string');
        Assertion::string($correlationId, 'Correlation ID must be a string');
        Assertion::string($replyTo, 'Reply To must be a string');

        $this->checkHeaders($headers);

        $this->body = $body;
        $this->routingKey = $routingKey;
        $this->headers = $headers;
        $this->correlationId = $correlationId;
        $this->replyTo = $replyTo;
    }

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

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

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

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

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

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

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

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

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

    /**
     * @param string[] $headers
     *
     * @throws AssertionFailedException
     * @throws \InvalidArgumentException
     */
    private function checkHeaders(array $headers)
    {
        foreach ($headers as $key => $value) {
            Assertion::string($key, 'Header key must be a string');
            Assertion::notBlank($key, 'Header key must be a non empty string');
            Assertion::notNull($value, 'Value cannot be null');

            if (!is_string($value) &&
                !is_numeric($value) &&
                !is_bool($value)
            ) {
                throw new \InvalidArgumentException('Value must be a string, a number or a boolean.');
            }
        }
    }
}


<?php

namespace Burrow\Driver;

use Assert\AssertionFailedException;
use Burrow\Driver;
use Burrow\Exception\ConsumerException;
use Burrow\Exception\TimeoutException;
use Burrow\Message;
use Burrow\QueueHandler;
use PhpAmqpLib\Channel\AMQPChannel;
use PhpAmqpLib\Connection\AbstractConnection;
use PhpAmqpLib\Exception\AMQPExceptionInterface;
use PhpAmqpLib\Exception\AMQPTimeoutException;
use PhpAmqpLib\Message\AMQPMessage;
use PhpAmqpLib\Wire\AMQPTable;

/**
 * @codeCoverageIgnore
 */
class PhpAmqpLibDriver implements Driver
{
    const DELIVERY_MODE = 'delivery_mode';
    const CONTENT_TYPE = 'content_type';
    const APPLICATION_HEADERS = 'application_headers';
    const CORRELATION_ID = 'correlation_id';
    const REPLY_TO = 'reply_to';

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

    /** @var AMQPChannel */
    private $channel;

    /** @var bool */
    private $stop = false;

    /**
     * PhpAmqpLibDriver constructor.
     *
     * @param AbstractConnection $connection
     */
    public function __construct(AbstractConnection $connection)
    {
        $this->connection = $connection;
    }

    /**
     * Declare a persistent queue
     *
     * @param string $queueName
     * @param string $type
     *
     * @return string
     */
    public function declareSimpleQueue($queueName = '', $type = self::QUEUE_DURABLE)
    {
        $durable = ($type === self::QUEUE_DURABLE);
        $exclusive = ($type === self::QUEUE_EXCLUSIVE);

        list($name, , ) = $this->getChannel()->queue_declare($queueName, false, $durable, $exclusive, false);

        return $name;
    }

    /**
     * Declare an exchange
     *
     * @param  string $exchangeName
     * @param  string $type
     *
     * @return string
     */
    public function declareExchange($exchangeName = '', $type = self::EXCHANGE_TYPE_FANOUT)
    {
        list($name, , ) = $this->getChannel()->exchange_declare($exchangeName, $type, false, true, false);

        return $name;
    }

    /**
     * Bind an existing queue to an exchange
     *
     * @param  string $exchange
     * @param  string $queueName
     * @param  string $routingKey
     * @return void
     */
    public function bindQueue($exchange, $queueName, $routingKey = '')
    {
        $this->getChannel()->queue_bind($queueName, $exchange, $routingKey);
    }

    /**
     * Create a persisting queue and bind it to an exchange
     *
     * @param  string $exchange
     * @param  string $queueName
     * @param  string $routingKey
     * @return void
     */
    public function declareAndBindQueue($exchange, $queueName, $routingKey = '')
    {
        $this->declareSimpleQueue($queueName);
        $this->bindQueue($exchange, $queueName, $routingKey);
    }

    /**
     * Delete a queue
     *
     * @param string $queueName
     * @return void
     */
    public function deleteQueue($queueName)
    {
        $this->getChannel()->queue_delete($queueName);
    }

    /**
     * Delete an exchange
     *
     * @param string $exchangeName
     * @return void
     */
    public function deleteExchange($exchangeName)
    {
        $this->getChannel()->exchange_delete($exchangeName);
    }

    /**
     * Publish a message in the exchange
     *
     * @param string  $exchangeName
     * @param Message $message
     *
     * @return void
     */
    public function publish($exchangeName, Message $message)
    {
        $this->getChannel()->basic_publish(
            new AMQPMessage($message->getBody(), self::getMessageProperties($message)),
            $exchangeName,
            $message->getRoutingKey()
        );
    }

    /**
     * Consume the queue
     *
     * @param string   $queueName
     * @param callable $callback
     * @param int      $timeout
     * @param bool     $autoAck
     *
     * @return void
     * @throws AssertionFailedException
     * @throws \OutOfBoundsException
     * @throws \InvalidArgumentException
     * @throws \Exception
     */
    public function consume($queueName, callable $callback, $timeout = 0, $autoAck = true)
    {
        $this->stop = false;

        $this->getChannel()->basic_qos(null, 1, null);
        $this->getChannel()->basic_consume(
            $queueName,
            '',
            false,
            $autoAck,
            false,
            false,
            function (AMQPMessage $message) use ($callback, $queueName) {
                $burrowMessage = new Message(
                    $message->getBody(),
                    '', // Impossible to retrieve here
                    self::getHeaders($message),
                    self::getCorrelationId($message),
                    self::getReplyTo($message)
                );
                $burrowMessage->setDeliveryTag($message->delivery_info['delivery_tag']);
                $burrowMessage->setQueue($queueName);

                $success = $callback($burrowMessage);
                if ($success === QueueHandler::STOP_CONSUMING) {
                    $this->stop = true;
                }
            }
        );

        $this->wait($timeout);
    }

    /**
     * Acknowledge the reception of the message
     *
     * @param Message $message
     *
     * @return void
     */
    public function ack(Message $message)
    {
        $this->getChannel()->basic_ack($message->getDeliveryTag());
    }

    /**
     * Aknowledge an error during the consumption of the message
     *
     * @param Message $message
     * @param bool   $requeue
     *
     * @return void
     */
    public function nack(Message $message, $requeue = true)
    {
        $this->getChannel()->basic_reject($message->getDeliveryTag(), $requeue);
    }

    /**
     * Close the connection
     *
     * @return void
     */
    public function close()
    {
        $this->stop = true;

        $this->getChannel()->close();
        $this->connection->close();
    }

    /**
     * @return AMQPChannel
     */
    private function getChannel()
    {
        if (null === $this->channel) {
            $this->channel = $this->connection->channel();
        }

        return $this->channel;
    }

    /**
     * @param $timeout
     *
     * @throws \Exception
     */
    private function wait($timeout)
    {
        while (count($this->getChannel()->callbacks) && !$this->stop) {
            try {
                $this->getChannel()->wait(null, false, $timeout);
            } catch (AMQPTimeoutException $e) {
                throw TimeoutException::build($e, $timeout);
            } catch (\Exception $e) {
                if ($e instanceof AMQPExceptionInterface) {
                    throw ConsumerException::build($e);
                }
                throw $e;
            }
        }
    }

    /**
     * Returns the message parameters
     *
     * @param Message $message
     *
     * @return array
     */
    private static function getMessageProperties(Message $message)
    {
        $properties = [
            self::DELIVERY_MODE       => 2,
            self::CONTENT_TYPE        => 'text/plain',
            self::APPLICATION_HEADERS => new AMQPTable($message->getHeaders())
        ];

        if ($message->getCorrelationId() !== null) {
            $properties[self::CORRELATION_ID] = $message->getCorrelationId();
        }

        if ($message->getReplyTo() !== null) {
            $properties[self::REPLY_TO] = $message->getReplyTo();
        }

        return $properties;
    }

    /**
     * @param AMQPMessage $message
     *
     * @return array
     *
     * @throws \OutOfBoundsException
     */
    private static function getHeaders(AMQPMessage $message)
    {
        return $message->has(self::APPLICATION_HEADERS) ?
            $message->get(self::APPLICATION_HEADERS)->getNativeData() : [];
    }

    /**
     * @param AMQPMessage $message
     *
     * @return string
     *
     * @throws \OutOfBoundsException
     */
    private static function getCorrelationId(AMQPMessage $message)
    {
        return $message->has(self::CORRELATION_ID) ?
            $message->get(self::CORRELATION_ID) : '';
    }

    /**
     * @param AMQPMessage $message
     *
     * @return string
     *
     * @throws \OutOfBoundsException
     */
    private static function getReplyTo(AMQPMessage $message)
    {
        return $message->has(self::REPLY_TO) ?
            $message->get(self::REPLY_TO) : '';
    }
}


<?php

namespace Burrow\Consumer;

use Burrow\QueueConsumer;
use Burrow\Serializer;

class SerializingConsumer implements QueueConsumer
{
    /** @var QueueConsumer */
    private $consumer;

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

    /**
     * SerializingConsumer constructor.
     *
     * @param QueueConsumer $consumer
     * @param Serializer    $serializer
     */
    public function __construct(QueueConsumer $consumer, Serializer $serializer)
    {
        $this->consumer = $consumer;
        $this->serializer = $serializer;
    }

    /**
     * Consumes a message.
     *
     * @param mixed    $message
     * @param string[] $headers
     *
     * @return string
     */
    public function consume($message, array $headers = [])
    {
        return $this->serializer->serialize(
            $this->consumer->consume(
                $this->serializer->deserialize($message),
                $headers
            )
        );
    }
}


<?php

namespace Yajra\DataTables\Generators;

use Illuminate\Support\Str;
use Illuminate\Console\GeneratorCommand;

class DataTablesEditorCommand extends GeneratorCommand
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'datatables:editor
                            {name : The name of the dataTable editor.}
                            {--model : The name given will be used as the model is singular form.}
                            {--model-namespace= : The namespace of the model to be used.}';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Create a new DataTables Editor class.';

    /**
     * The type of class being generated.
     *
     * @var string
     */
    protected $type = 'DataTablesEditor';

    /**
     * Build the class with the given name.
     *
     * @param  string $name
     * @return string
     */
    protected function buildClass($name)
    {
        $stub = parent::buildClass($name);

        return $this->replaceModelImport($stub)->replaceModel($stub);
    }

    /**
     * Replace model name.
     *
     * @param string $stub
     * @return string
     */
    protected function replaceModel(&$stub)
    {
        $model = explode('\\', $this->getModel());
        $model = array_pop($model);
        $stub  = str_replace('ModelName', $model, $stub);

        return $stub;
    }

    /**
     * Get model name to use.
     */
    protected function getModel()
    {
        $name           = $this->getNameInput();
        $rootNamespace  = $this->laravel->getNamespace();
        $model          = $this->option('model') || $this->option('model-namespace');
        $modelNamespace = $this->option('model-namespace') ? $this->option('model-namespace') : $this->laravel['config']->get('datatables-buttons.namespace.model');

        return $model
            ? $rootNamespace . '\\' . ($modelNamespace ? $modelNamespace . '\\' : '') . str_singular($name)
            : $rootNamespace . '\\User';
    }

    /**
     * Replace model import.
     *
     * @param string $stub
     * @return $this
     */
    protected function replaceModelImport(&$stub)
    {
        $stub = str_replace(
            'DummyModel', str_replace('\\\\', '\\', $this->getModel()), $stub
        );

        return $this;
    }

    /**
     * Get the stub file for the generator.
     *
     * @return string
     */
    protected function getStub()
    {
        return __DIR__ . '/stubs/editor.stub';
    }

    /**
     * Replace the filename.
     *
     * @param string $stub
     * @return string
     */
    protected function replaceFilename(&$stub)
    {
        $stub = str_replace(
            'DummyFilename', str_slug($this->getNameInput()), $stub
        );

        return $stub;
    }

    /**
     * Parse the name and format according to the root namespace.
     *
     * @param  string $name
     * @return string
     */
    protected function qualifyClass($name)
    {
        $rootNamespace = $this->laravel->getNamespace();

        if (Str::startsWith($name, $rootNamespace)) {
            return $name;
        }

        if (Str::contains($name, '/')) {
            $name = str_replace('/', '\\', $name);
        }

        if (! Str::contains(Str::lower($name), 'datatable')) {
            $name .= $this->type;
        }

        return $this->getDefaultNamespace(trim($rootNamespace, '\\')) . '\\' . $name;
    }

    /**
     * Get the default namespace for the class.
     *
     * @param  string $rootNamespace
     * @return string
     */
    protected function getDefaultNamespace($rootNamespace)
    {
        return $rootNamespace . '\\' . $this->laravel['config']->get('datatables-buttons.namespace.base', 'DataTables');
    }
}


<?php

namespace Yajra\DataTables;

use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\QueryException;
use Illuminate\Contracts\Validation\Validator;
use Illuminate\Foundation\Validation\ValidatesRequests;

abstract class DataTablesEditor
{
    use ValidatesRequests;

    /**
     * Allowed dataTables editor actions.
     *
     * @var array
     */
    protected $actions = ['create', 'edit', 'remove'];

    /**
     * @var \Illuminate\Database\Eloquent\Model
     */
    protected $model = null;

    /**
     * Process dataTables editor action request.
     *
     * @param Request $request
     * @return JsonResponse|mixed
     * @throws DataTablesEditorException
     */
    public function process(Request $request)
    {
        $action = $request->get('action');

        if (! in_array($action, $this->actions)) {
            throw new DataTablesEditorException('Requested action not supported!');
        }

        return $this->{$action}($request);
    }

    /**
     * Process create action request.
     *
     * @param Request $request
     * @return JsonResponse
     */
    public function create(Request $request)
    {
        $instance   = $this->resolveModel();
        $connection = $instance->getConnection();
        $affected   = [];
        $errors     = [];

        $connection->beginTransaction();
        foreach ($request->get('data') as $data) {
            $validator = $this->getValidationFactory()->make($data, $this->createRules(), $this->createMessages(), $this->attributes());
            if ($validator->fails()) {
                foreach ($this->formatErrors($validator) as $error) {
                    $errors[] = $error;
                }

                continue;
            }

            if (method_exists($this, 'creating')) {
                $data = $this->creating($instance, $data);
            }

            if (method_exists($this, 'saving')) {
                $data = $this->saving($instance, $data);
            }

            $model = $instance->newQuery()->create($data);
            $model->setAttribute('DT_RowId', $model->getKey());

            if (method_exists($this, 'created')) {
                $this->created($model, $data);
            }

            if (method_exists($this, 'saved')) {
                $this->saved($model, $data);
            }

            $affected[] = $model;
        }

        if (! $errors) {
            $connection->commit();
        } else {
            $connection->rollBack();
        }

        return $this->toJson($affected, $errors);
    }

    /**
     * Resolve model to used.
     *
     * @return Model
     */
    protected function resolveModel()
    {
        if ($this->model instanceof Model) {
            return $this->model;
        }

        return new $this->model;
    }

    /**
     * Get create action validation rules.
     *
     * @return array
     */
    abstract public function createRules();

    /**
     * Get create validation messages.
     *
     * @return array
     */
    protected function createMessages()
    {
        return [];
    }

    /**
     * @param Validator $validator
     * @return array
     */
    protected function formatErrors(Validator $validator)
    {
        $errors = [];

        collect($validator->errors())->each(function ($error, $key) use (&$errors) {
            $errors[] = [
                'name'   => $key,
                'status' => $error[0],
            ];
        });

        return $errors;
    }

    /**
     * Display success data in dataTables editor format.
     *
     * @param array $data
     * @param array $errors
     * @return JsonResponse
     */
    protected function toJson(array $data, array $errors = [])
    {
        $response = ['data' => $data];
        if ($errors) {
            $response['fieldErrors'] = $errors;
        }

        return new JsonResponse($response, 200);
    }

    /**
     * Process edit action request.
     *
     * @param Request $request
     * @return JsonResponse
     */
    public function edit(Request $request)
    {
        $instance   = $this->resolveModel();
        $connection = $instance->getConnection();
        $affected   = [];
        $errors     = [];

        $connection->beginTransaction();
        foreach ($request->get('data') as $key => $data) {
            $model     = $instance->newQuery()->find($key);
            $validator = $this->getValidationFactory()->make($data, $this->editRules($model), $this->editMessages(), $this->attributes());
            if ($validator->fails()) {
                foreach ($this->formatErrors($validator) as $error) {
                    $errors[] = $error;
                }

                continue;
            }

            if (method_exists($this, 'updating')) {
                $data = $this->updating($model, $data);
            }

            if (method_exists($this, 'saving')) {
                $data = $this->saving($model, $data);
            }

            $model->update($data);

            if (method_exists($this, 'updated')) {
                $this->updated($model, $data);
            }

            if (method_exists($this, 'saved')) {
                $this->saved($model, $data);
            }

            $model->setAttribute('DT_RowId', $model->getKey());
            $affected[] = $model;
        }

        if (! $errors) {
            $connection->commit();
        } else {
            $connection->rollBack();
        }

        return $this->toJson($affected, $errors);
    }

    /**
     * Get edit action validation rules.
     *
     * @param Model $model
     * @return array
     */
    abstract public function editRules(Model $model);

    /**
     * Get edit validation messages.
     *
     * @return array
     */
    protected function editMessages()
    {
        return [];
    }

    /**
     * Process remove action request.
     *
     * @param Request $request
     * @return JsonResponse
     */
    public function remove(Request $request)
    {
        $instance   = $this->resolveModel();
        $connection = $instance->getConnection();
        $affected   = [];
        $errors     = [];

        $connection->beginTransaction();
        foreach ($request->get('data') as $key => $data) {
            $model     = $instance->newQuery()->find($key);
            $validator = $this->getValidationFactory()
                              ->make($data, $this->removeRules($model), $this->removeMessages(), $this->attributes());
            if ($validator->fails()) {
                foreach ($this->formatErrors($validator) as $error) {
                    $errors[] = $error['status'];
                }

                continue;
            }

            try {
                if (method_exists($this, 'deleting')) {
                    $this->deleting($model, $data);
                }

                $model->delete();

                if (method_exists($this, 'deleted')) {
                    $this->deleted($model, $data);
                }
            } catch (QueryException $exception) {
                $error    = config('app.debug') ? $exception->errorInfo[2] : $this->removeExceptionMessage($exception, $model);
                $errors[] = $error;
            }

            $affected[] = $model;
        }

        if (! $errors) {
            $connection->commit();
        } else {
            $connection->rollBack();
        }

        $response = ['data' => $affected];
        if ($errors) {
            $response['error'] = implode("\n", $errors);
        }

        return new JsonResponse($response, 200);
    }

    /**
     * Get remove action validation rules.
     *
     * @param Model $model
     * @return array
     */
    abstract public function removeRules(Model $model);

    /**
     * Get remove validation messages.
     *
     * @return array
     */
    protected function removeMessages()
    {
        return [];
    }

    /**
     * Get remove query exception message.
     *
     * @param QueryException $exception
     * @param Model          $model
     * @return string
     */
    protected function removeExceptionMessage(QueryException $exception, Model $model)
    {
        return "Record {$model->getKey()} is protected and cannot be deleted!";
    }

    /**
     * Display dataTables editor validation errors.
     *
     * @param Validator $validator
     * @return JsonResponse
     */
    protected function displayValidationErrors(Validator $validator)
    {
        $errors = $this->formatErrors($validator);

        return new JsonResponse([
            'data'        => [],
            'fieldErrors' => $errors,
        ]);
    }

    /**
     * Get custom attributes for validator errors.
     *
     * @return array
     */
    public function attributes()
    {
        return [];
    }
}


<?php
/**
 * Date: 9/12/16
 *
 * @author Portey Vasil <portey@gmail.com>
 */

namespace Youshido\GraphQLBundle\Security\Voter;

use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Youshido\GraphQL\Parser\Ast\Query;

class BlacklistVoter extends AbstractListVoter
{

    /**
     * Perform a single access check operation on a given attribute, subject and token.
     *
     * @param string         $attribute
     * @param mixed          $subject
     * @param TokenInterface $token
     *
     * @return bool
     */
    protected function voteOnAttribute($attribute, $subject, TokenInterface $token)
    {
        /** @var $subject Query */
        return $this->isLoggedInUser($token) || !$this->inList($subject->getName());
    }
}


<?php
/**
 * Date: 31.08.16
 *
 * @author Portey Vasil <portey@gmail.com>
 */

namespace Youshido\GraphQLBundle\Controller;

use Sensio\Bundle\FrameworkExtraBundle\Configuration\Cache;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;

class GraphQLExplorerController extends Controller
{
    /**
     * @Route("/graphql/explorer")
     *
     * @return \Symfony\Component\HttpFoundation\Response
     */
    public function explorerAction()
    {
        $response = $this->render('@GraphQLBundle/Feature/explorer.html.twig', [
            'graphQLUrl' => $this->generateUrl('youshido_graphql_graphql_default'),
            'tokenHeader' => 'access-token'
        ]);

        $date = \DateTime::createFromFormat('U', strtotime('tomorrow'), new \DateTimeZone('UTC'));
        $response->setExpires($date);
        $response->setPublic();

        return $response;
    }
}


<?php
/**
 * Date: 29.08.16
 *
 * @author Portey Vasil <portey@gmail.com>
 */

namespace Youshido\GraphQLBundle\Security\Manager;

use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
use Youshido\GraphQL\Execution\ResolveInfo;
use Youshido\GraphQL\Parser\Ast\Query;

class DefaultSecurityManager implements SecurityManagerInterface
{

    /** @var bool */
    private $fieldSecurityEnabled = false;

    /** @var bool */
    private $rootOperationSecurityEnabled = false;

    /** @var  AuthorizationCheckerInterface */
    private $authorizationChecker;

    public function __construct(AuthorizationCheckerInterface $authorizationChecker, array $guardConfig = [])
    {
        $this->authorizationChecker         = $authorizationChecker;
        $this->fieldSecurityEnabled         = isset($guardConfig['field']) ? $guardConfig['field'] : false;
        $this->rootOperationSecurityEnabled = isset($guardConfig['operation']) ? $guardConfig['operation'] : false;
    }

    /**
     * @param string $attribute
     *
     * @return bool
     */
    public function isSecurityEnabledFor($attribute)
    {
        if (SecurityManagerInterface::RESOLVE_FIELD_ATTRIBUTE == $attribute) {
            return $this->fieldSecurityEnabled;
        } else if (SecurityManagerInterface::RESOLVE_ROOT_OPERATION_ATTRIBUTE == $attribute) {
            return $this->rootOperationSecurityEnabled;
        }

        return false;
    }

    /**
     * @param boolean $fieldSecurityEnabled
     */
    public function setFieldSecurityEnabled($fieldSecurityEnabled)
    {
        $this->fieldSecurityEnabled = $fieldSecurityEnabled;
    }

    /**
     * @param boolean $rootOperationSecurityEnabled
     */
    public function setRooOperationSecurityEnabled($rootOperationSecurityEnabled)
    {
        $this->rootOperationSecurityEnabled = $rootOperationSecurityEnabled;
    }

    /**
     * @param Query $query
     *
     * @return bool
     */
    public function isGrantedToOperationResolve(Query $query)
    {
        return $this->authorizationChecker->isGranted(SecurityManagerInterface::RESOLVE_ROOT_OPERATION_ATTRIBUTE, $query);
    }

    /**
     * @param ResolveInfo $resolveInfo
     *
     * @return bool
     */
    public function isGrantedToFieldResolve(ResolveInfo $resolveInfo)
    {
        return $this->authorizationChecker->isGranted(SecurityManagerInterface::RESOLVE_FIELD_ATTRIBUTE, $resolveInfo);
    }

    /**
     * @param ResolveInfo $resolveInfo
     *
     * @return mixed
     *
     * @throw \Exception
     */
    public function createNewFieldAccessDeniedException(ResolveInfo $resolveInfo)
    {
        return new AccessDeniedException();
    }

    /**
     * @param Query $query
     *
     * @return mixed
     *
     * @throw \Exception
     */
    public function createNewOperationAccessDeniedException(Query $query)
    {
        return new AccessDeniedException();
    }
}


<?php

namespace Youshido\GraphQLBundle\DependencyInjection;

use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Loader;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;

/**
 * This is the class that loads and manages your bundle configuration
 *
 * To learn more see {@link http://symfony.com/doc/current/cookbook/bundles/extension.html}
 */
class GraphQLExtension extends Extension
{
    private $config = [];

    /**
     * {@inheritdoc}
     */
    public function load(array $configs, ContainerBuilder $container)
    {
        $configuration = new Configuration();
        $this->config  = $this->processConfiguration($configuration, $configs);

        $preparedHeaders = [];
        $headers         = $this->config['response']['headers'] ? $this->config['response']['headers'] : $this->getDefaultHeaders();
        foreach ($headers as $header) {
            $preparedHeaders[$header['name']] = $header['value'];
        }

        $container->setParameter('graphql.response.headers', $preparedHeaders);
        $container->setParameter('graphql.schema_class', $this->config['schema_class']);
        $container->setParameter('graphql.schema_service', $this->config['schema_service']);
        $container->setParameter('graphql.logger', $this->config['logger']);
        $container->setParameter('graphql.max_complexity', $this->config['max_complexity']);
        $container->setParameter('graphql.response.json_pretty', $this->config['response']['json_pretty']);

        $container->setParameter('graphql.security.guard_config', [
            'field'     => $this->config['security']['guard']['field'],
            'operation' => $this->config['security']['guard']['operation']
        ]);

        $container->setParameter('graphql.security.black_list', $this->config['security']['black_list']);
        $container->setParameter('graphql.security.white_list', $this->config['security']['white_list']);

        $loader = new Loader\XmlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config'));
        $loader->load('services.xml');
    }

    private function getDefaultHeaders()
    {
        return [
            ['name' => 'Access-Control-Allow-Origin', 'value' => '*'],
            ['name' => 'Access-Control-Allow-Headers', 'value' => 'Content-Type'],
        ];
    }

    public function getAlias()
    {
        return "graphql";
    }
}


<?php

namespace Youshido\GraphQLBundle\DependencyInjection;

use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface;

/**
 * This is the class that validates and merges configuration from your app/config files
 *
 * To learn more see {@link
 * http://symfony.com/doc/current/cookbook/bundles/extension.html#cookbook-bundles-extension-config-class}
 */
class Configuration implements ConfigurationInterface
{
    /**
     * {@inheritdoc}
     */
    public function getConfigTreeBuilder()
    {
        $treeBuilder = new TreeBuilder();
        $rootNode    = $treeBuilder->root('graphql');

        $rootNode
            ->children()
                ->scalarNode('schema_class')->defaultValue(null)->end()
                ->scalarNode('schema_service')->defaultValue(null)->end()
                ->integerNode('max_complexity')->defaultValue(null)->end()
                ->scalarNode('logger')->defaultValue(null)->end()
                ->arrayNode('security')
                    ->addDefaultsIfNotSet()
                    ->canBeUnset()
                    ->children()
                        ->arrayNode('guard')
                            ->addDefaultsIfNotSet()
                            ->canBeUnset()
                            ->children()
                                ->booleanNode('operation')->defaultFalse()->end()
                                ->booleanNode('field')->defaultFalse()->end()
                            ->end()
                        ->end()
                        ->arrayNode('white_list')
                            ->canBeUnset()
                            ->defaultValue([])
                            ->prototype('scalar')->end()
                        ->end()
                        ->arrayNode('black_list')
                            ->canBeUnset()
                            ->defaultValue([])
                            ->prototype('scalar')->end()
                        ->end()
                    ->end()
                ->end()
                ->arrayNode('response')
                    ->addDefaultsIfNotSet()
                    ->canBeUnset()
                    ->children()
                        ->booleanNode('json_pretty')->defaultTrue()->end()
                        ->arrayNode('headers')
                            ->prototype('array')
                                ->children()
                                    ->scalarNode('name')->end()
                                    ->scalarNode('value')->defaultValue(null)->end()
                                ->end()
                            ->end()
                        ->end()
                    ->end()
                ->end()
            ->end();

        return $treeBuilder;
    }
}


<?php
/**
 * Date: 25.11.15
 *
 * @author Portey Vasil <portey@gmail.com>
 */

namespace Youshido\GraphQLBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\Routing\Annotation\Route;
use Youshido\GraphQL\Exception\ConfigurationException;
use Youshido\GraphQLBundle\Exception\UnableToInitializeSchemaServiceException;
use Youshido\GraphQLBundle\Execution\Processor;

class GraphQLController extends Controller
{
    /**
     * @Route("/graphql")
     *
     * @throws \Exception
     *
     * @return JsonResponse
     */
    public function defaultAction()
    {
        try {
            $this->initializeSchemaService();
        } catch (UnableToInitializeSchemaServiceException $e) {
            return new JsonResponse(
                [['message' => 'Schema class ' . $this->getSchemaClass() . ' does not exist']],
                200,
                $this->getResponseHeaders()
            );
        }

        if ($this->get('request_stack')->getCurrentRequest()->getMethod() == 'OPTIONS') {
            return $this->createEmptyResponse();
        }

        list($queries, $isMultiQueryRequest) = $this->getPayload();

        $queryResponses = array_map(function($queryData) {
            return $this->executeQuery($queryData['query'], $queryData['variables']);
        }, $queries);

        $response = new JsonResponse($isMultiQueryRequest ? $queryResponses : $queryResponses[0], 200, $this->getParameter('graphql.response.headers'));

        if ($this->getParameter('graphql.response.json_pretty')) {
            $response->setEncodingOptions($response->getEncodingOptions() | JSON_PRETTY_PRINT);
        }

        return $response;
    }

    private function createEmptyResponse()
    {
        return new JsonResponse([], 200, $this->getResponseHeaders());
    }

    private function executeQuery($query, $variables)
    {
        /** @var Processor $processor */
        $processor = $this->get('graphql.processor');
        $processor->processPayload($query, $variables);

        return $processor->getResponseData();
    }

    /**
     * @return array
     *
     * @throws \Exception
     */
    private function getPayload()
    {
        $request = $this->get('request_stack')->getCurrentRequest();
        $query = $request->get('query', null);
        $variables = $request->get('variables', []);
        $isMultiQueryRequest = false;
        $queries = [];

        $variables = is_string($variables) ? json_decode($variables, true) ?: [] : [];

        $content = $request->getContent();
        if (!empty($content)) {
            if ($request->headers->has('Content-Type') && 'application/graphql' == $request->headers->get('Content-Type')) {
                $queries[] = [
                    'query' => $content,
                    'variables' => [],
                ];
            } else {
                $params = json_decode($content, true);

                if ($params) {
                    // check for a list of queries
                    if (isset($params[0]) === true) {
                        $isMultiQueryRequest = true;
                    } else {
                        $params = [$params];
                    }

                    foreach ($params as $queryParams) {
                        $query = isset($queryParams['query']) ? $queryParams['query'] : $query;

                        if (isset($queryParams['variables'])) {
                            if (is_string($queryParams['variables'])) {
                                $variables = json_decode($queryParams['variables'], true) ?: $variables;
                            } else {
                                $variables = $queryParams['variables'];
                            }

                            $variables = is_array($variables) ? $variables : [];
                        }

                        $queries[] = [
                            'query' => $query,
                            'variables' => $variables,
                        ];
                    }
                }
            }
        } else {
            $queries[] = [
                'query' => $query,
                'variables' => $variables,
            ];
        }

        return [$queries, $isMultiQueryRequest];
    }

    /**
     * @throws \Exception
     */
    private function initializeSchemaService()
    {
        if ($this->container->initialized('graphql.schema')) {
            return;
        }

        $this->container->set('graphql.schema', $this->makeSchemaService());
    }

    /**
     * @return object
     *
     * @throws \Exception
     */
    private function makeSchemaService()
    {
        if ($this->container->has($this->getSchemaService())) {
            return $this->container->get($this->getSchemaService());
        }

        $schemaClass = $this->getSchemaClass();
        if (!$schemaClass || !class_exists($schemaClass)) {
            throw new UnableToInitializeSchemaServiceException();
        }

        if ($this->container->has($schemaClass)) {
            return $this->container->get($schemaClass);
        }

        $schema = new $schemaClass();
        if ($schema instanceof ContainerAwareInterface) {
            $schema->setContainer($this->container);
        }

        return $schema;
    }

    /**
     * @return string
     */
    private function getSchemaClass()
    {
        return $this->getParameter('graphql.schema_class');
    }

    /**
     * @return string
     */
    private function getSchemaService()
    {
        $serviceName = $this->getParameter('graphql.schema_service');

        if (substr($serviceName, 0, 1) === '@') {
            return substr($serviceName, 1, strlen($serviceName) - 1);
        }

        return $serviceName;
    }

    private function getResponseHeaders()
    {
        return $this->getParameter('graphql.response.headers');
    }
}


<?php

namespace Youshido\GraphQLBundle\Command;

use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
use Symfony\Component\Config\Resource\DirectoryResource;
use Symfony\Component\Config\Resource\FileResource;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Question\ConfirmationQuestion;

class GraphQLConfigureCommand extends ContainerAwareCommand
{
    const PROJECT_NAMESPACE = 'App';

    /**
     * {@inheritdoc}
     */
    protected function configure()
    {
        $this
            ->setName('graphql:configure')
            ->setDescription('Generates GraphQL Schema class')
            ->addOption('composer');
    }

    /**
     * {@inheritdoc}
     */
    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $isComposerCall = $input->getOption('composer');

        $container  = $this->getContainer();
        $rootDir    = $container->getParameter('kernel.root_dir');
        $configFile = $rootDir . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'config/packages/graphql.yml';

        $className       = 'Schema';
        $schemaNamespace = self::PROJECT_NAMESPACE . '\\GraphQL';
        $graphqlPath     = rtrim($rootDir, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'GraphQL';
        $classPath       = $graphqlPath . DIRECTORY_SEPARATOR . $className . '.php';

        $inputHelper = $this->getHelper('question');
        if (file_exists($classPath)) {
            if (!$isComposerCall) {
                $output->writeln(sprintf('Schema class %s was found.', $schemaNamespace . '\\' . $className));
            }
        } else {
            $question = new ConfirmationQuestion(sprintf('Confirm creating class at %s ? [Y/n]', $schemaNamespace . '\\' . $className), true);
            if (!$inputHelper->ask($input, $output, $question)) {
                return;
            }

            if (!is_dir($graphqlPath)) {
                mkdir($graphqlPath, 0777, true);
            }
            file_put_contents($classPath, $this->getSchemaClassTemplate($schemaNamespace, $className));

            $output->writeln('Schema file has been created at');
            $output->writeln($classPath . "\n");

            if (!file_exists($configFile)) {
                $question = new ConfirmationQuestion(sprintf('Config file not found (look at %s). Create it? [Y/n]', $configFile), true);
                if (!$inputHelper->ask($input, $output, $question)) {
                    return;
                }

                touch($configFile);
            }

            $originalConfigData = file_get_contents($configFile);
            if (strpos($originalConfigData, 'graphql') === false) {
                $projectNameSpace = self::PROJECT_NAMESPACE;
                $configData       = <<<CONFIG
graphql:
    schema_class: "{$projectNameSpace}\\\\GraphQL\\\\{$className}"

CONFIG;
                file_put_contents($configFile, $configData . $originalConfigData);
            }
        }
        if (!$this->graphQLRouteExists()) {
            $question = new ConfirmationQuestion('Confirm adding GraphQL route? [Y/n]', true);
            $resource = $this->getMainRouteConfig();
            if ($resource && $inputHelper->ask($input, $output, $question)) {
                $routeConfigData = <<<CONFIG

graphql:
    resource: "@GraphQLBundle/Controller/"
CONFIG;
                file_put_contents($resource, $routeConfigData, FILE_APPEND);
                $output->writeln('Config was added to ' . $resource);
            }
        } else {
            if (!$isComposerCall) {
                $output->writeln('GraphQL default route was found.');
            }
        }
    }

    /**
     * @return null|string
     *
     * @throws \Exception
     */
    protected function getMainRouteConfig()
    {
        $routerResources = $this->getContainer()->get('router')->getRouteCollection()->getResources();
        foreach ($routerResources as $resource) {
            /** @var FileResource|DirectoryResource $resource */
            if (method_exists($resource, 'getResource') && substr($resource->getResource(), -11) == 'routes.yaml') {
                return $resource->getResource();
            }
        }

        return null;
    }

    /**
     * @return bool
     * @throws \Exception
     */
    protected function graphQLRouteExists()
    {
        $routerResources = $this->getContainer()->get('router')->getRouteCollection()->getResources();
        foreach ($routerResources as $resource) {
            /** @var FileResource|DirectoryResource $resource */
            if (method_exists($resource, 'getResource') && strpos($resource->getResource(), 'GraphQLController.php') !== false) {
                return true;
            }
        }

        return false;
    }

    protected function generateRoutes()
    {

    }

    protected function getSchemaClassTemplate($nameSpace, $className = 'Schema')
    {
        $tpl = <<<TEXT
<?php
/**
 * This class was automatically generated by GraphQL Schema generator
 */

namespace $nameSpace;

use Youshido\GraphQL\Schema\AbstractSchema;
use Youshido\GraphQL\Config\Schema\SchemaConfig;
use Youshido\GraphQL\Type\Scalar\StringType;

class $className extends AbstractSchema
{
    public function build(SchemaConfig \$config)
    {
        \$config->getQuery()->addFields([
            'hello' => [
                'type'    => new StringType(),
                'args'    => [
                    'name' => [
                        'type' => new StringType(),
                        'defaultValue' => 'Stranger'
                    ]
                ],
                'resolve' => function (\$context, \$args) {
                    return 'Hello ' . \$args['name'];
                }
            ]
        ]);
    }

}

TEXT;

        return $tpl;
    }
}


<?php

namespace Youshido\GraphQLBundle\DependencyInjection\Compiler;

use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
use Youshido\GraphQLBundle\Security\Voter\BlacklistVoter;
use Youshido\GraphQLBundle\Security\Voter\WhitelistVoter;

/**
 * Date: 25.08.16
 *
 * @author Portey Vasil <portey@gmail.com>
 */
class GraphQlCompilerPass implements CompilerPassInterface
{
    /**
     * You can modify the container here before it is dumped to PHP code.
     *
     * @param ContainerBuilder $container
     *
     * @throws \Exception
     */
    public function process(ContainerBuilder $container)
    {
        if ($loggerAlias = $container->getParameter('graphql.logger')) {
            if (strpos($loggerAlias, '@') === 0) {
                $loggerAlias = substr($loggerAlias, 1);
            }

            if (!$container->has($loggerAlias)) {
                throw new \RuntimeException(sprintf('Logger "%s" not found', $loggerAlias));
            }

            $container->getDefinition('graphql.processor')->addMethodCall('setLogger', [new Reference($loggerAlias)]);
        }

        if ($maxComplexity = $container->getParameter('graphql.max_complexity')) {
            $container->getDefinition('graphql.processor')->addMethodCall('setMaxComplexity', [$maxComplexity]);
        }

        $this->processSecurityGuard($container);
    }

    /**
     * @param ContainerBuilder $container
     *
     * @throws \Exception
     */
    private function processSecurityGuard(ContainerBuilder $container)
    {
        $guardConfig = $container->getParameter('graphql.security.guard_config');
        $whiteList   = $container->getParameter('graphql.security.white_list');
        $blackList   = $container->getParameter('graphql.security.black_list');

        if ((!$guardConfig['field'] && !$guardConfig['operation']) && ($whiteList || $blackList)) {
            if ($whiteList && $blackList) {
                throw new \RuntimeException('Configuration error: Only one white or black list allowed');
            }

            $this->addListVoter($container, BlacklistVoter::class, $blackList);
            $this->addListVoter($container, WhitelistVoter::class, $whiteList);
        }
    }

    /**
     * @param ContainerBuilder $container
     * @param                  $voterClass
     * @param array            $list
     *
     * @throws \Exception
     */
    private function addListVoter(ContainerBuilder $container, $voterClass, array $list)
    {
        if ($list) {
            $container
                ->getDefinition('graphql.security.voter')
                ->setClass($voterClass)
                ->addMethodCall('setEnabled', [true])
                ->addMethodCall('setList', [$list]);

            $container->setParameter('graphql.security.guard_config', [
                'operation' => true,
                'field'     => false,
            ]);
        }
    }
}


<?php
/**
 * Created by PhpStorm.
 * User: Administrador
 * Date: 04/10/2017
 * Time: 04:41 PM.
 */

namespace Greenter\Report;

/**
 * Class XmlUtils.
 */
final class XmlUtils
{
    const EXT_NAMESPACE = 'urn:oasis:names:specification:ubl:schema:xsd:CommonExtensionComponents-2';
    const DS_NAMESPACE = 'http://www.w3.org/2000/09/xmldsig#';
    const DIGEST_QUERY = 'ext:ExtensionContent/ds:Signature/ds:SignedInfo/ds:Reference/ds:DigestValue';

    /**
     * @param string $xml
     *
     * @return string
     */
    public function getHashSign($xml)
    {
        $doc = new \DOMDocument();
        @$doc->loadXML($xml);

        return $this->getHashSignFromDoc($doc);
    }

    /**
     * @param string $filename
     *
     * @return string
     */
    public function getHashSignFromFile($filename)
    {
        $doc = new \DOMDocument();
        @$doc->load($filename);

        return $this->getHashSignFromDoc($doc);
    }

    /**
     * @param \DOMDocument $document
     *
     * @return string
     */
    public function getHashSignFromDoc(\DOMDocument $document)
    {
        $xpt = $this->getXpath($document);

        $exts = $xpt->query('ext:UBLExtensions/ext:UBLExtension', $document->documentElement);
        if ($exts->length == 0) {
            return '';
        }

        return $this->getHash($exts, $xpt);
    }

    /**
     * @param \DOMDocument $document
     *
     * @return \DOMXPath
     */
    private function getXpath(\DOMDocument $document)
    {
        $xpt = new \DOMXPath($document);
        $xpt->registerNamespace('ext', self::EXT_NAMESPACE);
        $xpt->registerNamespace('ds', self::DS_NAMESPACE);

        return $xpt;
    }

    /**
     * @param \DOMNodeList $exts
     * @param \DOMXPath $xpt
     * @return string
     */
    private function getHash(\DOMNodeList $exts, \DOMXPath $xpt)
    {
        for ($i = $exts->length; $i-- > 0;) {
            $nodeSign = $exts->item($i);
            $hash = $xpt->query(self::DIGEST_QUERY, $nodeSign);

            if ($hash->length == 0) {
                continue;
            }

            return $hash->item(0)->nodeValue;
        }

        return '';
    }
}


<?php
/**
 * Created by PhpStorm.
 * User: Giansalex
 * Date: 08/09/2018
 * Time: 22:59.
 */

namespace Greenter\Report\Render;

use BaconQrCode\Common\ErrorCorrectionLevel;
use BaconQrCode\Renderer\Image\Png;
use BaconQrCode\Writer;
use Greenter\Model\Sale\BaseSale;

/**
 * Class QrRender.
 */
class QrRender
{
    /**
     * @param BaseSale $sale
     *
     * @return string
     */
    public function getImage($sale)
    {
        $client = $sale->getClient();
        $params = [
            $sale->getCompany()->getRuc(),
            $sale->getTipoDoc(),
            $sale->getSerie(),
            $sale->getCorrelativo(),
            number_format($sale->getMtoIGV(), 2, '.', ''),
            number_format($sale->getMtoImpVenta(), 2, '.', ''),
            $sale->getFechaEmision()->format('Y-m-d'),
            $client->getTipoDoc(),
            $client->getNumDoc(),
        ];
        $content = implode('|', $params).'|';

        return $this->getQrImage($content);
    }

    private function getQrImage($content)
    {
        $renderer = new Png();
        $renderer->setHeight(120);
        $renderer->setWidth(120);
        $renderer->setMargin(0);
        $writer = new Writer($renderer);
        $qrCode = $writer->writeString($content, 'UTF-8', ErrorCorrectionLevel::Q);

        return $qrCode;
    }
}


<?php
/**
 * Created by PhpStorm.
 * User: Giansalex
 * Date: 16/02/2019
 * Time: 21:25.
 */

namespace Greenter\Report\Resolver;

use Greenter\Model\DocumentInterface;

class DefaultTemplateResolver implements TemplateResolverInterface
{
    /**
     * @param DocumentInterface $document
     *
     * @return string
     *
     * @throws \Exception
     */
    public function getTemplate($document)
    {
        $className = get_class($document);
        switch ($className) {
            case \Greenter\Model\Sale\Invoice::class:
            case \Greenter\Model\Sale\Note::class:
                $name = 'invoice';
                break;
            case \Greenter\Model\Retention\Retention::class:
                $name = 'retention';
                break;
            case \Greenter\Model\Perception\Perception::class:
                $name = 'perception';
                break;
            case \Greenter\Model\Despatch\Despatch::class:
                $name = 'despatch';
                break;
            case \Greenter\Model\Summary\Summary::class:
                $name = 'summary';
                break;
            case \Greenter\Model\Voided\Voided::class:
            case \Greenter\Model\Voided\Reversion::class:
                $name = 'voided';
                break;
            default:
                throw new \Exception('Not found template for '.$className);
        }

        return $name.'.html.twig';
    }
}


<?php
/**
 * Created by PhpStorm.
 * User: Administrador
 * Date: 20/01/2018
 * Time: 01:47 PM.
 */

namespace Greenter\Report\Filter;

use Greenter\Model\Sale\Legend;

/**
 * Class ResolveFilter.
 */
class ResolveFilter
{
    /**
     * @param Legend[] $legends
     * @param $code
     *
     * @return string
     */
    public function getValueLegend($legends, $code)
    {
        foreach ($legends as $legend) {
            if ($legend->getCode() == $code) {
                return $legend->getValue();
            }
        }

        return '';
    }
}


<?php
/**
 * Created by PhpStorm.
 * User: Giansalex
 * Date: 17/09/2017
 * Time: 21:55.
 */

namespace Greenter\Report;

use Greenter\Model\DocumentInterface;
use Greenter\Report\Extension\ReportTwigExtension;
use Greenter\Report\Extension\RuntimeLoader;

/**
 * Class HtmlReport.
 */
class HtmlReport implements ReportInterface
{
    /**
     * @var \Twig_Environment
     */
    private $twig;

    /**
     * @var string
     */
    private $template = 'invoice.html.twig';

    /**
     * HtmlReport constructor.
     *
     * @param string $templatesDir
     * @param array  $optionTwig
     */
    public function __construct($templatesDir = '', $optionTwig = [])
    {
        if (!isset($optionTwig['autoescape'])) {
            $optionTwig['autoescape'] = false;
        }

        $this->twig = $this->buildTwig($templatesDir, $optionTwig);
    }

    /**
     * Build html report.
     *
     * @param DocumentInterface $document
     * @param array             $parameters
     *
     * @return mixed
     *
     * @throws \Twig_Error_Loader
     * @throws \Twig_Error_Runtime
     * @throws \Twig_Error_Syntax
     */
    public function render(DocumentInterface $document, $parameters = [])
    {
        $html = $this->twig->render($this->template, [
            'doc' => $document,
            'params' => $parameters,
        ]);

        return $html;
    }

    /**
     * Set filename templte.
     *
     * @param string $template
     */
    public function setTemplate($template)
    {
        $this->template = $template;
    }

    /**
     * @return \Twig_Environment
     */
    public function getTwig()
    {
        return $this->twig;
    }

    /**
     * @param $directory
     * @param $options
     *
     * @return \Twig_Environment
     */
    private function buildTwig($directory, $options)
    {
        $dirs = $this->getDirectories($directory);

        $loader = new \Twig_Loader_Filesystem($dirs);
        $twig = new \Twig_Environment($loader, $options);

        $twig->addRuntimeLoader(new RuntimeLoader());
        $twig->addExtension(new ReportTwigExtension());

        return $twig;
    }

    /**
     * @param $directory
     *
     * @return array
     */
    private function getDirectories($directory)
    {
        $dirs = [];
        if ($directory) {
            $dirs[] = $directory;
        }
        $dirs[] = __DIR__.'/Templates';

        return $dirs;
    }
}


<?php
/**
 * This code is free software; you can redistribute it and/or modify it under
 * the terms of the new BSD License.
 *
 * Copyright (c) 2008-2014, Sebastian Staudt
 *
 * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
 */

namespace SteamCondenser;

use SteamCondenser\Exceptions\BufferUnderflowException;

/**
 * This class represents a byte buffer which helps reading byte-wise data from
 * a string which acts as a raw byte array.
 *
 * @author  Sebastian Staudt
 * @package steam-condenser
 */
class ByteBuffer {

    /**
     * @var string The string holding the buffer's bytes
     */
    private $byteArray;

    /**
     * @var int The size of the buffer
     */
    private $capacity;

    /**
     * @var int The limit to which the buffer may be filled
     */
    private $limit;

    /**
     * @var int The current position of the read pointer
     */
    private $position;

    /**
     * Allocates a string with the specified amount of bytes wrapped into a
     * byte buffer object
     *
     * @param int $length The size of the byte buffer
     * @return ByteBuffer The new byte buffer object
     */
    public static function allocate($length) {
        return new ByteBuffer(str_repeat("\0", $length));
    }

    /**
     * Wraps an existing string into a byte buffer object
     *
     * @param string $byteArray The string to encapsulate into the byte buffer
     * @return ByteBuffer The new ByteBuffer object
     */
    public static function wrap($byteArray) {
        return new ByteBuffer($byteArray);
    }

    /**
     * Creates a new byte buffer instance
     *
     * @param string $byteArray The string to encapsulate into the
     *        byte buffer
     */
    public function __construct($byteArray) {
        $this->byteArray = $byteArray;
        $this->capacity = strlen($byteArray);
        $this->limit = $this->capacity;
        $this->position = 0;
    }

    /**
     * Returns the string wrapped into this byte buffer object
     *
     * @return string The string encapsulated in this byte buffer
     */
    public function _array() {
        return $this->byteArray;
    }

    /**
     * Clears the state of this byte buffer object
     *
     * Sets the <var>limit</var> to the <var>capacity</var> of the buffer and
     * resets the <var>position</var>.
     */
    public function clear() {
        $this->limit = $this->capacity;
        $this->position = 0;
    }

    /**
     * Sets the <var>limit</var> to the current <var>position</var> before
     * resetting the <var>position</var>.
     *
     * @return ByteBuffer This byte buffer
     */
    public function flip() {
        $this->limit = $this->position;
        $this->position = 0;

        return $this;
    }

    /**
     * Reads the specified amount of bytes from the current <var>position</var>
     * of the byte buffer
     *
     * @param int $length The amount of bytes to read from the buffer or
     *        <var>null</var> if everything up to <var>limit</var> should be
     *        read
     * @return string The data read from the buffer
     * @throws BufferUnderflowException if the buffer does not contain $length
     *         or more bytes after the current position
     */
    public function get($length = null) {
        if($length === null) {
            $length = $this->limit - $this->position;
        } elseif($length > $this->remaining()) {
            throw new BufferUnderFlowException();
        }

        $data = substr($this->byteArray, $this->position, $length);
        $this->position += $length;

        return $data;
    }

    /**
     * Reads a single byte from the buffer
     *
     * @return int The byte at the current position
     */
    public function getByte() {
        return ord($this->get(1));
    }

    /**
     * Reads a floating point number from the buffer
     *
     * @return float The floating point number, i.e. four bytes converted to a
     *         <var>float</var> read at the current position
     */
    public function getFloat() {
        $data = unpack('f', $this->get(4));

        return $data[1];
    }

    /**
     * Reads a long integer from the buffer
     *
     * @return int The long integer, i.e. four bytes converted to an
     *         <var>int</var> read at the current position
     */
    public function getLong() {
        $data = unpack('l', $this->get(4));

        return $data[1];
    }

    /**
     * Reads a short integer from the buffer
     *
     * @return int The short integer, i.e. two bytes converted to an
     *         <var>int</var> read at the current position
     */
    public function getShort() {
        $data = unpack('v', $this->get(2));

        return $data[1];
    }

    /**
     * Reads a zero-byte terminated string from the current position of the
     * byte buffer
     *
     * This reads the buffer up until the first occurance of a zero-byte or the
     * end of the buffer. The zero-byte is not included in the returned string.
     *
     * @return string The zero-byte terminated string read from the byte stream
     */
    public function getString() {
        $zeroByteIndex = strpos($this->byteArray, "\0", $this->position);
        if($zeroByteIndex === false) {
            return '';
        } else {
            $dataString = $this->get($zeroByteIndex - $this->position);
            $this->position ++;

            return $dataString;
        }
    }

    /**
     * Reads an unsigned long integer from the buffer
     *
     * @return int The long integer, i.e. four bytes converted to an unsigned
     *         <var>float</var> read at the current position
     */
    public function getUnsignedLong() {
        $data = unpack('V', $this->get(4));

        return $data[1];
    }

    /**
     * Sets or returns the <var>limit</var> of the buffer
     *
     * @param int $newLimit Sets the buffer's <var>limit</var> to this value
     * @return int If no new <var>limit</var> value is given, the current value
     */
    public function limit($newLimit = null) {
        if($newLimit == null) {
            return $this->limit;
        } else {
            $this->limit = $newLimit;
            return null;
        }
    }

    /**
     * Returns the current <var>position</var> of the buffer
     *
     * @return int The current <var>position</var> of the buffer
     */
    public function position() {
        return $this->position;
    }

    /**
     * Replaces the contents of the byte buffer with the bytes from the source
     * string beginning at the current <var>position</var>
     *
     * @param string $sourceByteArray The string to take bytes from
     * @return ByteBuffer This byte buffer
     */
    public function put($sourceByteArray) {
        $newPosition = min($this->remaining(), strlen($sourceByteArray));
        $this->byteArray = substr_replace($this->byteArray, $sourceByteArray, $this->position, $newPosition);
        $this->position = $newPosition;

        return $this;
    }

    /**
     * Returns the remaining number of byte from the current
     * <var>position</var> to the <var>limit</var> of the buffer
     *
     * @return int The number of bytes remaining in the buffer
     */
    public function remaining() {
        return $this->limit - $this->position;
    }

    /**
     * Resets the <var>position</var> of this buffer
     *
     * @return ByteBuffer This byte buffer
     */
    public function rewind() {
        $this->position = 0;

        return $this;
    }
}


<?php
/**
 * This code is free software; you can redistribute it and/or modify it under
 * the terms of the new BSD License.
 *
 * Copyright (c) 2008-2015, Sebastian Staudt
 *
 * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
 */

namespace SteamCondenser\Servers\Packets;

use SteamCondenser\Exceptions\PacketFormatException;
use SteamCondenser\Servers\Packets\RCON\RCONGoldSrcResponse;

/**
 * This module provides functionality to handle raw packet data, including data
 * split into several UDP / TCP packets and BZIP2 compressed data. It's the
 * main utility to transform data bytes into packet objects.
 *
 * @author     Sebastian Staudt
 * @package    steam-condenser
 * @subpackage packets
 * @see        SteamPacket
 */
abstract class SteamPacketFactory {

    /**
     * Creates a new packet object based on the header byte of the given raw
     * data
     *
     * @param string $rawData The raw data of the packet
     * @throws PacketFormatException if the packet header is not recognized
     * @return SteamPacket The packet object generated from the packet data
     */
    public static function getPacketFromData($rawData) {
        $header = ord($rawData[0]);
        $data = substr($rawData, 1);

        switch($header) {
            case SteamPacket::S2A_INFO_DETAILED_HEADER:
                return new S2AINFODETAILEDPacket($data);

            case SteamPacket::S2A_INFO2_HEADER:
                return new S2AINFO2Packet($data);

            case SteamPacket::S2A_PLAYER_HEADER:
                return new S2APLAYERPacket($data);

            case SteamPacket::S2A_RULES_HEADER:
                return new S2ARULESPacket($data);

            case SteamPacket::S2C_CHALLENGE_HEADER:
                return new S2CCHALLENGEPacket($data);

            case SteamPacket::M2A_SERVER_BATCH_HEADER:
                return new M2ASERVERBATCHPacket($data);

            case SteamPacket::RCON_GOLDSRC_CHALLENGE_HEADER:
            case SteamPacket::RCON_GOLDSRC_NO_CHALLENGE_HEADER:
            case SteamPacket::RCON_GOLDSRC_RESPONSE_HEADER:
                return new RCONGoldSrcResponse($data);

            default:
                throw new PacketFormatException('Unknown packet with header 0x' . dechex($header) . ' received.');
        }
    }

    /**
     * Reassembles the data of a split and/or compressed packet into a single
     * packet object
     *
     * @param array $splitPackets An array of packet data
     * @param bool $isCompressed whether the data of this packet is compressed
     * @param int $packetChecksum The CRC32 checksum of the decompressed
     *        packet data
     * @throws PacketFormatException if the calculated CRC32 checksum does not
     *         match the expected value
     * @return SteamPacket The reassembled packet
     * @see packetFromData()
     */
    public static function reassemblePacket($splitPackets, $isCompressed = false, $packetChecksum = 0) {
        $packetData = join('', $splitPackets);

        if($isCompressed) {
            $packetData = bzdecompress($packetData);

            if(crc32($packetData) != $packetChecksum) {
                throw new PacketFormatException('CRC32 checksum mismatch of uncompressed packet data.');
            }
        }

        $packetData = substr($packetData, 4);

        return self::getPacketFromData($packetData);
    }
}


<?php
/**
 * This code is free software; you can redistribute it and/or modify it under
 * the terms of the new BSD License.
 *
 * Copyright (c) 2008-2015, Sebastian Staudt
 *
 * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
 */

namespace SteamCondenser\Community;

use SteamCondenser\Community\GameAchievement\Instance;

/**
 * The GameAchievement class represents a specific achievement for a single
 * game and for a single user
 *
 * It also provides the ability to load the global unlock percentages of all
 * achievements of a specific game.
 *
 * @author     Sebastian Staudt
 * @package    steam-condenser
 * @subpackage community
 */
class GameAchievement {

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

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

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

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

    /**
     * @var GameStatsSchema
     */
    protected $schema;

    /**
     * Loads the global unlock percentages of all achievements for the given
     * game
     *
     * @param int $appId The unique Steam Application ID of the game (e.g.
     *        <var>440</var> for Team Fortress 2). See
     *        http://developer.valvesoftware.com/wiki/Steam_Application_IDs for
     *        all application IDs
     * @return array The symbolic achievement names with the corresponding
     *         global unlock percentages
     * @throws \SteamCondenser\Exceptions\WebApiException if a request to
     *         Steam's Web API fails
     */
    public static function getGlobalPercentages($appId) {
        $params = ['gameid' => $appId];
        $data = WebApi::getJSONObject('ISteamUserStats', 'GetGlobalAchievementPercentagesForApp', 2, $params);

        $percentages = [];
        foreach($data->achievementpercentages->achievements as $achievementData) {
            $percentages[$achievementData->name] = (float) $achievementData->percent;
        }

        return $percentages;
    }

    /**
     * Creates the achievement with the given name for the given user and game
     * and achievement data
     *
     * @param GameStatsSchema $schema The game this achievement belongs to
     * @param \stdClass $data The achievement data extracted from the game schema
     */
    public function __construct(GameStatsSchema $schema, $data) {
        $this->apiName = $data->name;
        $this->schema = $schema;
        $this->hidden = $data->hidden == 1;
        $this->iconClosedUrl = $data->icon;
        $this->iconOpenUrl = $data->icongray;
    }

    /**
     * Returns the symbolic API name of this achievement
     *
     * @return string The API name of this achievement
     */
    public function getApiName() {
        return $this->apiName;
    }

    /**
     * Returns the url for the closed icon of this achievement
     *
     * @return string The url of the closed achievement icon
     */
    public function getIconClosedUrl() {
        return $this->iconClosedUrl;
    }

    /**
     * Returns the url for the open icon of this achievement
     *
     * @return string The url of the open achievement icon
     */
    public function getIconOpenUrl() {
        return $this->iconOpenUrl;
    }

    /**
     * Returns an instance of this achievement for the given user and the given
     * unlock state
     *
     * @param SteamId $user The user the instance should be returned for
     * @param bool $unlocked The state of the achievement for this user
     * @return Instance The achievement instance for this user
     */
    public function getInstance(SteamId $user, $unlocked) {
        return new Instance($this, $user, $unlocked);
    }

    /**
     * Returns the stats schema of the game this achievement belongs to
     *
     * @return GameStatsSchema The stats schema of game this achievement
     *         belongs to
     */
    public function getSchema() {
        return $this->schema;
    }

    /**
     * Returns whether this achievement is hidden
     *
     * @return bool <var>true</var> if this achievement is hidden
     */
    public function isHidden() {
        return $this->hidden;
    }

}


<?php
/**
 * This code is free software; you can redistribute it and/or modify it under
 * the terms of the new BSD License.
 *
 * Copyright (c) 2008-2015, Sebastian Staudt
 *
 * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
 */

namespace SteamCondenser\Servers\Sockets;

use Psr\Log\LoggerAwareInterface;
use Psr\Log\LoggerInterface;
use SteamCondenser\ByteBuffer;
use SteamCondenser\UDPSocket;
use SteamCondenser\Exceptions\ConnectionResetException;
use SteamCondenser\Exceptions\SocketException;
use SteamCondenser\Exceptions\TimeoutException;
use SteamCondenser\Servers\Packets\SteamPacket;

/**
 * This abstract class implements common functionality for sockets used to
 * connect to game and master servers
 *
 * @author     Sebastian Staudt
 * @package    steam-condenser
 * @subpackage sockets
 */
abstract class SteamSocket implements LoggerAwareInterface {

    /**
     * @var int The default socket timeout
     */
    protected static $timeout = 1000;

    /**
     * @var ByteBuffer
     */
    protected $buffer;

    /**
     * @var LoggerInterface The logger for this instance
     */
    protected $logger;

    /**
     * @var UDPSocket
     */
    protected $socket;

    /**
     * Sets the timeout for socket operations
     *
     * Any request that takes longer than this time will cause a {@link
     * TimeoutException}.
     *
     * @param int $timeout The amount of milliseconds before a request times
     *        out
     */
    public static function setTimeout($timeout) {
        self::$timeout = $timeout;
    }

    /**
     * Creates a new UDP socket to communicate with the server on the given IP
     * address and port
     *
     * @param string $ipAddress Either the IP address or the DNS name of the
     *        server
     * @param int $portNumber The port the server is listening on
     */
    public function __construct($ipAddress, $portNumber = 27015) {
        $this->logger = \SteamCondenser\getLogger(get_class($this));

        $this->socket = new UDPSocket();
        $this->socket->connect($ipAddress, $portNumber, 0);
    }

    /**
     * Closes this socket
     *
     * @see #close()
     */
    public function __destruct() {
        $this->close();
    }

    /**
     * Closes the underlying socket
     *
     * @see UDPSocket::close()
     */
    public function close() {
        if(!empty($this->socket) && $this->socket->isOpen()) {
            $this->socket->close();
        }
    }

    /**
     * Subclasses have to implement this method for their individual packet
     * formats
     *
     * @return SteamPacket The packet replied from the server
     */
    abstract public function getReply();

    /**
     * Reads the given amount of data from the socket and wraps it into the
     * buffer
     *
     * @param int $bufferLength The data length to read from the socket
     * @throws SocketException if an error occurs while reading data
     * @throws TimeoutException if no packet is received on time
     * @return int The number of bytes that have been read from the socket
     * @see ByteBuffer
     */
    public function receivePacket($bufferLength = 0) {
        if(!$this->socket->select(self::$timeout)) {
            throw new TimeoutException();
        }

        if($bufferLength == 0) {
            $this->buffer->clear();
        } else {
            $this->buffer = ByteBuffer::allocate($bufferLength);
        }

        try {
            $data = $this->socket->recv($this->buffer->remaining());
            $this->buffer->put($data);
        } catch (ConnectionResetException $e) {
            $this->socket->close();
            throw $e;
        }

        $bytesRead = $this->buffer->position();
        $this->buffer->rewind();
        $this->buffer->limit($bytesRead);

        return $bytesRead;
    }

    /**
     * Sends the given packet to the server
     *
     * This converts the packet into a byte stream first before writing it to
     * the socket.
     *
     * @param SteamPacket $dataPacket The packet to send to the server
     * @see SteamPacket::__toString()
     */
    public function send(SteamPacket $dataPacket) {
        $this->logger->debug("Sending packet of type \"" . get_class($dataPacket) . "\"...");

        $this->socket->send($dataPacket->__toString());
    }

    /**
     * @inheritdoc
     */
    public function setLogger(LoggerInterface $logger) {
        $this->logger = $logger;
    }

}


<?php
/**
 * This code is free software; you can redistribute it and/or modify it under
 * the terms of the new BSD License.
 *
 * Copyright (c) 2008-2015, Sebastian Staudt
 *
 * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
 */

namespace SteamCondenser\Servers\Sockets;

use SteamCondenser\Exceptions\TimeoutException;
use SteamCondenser\Servers\Packets\SteamPacketFactory;

/**
 * This class represents a socket used to communicate with game servers based
 * on the Source engine (e.g. Team Fortress 2, Counter-Strike: Source)
 *
 * @author     Sebastian Staudt
 * @package    steam-condenser
 * @subpackage sockets
 */
class SourceSocket extends SteamSocket {

    /**
     * Creates a new UDP socket to communicate with the Source server on the
     * given IP address and port
     *
     * @param string $ipAddress Either the IP address or the DNS name of the
     *        server
     * @param int $portNumber The port the server is listening on
     */
    public function __construct($ipAddress, $portNumber = 27015) {
        parent::__construct($ipAddress, $portNumber);
    }

    /**
     * Reads a packet from the socket
     *
     * The Source query protocol specifies a maximum packet size of 1,400
     * bytes. Bigger packets will be split over several UDP packets. This
     * method reassembles split packets into single packet objects.
     * Additionally Source may compress big packets using bzip2. Those packets
     * will be compressed.
     *
     * @return SteamPacket The packet replied from the server
     */
    public function getReply() {
        $this->receivePacket(1400);
        $isCompressed = false;

        if($this->buffer->getLong() == -2) {
            do {
                $requestId = $this->buffer->getLong();
                $isCompressed = (($requestId & 0x80000000) != 0);
                $packetCount = $this->buffer->getByte();
                $packetNumber = $this->buffer->getByte() + 1;

                if($isCompressed) {
                    $splitSize = $this->buffer->getLong();
                    $packetChecksum = $this->buffer->getUnsignedLong();
                } else {
                    $splitSize = $this->buffer->getShort();
                }

                $splitPackets[$packetNumber] = $this->buffer->get();

                $this->logger->debug("Received packet $packetNumber of $packetCount for request #$requestId");

                if(sizeof($splitPackets) < $packetCount) {
                    try {
                        $bytesRead = $this->receivePacket();
                    } catch(TimeoutException $e) {
                        $bytesRead = 0;
                    }
                } else {
                    $bytesRead = 0;
                }
            } while($bytesRead > 0 && $this->buffer->getLong() == -2);

            if($isCompressed) {
                $packet = SteamPacketFactory::reassemblePacket($splitPackets, true, $packetChecksum);
            } else {
                $packet = SteamPacketFactory::reassemblePacket($splitPackets);
            }
        } else {
            $packet = SteamPacketFactory::getPacketFromData($this->buffer->get());
        }

        if($isCompressed) {
            $this->logger->debug("Received compressed reply of type \"" . get_class($packet) . "\"");
        } else {
            $this->logger->debug("Received reply of type \"" . get_class($packet) . "\"");
        }

        return $packet;
    }
}


<?php
/**
 * This code is free software; you can redistribute it and/or modify it under
 * the terms of the new BSD License.
 *
 * Copyright (c) 2008-2015, Sebastian Staudt
 *
 * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
 */

namespace SteamCondenser\Servers\Sockets;

use SteamCondenser\Exceptions\PacketFormatException;
use SteamCondenser\Servers\Packets\SteamPacketFactory;

/**
 * This class represents a socket used to communicate with master servers
 *
 * @author     Sebastian Staudt
 * @package    steam-condenser
 * @subpackage sockets
 */
class MasterServerSocket extends SteamSocket {

    /**
     * Creates a new UDP socket to communicate with the server on the given IP
     * address and port
     *
     * @param string $ipAddress Either the IP address or the DNS name of the
     *        server
     * @param int $portNumber The port the server is listening on
     */
    public function __construct($ipAddress, $portNumber = 27015) {
        parent::__construct($ipAddress, $portNumber);
    }

    /**
     * Reads a single packet from the socket
     *
     * @return SteamPacket The packet replied from the server
     * @throws PacketFormatException if the packet has the wrong format
     */
    public function getReply() {
        $this->receivePacket(1500);

        if($this->buffer->getLong() != -1) {
            throw new PacketFormatException("Master query response has wrong packet header.");
        }

        $packet = SteamPacketFactory::getPacketFromData($this->buffer->get());

        $this->logger->debug("Received reply of type \"" . get_class($packet) . "\"");

        return $packet;
    }

}


<?php
/**
 * This code is free software; you can redistribute it and/or modify it under
 * the terms of the new BSD License.
 *
 * Copyright (c) 2011-2014, Sebastian Staudt
 *
 * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
 */

namespace SteamCondenser\Community\Portal2;

use SteamCondenser\Community\GameInventory;

/**
 * Represents the inventory (aka. Robot Enrichment) of a Portal 2 player
 *
 * @author     Sebastian Staudt
 * @package    steam-condenser
 * @subpackage community
 */
class Portal2Inventory extends GameInventory {

    const APP_ID = 620;

    const ITEM_CLASS = '\SteamCondenser\Community\Portal2\Portal2Item';

    /**
     * This checks the cache for an existing inventory. If it exists it is
     * returned. Otherwise a new inventory is created.
     *
     * @param string $steamId The 64bit Steam ID or vanity URL of the user
     * @param bool $fetchNow Whether the data should be fetched now
     * @param bool $bypassCache Whether the cache should be bypassed
     * @return Portal2Inventory The inventory created from the given options
     */
    public static function createInventory($steamId, $fetchNow = true, $bypassCache = false) {
        return parent::create(self::APP_ID, $steamId, $fetchNow, $bypassCache);
    }

}


<?php
/**
 * This code is free software; you can redistribute it and/or modify it under
 * the terms of the new BSD License.
 *
 * Copyright (c) 2008-2015, Sebastian Staudt
 *
 * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
 */

namespace SteamCondenser\Servers\Sockets;

use \SteamCondenser\Exceptions\RCONBanException;
use \SteamCondenser\Servers\Packets\SteamPacketFactory;

/**
 * This class represents a socket used to communicate with game servers based
 * on the GoldSrc engine (e.g. Half-Life, Counter-Strike)
 *
 * @author     Sebastian Staudt
 * @package    steam-condenser
 * @subpackage sockets
 */
class GoldSrcSocket extends SteamSocket {

    /**
     * @var boolean
     */
    private $isHLTV;

    /**
     * @var int
     */
    private $rconChallenge = -1;

    /**
     * Creates a new socket to communicate with the server on the given IP
     * address and port
     *
     * @param string $ipAddress Either the IP address or the DNS name of the
     *        server
     * @param int $portNumber The port the server is listening on
     * @param bool $isHLTV <var>true</var> if the target server is a HTLV
     *        instance. HLTV behaves slightly different for RCON commands, this
     *        flag increases compatibility.
     */
    public function __construct($ipAddress, $portNumber = 27015, $isHLTV = false) {
        parent::__construct($ipAddress, $portNumber);

        $this->isHLTV = $isHLTV;
    }

    /**
     * Reads a packet from the socket
     *
     * The Source query protocol specifies a maximum packet size of 1,400
     * bytes. Bigger packets will be split over several UDP packets. This
     * method reassembles split packets into single packet objects.
     *
     * @return \SteamCondenser\Servers\Packets\SteamPacket The packet replied
     *         from the server
     */
    public function getReply() {
        $bytesRead = $this->receivePacket(1400);

        if($this->buffer->getLong() == -2) {
            do {
                $requestId = $this->buffer->getLong();
                $packetCountAndNumber = $this->buffer->getByte();
                $packetCount = $packetCountAndNumber & 0xF;
                $packetNumber = ($packetCountAndNumber >> 4) + 1;

                $splitPackets[$packetNumber - 1] = $this->buffer->get();

                $this->logger->debug("Received packet $packetNumber of $packetCount for request #$requestId");

                if(sizeof($splitPackets) < $packetCount) {
                    try {
                        $bytesRead = $this->receivePacket();
                    } catch(\SteamCondenser\Exceptions\TimeoutException $e) {
                        $bytesRead = 0;
                    }
                } else {
                    $bytesRead = 0;
                }
            } while($bytesRead > 0 && $this->buffer->getLong() == -2);

            $packet = SteamPacketFactory::reassemblePacket($splitPackets);
        } else {
            $packet = SteamPacketFactory::getPacketFromData($this->buffer->get());
        }

        $this->logger->debug("Received packet of type \"" . get_class($packet) . "\"");

        return $packet;
    }

    /**
     * Executes the given command on the server via RCON
     *
     * @param string $password The password to authenticate with the server
     * @param string $command The command to execute on the server
     * @return RCONGoldSrcResponse The response replied by the server
     * @see rconChallenge()
     * @see rconSend()
     * @throws RCONBanException if the IP of the local machine has been banned
     *         on the game server
     * @throws RCONNoAuthException if the password is incorrect
     */
    public function rconExec($password, $command) {
        if($this->rconChallenge == -1 || $this->isHLTV) {
            $this->rconGetChallenge();
        }

        $this->rconSend("rcon {$this->rconChallenge} $password $command");
        if($this->isHLTV) {
            try {
                $response = $this->getReply()->getResponse();
            } catch(\SteamCondenser\Exceptions\TimeoutException $e) {
                $response = '';
            }
        } else {
            $response = $this->getReply()->getResponse();
        }

        if(trim($response) == 'Bad rcon_password.') {
            throw new \SteamCondenser\Exceptions\RCONNoAuthException();
        } elseif(trim($response) == 'You have been banned from this server.') {
            throw new \SteamCondenser\Exceptions\RCONBanException();
        }

        $this->rconSend("rcon {$this->rconChallenge} $password");

        do {
            $responsePart = $this->getReply()->getResponse();
            $response .= $responsePart;
        } while(strlen($responsePart) > 0);

        return $response;
    }

    /**
     * Requests a challenge number from the server to be used for further
     * requests
     *
     * @throws RCONBanException if the IP of the local machine has been banned
     *         on the game server
     * @see rconSend()
     */
    public function rconGetChallenge() {
        $this->rconSend('challenge rcon');
        $response = trim($this->getReply()->getResponse());

        if($response == 'You have been banned from this server.') {
            throw new RCONBanException();
        }

        $this->rconChallenge = floatval(substr($response, 14));
    }

    /**
     * Wraps the given command in a RCON request packet and send it to the
     * server
     *
     * @param string $command The RCON command to send to the server
     */
    public function rconSend($command) {
        $this->send(new \SteamCondenser\Servers\Packets\RCON\RCONGoldSrcRequest($command));
    }
}


<?php
/**
 * This code is free software; you can redistribute it and/or modify it under
 * the terms of the new BSD License.
 *
 * Copyright (c) 2008-2015, Sebastian Staudt
 *
 * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
 */

namespace SteamCondenser;

use SteamCondenser\Exceptions\SocketException;

/**
 * This class represents a TCP socket
 *
 * It can connect to a remote host, send and receive packets
 *
 * @author  Sebastian Staudt
 * @package steam-condenser
 */
class TCPSocket extends Socket {

    /**
     * Connects the TCP socket to the host with the given IP address and port
     * number
     *
     * Depending on whether PHP's sockets extension is loaded, this uses either
     * <var>socket_create</var>/<var>socket_connect</var> or
     * <var>fsockopen</var>.
     *
     * @param string $ipAddress The IP address to connect to
     * @param int $portNumber The TCP port to connect to
     * @param int $timeout The timeout in milliseconds
     * @throws SocketException if an error occurs during connecting the socket
     */
    public function connect($ipAddress, $portNumber, $timeout) {
        $this->ipAddress = $ipAddress;
        $this->portNumber = $portNumber;

        if($this->socketsEnabled) {
            if (!$this->socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) {
                throw new SocketException(socket_last_error($this->socket));
            }

            socket_set_nonblock($this->socket);
            socket_connect($this->socket, $ipAddress, $portNumber);
            $write = [$this->socket];
            $read = $except = null;
            $sec = floor($timeout / 1000);
            $usec = $timeout % 1000;
            if(!socket_select($read, $write, $except, $sec, $usec)) {
                $errorCode = socket_last_error($this->socket);
            } else {
                $errorCode = socket_get_option($this->socket, SOL_SOCKET, SO_ERROR);
            }

            if ($errorCode) {
                throw new SocketException($errorCode);
            }

            socket_set_block($this->socket);
        } else {
            if (!$this->socket = fsockopen("tcp://$ipAddress", $portNumber, $socketErrno, $socketErrstr, $timeout / 1000)) {
                throw new SocketException($socketErrstr);
            }
            stream_set_blocking($this->socket, true);
        }
    }
}