private function loadTypePagerProvider(array $typeConfig, ContainerBuilder $container, $indexName, $typeName)
    {
        if (isset($typeConfig['provider']['service'])) {
            return $typeConfig['provider']['service'];
        }

        $baseConfig = $typeConfig['provider'];
        unset($baseConfig['service']);

        $driver = $typeConfig['driver'];

        switch ($driver) {
            case 'orm':
                $providerDef = new ChildDefinition('fos_elastica.pager_provider.prototype.'.$driver);
                $providerDef->replaceArgument(2, $typeConfig['model']);
                $providerDef->replaceArgument(3, $baseConfig);

                break;
            case 'mongodb':
                $providerDef = new ChildDefinition('fos_elastica.pager_provider.prototype.'.$driver);
                $providerDef->replaceArgument(2, $typeConfig['model']);
                $providerDef->replaceArgument(3, $baseConfig);

                break;
            case 'phpcr':
                $providerDef = new ChildDefinition('fos_elastica.pager_provider.prototype.'.$driver);
                $providerDef->replaceArgument(2, $typeConfig['model']);
                $providerDef->replaceArgument(3, $baseConfig);

                break;
            default:
                throw new \LogicException(sprintf('The pager provider for driver "%s" does not exist.', $driver));
        }

        /* Note: provider services may conflict with "prototype.driver", if the
         * index and type names were "prototype" and a driver, respectively.
         */
        $providerId = sprintf('fos_elastica.pager_provider.%s.%s', $indexName, $typeName);
        $providerDef->addTag('fos_elastica.pager_provider', ['index' => $indexName, 'type' => $typeName]);

        $container->setDefinition($providerId, $providerDef);

        return $providerId;
    }

Loads a pager provider for a type.

@param array            $typeConfig
@param ContainerBuilder $container
@param string           $indexName
@param string           $typeName

@return string


private function loadTypeListener(array $typeConfig, ContainerBuilder $container, $objectPersisterId, $indexName, $typeName)
    {
        if (isset($typeConfig['listener']['service'])) {
            return $typeConfig['listener']['service'];
        }

        /* Note: listener services may conflict with "prototype.driver", if the
         * index and type names were "prototype" and a driver, respectively.
         */
        $abstractListenerId = sprintf('fos_elastica.listener.prototype.%s', $typeConfig['driver']);
        $listenerId = sprintf('fos_elastica.listener.%s.%s', $indexName, $typeName);
        $listenerDef = new ChildDefinition($abstractListenerId);
        $listenerDef->replaceArgument(0, new Reference($objectPersisterId));
        $listenerDef->replaceArgument(3, $typeConfig['listener']['logger'] ?
            new Reference($typeConfig['listener']['logger']) :
            null
        );
        $listenerConfig = [
            'identifier' => $typeConfig['identifier'],
            'indexName' => $indexName,
            'typeName' => $typeName,
        ];

        $tagName = null;
        switch ($typeConfig['driver']) {
            case 'orm':
                $tagName = 'doctrine.event_listener';
                break;
            case 'phpcr':
                $tagName = 'doctrine_phpcr.event_listener';
                break;
            case 'mongodb':
                $tagName = 'doctrine_mongodb.odm.event_listener';
                break;
        }

        if ($typeConfig['listener']['defer']) {
            $listenerDef->setPublic(true);
            $listenerDef->addTag(
                'kernel.event_listener',
                ['event' => 'kernel.terminate', 'method' => 'onTerminate']
            );
            $listenerDef->addTag(
                'kernel.event_listener',
                ['event' => 'console.terminate', 'method' => 'onTerminate']
            );
            $listenerConfig['defer'] = true;
        }

        $listenerDef->replaceArgument(2, $listenerConfig);

        if (null !== $tagName) {
            foreach ($this->getDoctrineEvents($typeConfig) as $event) {
                $listenerDef->addTag($tagName, ['event' => $event]);
            }
        }

        $container->setDefinition($listenerId, $listenerDef);

        return $listenerId;
    }

Loads doctrine listeners to handle indexing of new or updated objects.

@param array            $typeConfig
@param ContainerBuilder $container
@param string           $objectPersisterId
@param string           $indexName
@param string           $typeName

@return string

Loads doctrine listeners to handle indexing of new or updated objects .


private function getDoctrineEvents(array $typeConfig)
    {
        switch ($typeConfig['driver']) {
            case 'orm':
                $eventsClass = '\Doctrine\ORM\Events';
                break;
            case 'phpcr':
                $eventsClass = '\Doctrine\ODM\PHPCR\Event';
                break;
            case 'mongodb':
                $eventsClass = '\Doctrine\ODM\MongoDB\Events';
                break;
            default:
                throw new \InvalidArgumentException(sprintf('Cannot determine events for driver "%s"', $typeConfig['driver']));
        }

        $events = [];
        $eventMapping = [
            'insert' => [constant($eventsClass.'::postPersist')],
            'update' => [constant($eventsClass.'::postUpdate')],
            'delete' => [constant($eventsClass.'::preRemove')],
            'flush' => [constant($eventsClass.'::postFlush')],
        ];

        foreach ($eventMapping as $event => $doctrineEvents) {
            if (isset($typeConfig['listener'][$event]) && $typeConfig['listener'][$event]) {
                $events = array_merge($events, $doctrineEvents);
            }
        }

        return $events;
    }

Map Elastica to Doctrine events for the current driver.

Map Elastica to Doctrine events for the current driver .


private function loadTypeFinder(array $typeConfig, ContainerBuilder $container, $elasticaToModelId, Reference $typeRef, $indexName, $typeName)
    {
        if (isset($typeConfig['finder']['service'])) {
            $finderId = $typeConfig['finder']['service'];
        } else {
            $finderId = sprintf('fos_elastica.finder.%s.%s', $indexName, $typeName);
            $finderDef = new ChildDefinition('fos_elastica.finder');
            $finderDef->replaceArgument(0, $typeRef);
            $finderDef->replaceArgument(1, new Reference($elasticaToModelId));
            $container->setDefinition($finderId, $finderDef);
        }

        $indexTypeName = "$indexName/$typeName";
        $arguments = [$indexTypeName, new Reference($finderId)];
        if (isset($typeConfig['repository'])) {
            $arguments[] = $typeConfig['repository'];
        }

        $container->getDefinition('fos_elastica.repository_manager')
            ->addMethodCall('addType', $arguments);

        $managerId = sprintf('fos_elastica.manager.%s', $typeConfig['driver']);
        $container->getDefinition($managerId)
            ->addMethodCall('addEntity', [$typeConfig['model'], $indexTypeName]);

        return $finderId;
    }

private function loadTypeFinder ( array $ typeConfig , ContainerBuilder $ container , $ elasticaToModelId , Reference $ typeRef , $ indexName , $ typeName ) { if ( isset ( $ typeConfig [ 'finder' ] [ 'service' ] ) ) { $ finderId = $ typeConfig [ 'finder' ] [ 'service' ] ; } else { $ finderId = sprintf ( 'fos_elastica.finder.%s.%s' , $ indexName , $ typeName ) ; $ finderDef = new ChildDefinition ( 'fos_elastica.finder' ) ; $ finderDef -> replaceArgument ( 0 , $ typeRef ) ; $ finderDef -> replaceArgument ( 1 , new Reference ( $ elasticaToModelId ) ) ; $ container -> setDefinition ( $ finderId , $ finderDef ) ; } $ indexTypeName = "$indexName/$typeName" ; $ arguments = [ $ indexTypeName , new Reference ( $ finderId ) ] ; if ( isset ( $ typeConfig [ 'repository' ] ) ) { $ arguments [ ] = $ typeConfig [ 'repository' ] ; } $ container -> getDefinition ( 'fos_elastica.repository_manager' ) -> addMethodCall ( 'addType' , $ arguments ) ; $ managerId = sprintf ( 'fos_elastica.manager.%s' , $ typeConfig [ 'driver' ] ) ; $ container -> getDefinition ( $ managerId ) -> addMethodCall ( 'addEntity' , [ $ typeConfig [ 'model' ] , $ indexTypeName ] ) ; return $ finderId ; }

Loads a Type specific Finder.

@param array            $typeConfig
@param ContainerBuilder $container
@param string           $elasticaToModelId
@param Reference        $typeRef
@param string           $indexName
@param string           $typeName

@return string


private function loadIndexManager(ContainerBuilder $container)
    {
        $indexRefs = array_map(function ($index) {
            return $index['reference'];
        }, $this->indexConfigs);

        $managerDef = $container->getDefinition('fos_elastica.index_manager');
        $managerDef->replaceArgument(0, $indexRefs);
    }

private function loadIndexManager ( ContainerBuilder $ container ) { $ indexRefs = array_map ( function ( $ index ) { return $ index [ 'reference' ] ; } , $ this -> indexConfigs ) ; $ managerDef = $ container -> getDefinition ( 'fos_elastica.index_manager' ) ; $ managerDef -> replaceArgument ( 0 , $ indexRefs ) ; }

Loads the index manager.

@param ContainerBuilder $container


private function loadIndexTemplateManager(ContainerBuilder $container)
    {
        $indexTemplateRefs = array_map(function ($index) {
            return $index['reference'];
        }, $this->indexTemplateConfigs);

        $managerDef = $container->getDefinition('fos_elastica.index_template_manager');
        $managerDef->replaceArgument(0, $indexTemplateRefs);
    }

private function loadIndexTemplateManager ( ContainerBuilder $ container ) { $ indexTemplateRefs = array_map ( function ( $ index ) { return $ index [ 'reference' ] ; } , $ this -> indexTemplateConfigs ) ; $ managerDef = $ container -> getDefinition ( 'fos_elastica.index_template_manager' ) ; $ managerDef -> replaceArgument ( 0 , $ indexTemplateRefs ) ; }

Load index template manager

@param ContainerBuilder $container

@return void


private function loadDriver(ContainerBuilder $container, $driver)
    {
        if (in_array($driver, $this->loadedDrivers)) {
            return;
        }

        $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
        $loader->load($driver.'.xml');
        $this->loadedDrivers[] = $driver;
    }

private function loadDriver ( ContainerBuilder $ container , $ driver ) { if ( in_array ( $ driver , $ this -> loadedDrivers ) ) { return ; } $ loader = new XmlFileLoader ( $ container , new FileLocator ( __DIR__ . '/../Resources/config' ) ) ; $ loader -> load ( $ driver . '.xml' ) ; $ this -> loadedDrivers [ ] = $ driver ; }

Makes sure a specific driver has been loaded.

@param ContainerBuilder $container
@param string           $driver

Makes sure a specific driver has been loaded .


private function loadSerializer($config, ContainerBuilder $container)
    {
        $container->setAlias('fos_elastica.serializer', $config['serializer']);

        $serializer = $container->getDefinition('fos_elastica.serializer_callback_prototype');
        $serializer->setClass($config['callback_class']);

        if (is_subclass_of($config['callback_class'], ContainerAwareInterface::class)) {
            $serializer->addMethodCall('setContainer', [new Reference('service_container')]);
        }
    }

Loads and configures the serializer prototype.

@param array            $config
@param ContainerBuilder $container

Loads and configures the serializer prototype .


private function createDefaultManagerAlias($defaultManager, ContainerBuilder $container)
    {
        if (0 == count($this->loadedDrivers)) {
            return;
        }

        if (count($this->loadedDrivers) > 1
            && in_array($defaultManager, $this->loadedDrivers)
        ) {
            $defaultManagerService = $defaultManager;
        } else {
            $defaultManagerService = $this->loadedDrivers[0];
        }

        $container->setAlias('fos_elastica.manager', sprintf('fos_elastica.manager.%s', $defaultManagerService));
        $container->getAlias('fos_elastica.manager')->setPublic(true);
        $container->setAlias(RepositoryManagerInterface::class, 'fos_elastica.manager');
        $container->getAlias(RepositoryManagerInterface::class)->setPublic(false);
    }

