Completed
Push — master ( 229d16...5190dc )
by Simonas
122:26 queued 57:21
created

Translation/TranslationManager.php (3 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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\TranslationsBundle\Translation;
13
14
use Elasticsearch\Common\Exceptions\Missing404Exception;
15
use ONGR\ElasticsearchBundle\Result\Result;
16
use ONGR\ElasticsearchDSL\Query\ExistsQuery;
17
use ONGR\ElasticsearchDSL\Query\TermsQuery;
18
use ONGR\ElasticsearchBundle\Service\Repository;
19
use ONGR\TranslationsBundle\Event\Events;
20
use ONGR\TranslationsBundle\Event\TranslationEditMessageEvent;
21
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
22
use Symfony\Component\HttpFoundation\Request;
23
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
24
use Symfony\Component\PropertyAccess\PropertyAccess;
25
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
26
27
/**
28
 * Handles translation objects by http requests.
29
 */
30
class TranslationManager
31
{
32
    /**
33
     * @var Repository
34
     */
35
    private $repository;
36
37
    /**
38
     * @var PropertyAccessorInterface
39
     */
40
    private $accessor;
41
42
    /**
43
     * @var EventDispatcherInterface
44
     */
45
    private $dispatcher;
46
47
    /**
48
     * @param Repository               $repository
49
     * @param EventDispatcherInterface $dispatcher
50
     */
51
    public function __construct(Repository $repository, EventDispatcherInterface $dispatcher)
52
    {
53
        $this->repository = $repository;
54
        $this->dispatcher = $dispatcher;
55
    }
56
57
    /**
58
     * Adds object to translations.
59
     *
60
     * @param Request $request
61
     */
62 View Code Duplication
    public function add(Request $request)
0 ignored issues
show
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
63
    {
64
        $content = $this->parseJsonContent($request);
65
        $document = $this->getTranslation($content['id']);
66
        $this->addObject($document, $content);
67
        $this->commitTranslation($document);
68
    }
69
70
    /**
71
     * Edits object from translation.
72
     *
73
     * @param Request $request Http request object.
74
     */
75
    public function edit(Request $request)
76
    {
77
        $content = $this->parseJsonContent($request);
78
        $document = $this->getTranslation($content['id']);
79
80
        if ($content['name'] == 'messages') {
81
            $this->dispatcher->dispatch(Events::ADD_HISTORY, new TranslationEditMessageEvent($request, $document));
82
        }
83
        $this->editObject($document, $content);
84
        $this->commitTranslation($document);
85
    }
86
87
    /**
88
     * Removes object from translations.
89
     *
90
     * @param Request $request Http request object.
91
     */
92 View Code Duplication
    public function delete(Request $request)
0 ignored issues
show
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
93
    {
94
        $content = $this->parseJsonContent($request);
95
        $document = $this->getTranslation($content['id']);
96
        $this->deleteObject($document, $content);
97
        $this->commitTranslation($document);
98
    }
99
100
    /**
101
     * Returns specific values from objects.
102
     *
103
     * @param Request $request Http request object.
104
     *
105
     * @return array
106
     */
107
    public function get(Request $request)
108
    {
109
        $content = $this->parseJsonContent($request);
110
111
        $search = $this
112
            ->repository
113
            ->createSearch()
114
            ->addFilter(new ExistsQuery($content['name']));
115
116
        if (array_key_exists('properties', $content)) {
117
            foreach ($content['properties'] as $property) {
118
                $search->setSource($content['name'] . '.' . $property);
119
            }
120
        }
121
122
        if (array_key_exists('findBy', $content)) {
123
            foreach ($content['findBy'] as $field => $value) {
124
                $search->addQuery(
125
                    new TermsQuery($content['name'] . '.' . $field, is_array($value) ? $value : [$value]),
126
                    'must'
127
                );
128
            }
129
        }
130
131
        return $this->repository->execute($search, Result::RESULTS_ARRAY);
132
    }
133
134
    /**
135
     * Adds object to translation.
136
     *
137
     * @param object $document
138
     * @param array  $options
139
     */
140
    private function addObject($document, $options)
141
    {
142
        $meta = $this->repository->getManager()->getMetadataCollector()
143
            ->getBundleMapping('ONGRTranslationsBundle:Translation');
144
        $objectClass = reset($meta)['aliases'][$options['name']]['namespace'];
145
146
        $object = new $objectClass();
147
        $this->setObjectProperties($object, $options['properties']);
148
149
        $this->updateTimestamp($object);
150
        $this->updateTimestamp($document);
151
    }
152
153
    /**
154
     * Removes message from document based on options.
155
     *
156
     * @param object $document
157
     * @param array  $options
158
     */
159
    private function deleteObject($document, $options)
160
    {
161
        $accessor = $this->getAccessor();
162
        $objects = $accessor->getValue($document, $options['name']);
163
164
        $key = $this->findObject($objects, $options['findBy']);
165
166
        if ($key >= 0) {
167
            unset($objects[$key]);
168
            $accessor->setValue($document, $options['name'], $objects);
169
        }
170
    }
171
172
    /**
173
     * Edits message from document based on options.
174
     *
175
     * @param object $document
176
     * @param array  $options
177
     */
178
    private function editObject($document, $options)
179
    {
180
        $accessor = $this->getAccessor();
181
        $objects = $accessor->getValue($document, $options['name']);
182
183
        if ($objects === null) {
184
            $this->addObject($document, $options);
185
        } else {
186
            $key = $this->findObject($objects, $options['findBy']);
187
188
            if ($key < 0) {
189
                $this->addObject($document, $options);
190
            } else {
191
                $this->setObjectProperties($objects[$key], $options['properties']);
192
                $this->updateTimestamp($objects[$key]);
193
                $this->updateTimestamp($document);
194
                $accessor->setValue($document, $options['name'], $objects);
195
            }
196
        }
197
    }
198
199
    /**
200
     * Finds object by property and its value from iterator and returns key.
201
     *
202
     * @param \Iterator $objects
203
     * @param array     $options
204
     *
205
     * @return int
206
     */
207
    private function findObject($objects, $options)
208
    {
209
        foreach ($objects as $key => $object) {
210
            $fit = true;
211
212
            foreach ($options as $property => $value) {
213
                if ($this->getAccessor()->getValue($object, $property) !== $value) {
214
                    $fit = false;
215
                    break;
216
                }
217
            }
218
219
            if ($fit) {
220
                return $key;
221
            }
222
        }
223
224
        return -1;
225
    }
226
227
    /**
228
     * Parses http request content from json to array.
229
     *
230
     * @param Request $request Http request object.
231
     *
232
     * @return array
233
     *
234
     * @throws BadRequestHttpException
235
     */
236 View Code Duplication
    private function parseJsonContent(Request $request)
0 ignored issues
show
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
237
    {
238
        $content = json_decode($request->getContent(), true);
239
240
        if (empty($content)) {
241
            throw new BadRequestHttpException('No content found.');
242
        }
243
244
        return $content;
245
    }
246
247
    /**
248
     * Commits document into elasticsearch client.
249
     *
250
     * @param object $document
251
     */
252
    private function commitTranslation($document)
253
    {
254
        $this->repository->getManager()->persist($document);
255
        $this->repository->getManager()->commit();
256
    }
257
258
    /**
259
     * Returns translation from elasticsearch.
260
     *
261
     * @param string $id
262
     *
263
     * @return object
264
     *
265
     * @throws BadRequestHttpException
266
     */
267
    private function getTranslation($id)
268
    {
269
        try {
270
            $document = $this->repository->find($id);
271
        } catch (Missing404Exception $e) {
272
            $document = null;
273
        }
274
275
        if ($document === null) {
276
            throw new BadRequestHttpException('Invalid translation Id.');
277
        }
278
279
        return $document;
280
    }
281
282
    /**
283
     * Returns property accessor instance.
284
     *
285
     * @return PropertyAccessorInterface
286
     */
287
    private function getAccessor()
288
    {
289
        if (!$this->accessor) {
290
            $this->accessor = PropertyAccess::createPropertyAccessorBuilder()
291
                ->enableExceptionOnInvalidIndex()
292
                ->enableMagicCall()
293
                ->getPropertyAccessor();
294
        }
295
296
        return $this->accessor;
297
    }
298
299
    /**
300
     * Sets `updated_at` property.
301
     *
302
     * @param object $object
303
     */
304
    private function updateTimestamp($object)
305
    {
306
        $accessor = $this->getAccessor();
307
308
        if ($accessor->isWritable($object, 'updated_at')) {
309
            $accessor->setValue($object, 'updated_at', new \DateTime());
310
        }
311
    }
312
313
    /**
314
     * Sets object properties into provided object.
315
     *
316
     * @param object $object     Object to set properties into.
317
     * @param array  $properties Array of properties to set.
318
     */
319
    private function setObjectProperties($object, $properties)
320
    {
321
        foreach ($properties as $property => $value) {
322
            $this->getAccessor()->setValue($object, $property, $value);
323
        }
324
    }
325
}
326