Completed
Push — master ( 8386c2...ffd2be )
by Simonas
61:26
created

ONGRFilterManagerExtension::load()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 11
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 11
rs 9.4285
cc 3
eloc 7
nc 4
nop 2
1
<?php
2
3
/*
4
 * This file is part of the ONGR package.
5
 *
6
 * (c) NFQ Technologies UAB <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace ONGR\FilterManagerBundle\DependencyInjection;
13
14
use ONGR\FilterManagerBundle\DependencyInjection\Filter\AbstractFilterFactory;
15
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
16
use Symfony\Component\DependencyInjection\ContainerBuilder;
17
use Symfony\Component\Config\FileLocator;
18
use Symfony\Component\DependencyInjection\Definition;
19
use Symfony\Component\DependencyInjection\Reference;
20
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
21
use Symfony\Component\DependencyInjection\Loader;
22
23
/**
24
 * This is the class that loads and manages bundle configuration.
25
 */
26
class ONGRFilterManagerExtension extends Extension
27
{
28
    /**
29
     * @var AbstractFilterFactory[]
30
     */
31
    protected $factories = [];
32
    
33
    /**
34
     * {@inheritdoc}
35
     */
36
    public function load(array $configs, ContainerBuilder $container)
37
    {
38
        $configuration = new Configuration();
39
        $config = $this->processConfiguration($configuration, $configs);
40
41
        $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config'));
42
        $loader->load('services.yml');
43
44
        !isset($config['filters']) ? : $this->addFilters($config['filters'], $container);
45
        !isset($config['managers']) ? : $this->addFilterManagers($config, $container);
46
    }
47
48
    /**
49
     * Adds filter factory.
50
     *
51
     * @param AbstractFilterFactory $factory
52
     */
53
    public function addFilterFactory(AbstractFilterFactory $factory)
54
    {
55
        $this->factories[$factory->getName()] = $factory;
56
    }
57
58
    /**
59
     * Formats filter service id from given name.
60
     *
61
     * @param string $name Filter name.
62
     *
63
     * @return string
64
     */
65
    public static function getFilterId($name)
66
    {
67
        return sprintf('ongr_filter_manager.filter.%s', $name);
68
    }
69
70
    /**
71
     * Formats filter manager service id from given name.
72
     *
73
     * @param string $name Filter manager name.
74
     *
75
     * @return string
76
     */
77
    public static function getFilterManagerId($name)
78
    {
79
        return sprintf('ongr_filter_manager.%s', $name);
80
    }
81
82
    /**
83
     * Adds filters based on configuration.
84
     *
85
     * @param array            $config    Configuration.
86
     * @param ContainerBuilder $container Service container.
87
     */
88
    private function addFilters(array $config, ContainerBuilder $container)
89
    {
90
        $this->validateFilterNames($config);
91
92
        foreach ($config as $type => $filters) {
93
            foreach ($filters as $name => $config) {
94
                $filterDefinition = $this
95
                    ->getFilterFactory($type)
96
                    ->setConfiguration($config)
97
                    ->getDefinition();
98
99
                $this->addRelation($filterDefinition, $config, 'search', 'include');
100
                $this->addRelation($filterDefinition, $config, 'search', 'exclude');
101
                $this->addRelation($filterDefinition, $config, 'reset', 'include');
102
                $this->addRelation($filterDefinition, $config, 'reset', 'exclude');
103
104
                $container->setDefinition(self::getFilterId($name), $filterDefinition);
105
            }
106
        }
107
    }
108
109
    /**
110
     * Checks if filter names are valid.
111
     *
112
     * @param array $filters Filters to validate.
113
     *
114
     * @throws InvalidConfigurationException
115
     */
116
    private function validateFilterNames(array $filters)
117
    {
118
        $existing = [];
119
120
        foreach ($filters as $type => $filters) {
121
            foreach ($filters as $name => $data) {
122
                if (in_array($name, $existing)) {
123
                    throw new InvalidConfigurationException(
124
                        "Found duplicate filter name `{$name}` in `{$type}` filter"
125
                    );
126
                }
127
128
                $existing[] = $name;
129
            }
130
        }
131
    }
132
133
    /**
134
     * Adds filters managers based on configuration.
135
     *
136
     * @param array            $config    Configuration array.
137
     * @param ContainerBuilder $container Service container.
138
     */
139
    private function addFilterManagers(array $config, ContainerBuilder $container)
140
    {
141
        foreach ($config['managers'] as $name => $manager) {
142
            $filterContainer = new Definition('ONGR\FilterManagerBundle\Search\FilterContainer');
143
            $cacheEngine = $config['cache']['engine'] ? new Reference($config['cache']['engine']) : null;
144
            
145
            $filterContainer
146
                ->addMethodCall('setCache', [$cacheEngine])
147
                ->addMethodCall('setExclude', [$config['cache']['exclude']])
148
                ->addMethodCall('setLifeTime', [$config['cache']['life_time']]);
149
150
            foreach ($manager['filters'] as $filter) {
151
                $filterContainer->addMethodCall(
152
                    'set',
153
                    [$filter, new Reference(self::getFilterId($filter))]
154
                );
155
            }
156
157
            $managerDefinition = new Definition(
158
                'ONGR\FilterManagerBundle\Search\FilterManager',
159
                [
160
                    $filterContainer,
161
                    new Reference($manager['repository']),
162
                ]
163
            );
164
            $managerDefinition->addTag('es.filter_manager');
165
166
            $container->setDefinition(self::getFilterManagerId($name), $managerDefinition);
167
        }
168
    }
169
170
    /**
171
     * Adds relation to filter.
172
     *
173
     * @param Definition $definition
174
     * @param array      $filter
175
     * @param string     $urlType
176
     * @param string     $relationType
177
     */
178
    private function addRelation(Definition $definition, $filter, $urlType, $relationType)
179
    {
180
        if (!empty($filter['relations'][$urlType][$relationType])) {
181
            $definition->addMethodCall(
182
                'set' . ucfirst($urlType) . 'Relation',
183
                [$this->getRelation($relationType, $filter['relations'][$urlType][$relationType])]
184
            );
185
        }
186
    }
187
188
    /**
189
     * Creates relation definition by given parameters.
190
     *
191
     * @param string $type
192
     * @param array  $relations
193
     *
194
     * @return Definition
195
     */
196
    private function getRelation($type, $relations)
197
    {
198
        return new Definition(
199
            sprintf('ONGR\FilterManagerBundle\Relation\%sRelation', ucfirst($type)),
200
            [$relations]
201
        );
202
    }
203
204
    /**
205
     * Returns filter factory.
206
     *
207
     * @param string $name Factory name.
208
     *
209
     * @return AbstractFilterFactory
210
     *
211
     * @throws InvalidConfigurationException Invaid filter name request.
212
     */
213
    private function getFilterFactory($name)
214
    {
215
        if (array_key_exists($name, $this->factories)) {
216
            return $this->factories[$name];
217
        }
218
        
219
        throw new InvalidConfigurationException(
220
            sprintf(
221
                "Invalid filter name provided in configuration. Got '%s', available: %s",
222
                $name,
223
                implode(', ', array_keys($this->factories))
224
            )
225
        );
226
    }
227
}
228