private function createDefaultManagerAlias ( $ defaultManager , ContainerBuilder $ container ) { if ( 0 == count ( $ this -> loadedDrivers ) ) { return ; } if ( count ( $ this -> loadedDrivers ) > 1 && in_array ( $ defaultManager , $ this -> loadedDrivers ) ) { $ defaultManagerService = $ defaultManager ; } else { $ defaultManagerService = $ this -> loadedDrivers [ 0 ] ; } $ container -> setAlias ( 'fos_elastica.manager' , sprintf ( 'fos_elastica.manager.%s' , $ defaultManagerService ) ) ; $ container -> getAlias ( 'fos_elastica.manager' ) -> setPublic ( true ) ; $ container -> setAlias ( RepositoryManagerInterface :: class , 'fos_elastica.manager' ) ; $ container -> getAlias ( RepositoryManagerInterface :: class ) -> setPublic ( false ) ; }

Creates a default manager alias for defined default manager or the first loaded driver.

@param string           $defaultManager
@param ContainerBuilder $container

Creates a default manager alias for defined default manager or the first loaded driver .


private function getDynamicTemplateNode()
    {
        $node = $this->createTreeBuilderNode('dynamic_templates');

        $node
            ->prototype('array')
                ->prototype('array')
                    ->children()
                        ->scalarNode('match')->end()
                        ->scalarNode('unmatch')->end()
                        ->scalarNode('match_mapping_type')->end()
                        ->scalarNode('path_match')->end()
                        ->scalarNode('path_unmatch')->end()
                        ->scalarNode('match_pattern')->end()
                        ->arrayNode('mapping')
                            ->prototype('variable')
                                ->treatNullLike([])
                            ->end()
                        ->end()
                    ->end()
                ->end()
            ->end()
        ;

        return $node;
    }

private function getDynamicTemplateNode ( ) { $ node = $ this -> createTreeBuilderNode ( 'dynamic_templates' ) ; $ node -> prototype ( 'array' ) -> prototype ( 'array' ) -> children ( ) -> scalarNode ( 'match' ) -> end ( ) -> scalarNode ( 'unmatch' ) -> end ( ) -> scalarNode ( 'match_mapping_type' ) -> end ( ) -> scalarNode ( 'path_match' ) -> end ( ) -> scalarNode ( 'path_unmatch' ) -> end ( ) -> scalarNode ( 'match_pattern' ) -> end ( ) -> arrayNode ( 'mapping' ) -> prototype ( 'variable' ) -> treatNullLike ( [ ] ) -> end ( ) -> end ( ) -> end ( ) -> end ( ) -> end ( ) ; return $ node ; }

Returns the array node used for "dynamic_templates".

Returns the array node used for dynamic_templates .


private function getTypesNode()
    {
        $node = $this->createTreeBuilderNode('types');

        $node
            ->useAttributeAsKey('name')
            ->prototype('array')
                ->treatNullLike([])
                ->beforeNormalization()
                ->ifNull()
                    ->thenEmptyArray()
                ->end()
                // Support multiple dynamic_template formats to match the old bundle style
                // and the way ElasticSearch expects them
                ->beforeNormalization()
                ->ifTrue(function ($v) {
                    return isset($v['dynamic_templates']);
                })
                ->then(function ($v) {
                    $dt = [];
                    foreach ($v['dynamic_templates'] as $key => $type) {
                        if (is_int($key)) {
                            $dt[] = $type;
                        } else {
                            $dt[][$key] = $type;
                        }
                    }

                    $v['dynamic_templates'] = $dt;

                    return $v;
                })
                ->end()
                ->children()
                    ->booleanNode('date_detection')->end()
                    ->arrayNode('dynamic_date_formats')->prototype('scalar')->end()->end()
                    ->scalarNode('analyzer')->end()
                    ->booleanNode('numeric_detection')->end()
                    ->scalarNode('dynamic')->end()
                    ->variableNode('indexable_callback')->end()
                    ->append($this->getPersistenceNode())
                    ->append($this->getSerializerNode())
                ->end()
                ->append($this->getIdNode())
                ->append($this->getPropertiesNode())
                ->append($this->getDynamicTemplateNode())
                ->append($this->getSourceNode())
                ->append($this->getRoutingNode())
                ->append($this->getParentNode())
                ->append($this->getAllNode())
            ->end()
        ;

        return $node;
    }

Returns the array node used for "types".


private function getIdNode()
    {
        $node = $this->createTreeBuilderNode('_id');

        $node
            ->children()
            ->scalarNode('path')->end()
            ->end()
        ;

        return $node;
    }

private function getIdNode ( ) { $ node = $ this -> createTreeBuilderNode ( '_id' ) ; $ node -> children ( ) -> scalarNode ( 'path' ) -> end ( ) -> end ( ) ; return $ node ; }


private function getSourceNode()
    {
        $node = $this->createTreeBuilderNode('_source');

        $node
            ->children()
                ->arrayNode('excludes')
                    ->useAttributeAsKey('name')
                    ->prototype('scalar')->end()
                ->end()
                ->arrayNode('includes')
                    ->useAttributeAsKey('name')
                    ->prototype('scalar')->end()
                ->end()
                ->scalarNode('compress')->end()
                ->scalarNode('compress_threshold')->end()
                ->scalarNode('enabled')->defaultTrue()->end()
            ->end()
        ;

        return $node;
    }

private function getSourceNode ( ) { $ node = $ this -> createTreeBuilderNode ( '_source' ) ; $ node -> children ( ) -> arrayNode ( 'excludes' ) -> useAttributeAsKey ( 'name' ) -> prototype ( 'scalar' ) -> end ( ) -> end ( ) -> arrayNode ( 'includes' ) -> useAttributeAsKey ( 'name' ) -> prototype ( 'scalar' ) -> end ( ) -> end ( ) -> scalarNode ( 'compress' ) -> end ( ) -> scalarNode ( 'compress_threshold' ) -> end ( ) -> scalarNode ( 'enabled' ) -> defaultTrue ( ) -> end ( ) -> end ( ) ; return $ node ; }

Returns the array node used for "_source".

Returns the array node used for _source .


private function getRoutingNode()
    {
        $node = $this->createTreeBuilderNode('_routing');

        $node
            ->children()
                ->scalarNode('required')->end()
                ->scalarNode('path')->end()
            ->end()
        ;

        return $node;
    }

private function getRoutingNode ( ) { $ node = $ this -> createTreeBuilderNode ( '_routing' ) ; $ node -> children ( ) -> scalarNode ( 'required' ) -> end ( ) -> scalarNode ( 'path' ) -> end ( ) -> end ( ) ; return $ node ; }

Returns the array node used for "_routing".

Returns the array node used for _routing .


private function getParentNode()
    {
        $node = $this->createTreeBuilderNode('_parent');

        $node
            ->children()
                ->scalarNode('type')->end()
                ->scalarNode('property')->defaultValue(null)->end()
                ->scalarNode('identifier')->defaultValue('id')->end()
            ->end()
        ;

        return $node;
    }

private function getParentNode ( ) { $ node = $ this -> createTreeBuilderNode ( '_parent' ) ; $ node -> children ( ) -> scalarNode ( 'type' ) -> end ( ) -> scalarNode ( 'property' ) -> defaultValue ( null ) -> end ( ) -> scalarNode ( 'identifier' ) -> defaultValue ( 'id' ) -> end ( ) -> end ( ) ; return $ node ; }

Returns the array node used for "_parent".

Returns the array node used for _parent .


private function getAllNode()
    {
        $node = $this->createTreeBuilderNode('_all');

        $node
            ->children()
            ->scalarNode('enabled')->defaultValue(true)->end()
            ->scalarNode('analyzer')->end()
            ->end()
        ;

        return $node;
    }

private function getAllNode ( ) { $ node = $ this -> createTreeBuilderNode ( '_all' ) ; $ node -> children ( ) -> scalarNode ( 'enabled' ) -> defaultValue ( true ) -> end ( ) -> scalarNode ( 'analyzer' ) -> end ( ) -> end ( ) ; return $ node ; }


private function addIndexesSection(ArrayNodeDefinition $rootNode)
    {
        $rootNode
            ->fixXmlConfig('index')
            ->children()
                ->arrayNode('indexes')
                    ->useAttributeAsKey('name')
                    ->prototype('array')
                        ->children()
                            ->scalarNode('index_name')
                                ->info('Defaults to the name of the index, but can be modified if the index name is different in ElasticSearch')
                            ->end()
                            ->booleanNode('use_alias')->defaultValue(false)->end()
                            ->scalarNode('client')->end()
                            ->scalarNode('finder')
                                ->treatNullLike(true)
                                ->defaultFalse()
                            ->end()
                            ->arrayNode('type_prototype')
                                ->children()
                                    ->scalarNode('analyzer')->end()
                                    ->append($this->getPersistenceNode())
                                    ->append($this->getSerializerNode())
                                ->end()
                            ->end()
                            ->variableNode('settings')->defaultValue([])->end()
                        ->end()
                        ->append($this->getTypesNode())
                    ->end()
                ->end()
            ->end()
        ;
    }

Adds the configuration for the "indexes" key.

Adds the configuration for the indexes key .


private function addIndexTemplatesSection(ArrayNodeDefinition $rootNode)
    {
        $rootNode
            ->fixXmlConfig('index_template')
            ->children()
                ->arrayNode('index_templates')
                    ->useAttributeAsKey('name')
                    ->prototype('array')
                        ->children()
                            ->scalarNode('template_name')
                                ->info('Defaults to the name of the index template, but can be modified if the index name is different in ElasticSearch')
                            ->end()
                            ->scalarNode('template')->isRequired()->end()
                            ->scalarNode('client')->end()
                            ->variableNode('settings')->defaultValue([])->end()
                        ->end()
                        ->append($this->getTypesNode())
                    ->end()
                ->end()
            ->end()
        ;
    }

Adds the configuration for the "index_templates" key.

@param ArrayNodeDefinition $rootNode

@return void

Adds the configuration for the index_templates key .


public function transform(array $elasticaObjects)
    {
        $ids = $highlights = [];
        foreach ($elasticaObjects as $elasticaObject) {
            $ids[] = $elasticaObject->getId();
            $highlights[$elasticaObject->getId()] = $elasticaObject->getHighlights();
        }

        $objects = $this->findByIdentifiers($ids, $this->options['hydrate']);
        $objectsCnt = count($objects);
        $elasticaObjectsCnt = count($elasticaObjects);
        if (!$this->options['ignore_missing'] && $objectsCnt < $elasticaObjectsCnt) {
            throw new \RuntimeException(sprintf('Cannot find corresponding Doctrine objects (%d) for all Elastica results (%d). IDs: %s', $objectsCnt, $elasticaObjectsCnt, implode(', ', $ids)));
        }

        $propertyAccessor = $this->propertyAccessor;
        $identifier = $this->options['identifier'];
        foreach ($objects as $object) {
            if ($object instanceof HighlightableModelInterface) {
                $id = $propertyAccessor->getValue($object, $identifier);
                $object->setElasticHighlights($highlights[(string) $id]);
            }
        }

        // sort objects in the order of ids
        $idPos = array_flip($ids);
        usort(
            $objects,
            function ($a, $b) use ($idPos, $identifier, $propertyAccessor) {
                if ($this->options['hydrate']) {
                    return $idPos[(string) $propertyAccessor->getValue(
                        $a,
                        $identifier
                    )] > $idPos[(string) $propertyAccessor->getValue($b, $identifier)];
                }

                return $idPos[$a[$identifier]] > $idPos[$b[$identifier]];
            }
        );

        return $objects;
    }

Transforms an array of elastica objects into an array of
model objects fetched from the doctrine repository.

@param array $elasticaObjects of elastica objects

@throws \RuntimeException

@return array

Transforms an array of elastica objects into an array of model objects fetched from the doctrine repository .


public function isObjectIndexable($indexName, $typeName, $object)
    {
        $type = sprintf('%s/%s', $indexName, $typeName);
        $callback = $this->getCallback($type, $object);
        if (!$callback) {
            return true;
        }

        if ($callback instanceof Expression) {
            return (bool) $this->getExpressionLanguage()->evaluate($callback, [
                'object' => $object,
                $this->getExpressionVar($object) => $object,
            ]);
        }

        return is_string($callback)
            ? call_user_func([$object, $callback])
            : call_user_func($callback, $object);
    }

public function isObjectIndexable ( $ indexName , $ typeName , $ object ) { $ type = sprintf ( '%s/%s' , $ indexName , $ typeName ) ; $ callback = $ this -> getCallback ( $ type , $ object ) ; if ( ! $ callback ) { return true ; } if ( $ callback instanceof Expression ) { return ( bool ) $ this -> getExpressionLanguage ( ) -> evaluate ( $ callback , [ 'object' => $ object , $ this -> getExpressionVar ( $ object ) => $ object , ] ) ; } return is_string ( $ callback ) ? call_user_func ( [ $ object , $ callback ] ) : call_user_func ( $ callback , $ object ) ; }

Return whether the object is indexable with respect to the callback.

@param string $indexName
@param string $typeName
@param mixed  $object

@return bool

Return whether the object is indexable with respect to the callback .


private function buildCallback($type, $object)
    {
        if (!array_key_exists($type, $this->callbacks)) {
            return null;
        }

        $callback = $this->callbacks[$type];

        if (is_callable($callback) or is_callable([$object, $callback])) {
            return $callback;
        }

        if (is_string($callback)) {
            return $this->buildExpressionCallback($type, $object, $callback);
        }

        throw new \InvalidArgumentException(sprintf('Callback for type "%s" is not a valid callback.', $type));
    }

Builds and initialises a callback.

@param string $type
@param object $object

@return callable|string|ExpressionLanguage|null


private function buildExpressionCallback($type, $object, $callback)
    {
        $expression = $this->getExpressionLanguage();
        if (!$expression) {
            throw new \RuntimeException('Unable to process an expression without the ExpressionLanguage component.');
        }

        try {
            $callback = new Expression($callback);
            $expression->compile($callback, [
                'object', $this->getExpressionVar($object),
            ]);

            return $callback;
        } catch (SyntaxError $e) {
            throw new \InvalidArgumentException(sprintf(
                'Callback for type "%s" is an invalid expression',
                $type
            ), $e->getCode(), $e);
        }
    }

Processes a string expression into an Expression.

@param string $type
@param mixed  $object
@param string $callback

@return Expression

Processes a string expression into an Expression .


private function getCallback($type, $object)
    {
        if (!array_key_exists($type, $this->initialisedCallbacks)) {
            $this->initialisedCallbacks[$type] = $this->buildCallback($type, $object);
        }

        return $this->initialisedCallbacks[$type];
    }

private function getCallback ( $ type , $ object ) { if ( ! array_key_exists ( $ type , $ this -> initialisedCallbacks ) ) { $ this -> initialisedCallbacks [ $ type ] = $ this -> buildCallback ( $ type , $ object ) ; } return $ this -> initialisedCallbacks [ $ type ] ; }

Retreives a cached callback, or creates a new callback if one is not found.

@param string $type
@param object $object

@return mixed

Retreives a cached callback or creates a new callback if one is not found .


private function getExpressionVar($object = null)
    {
        if (!is_object($object)) {
            return 'object';
        }

        $ref = new \ReflectionClass($object);

        return strtolower($ref->getShortName());
    }

private function getExpressionVar ( $ object = null ) { if ( ! is_object ( $ object ) ) { return 'object' ; } $ ref = new \ ReflectionClass ( $ object ) ; return strtolower ( $ ref -> getShortName ( ) ) ; }

Returns the variable name to be used to access the object when using the ExpressionLanguage
component to parse and evaluate an expression.

@param mixed $object

@return string

Returns the variable name to be used to access the object when using the ExpressionLanguage component to parse and evaluate an expression .


public function setRootName(IndexConfig $indexConfig, Index $index)
    {
        $index->overrideName(
            sprintf('%s_%s',
                $indexConfig->getElasticSearchName(),
                date('Y-m-d-His')
            )
        );
    }

public function setRootName ( IndexConfig $ indexConfig , Index $ index ) { $ index -> overrideName ( sprintf ( '%s_%s' , $ indexConfig -> getElasticSearchName ( ) , date ( 'Y-m-d-His' ) ) ) ; }

Sets the randomised root name for an index.

@param IndexConfig $indexConfig
@param Index       $index

Sets the randomised root name for an index .


public function switchIndexAlias(IndexConfig $indexConfig, Index $index, $force = false, $delete = true)
    {
        $client = $index->getClient();

        $aliasName = $indexConfig->getElasticSearchName();
        $oldIndexName = null;
        $newIndexName = $index->getName();

        try {
            $oldIndexName = $this->getAliasedIndex($client, $aliasName);
        } catch (AliasIsIndexException $e) {
            if (!$force) {
                throw $e;
            }

            if ($delete) {
                $this->deleteIndex($client, $aliasName);
            } else {
                $this->closeIndex($client, $aliasName);
            }
        }

        try {
            $aliasUpdateRequest = $this->buildAliasUpdateRequest($oldIndexName, $aliasName, $newIndexName);
            $client->request('_aliases', 'POST', $aliasUpdateRequest);
        } catch (ExceptionInterface $e) {
            $this->cleanupRenameFailure($client, $newIndexName, $e);
        }

        // Delete the old index after the alias has been switched
        if (null !== $oldIndexName) {
            if ($delete) {
                $this->deleteIndex($client, $oldIndexName);
            } else {
                $this->closeIndex($client, $oldIndexName);
            }
        }
    }

Switches an index to become the new target for an alias. Only applies for
indexes that are set to use aliases.

$force will delete an index encountered where an alias is expected.

@param IndexConfig $indexConfig
@param Index       $index
@param bool        $force
@param bool        $delete

@throws AliasIsIndexException

Switches an index to become the new target for an alias . Only applies for indexes that are set to use aliases .


private function buildAliasUpdateRequest($aliasedIndex, $aliasName, $newIndexName)
    {
        $aliasUpdateRequest = ['actions' => []];
        if (null !== $aliasedIndex) {
            // if the alias is set - add an action to remove it
            $aliasUpdateRequest['actions'][] = [
                'remove' => ['index' => $aliasedIndex, 'alias' => $aliasName],
            ];
        }

        // add an action to point the alias to the new index
        $aliasUpdateRequest['actions'][] = [
            'add' => ['index' => $newIndexName, 'alias' => $aliasName],
        ];

        return $aliasUpdateRequest;
    }

Builds an ElasticSearch request to rename or create an alias.

@param string|null $aliasedIndex
@param string      $aliasName
@param string      $newIndexName

@return array

Builds an ElasticSearch request to rename or create an alias .


private function cleanupRenameFailure(Client $client, $indexName, \Exception $renameAliasException)
    {
        $additionalError = '';
        try {
            $this->deleteIndex($client, $indexName);
        } catch (ExceptionInterface $deleteNewIndexException) {
            $additionalError = sprintf(
                'Tried to delete newly built index %s, but also failed: %s',
                $indexName,
                $deleteNewIndexException->getMessage()
            );
        }

        throw new \RuntimeException(sprintf(
            'Failed to updated index alias: %s. %s',
            $renameAliasException->getMessage(),
            $additionalError ?: sprintf('Newly built index %s was deleted', $indexName)
        ), 0, $renameAliasException);
    }

Cleans up an index when we encounter a failure to rename the alias.

@param Client     $client
@param string     $indexName
@param \Exception $renameAliasException

Cleans up an index when we encounter a failure to rename the alias .


private function closeIndex(Client $client, $indexName)
    {
        try {
            $path = sprintf('%s/_close', $indexName);
            $client->request($path, Request::POST);
        } catch (ExceptionInterface $e) {
            throw new \RuntimeException(
                sprintf(
                    'Failed to close index %s with message: %s',
                    $indexName,
                    $e->getMessage()
                ),
                0,
                $e
            );
        }
    }

Close an index.

@param Client $client
@param string $indexName


private function getAliasedIndex(Client $client, $aliasName)
    {
        $aliasesInfo = $client->request('_aliases', 'GET')->getData();
        $aliasedIndexes = [];

        foreach ($aliasesInfo as $indexName => $indexInfo) {
            if ($indexName === $aliasName) {
                throw new AliasIsIndexException($indexName);
            }
            if (!isset($indexInfo['aliases'])) {
                continue;
            }

            $aliases = array_keys($indexInfo['aliases']);
            if (in_array($aliasName, $aliases)) {
                $aliasedIndexes[] = $indexName;
            }
        }

        if (count($aliasedIndexes) > 1) {
            throw new \RuntimeException(sprintf(
                'Alias %s is used for multiple indexes: [%s]. Make sure it\'s'.
                'either not used or is assigned to one index only',
                $aliasName,
                implode(', ', $aliasedIndexes)
            ));
        }

        return array_shift($aliasedIndexes);
    }

Returns the name of a single index that an alias points to or throws
an exception if there is more than one.

@param Client $client
@param string $aliasName Alias name

@return string|null

@throws AliasIsIndexException

Returns the name of a single index that an alias points to or throws an exception if there is more than one .


private function logQuery($path, $method, $data, array $query, $queryTime, $engineMS = 0, $itemCount = 0)
    {
        if (!$this->_logger or !$this->_logger instanceof ElasticaLogger) {
            return;
        }

        $connection = $this->getLastRequest()->getConnection();

        $connectionArray = [
            'host' => $connection->getHost(),
            'port' => $connection->getPort(),
            'transport' => $connection->getTransport(),
            'headers' => $connection->hasConfig('headers') ? $connection->getConfig('headers') : [],
        ];

        /** @var ElasticaLogger $logger */
        $logger = $this->_logger;
        $logger->logQuery($path, $method, $data, $queryTime, $connectionArray, $query, $engineMS, $itemCount);
    }

private
function
logQuery
(
$
path
,
$
method
,
$
data
,
array
$
query
,
$
queryTime
,
$
engineMS
=
0
,
$
itemCount
=
0
)
{
if
(
!
$
this
->
_logger
or
!
$
this
->
_logger
instanceof
ElasticaLogger
)
{
return
;
}
$
connection
=
$
this
->
getLastRequest
(
)
->
getConnection
(
)
;
$
connectionArray
=
[
'host'
=>
$
connection
->
getHost
(
)
,
'port'
=>
$
connection
->
getPort
(
)
,
'transport'
=>
$
connection
->
getTransport
(
)
,
'headers'
=>
$
connection
->
hasConfig
(
'headers'
)
$
connection
->
getConfig
(
'headers'
)
:
[
]
,
]
;
/** @var ElasticaLogger $logger */
$
logger
=
$
this
->
_logger
;
$
logger
->
logQuery
(
$
path
,
$
method
,
$
data
,
$
queryTime
,
$
connectionArray
,
$
query
,
$
engineMS
,
$
itemCount
)
;
}

Log the query if we have an instance of ElasticaLogger.

@param string $path
@param string $method
@param array|string $data
@param array  $query
@param int    $queryTime
@param int    $engineMS
@param int    $itemCount

Log the query if we have an instance of ElasticaLogger .


public function postPersist(LifecycleEventArgs $eventArgs)
    {
        $entity = $eventArgs->getObject();

        if ($this->objectPersister->handlesObject($entity) && $this->isObjectIndexable($entity)) {
            $this->scheduledForInsertion[] = $entity;
        }
    }

public function postPersist ( LifecycleEventArgs $ eventArgs ) { $ entity = $ eventArgs -> getObject ( ) ; if ( $ this -> objectPersister -> handlesObject ( $ entity ) && $ this -> isObjectIndexable ( $ entity ) ) { $ this -> scheduledForInsertion [ ] = $ entity ; } }

Looks for new objects that should be indexed.

@param LifecycleEventArgs $eventArgs

Looks for new objects that should be indexed .


public function postUpdate(LifecycleEventArgs $eventArgs)
    {
        $entity = $eventArgs->getObject();

        if ($this->objectPersister->handlesObject($entity)) {
            if ($this->isObjectIndexable($entity)) {
                $this->scheduledForUpdate[] = $entity;
            } else {
                // Delete if no longer indexable
                $this->scheduleForDeletion($entity);
            }
        }
    }

public
function
postUpdate
(
LifecycleEventArgs
$
eventArgs
)
{
$
entity
=
$
eventArgs
->
getObject
(
)
;
if
(
$
this
->
objectPersister
->
handlesObject
(
$
entity
)
)
{
if
(
$
this
->
isObjectIndexable
(
$
entity
)
)
{
$
this
->
scheduledForUpdate
[
]
=
$
entity
;
}
else
{
// Delete if no longer indexable
$
this
->
scheduleForDeletion
(
$
entity
)
;
}
}
}

Looks for objects being updated that should be indexed or removed from the index.

@param LifecycleEventArgs $eventArgs

Looks for objects being updated that should be indexed or removed from the index .


public function preRemove(LifecycleEventArgs $eventArgs)
    {
        $entity = $eventArgs->getObject();

        if ($this->objectPersister->handlesObject($entity)) {
            $this->scheduleForDeletion($entity);
        }
    }

public function preRemove ( LifecycleEventArgs $ eventArgs ) { $ entity = $ eventArgs -> getObject ( ) ; if ( $ this -> objectPersister -> handlesObject ( $ entity ) ) { $ this -> scheduleForDeletion ( $ entity ) ; } }

Delete objects preRemove instead of postRemove so that we have access to the id.  Because this is called
preRemove, first check that the entity is managed by Doctrine.

@param LifecycleEventArgs $eventArgs

Delete objects preRemove instead of postRemove so that we have access to the id . Because this is called preRemove first check that the entity is managed by Doctrine .


private function persistScheduled()
    {
        if ($this->shouldPersist()) {
            if (count($this->scheduledForInsertion)) {
                $this->objectPersister->insertMany($this->scheduledForInsertion);
                $this->scheduledForInsertion = [];
            }
            if (count($this->scheduledForUpdate)) {
                $this->objectPersister->replaceMany($this->scheduledForUpdate);
                $this->scheduledForUpdate = [];
            }
            if (count($this->scheduledForDeletion)) {
                $this->objectPersister->deleteManyByIdentifiers($this->scheduledForDeletion);
                $this->scheduledForDeletion = [];
            }
        }
    }

private function persistScheduled ( ) { if ( $ this -> shouldPersist ( ) ) { if ( count ( $ this -> scheduledForInsertion ) ) { $ this -> objectPersister -> insertMany ( $ this -> scheduledForInsertion ) ; $ this -> scheduledForInsertion = [ ] ; } if ( count ( $ this -> scheduledForUpdate ) ) { $ this -> objectPersister -> replaceMany ( $ this -> scheduledForUpdate ) ; $ this -> scheduledForUpdate = [ ] ; } if ( count ( $ this -> scheduledForDeletion ) ) { $ this -> objectPersister -> deleteManyByIdentifiers ( $ this -> scheduledForDeletion ) ; $ this -> scheduledForDeletion = [ ] ; } } }

Persist scheduled objects to ElasticSearch
After persisting, clear the scheduled queue to prevent multiple data updates when using multiple flush calls.

Persist scheduled objects to ElasticSearch After persisting clear the scheduled queue to prevent multiple data updates when using multiple flush calls .


private function scheduleForDeletion($object)
    {
        if ($identifierValue = $this->propertyAccessor->getValue($object, $this->config['identifier'])) {
            $this->scheduledForDeletion[] = !is_scalar($identifierValue) ? (string) $identifierValue : $identifierValue;
        }
    }

private function scheduleForDeletion ( $ object ) { if ( $ identifierValue = $ this -> propertyAccessor -> getValue ( $ object , $ this -> config [ 'identifier' ] ) ) { $ this -> scheduledForDeletion [ ] = ! is_scalar ( $ identifierValue ) ? ( string ) $ identifierValue : $ identifierValue ; } }

Record the specified identifier to delete. Do not need to entire object.

@param object $object

Record the specified identifier to delete . Do not need to entire object .


private function isObjectIndexable($object)
    {
        return $this->indexable->isObjectIndexable(
            $this->config['indexName'],
            $this->config['typeName'],
            $object
        );
    }

private function isObjectIndexable ( $ object ) { return $ this -> indexable -> isObjectIndexable ( $ this -> config [ 'indexName' ] , $ this -> config [ 'typeName' ] , $ object ) ; }

Checks if the object is indexable or not.

@param object $object

@return bool

Checks if the object is indexable or not .


public function getRepository($entityName)
    {
        $realEntityName = $entityName;
        if (false !== strpos($entityName, ':')) {
            list($namespaceAlias, $simpleClassName) = explode(':', $entityName);
            $realEntityName = $this->managerRegistry->getAliasNamespace($namespaceAlias).'\\'.$simpleClassName;
        }

        if (isset($this->entities[$realEntityName])) {
            $realEntityName = $this->entities[$realEntityName];
        }

        return $this->repositoryManager->getRepository($realEntityName);
    }

public function getRepository ( $ entityName ) { $ realEntityName = $ entityName ; if ( false !== strpos ( $ entityName , ':' ) ) { list ( $ namespaceAlias , $ simpleClassName ) = explode ( ':' , $ entityName ) ; $ realEntityName = $ this -> managerRegistry -> getAliasNamespace ( $ namespaceAlias ) . '\\' . $ simpleClassName ; } if ( isset ( $ this -> entities [ $ realEntityName ] ) ) { $ realEntityName = $ this -> entities [ $ realEntityName ] ; } return $ this -> repositoryManager -> getRepository ( $ realEntityName ) ; }

Returns custom repository if one specified otherwise returns a basic repository.

{@inheritdoc}

Returns custom repository if one specified otherwise returns a basic repository .


public function transform($object, array $fields)
    {
        $identifier = $this->propertyAccessor->getValue($object, $this->options['identifier']);

        return new Document($identifier);
    }

public function transform ( $ object , array $ fields ) { $ identifier = $ this -> propertyAccessor -> getValue ( $ object , $ this -> options [ 'identifier' ] ) ; return new Document ( $ identifier ) ; }

Creates an elastica document with the id of the doctrine object as id.

@param object $object the object to convert
@param array  $fields the keys we want to have in the returned array

@return Document

Creates an elastica document with the id of the doctrine object as id .


public function getRepository($typeName)
    {
        if (isset($this->repositories[$typeName])) {
            return $this->repositories[$typeName];
        }

        if (!isset($this->types[$typeName])) {
            throw new RuntimeException(sprintf('No search finder configured for %s', $typeName));
        }

        $repository = $this->createRepository($typeName);
        $this->repositories[$typeName] = $repository;

        return $repository;
    }

public
function
getRepository
(
$
typeName
)
{
if
(
isset
(
$
this
->
repositories
[
$
typeName
]
)
)
{
return
$
this
->
repositories
[
$
typeName
]
;
}
if
(
!
isset
(
$
this
->
types
[
$
typeName
]
)
)
{
throw
new
RuntimeException
(
sprintf
(
'No search finder configured for %s'
,
$
typeName
)
)
;
}
$
repository
=
$
this
->
createRepository
(
$
typeName
)
;
$
this
->
repositories
[
$
typeName
]
=
$
repository
;
return
$
repository
;
}

Return repository for entity.

Returns custom repository if one specified otherwise
returns a basic repository.

@param string $typeName

@return Repository


public function make(array $config): Hashids
    {
        $config = $this->getConfig($config);

        return $this->getClient($config);
    }

public function make ( array $ config ) : Hashids { $ config = $ this -> getConfig ( $ config ) ; return $ this -> getClient ( $ config ) ; }

Make a new Hashids client.

@param array $config

@return \Hashids\Hashids


protected function registerFactory(): void
    {
        $this->app->singleton('hashids.factory', function () {
            return new HashidsFactory();
        });

        $this->app->alias('hashids.factory', HashidsFactory::class);
    }

protected function registerFactory ( ) : void { $ this -> app -> singleton ( 'hashids.factory' , function ( ) { return new HashidsFactory ( ) ; } ) ; $ this -> app -> alias ( 'hashids.factory' , HashidsFactory :: class ) ; }

Register the factory class.

@return void


public function verifyHash(array $params)
    {
        if (empty($params['HASH'])) {
            return false;
        }

        $hash = $params['HASH'];
        unset($params['HASH']);

        return $hash === $this->calculateHash($params);
    }

public function verifyHash ( array $ params ) { if ( empty ( $ params [ 'HASH' ] ) ) { return false ; } $ hash = $ params [ 'HASH' ] ; unset ( $ params [ 'HASH' ] ) ; return $ hash === $ this -> calculateHash ( $ params ) ; }

Verify if the hash of the given parameter is correct

@param array $params

@return bool


public static function createGuzzle()
    {
        $client = null;
        if (!class_exists(Client::class)) {
            @trigger_error('The function "HttpClientFactory::createGuzzle" is depcrecated and will be removed in 2.0.', E_USER_DEPRECATED);
            throw new \LogicException('Can not use "HttpClientFactory::createGuzzle" since Guzzle is not installed. This function is deprecated and will be removed in 2.0.');
        }

        $version = \GuzzleHttp\ClientInterface::VERSION;
        if (substr($version, 0, 1) !== '6') {
            throw new \LogicException('This version of Guzzle is not supported.');
        }

        $curl = curl_version();

        $curlOptions = [
             CURLOPT_USERAGENT => sprintf('Payum/1.x curl/%s PHP/%s', $curl['version'], phpversion()),
         ];

        return new \GuzzleHttp\Client([
             'curl' => $curlOptions,
         ]);
    }

Create a Guzzle client.

@return \GuzzleHttp\Client


public function addCookie(Cookie $cookie): void
    {
        $this->cookies[$this->getHash($cookie)] = $cookie;
    }

public function addCookie ( Cookie $ cookie ) : void { $ this -> cookies [ $ this -> getHash ( $ cookie ) ] = $ cookie ; }

Adds a cookie to the current cookie jar.

Adds a cookie to the current cookie jar .


public function addCookieHeaders(RequestInterface $request): RequestInterface
    {
        $cookies = [];
        foreach ($this->getCookies() as $cookie) {
            if ($cookie->matchesRequest($request)) {
                $cookies[] = $cookie->toCookieHeader();
            }
        }
        if ($cookies) {
            $request = $request->withAddedHeader('Cookie', implode('; ', $cookies));
        }

        return $request;
    }

public
function
addCookieHeaders
(
RequestInterface
$
request
)
:
RequestInterface
{
$
cookies
=
[
]
;
foreach
(
$
this
->
getCookies
(
)
as
$
cookie
)
{
if
(
$
cookie
->
matchesRequest
(
$
request
)
)
{
$
cookies
[
]
=
$
cookie
->
toCookieHeader
(
)
;
}
}
if
(
$
cookies
)
{
$
request
=
$
request
->
withAddedHeader
(
'Cookie'
,
implode
(
'; '
,
$
cookies
)
)
;
}
return
$
request
;
}

Adds Cookie headers to the supplied request.

Adds Cookie headers to the supplied request .


public function clearExpiredCookies(): void
    {
        $cookies = $this->getCookies();
        foreach ($cookies as $i => $cookie) {
            if ($cookie->isExpired()) {
                unset($cookies[$i]);
            }
        }

        $this->clear();
        $this->setCookies(array_values($cookies));
    }

public function clearExpiredCookies ( ) : void { $ cookies = $ this -> getCookies ( ) ; foreach ( $ cookies as $ i => $ cookie ) { if ( $ cookie -> isExpired ( ) ) { unset ( $ cookies [ $ i ] ) ; } } $ this -> clear ( ) ; $ this -> setCookies ( array_values ( $ cookies ) ) ; }


private function getHash(Cookie $cookie): string
    {
        return sha1(sprintf(
            '%s|%s|%s',
            $cookie->getName(),
            $cookie->getAttribute(Cookie::ATTR_DOMAIN),
            $cookie->getAttribute(Cookie::ATTR_PATH)
        ));
    }

private function getHash ( Cookie $ cookie ) : string { return sha1 ( sprintf ( '%s|%s|%s' , $ cookie -> getName ( ) , $ cookie -> getAttribute ( Cookie :: ATTR_DOMAIN ) , $ cookie -> getAttribute ( Cookie :: ATTR_PATH ) ) ) ; }

Create an unique identifier for the cookie. Two cookies with the same identifier
may have different values.

Create an unique identifier for the cookie . Two cookies with the same identifier may have different values .


public function addHeader(string $input): void
    {
        list($key, $value) = explode(':', $input, 2);
        $this->response = $this->response->withAddedHeader(trim($key), trim($value));
    }

public function addHeader ( string $ input ) : void { list ( $ key , $ value ) = explode ( ':' , $ input , 2 ) ; $ this -> response = $ this -> response -> withAddedHeader ( trim ( $ key ) , trim ( $ value ) ) ; }


public function parseHttpHeaders(array $headers): void
    {
        $headers = $this->filterHeaders($headers);
        $statusLine = array_shift($headers);

        try {
            $this->setStatus($statusLine);
        } catch (InvalidArgumentException $e) {
            array_unshift($headers, $statusLine);
        }

        foreach ($headers as $header) {
            $this->addHeader($header);
        }
    }

public function parseHttpHeaders ( array $ headers ) : void { $ headers = $ this -> filterHeaders ( $ headers ) ; $ statusLine = array_shift ( $ headers ) ; try { $ this -> setStatus ( $ statusLine ) ; } catch ( InvalidArgumentException $ e ) { array_unshift ( $ headers , $ statusLine ) ; } foreach ( $ headers as $ header ) { $ this -> addHeader ( $ header ) ; } }

Add HTTP headers. The input array is all the header lines from the HTTP message. Optionally including the
status line.

Add HTTP headers . The input array is all the header lines from the HTTP message . Optionally including the status line .


public function handleRequest(RequestInterface $request, callable $next)
    {
        $this->setUri($request->getUri()->getPath());
        $this->setMethod(strtoupper($request->getMethod()));
        $this->setEntityBody($request->getBody()->__toString());

        $header = $this->getHeader();
        if (null !== $header) {
            $request = $request->withHeader('Authorization', $header);
        }

        return $next($request);
    }

public function handleRequest ( RequestInterface $ request , callable $ next ) { $ this -> setUri ( $ request -> getUri ( ) -> getPath ( ) ) ; $ this -> setMethod ( strtoupper ( $ request -> getMethod ( ) ) ) ; $ this -> setEntityBody ( $ request -> getBody ( ) -> __toString ( ) ) ; $ header = $ this -> getHeader ( ) ; if ( null !== $ header ) { $ request = $ request -> withHeader ( 'Authorization' , $ header ) ; } return $ next ( $ request ) ; }

Populates uri, method and entityBody used to generate the Authentication header using the specified request object.
Appends the Authentication header if it is present and has been able to be calculated.

Populates uri method and entityBody used to generate the Authentication header using the specified request object . Appends the Authentication header if it is present and has been able to be calculated .


public function setOptions($options): void
    {
        if ($options & self::OPTION_QOP_AUTH_INT) {
            if ($options & self::OPTION_QOP_AUTH) {
                throw new \InvalidArgumentException('DigestAuthMiddleware: Only one value of OPTION_QOP_AUTH_INT or OPTION_QOP_AUTH may be set.');
            }
            $this->options = $this->options | self::OPTION_QOP_AUTH_INT;
        } elseif ($options & self::OPTION_QOP_AUTH) {
            $this->options = $this->options | self::OPTION_QOP_AUTH;
        }

        if ($options & self::OPTION_IGNORE_DOWNGRADE_REQUEST) {
            $this->options = $this->options | self::OPTION_IGNORE_DOWNGRADE_REQUEST;
        }

        if ($options & self::OPTION_DISCARD_CLIENT_NONCE) {
            $this->options = $this->options | self::OPTION_DISCARD_CLIENT_NONCE;
        }
    }

Sets the options to be used by this class.

@param mixed $options a bitmask of the constants defined in this class

Sets the options to be used by this class .


private function getClientNonce(): ?string
    {
        if (null == $this->clientNonce) {
            $this->clientNonce = uniqid();

            if (null == $this->nonceCount) {
                // If nonceCount is not set then set it to 00000001.
                $this->nonceCount = '00000001';
            } else {
                // If it is set then increment it.
                ++$this->nonceCount;
                // Ensure nonceCount is zero-padded at the start of the string to a length of 8
                while (\strlen($this->nonceCount) < 8) {
                    $this->nonceCount = '0'.$this->nonceCount;
                }
            }
        }

        return $this->clientNonce;
    }

Returns either the current value of clientNonce or generates a new value if clientNonce is null.
Also increments nonceCount.

@return string Returns either the current value of clientNonce the newly generated clientNonce;

Returns either the current value of clientNonce or generates a new value if clientNonce is null . Also increments nonceCount .


private function getHA1(): ?string
    {
        $username = $this->getUsername();
        $password = $this->getPassword();
        $realm = $this->getRealm();

        if (($username) && ($password) && ($realm)) {
            $algorithm = $this->getAlgorithm();

            if ('MD5' === $algorithm) {
                $A1 = "{$username}:{$realm}:{$password}";

                return $this->hash($A1);
            } elseif ('MD5-sess' === $algorithm) {
                $nonce = $this->getNonce();
                $cnonce = $this->getClientNonce();
                if (($nonce) && ($cnonce)) {
                    $A1 = $this->hash("{$username}:{$realm}:{$password}").":{$nonce}:{$cnonce}";

                    return $this->hash($A1);
                }
            }
        }

        return null;
    }

private function getHA1 ( ) : ? string { $ username = $ this -> getUsername ( ) ; $ password = $ this -> getPassword ( ) ; $ realm = $ this -> getRealm ( ) ; if ( ( $ username ) && ( $ password ) && ( $ realm ) ) { $ algorithm = $ this -> getAlgorithm ( ) ; if ( 'MD5' === $ algorithm ) { $ A1 = "{$username}:{$realm}:{$password}" ; return $ this -> hash ( $ A1 ) ; } elseif ( 'MD5-sess' === $ algorithm ) { $ nonce = $ this -> getNonce ( ) ; $ cnonce = $ this -> getClientNonce ( ) ; if ( ( $ nonce ) && ( $ cnonce ) ) { $ A1 = $ this -> hash ( "{$username}:{$realm}:{$password}" ) . ":{$nonce}:{$cnonce}" ; return $ this -> hash ( $ A1 ) ; } } } return null ; }

Calculates the value of HA1 according to RFC 2617 and RFC 2069.

@return string|null The value of HA1

Calculates the value of HA1 according to RFC 2617 and RFC 2069 .


private function getHA2(): ?string
    {
        $method = $this->getMethod();
        $uri = $this->getUri();

        if (($method) && ($uri)) {
            $qop = $this->getQOP();

            if (null === $qop || 'auth' === $qop) {
                $A2 = "{$method}:{$uri}";
            } elseif ('auth-int' === $qop) {
                $entityBody = (string) $this->getEntityBody();
                $A2 = "{$method}:{$uri}:".(string) $this->hash($entityBody);
            } else {
                return null;
            }

            $HA2 = $this->hash($A2);

            return $HA2;
        }

        return null;
    }

private function getHA2 ( ) : ? string { $ method = $ this -> getMethod ( ) ; $ uri = $ this -> getUri ( ) ; if ( ( $ method ) && ( $ uri ) ) { $ qop = $ this -> getQOP ( ) ; if ( null === $ qop || 'auth' === $ qop ) { $ A2 = "{$method}:{$uri}" ; } elseif ( 'auth-int' === $ qop ) { $ entityBody = ( string ) $ this -> getEntityBody ( ) ; $ A2 = "{$method}:{$uri}:" . ( string ) $ this -> hash ( $ entityBody ) ; } else { return null ; } $ HA2 = $ this -> hash ( $ A2 ) ; return $ HA2 ; } return null ; }

Calculates the value of HA2 according to RFC 2617 and RFC 2069.

@return string The value of HA2

Calculates the value of HA2 according to RFC 2617 and RFC 2069 .


private function getHeader(): ?string
    {
        if ('Digest' == $this->getAuthenticationMethod()) {
            $username = $this->getUsername();
            $realm = $this->getRealm();
            $nonce = $this->getNonce();
            $response = $this->getResponse();
            if (($username) && ($realm) && ($nonce) && ($response)) {
                $uri = $this->getUri();
                $opaque = $this->getOpaque();
                $qop = $this->getQOP();

                $header = 'Digest';
                $header .= ' username="'.$username.'",';
                $header .= ' realm="'.$realm.'",';
                $header .= ' nonce="'.$nonce.'",';
                $header .= ' response="'.$response.'",';

                if ($uri) {
                    $header .= ' uri="'.$uri.'",';
                }
                if ($opaque) {
                    $header .= ' opaque="'.$opaque.'",';
                }

                if ($qop) {
                    $header .= ' qop='.$qop.',';

                    $cnonce = $this->getClientNonce();
                    $nc = $this->getNonceCount();

                    if ($cnonce) {
                        $header .= ' nc='.$nc.',';
                    }
                    if ($cnonce) {
                        $header .= ' cnonce="'.$cnonce.'",';
                    }
                }

                // Remove the last comma from the header
                $header = substr($header, 0, \strlen($header) - 1);
                // Discard the Client Nonce if OPTION_DISCARD_CLIENT_NONCE is set.
                if ($this->options & self::OPTION_DISCARD_CLIENT_NONCE) {
                    $this->discardClientNonce();
                }

                return $header;
            }
        }
        if ('Basic' == $this->getAuthenticationMethod()) {
            $username = $this->getUsername();
            $password = $this->getPassword();
            if (($username) && ($password)) {
                $header = 'Basic '.base64_encode("{$username}:{$password}");

                return $header;
            }
        }

        return null;
    }

Returns the full Authentication header for use in authenticating the client with either Digest or Basic authentication.

@return string the Authentication header to be sent to the server

Returns the full Authentication header for use in authenticating the client with either Digest or Basic authentication .


private function getResponse(): ?string
    {
        $HA1 = $this->getHA1();
        $nonce = $this->getNonce();
        $HA2 = $this->getHA2();

        if (null !== $HA1 && ($nonce) && null !== $HA2) {
            $qop = $this->getQOP();

            if (empty($qop)) {
                $response = $this->hash("{$HA1}:{$nonce}:{$HA2}");

                return $response;
            }

            $cnonce = $this->getClientNonce();
            $nc = $this->getNonceCount();
            if (($cnonce) && ($nc)) {
                $response = $this->hash("{$HA1}:{$nonce}:{$nc}:{$cnonce}:{$qop}:{$HA2}");

                return $response;
            }
        }

        return null;
    }

Calculates the value of response according to RFC 2617 and RFC 2069.

@return string The value of response

Calculates the value of response according to RFC 2617 and RFC 2069 .


private function getQOP(): ?string
    {
        // Has the server specified any options for Quality of Protection
        if (\count($this->qop) > 0) {
            if ($this->options & self::OPTION_QOP_AUTH_INT) {
                if (\in_array('auth-int', $this->qop)) {
                    return 'auth-int';
                }
                if (\in_array('auth', $this->qop)) {
                    return 'auth';
                }
            }
            if ($this->options & self::OPTION_QOP_AUTH) {
                if (\in_array('auth', $this->qop)) {
                    return 'auth';
                }
                if (\in_array('auth-int', $this->qop)) {
                    return 'auth-int';
                }
            }
        }
        // Server has not specified any value for Quality of Protection so return null
        return null;
    }

Returns the Quality of Protection to be used when authenticating with the server.

@return string this will either be auth-int or auth

Returns the Quality of Protection to be used when authenticating with the server .


private function hash($value): ?string
    {
        $algorithm = $this->getAlgorithm();
        if (('MD5' == $algorithm) || ('MD5-sess' == $algorithm)) {
            return hash('md5', $value);
        }

        return null;
    }

private function hash ( $ value ) : ? string { $ algorithm = $ this -> getAlgorithm ( ) ; if ( ( 'MD5' == $ algorithm ) || ( 'MD5-sess' == $ algorithm ) ) { return hash ( 'md5' , $ value ) ; } return null ; }

Calculates the hash for a given value using the algorithm specified by the server.

@param string $value The value to be hashed

@return string the hashed value

Calculates the hash for a given value using the algorithm specified by the server .


private function parseAuthenticationInfoHeader(string $authenticationInfo): void
    {
        $nameValuePairs = $this->parseNameValuePairs($authenticationInfo);
        foreach ($nameValuePairs as $name => $value) {
            switch ($name) {
                case 'message-qop':

                    break;
                case 'nextnonce':
                    // This function needs to only set the Nonce once the rspauth has been verified.
                    $this->setNonce($value);

                    break;
                case 'rspauth':
                    // Check server rspauth value
                    break;
            }
        }
    }

Parses the Authentication-Info header received from the server and calls the relevant setter method on each variable received.

@param string $authenticationInfo the full Authentication-Info header

Parses the Authentication - Info header received from the server and calls the relevant setter method on each variable received .


private function parseNameValuePairs(string $nameValuePairs): array
    {
        $parsedNameValuePairs = [];
        $nameValuePairs = explode(',', $nameValuePairs);
        foreach ($nameValuePairs as $nameValuePair) {
            // Trim the Whitespace from the start and end of the name value pair string
            $nameValuePair = trim($nameValuePair);
            // Split $nameValuePair (name=value) into $name and $value
            list($name, $value) = explode('=', $nameValuePair, 2);
            // Remove quotes if the string is quoted
            $value = $this->unquoteString($value);
            // Add pair to array[name] => value
            $parsedNameValuePairs[$name] = $value;
        }

        return $parsedNameValuePairs;
    }

Parses a string of name=value pairs separated by commas and returns and array with the name as the index.

@param string $nameValuePairs the string containing the name=value pairs

@return array an array with the name used as the index and the values stored within

Parses a string of name = value pairs separated by commas and returns and array with the name as the index .


private function parseWwwAuthenticateHeader(string $wwwAuthenticate): void
    {
        if ('Digest ' == substr($wwwAuthenticate, 0, 7)) {
            $this->setAuthenticationMethod('Digest');
            // Remove "Digest " from start of header
            $wwwAuthenticate = substr($wwwAuthenticate, 7, \strlen($wwwAuthenticate) - 7);

            $nameValuePairs = $this->parseNameValuePairs($wwwAuthenticate);

            foreach ($nameValuePairs as $name => $value) {
                switch ($name) {
                    case 'algorithm':
                        $this->setAlgorithm($value);

                        break;
                    case 'domain':
                        $this->setDomain($value);

                        break;
                    case 'nonce':
                        $this->setNonce($value);

                        break;
                    case 'realm':
                        $this->setRealm($value);

                        break;
                    case 'opaque':
                        $this->setOpaque($value);

                        break;
                    case 'qop':
                        $this->setQOP(explode(',', $value));

                        break;
                }
            }
        }
        if ('Basic ' == substr($wwwAuthenticate, 0, 6)) {
            $this->setAuthenticationMethod('Basic');
            // Remove "Basic " from start of header
            $wwwAuthenticate = substr($wwwAuthenticate, 6, \strlen($wwwAuthenticate) - 6);

            $nameValuePairs = $this->parseNameValuePairs($wwwAuthenticate);

            foreach ($nameValuePairs as $name => $value) {
                switch ($name) {
                    case 'realm':
                        $this->setRealm($value);

                        break;
                }
            }
        }
    }

Parses the WWW-Authenticate header received from the server and calls the relevant setter method on each variable received.

@param string $wwwAuthenticate the full WWW-Authenticate header

Parses the WWW - Authenticate header received from the server and calls the relevant setter method on each variable received .


private function setAlgorithm(string $algorithm): void
    {
        if (('MD5' == $algorithm) || ('MD5-sess' == $algorithm)) {
            $this->algorithm = $algorithm;
        } else {
            throw new \InvalidArgumentException('DigestAuthMiddleware: Only MD5 and MD5-sess algorithms are currently supported.');
        }
    }

Sets the hashing algorithm to be used. Currently only uses MD5 specified by either MD5 or MD5-sess.
RFCs are currently in draft stage for the proposal of SHA-256 and SHA-512-256.
Support will be added once the RFC leaves the draft stage.

@param string $algorithm the algorithm the server has requested to use

@throws \InvalidArgumentException if $algorithm is set to anything other than MD5 or MD5-sess

Sets the hashing algorithm to be used . Currently only uses MD5 specified by either MD5 or MD5 - sess . RFCs are currently in draft stage for the proposal of SHA - 256 and SHA - 512 - 256 . Support will be added once the RFC leaves the draft stage .


private function setMethod(string $method = null): void
    {
        if ('GET' == $method) {
            $this->method = 'GET';

            return;
        }
        if ('POST' == $method) {
            $this->method = 'POST';

            return;
        }
        if ('PUT' == $method) {
            $this->method = 'PUT';

            return;
        }
        if ('DELETE' == $method) {
            $this->method = 'DELETE';

            return;
        }
        if ('HEAD' == $method) {
            $this->method = 'HEAD';

            return;
        }

        throw new \InvalidArgumentException('DigestAuthMiddleware: Only GET,POST,PUT,DELETE,HEAD HTTP methods are currently supported.');
    }

Sets the HTTP method being used for the request.

@param string $method The HTTP method

@throws \InvalidArgumentException if $method is set to anything other than GET,POST,PUT,DELETE or HEAD

Sets the HTTP method being used for the request .


private function unquoteString(string $str = null): ?string
    {
        if ($str) {
            if ('"' == substr($str, 0, 1)) {
                $str = substr($str, 1, \strlen($str) - 1);
            }
            if ('"' == substr($str, \strlen($str) - 1, 1)) {
                $str = substr($str, 0, \strlen($str) - 1);
            }
        }

        return $str;
    }

private function unquoteString ( string $ str = null ) : ? string { if ( $ str ) { if ( '"' == substr ( $ str , 0 , 1 ) ) { $ str = substr ( $ str , 1 , \ strlen ( $ str ) - 1 ) ; } if ( '"' == substr ( $ str , \ strlen ( $ str ) - 1 , 1 ) ) { $ str = substr ( $ str , 0 , \ strlen ( $ str ) - 1 ) ; } } return $ str ; }

If a string contains quotation marks at either end this function will strip them. Otherwise it will remain unchanged.

@param string $str the string to be stripped of quotation marks

@return string returns the original string without the quotation marks at either end

If a string contains quotation marks at either end this function will strip them . Otherwise it will remain unchanged .


public function add(array $parameters = []): self
    {
        // Make sure to merge Curl parameters
        if (isset($this->parameters['curl'])
            && isset($parameters['curl'])
            && \is_array($this->parameters['curl'])
            && \is_array($parameters['curl'])) {
            $parameters['curl'] = array_replace($this->parameters['curl'], $parameters['curl']);
        }

        $newParameters = array_replace($this->parameters, $parameters);

        return new self($newParameters);
    }

public
function
add
(
array
$
parameters
=
[
]
)
:
self
{
// Make sure to merge Curl parameters
if
(
isset
(
$
this
->
parameters
[
'curl'
]
)
&&
isset
(
$
parameters
[
'curl'
]
)
&&
\
is_array
(
$
this
->
parameters
[
'curl'
]
)
&&
\
is_array
(
$
parameters
[
'curl'
]
)
)
{
$
parameters
[
'curl'
]
=
array_replace
(
$
this
->
parameters
[
'curl'
]
,
$
parameters
[
'curl'
]
)
;
}
$
newParameters
=
array_replace
(
$
this
->
parameters
,
$
parameters
)
;
return
new
self
(
$
newParameters
)
;
}

Adds parameters to the existing ones.

@param array $parameters An array of parameters


public static function toBuzzHeaders(array $headers): array
    {
        $buzz = [];

        foreach ($headers as $key => $values) {
            if (!\is_array($values)) {
                $buzz[] = sprintf('%s: %s', $key, $values);
            } else {
                foreach ($values as $value) {
                    $buzz[] = sprintf('%s: %s', $key, $value);
                }
            }
        }

        return $buzz;
    }

public
static
function
toBuzzHeaders
(
array
$
headers
)
:
array
{
$
buzz
=
[
]
;
foreach
(
$
headers
as
$
key
=>
$
values
)
{
if
(
!
\
is_array
(
$
values
)
)
{
$
buzz
[
]
=
sprintf
(
'%s: %s'
,
$
key
,
$
values
)
;
}
else
{
foreach
(
$
values
as
$
value
)
{
$
buzz
[
]
=
sprintf
(
'%s: %s'
,
$
key
,
$
value
)
;
}
}
}
return
$
buzz
;
}

Convert from Buzz style headers to PSR style.

Convert from Buzz style headers to PSR style .


public static function toPsrHeaders(array $headers): array
    {
        $psr = [];
        foreach ($headers as $header) {
            list($key, $value) = explode(':', $header, 2);
            $psr[trim($key)][] = trim($value);
        }

        return $psr;
    }

public static function toPsrHeaders ( array $ headers ) : array { $ psr = [ ] ; foreach ( $ headers as $ header ) { list ( $ key , $ value ) = explode ( ':' , $ header , 2 ) ; $ psr [ trim ( $ key ) ] [ ] = trim ( $ value ) ; } return $ psr ; }

Convert from PSR style headers to Buzz style.

Convert from PSR style headers to Buzz style .


public function sendAsyncRequest(RequestInterface $request, array $options = []): void
    {
        $options = $this->validateOptions($options);

        $this->addToQueue($request, $options);
    }

public function sendAsyncRequest ( RequestInterface $ request , array $ options = [ ] ) : void { $ options = $ this -> validateOptions ( $ options ) ; $ this -> addToQueue ( $ request , $ options ) ; }

Populates the supplied response with the response for the supplied request.

If a "callback" option is supplied, its value will be called when the
request completes. It is ONLY in the callback you will see the response
or an exception.

This is a non-blocking function call.

The callable should have the following signature:

$callback = function($request, $response, $exception) {
if (!$exception) {
// success
} else {
// error ($error is one of the CURLE_* constants)
}
};

Populates the supplied response with the response for the supplied request .


public function sendRequest(RequestInterface $request, array $options = []): ResponseInterface
    {
        $options = $this->validateOptions($options);
        $originalCallback = $options->get('callback');
        $responseToReturn = null;
        $options = $options->add(['callback' => function (RequestInterface $request, ResponseInterface $response = null, ClientException $e = null) use (&$responseToReturn, $originalCallback) {
            $responseToReturn = $response;
            $originalCallback($request, $response, $e);

            if (null !== $e) {
                throw $e;
            }
        }]);

        $this->addToQueue($request, $options);
        $this->flush();

        return $responseToReturn;
    }

public function sendRequest ( RequestInterface $ request , array $ options = [ ] ) : ResponseInterface { $ options = $ this -> validateOptions ( $ options ) ; $ originalCallback = $ options -> get ( 'callback' ) ; $ responseToReturn = null ; $ options = $ options -> add ( [ 'callback' => function ( RequestInterface $ request , ResponseInterface $ response = null , ClientException $ e = null ) use ( & $ responseToReturn , $ originalCallback ) { $ responseToReturn = $ response ; $ originalCallback ( $ request , $ response , $ e ) ; if ( null !== $ e ) { throw $ e ; } } ] ) ; $ this -> addToQueue ( $ request , $ options ) ; $ this -> flush ( ) ; return $ responseToReturn ; }


public function proceed(): void
    {
        if (empty($this->queue)) {
            return;
        }

        if (!$this->curlm) {
            $this->initMultiCurlHandle();
        }

        $this->initQueue();
        $exception = null;
        do {
            // Start processing each handler in the stack
            $mrc = curl_multi_exec($this->curlm, $stillRunning);
        } while (CURLM_CALL_MULTI_PERFORM === $mrc);

        while ($info = curl_multi_info_read($this->curlm)) {
            // handle any completed requests
            if (CURLMSG_DONE !== $info['msg']) {
                continue;
            }

            $handled = false;

            /** @var RequestInterface $request */
            /** @var ParameterBag $options */
            /** @var ResponseBuilder $responseBuilder */
            foreach ($this->queue as $i => list($request, $options, $curl, $responseBuilder)) {
                // Try to find the correct handle from the queue.
                if ($curl !== $info['handle']) {
                    continue;
                }

                $handled = true;
                $response = null;
                try {
                    $this->parseError($request, $info['result'], $curl);
                    $response = $responseBuilder->getResponse();
                    if ($options->get('expose_curl_info', false)) {
                        $response = $response->withHeader('__curl_info', json_encode(curl_getinfo($curl)));
                    }
                } catch (\Throwable $e) {
                    if (null === $exception) {
                        $exception = $e;
                    }
                }

                // remove from queue
                curl_multi_remove_handle($this->curlm, $curl);
                $this->releaseHandle($curl);
                unset($this->queue[$i]);

                // callback
                \call_user_func($options->get('callback'), $request, $response, $exception);
                $exception = null;
            }

            if (!$handled) {
                // It must be a pushed response.
                $this->handlePushedResponse($info['handle']);
            }
        }

        $this->cleanup();
    }

See if any connection is ready to be processed.

This is a non-blocking function call.

@throws ClientException if we fail to initialized cUrl

See if any connection is ready to be processed .


private function initMultiCurlHandle(): void
    {
        $this->curlm = curl_multi_init();
        if (false === $this->curlm) {
            throw new ClientException('Unable to create a new cURL multi handle');
        }

        if ($this->serverPushSupported) {
            $userCallbacks = $this->pushFunctions;

            curl_multi_setopt($this->curlm, CURLMOPT_PIPELINING, CURLPIPE_MULTIPLEX);
            // We need to use $this->pushCb[] because of a bug in PHP
            curl_multi_setopt(
                $this->curlm,
                CURLMOPT_PUSHFUNCTION,
                $this->pushCb[] = function ($parent, $pushed, $headers) use ($userCallbacks) {
                    // If any callback say no, then do not accept.
                    foreach ($userCallbacks as $callback) {
                        if (CURL_PUSH_DENY === $callback($parent, $pushed, $headers)) {
                            return CURL_PUSH_DENY;
                        }
                    }

                    curl_setopt($pushed, CURLOPT_RETURNTRANSFER, true);
                    curl_setopt($pushed, CURLOPT_HEADER, true);
                    $this->addPushHandle($headers, $pushed);

                    return CURL_PUSH_OK;
                }
            );
        }
    }

Create a multi curl handle and add some properties to it.

Create a multi curl handle and add some properties to it .


private function cleanup(): void
    {
        if (empty($this->queue)) {
            curl_multi_close($this->curlm);
            $this->curlm = null;
            $this->pushFunctions = [];
            $this->pushCb = [];
        }
    }

private function cleanup ( ) : void { if ( empty ( $ this -> queue ) ) { curl_multi_close ( $ this -> curlm ) ; $ this -> curlm = null ; $ this -> pushFunctions = [ ] ; $ this -> pushCb = [ ] ; } }

If we got no requests in the queue, do a clean up to save some memory.

If we got no requests in the queue do a clean up to save some memory .


public function matchesRequest(RequestInterface $request): bool
    {
        $uri = $request->getUri();
        // domain
        if (!$this->matchesDomain($uri->getHost())) {
            return false;
        }

        // path
        if (!$this->matchesPath($uri->getPath())) {
            return false;
        }

        // secure
        if ($this->hasAttribute(static::ATTR_SECURE) && 'https' !== $uri->getScheme()) {
            return false;
        }

        return true;
    }

public
function
matchesRequest
(
RequestInterface
$
request
)
:
bool
{
$
uri
=
$
request
->
getUri
(
)
;
// domain
if
(
!
$
this
->
matchesDomain
(
$
uri
->
getHost
(
)
)
)
{
return
false
;
}
// path
if
(
!
$
this
->
matchesPath
(
$
uri
->
getPath
(
)
)
)
{
return
false
;
}
// secure
if
(
$
this
->
hasAttribute
(
static
::
ATTR_SECURE
)
&&
'https'
!==
$
uri
->
getScheme
(
)
)
{
return
false
;
}
return
true
;
}

Returns true if the current cookie matches the supplied request.

@param RequestInterface $request A request object

Returns true if the current cookie matches the supplied request .


public function isExpired(): bool
    {
        $maxAge = $this->getAttribute(static::ATTR_MAX_AGE);
        if ($maxAge && time() - $this->getCreatedAt() > $maxAge) {
            return true;
        }

        $expires = $this->getAttribute(static::ATTR_EXPIRES);
        if ($expires && strtotime($expires) < time()) {
            return true;
        }

        return false;
    }

public function isExpired ( ) : bool { $ maxAge = $ this -> getAttribute ( static :: ATTR_MAX_AGE ) ; if ( $ maxAge && time ( ) - $ this -> getCreatedAt ( ) > $ maxAge ) { return true ; } $ expires = $ this -> getAttribute ( static :: ATTR_EXPIRES ) ; if ( $ expires && strtotime ( $ expires ) < time ( ) ) { return true ; } return false ; }

Returns true of the current cookie has expired.

Checks the max-age and expires attributes.

@return bool Whether the current cookie has expired

Returns true of the current cookie has expired .


public function matchesDomain(string $domain): bool
    {
        $cookieDomain = $this->getAttribute(static::ATTR_DOMAIN) ?? '';

        if (0 === strpos($cookieDomain, '.')) {
            $pattern = '/\b'.preg_quote(substr($cookieDomain, 1), '/').'$/i';

            return (bool) preg_match($pattern, $domain);
        } else {
            return 0 == strcasecmp($cookieDomain, $domain);
        }
    }

public function matchesDomain ( string $ domain ) : bool { $ cookieDomain = $ this -> getAttribute ( static :: ATTR_DOMAIN ) ?? '' ; if ( 0 === strpos ( $ cookieDomain , '.' ) ) { $ pattern = '/\b' . preg_quote ( substr ( $ cookieDomain , 1 ) , '/' ) . '$/i' ; return ( bool ) preg_match ( $ pattern , $ domain ) ; } else { return 0 == strcasecmp ( $ cookieDomain , $ domain ) ; } }

Returns true if the current cookie matches the supplied domain.

@param string $domain A domain hostname

Returns true if the current cookie matches the supplied domain .


public function matchesPath(string $path): bool
    {
        $needle = $this->getAttribute(static::ATTR_PATH);

        return null === $needle || 0 === strpos($path, $needle);
    }

public function matchesPath ( string $ path ) : bool { $ needle = $ this -> getAttribute ( static :: ATTR_PATH ) ; return null === $ needle || 0 === strpos ( $ path , $ needle ) ; }

Returns true if the current cookie matches the supplied path.

@param string $path A path

Returns true if the current cookie matches the supplied path .


public function fromSetCookieHeader(string $header, string $issuingDomain): void
    {
        list($this->name, $header) = explode('=', $header, 2);
        if (false === strpos($header, ';')) {
            $this->value = $header;
            $header = null;
        } else {
            list($this->value, $header) = explode(';', $header, 2);
        }

        $this->clearAttributes();
        if (null !== $header) {
            foreach (array_map('trim', explode(';', trim($header))) as $pair) {
                if (false === strpos($pair, '=')) {
                    $name = $pair;
                    $value = null;
                } else {
                    list($name, $value) = explode('=', $pair);
                }

                $this->setAttribute($name, $value);
            }
        }

        if (!$this->getAttribute(static::ATTR_DOMAIN)) {
            $this->setAttribute(static::ATTR_DOMAIN, $issuingDomain);
        }
    }

public function fromSetCookieHeader ( string $ header , string $ issuingDomain ) : void { list ( $ this -> name , $ header ) = explode ( '=' , $ header , 2 ) ; if ( false === strpos ( $ header , ';' ) ) { $ this -> value = $ header ; $ header = null ; } else { list ( $ this -> value , $ header ) = explode ( ';' , $ header , 2 ) ; } $ this -> clearAttributes ( ) ; if ( null !== $ header ) { foreach ( array_map ( 'trim' , explode ( ';' , trim ( $ header ) ) ) as $ pair ) { if ( false === strpos ( $ pair , '=' ) ) { $ name = $ pair ; $ value = null ; } else { list ( $ name , $ value ) = explode ( '=' , $ pair ) ; } $ this -> setAttribute ( $ name , $ value ) ; } } if ( ! $ this -> getAttribute ( static :: ATTR_DOMAIN ) ) { $ this -> setAttribute ( static :: ATTR_DOMAIN , $ issuingDomain ) ; } }

Populates the current cookie with data from the supplied Set-Cookie header.

@param string $header        A Set-Cookie header
@param string $issuingDomain The domain that issued the header

Populates the current cookie with data from the supplied Set - Cookie header .


protected function releaseHandle($curl): void
    {
        if (\count($this->handles) >= $this->maxHandles) {
            curl_close($curl);
        } else {
            // Remove all callback functions as they can hold onto references
            // and are not cleaned up by curl_reset. Using curl_setopt_array
            // does not work for some reason, so removing each one
            // individually.
            curl_setopt($curl, CURLOPT_HEADERFUNCTION, null);
            curl_setopt($curl, CURLOPT_READFUNCTION, null);
            curl_setopt($curl, CURLOPT_WRITEFUNCTION, null);
            curl_setopt($curl, CURLOPT_PROGRESSFUNCTION, null);
            curl_reset($curl);

            if (!\in_array($curl, $this->handles)) {
                $this->handles[] = $curl;
            }
        }
    }

Release a cUrl resource. This function is from Guzzle.

@param resource $curl

Release a cUrl resource . This function is from Guzzle .


protected function prepare($curl, RequestInterface $request, ParameterBag $options): ResponseBuilder
    {
        if (\defined('CURLOPT_PROTOCOLS')) {
            curl_setopt($curl, CURLOPT_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS);
            curl_setopt($curl, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS);
        }

        curl_setopt($curl, CURLOPT_HEADER, false);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, false);
        curl_setopt($curl, CURLOPT_FAILONERROR, false);

        $this->setOptionsFromParameterBag($curl, $options);
        $this->setOptionsFromRequest($curl, $request);

        $responseBuilder = new ResponseBuilder($this->responseFactory);
        curl_setopt($curl, CURLOPT_HEADERFUNCTION, function ($ch, $data) use ($responseBuilder) {
            $str = trim($data);
            if ('' !== $str) {
                if (0 === strpos(strtolower($str), 'http/')) {
                    $responseBuilder->setStatus($str);
                } else {
                    $responseBuilder->addHeader($str);
                }
            }

            return \strlen($data);
        });

        curl_setopt($curl, CURLOPT_WRITEFUNCTION, function ($ch, $data) use ($responseBuilder) {
            return $responseBuilder->writeBody($data);
        });

        // apply additional options
        curl_setopt_array($curl, $options->get('curl'));

        return $responseBuilder;
    }

protected
function
prepare
(
$
curl
,
RequestInterface
$
request
,
ParameterBag
$
options
)
:
ResponseBuilder
{
if
(
\
defined
(
'CURLOPT_PROTOCOLS'
)
)
{
curl_setopt
(
$
curl
,
CURLOPT_PROTOCOLS
,
CURLPROTO_HTTP
|
CURLPROTO_HTTPS
)
;
curl_setopt
(
$
curl
,
CURLOPT_REDIR_PROTOCOLS
,
CURLPROTO_HTTP
|
CURLPROTO_HTTPS
)
;
}
curl_setopt
(
$
curl
,
CURLOPT_HEADER
,
false
)
;
curl_setopt
(
$
curl
,
CURLOPT_RETURNTRANSFER
,
false
)
;
curl_setopt
(
$
curl
,
CURLOPT_FAILONERROR
,
false
)
;
$
this
->
setOptionsFromParameterBag
(
$
curl
,
$
options
)
;
$
this
->
setOptionsFromRequest
(
$
curl
,
$
request
)
;
$
responseBuilder
=
new
ResponseBuilder
(
$
this
->
responseFactory
)
;
curl_setopt
(
$
curl
,
CURLOPT_HEADERFUNCTION
,
function
(
$
ch
,
$
data
)
use
(
$
responseBuilder
)
{
$
str
=
trim
(
$
data
)
;
if
(
''
!==
$
str
)
{
if
(
0
===
strpos
(
strtolower
(
$
str
)
,
'http/'
)
)
{
$
responseBuilder
->
setStatus
(
$
str
)
;
}
else
{
$
responseBuilder
->
addHeader
(
$
str
)
;
}
}
return
\
strlen
(
$
data
)
;
}
)
;
curl_setopt
(
$
curl
,
CURLOPT_WRITEFUNCTION
,
function
(
$
ch
,
$
data
)
use
(
$
responseBuilder
)
{
return
$
responseBuilder
->
writeBody
(
$
data
)
;
}
)
;
// apply additional options
curl_setopt_array
(
$
curl
,
$
options
->
get
(
'curl'
)
)
;
return
$
responseBuilder
;
}

Prepares a cURL resource to send a request.

@param resource $curl

Prepares a cURL resource to send a request .


private function setOptionsFromRequest($curl, RequestInterface $request): void
    {
        $options = [
            CURLOPT_CUSTOMREQUEST => $request->getMethod(),
            CURLOPT_URL => $request->getUri()->__toString(),
            CURLOPT_HTTPHEADER => HeaderConverter::toBuzzHeaders($request->getHeaders()),
        ];

        if (0 !== $version = $this->getProtocolVersion($request)) {
            $options[CURLOPT_HTTP_VERSION] = $version;
        }

        if ($request->getUri()->getUserInfo()) {
            $options[CURLOPT_USERPWD] = $request->getUri()->getUserInfo();
        }

        switch (strtoupper($request->getMethod())) {
            case 'HEAD':
                $options[CURLOPT_NOBODY] = true;

                break;

            case 'GET':
                $options[CURLOPT_HTTPGET] = true;

                break;

            case 'POST':
            case 'PUT':
            case 'DELETE':
            case 'PATCH':
            case 'OPTIONS':
                $body = $request->getBody();
                $bodySize = $body->getSize();
                if (0 !== $bodySize) {
                    if ($body->isSeekable()) {
                        $body->rewind();
                    }

                    // Message has non empty body.
                    if (null === $bodySize || $bodySize > 1024 * 1024) {
                        // Avoid full loading large or unknown size body into memory
                        $options[CURLOPT_UPLOAD] = true;
                        if (null !== $bodySize) {
                            $options[CURLOPT_INFILESIZE] = $bodySize;
                        }
                        $options[CURLOPT_READFUNCTION] = function ($ch, $fd, $length) use ($body) {
                            return $body->read($length);
                        };
                    } else {
                        // Small body can be loaded into memory
                        $options[CURLOPT_POSTFIELDS] = (string) $body;
                    }
                }
        }

        curl_setopt_array($curl, $options);
    }

Sets options on a cURL resource based on a request.

@param resource         $curl    A cURL resource
@param RequestInterface $request A request object

Sets options on a cURL resource based on a request .


public function sendRequest(RequestInterface $request, array $options = []): ResponseInterface
    {
        $chain = $this->createMiddlewareChain($this->middleware, function (RequestInterface $request, callable $responseChain) use ($options) {
            $response = $this->client->sendRequest($request, $options);
            $responseChain($request, $response);
        }, function (RequestInterface $request, ResponseInterface $response) {
            $this->lastRequest = $request;
            $this->lastResponse = $response;
        });

        // Call the chain
        $chain($request);

        return $this->lastResponse;
    }

public
function
sendRequest
(
RequestInterface
$
request
,
array
$
options
=
[
]
)
:
ResponseInterface
{
$
chain
=
$
this
->
createMiddlewareChain
(
$
this
->
middleware
,
function
(
RequestInterface
$
request
,
callable
$
responseChain
)
use
(
$
options
)
{
$
response
=
$
this
->
client
->
sendRequest
(
$
request
,
$
options
)
;
$
responseChain
(
$
request
,
$
response
)
;
}
,
function
(
RequestInterface
$
request
,
ResponseInterface
$
response
)
{
$
this
->
lastRequest
=
$
request
;
$
this
->
lastResponse
=
$
response
;
}
)
;
// Call the chain
$
chain
(
$
request
)
;
return
$
this
->
lastResponse
;
}

Send a PSR7 request.

@throws ClientException
@throws LogicException
@throws InvalidArgumentException


public function record(RequestInterface $request, ResponseInterface $response, float $duration = null): void
    {
        $this->addEntry(new Entry($request, $response, $duration));
    }

public function record ( RequestInterface $ request , ResponseInterface $ response , float $ duration = null ) : void { $ this -> addEntry ( new Entry ( $ request , $ response , $ duration ) ) ; }

Records an entry in the journal.

@param RequestInterface  $request  The request
@param ResponseInterface $response The response
@param float|null        $duration The duration in seconds


protected function createImage()
    {
        if ($this->_isCreated) {
            return false;
        }
        $command = $this->getCommand();
        $fileName = $this->getImageFilename();

        $command->addArgs($this->_options);
        // Always escape input and output filename
        $command->addArg((string) $this->_page, null, true);
        $command->addArg($fileName, null, true);
        if (!$command->execute()) {
            $this->_error = $command->getError();
            if (!(file_exists($fileName) && filesize($fileName)!==0 && $this->ignoreWarnings)) {
                return false;
            }
        }
        $this->_isCreated = true;
        return true;
    }

Run the Command to create the tmp image file

@return bool whether creation was successful


public function addCover($input, $options = array(), $type = null)
    {
        $options['input'] = ($this->version9 ? '--' : '') . 'cover';
        $options['inputArg'] = $this->ensureUrlOrFile($input, $type);
        $this->_objects[] = $this->ensureUrlOrFileOptions($options);
        return $this;
    }

public function addCover ( $ input , $ options = array ( ) , $ type = null ) { $ options [ 'input' ] = ( $ this -> version9 ? '--' : '' ) . 'cover' ; $ options [ 'inputArg' ] = $ this -> ensureUrlOrFile ( $ input , $ type ) ; $ this -> _objects [ ] = $ this -> ensureUrlOrFileOptions ( $ options ) ; return $ this ; }

Add a cover page object to the output

@param string $input either a URL, a HTML string or a filename
@param array $options optional options for the cover page
@param string|null $type a type hint if the input is a string of known
type. This can either be `TYPE_HTML` or `TYPE_XML`. If `null` (default)
the type is auto detected from the string content.
@return static the Pdf instance for method chaining


public function addToc($options = array())
    {
        $options['input'] = ($this->version9 ? '--' : '') . 'toc';
        $this->_objects[] = $this->ensureUrlOrFileOptions($options);
        return $this;
    }

public function addToc ( $ options = array ( ) ) { $ options [ 'input' ] = ( $ this -> version9 ? '--' : '' ) . 'toc' ; $ this -> _objects [ ] = $ this -> ensureUrlOrFileOptions ( $ options ) ; return $ this ; }

Add a TOC object to the output

@param array $options optional options for the table of contents
@return static the Pdf instance for method chaining


protected function createPdf()
    {
        if ($this->_isCreated) {
            return false;
        }
        $command = $this->getCommand();
        $fileName = $this->getPdfFilename();

        $command->addArgs($this->_options);
        foreach ($this->_objects as $object) {
            $command->addArgs($object);
        }
        $command->addArg($fileName, null, true);    // Always escape filename
        if (!$command->execute()) {
            $this->_error = $command->getError();
            if (!(file_exists($fileName) && filesize($fileName) !== 0 && $this->ignoreWarnings)) {
                return false;
            }
        }
        $this->_isCreated = true;
        return true;
    }

protected
function
createPdf
(
)
{
if
(
$
this
->
_isCreated
)
{
return
false
;
}
$
command
=
$
this
->
getCommand
(
)
;
$
fileName
=
$
this
->
getPdfFilename
(
)
;
$
command
->
addArgs
(
$
this
->
_options
)
;
foreach
(
$
this
->
_objects
as
$
object
)
{
$
command
->
addArgs
(
$
object
)
;
}
$
command
->
addArg
(
$
fileName
,
,
true
)
;
// Always escape filename
if
(
!
$
command
->
execute
(
)
)
{
$
this
->
_error
=
$
command
->
getError
(
)
;
if
(
!
(
file_exists
(
$
fileName
)
&&
filesize
(
$
fileName
)
!==
0
&&
$
this
->
ignoreWarnings
)
)
{
return
false
;
}
}
$
this
->
_isCreated
=
true
;
return
true
;
}

Run the Command to create the tmp PDF file

@return bool whether creation was successful