Completed
Pull Request — develop (#98)
by
unknown
14:04
created

ArticleController::getAuthor()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 8
ccs 4
cts 4
cp 1
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 4
nc 2
nop 1
crap 2
1
<?php
2
3
/*
4
 * This file is part of Sulu.
5
 *
6
 * (c) MASSIVE ART WebServices GmbH
7
 *
8
 * This source file is subject to the MIT license that is bundled
9
 * with this source code in the file LICENSE.
10
 */
11
12
namespace Sulu\Bundle\ArticleBundle\Controller;
13
14
use FOS\RestBundle\Controller\Annotations\Post;
15
use FOS\RestBundle\Routing\ClassResourceInterface;
16
use JMS\Serializer\SerializationContext;
17
use ONGR\ElasticsearchBundle\Service\Manager;
18
use ONGR\ElasticsearchDSL\Query\BoolQuery;
19
use ONGR\ElasticsearchDSL\Query\IdsQuery;
20
use ONGR\ElasticsearchDSL\Query\MatchAllQuery;
21
use ONGR\ElasticsearchDSL\Query\MatchQuery;
22
use ONGR\ElasticsearchDSL\Query\MultiMatchQuery;
23
use ONGR\ElasticsearchDSL\Query\TermQuery;
24
use ONGR\ElasticsearchDSL\Sort\FieldSort;
25
use Sulu\Bundle\ArticleBundle\Admin\ArticleAdmin;
26
use Sulu\Bundle\ArticleBundle\Document\Form\ArticleDocumentType;
27
use Sulu\Bundle\ArticleBundle\Metadata\ArticleViewDocumentIdTrait;
28
use Sulu\Component\Content\Form\Exception\InvalidFormException;
29
use Sulu\Component\Content\Mapper\ContentMapperInterface;
30
use Sulu\Component\DocumentManager\DocumentManagerInterface;
31
use Sulu\Component\Rest\Exception\MissingParameterException;
32
use Sulu\Component\Rest\Exception\RestException;
33
use Sulu\Component\Rest\ListBuilder\FieldDescriptor;
34
use Sulu\Component\Rest\ListBuilder\ListRepresentation;
35
use Sulu\Component\Rest\RequestParametersTrait;
36
use Sulu\Component\Rest\RestController;
37
use Sulu\Component\Security\SecuredControllerInterface;
38
use Symfony\Component\HttpFoundation\Request;
39
use Symfony\Component\HttpFoundation\Response;
40
41
/**
42
 * Provides API for articles.
43
 */
44
class ArticleController extends RestController implements ClassResourceInterface, SecuredControllerInterface
45
{
46
    const DOCUMENT_TYPE = 'article';
47
48
    use RequestParametersTrait;
49
    use ArticleViewDocumentIdTrait;
50
51
    /**
52
     * Create field-descriptor array.
53
     *
54
     * @return FieldDescriptor[]
55
     */
56
    private function getFieldDescriptors()
57
    {
58
        return [
59
            'uuid' => new FieldDescriptor('uuid', 'public.id', true),
60
            'typeTranslation' => new FieldDescriptor(
61
                'typeTranslation',
62
                'sulu_article.list.type',
63
                !$this->getParameter('sulu_article.display_tab_all'),
64
                false
65
            ),
66
            'title' => new FieldDescriptor('title', 'public.title', false, true),
67
            'creatorFullName' => new FieldDescriptor('creatorFullName', 'sulu_article.list.creator', true, false),
68
            'changerFullName' => new FieldDescriptor('changerFullName', 'sulu_article.list.changer', false, false),
69
            'authorFullName' => new FieldDescriptor('authorFullName', 'sulu_article.author', false, false),
70
            'created' => new FieldDescriptor('created', 'public.created', true, false, 'datetime'),
71
            'changed' => new FieldDescriptor('changed', 'public.changed', false, false, 'datetime'),
72
            'authored' => new FieldDescriptor('authored', 'sulu_article.authored', false, false, 'date'),
73
        ];
74
    }
75
76
    /**
77
     * Returns fields.
78
     *
79
     * @return Response
80
     */
81
    public function cgetFieldsAction()
82
    {
83
        $fieldDescriptors = $this->getFieldDescriptors();
84
85
        return $this->handleView($this->view(array_values($fieldDescriptors)));
0 ignored issues
show
Documentation introduced by
$this->view(array_values($fieldDescriptors)) is of type this<Sulu\Bundle\Article...ller\ArticleController>, but the function expects a object<FOS\RestBundle\View\View>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
86
    }
87
88
    /**
89
     * Returns list of articles.
90
     *
91
     * @param Request $request
92
     *
93
     * @return Response
94
     */
95 11
    public function cgetAction(Request $request)
96
    {
97 11
        $locale = $this->getRequestParameter($request, 'locale', true);
98
99 11
        $restHelper = $this->get('sulu_core.list_rest_helper');
100
101
        /** @var Manager $manager */
102 11
        $manager = $this->get('es.manager.default');
103 11
        $repository = $manager->getRepository($this->get('sulu_article.view_document.factory')->getClass('article'));
104 11
        $search = $repository->createSearch();
105
106 11
        $limit = (int) $restHelper->getLimit();
107 11
        $page = (int) $restHelper->getPage();
108
109 11
        if (null !== $locale) {
110 11
            $search->addQuery(new TermQuery('locale', $locale));
0 ignored issues
show
Deprecated Code introduced by
The class ONGR\ElasticsearchDSL\Query\TermQuery has been deprecated with message: Use the extended class instead. This class is left only for BC compatibility.

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
111
        }
112
113 11
        if (count($ids = array_filter(explode(',', $request->get('ids', ''))))) {
114 1
            $search->addQuery(new IdsQuery($this->getViewDocumentIds($ids, $locale)));
0 ignored issues
show
Deprecated Code introduced by
The class ONGR\ElasticsearchDSL\Query\IdsQuery has been deprecated with message: Use the extended class instead. This class is left only for BC compatibility.

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
115 1
            $limit = count($ids);
116
        }
117
118 11
        if (!empty($searchPattern = $restHelper->getSearchPattern())
119 11
            && 0 < count($searchFields = $restHelper->getSearchFields())
120
        ) {
121 2
            $search->addQuery(new MultiMatchQuery($searchFields, $searchPattern));
0 ignored issues
show
Deprecated Code introduced by
The class ONGR\ElasticsearchDSL\Query\MultiMatchQuery has been deprecated with message: Use the extended class instead. This class is left only for BC compatibility.

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
122
        }
123
124 11
        if (null !== ($type = $request->get('type'))) {
125 10
            $search->addQuery(new TermQuery('type', $type));
0 ignored issues
show
Deprecated Code introduced by
The class ONGR\ElasticsearchDSL\Query\TermQuery has been deprecated with message: Use the extended class instead. This class is left only for BC compatibility.

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
126
        }
127
128 11
        if (null !== ($contactId = $request->get('contactId'))) {
129 1
            $boolQuery = new BoolQuery();
0 ignored issues
show
Deprecated Code introduced by
The class ONGR\ElasticsearchDSL\Query\BoolQuery has been deprecated with message: Use the extended class instead. This class is left only for BC compatibility.

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
130 1
            $boolQuery->add(new MatchQuery('changer_contact_id', $contactId), BoolQuery::SHOULD);
0 ignored issues
show
Deprecated Code introduced by
The class ONGR\ElasticsearchDSL\Query\MatchQuery has been deprecated with message: Use the extended class instead. This class is left only for BC compatibility.

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
131 1
            $boolQuery->add(new MatchQuery('creator_contact_id', $contactId), BoolQuery::SHOULD);
0 ignored issues
show
Deprecated Code introduced by
The class ONGR\ElasticsearchDSL\Query\MatchQuery has been deprecated with message: Use the extended class instead. This class is left only for BC compatibility.

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
132 1
            $boolQuery->add(new MatchQuery('author_id', $contactId), BoolQuery::SHOULD);
0 ignored issues
show
Deprecated Code introduced by
The class ONGR\ElasticsearchDSL\Query\MatchQuery has been deprecated with message: Use the extended class instead. This class is left only for BC compatibility.

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
133 1
            $search->addQuery($boolQuery);
134
        }
135
136 11
        if (null === $search->getQueries()) {
137
            $search->addQuery(new MatchAllQuery());
138
        }
139
140 11
        $count = $repository->count($search);
141
142 11
        if (null !== $restHelper->getSortColumn()) {
143 1
            $search->addSort(
144 1
                new FieldSort($this->uncamelize($restHelper->getSortColumn()), $restHelper->getSortOrder())
145
            );
146
        }
147
148 11
        $search->setSize($limit);
149 11
        $search->setFrom(($page - 1) * $limit);
150
151 11
        $result = [];
152 11
        foreach ($repository->execute($search) as $document) {
0 ignored issues
show
Deprecated Code introduced by
The method ONGR\ElasticsearchBundle...e\Repository::execute() has been deprecated with message: Use strict execute functions instead. e.g. executeIterator, executeRawIterator.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
153 9
            if (false !== ($index = array_search($document->getUuid(), $ids))) {
154 1
                $result[$index] = $document;
155
            } else {
156 11
                $result[] = $document;
157
            }
158
        }
159
160 11
        if (count($ids)) {
161 1
            ksort($result);
162 1
            $result = array_values($result);
163
        }
164
165 11
        return $this->handleView(
166 11
            $this->view(
0 ignored issues
show
Documentation introduced by
$this->view(new \Sulu\Co...$page, $limit, $count)) is of type this<Sulu\Bundle\Article...ller\ArticleController>, but the function expects a object<FOS\RestBundle\View\View>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
167 11
                new ListRepresentation(
168
                    $result,
169 11
                    'articles',
170 11
                    'get_articles',
171 11
                    $request->query->all(),
172
                    $page,
173
                    $limit,
174
                    $count
0 ignored issues
show
Bug introduced by
It seems like $count defined by $repository->count($search) on line 140 can also be of type array; however, Sulu\Component\Rest\List...entation::__construct() does only seem to accept integer, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
175
                )
176
            )
177
        );
178
    }
179
180
    /**
181
     * Returns single article.
182
     *
183
     * @param string $uuid
184
     * @param Request $request
185
     *
186
     * @return Response
187
     */
188 2
    public function getAction($uuid, Request $request)
189
    {
190 2
        $locale = $this->getRequestParameter($request, 'locale', true);
191 2
        $document = $this->getDocumentManager()->find(
192
            $uuid,
193
            $locale,
194
            [
195 2
                'load_ghost_content' => true,
196
                'load_shadow_content' => false,
197
            ]
198
        );
199
200 2
        return $this->handleView(
201 2
            $this->view($document)->setSerializationContext(
0 ignored issues
show
Bug introduced by
The method setSerializationContext() does not seem to exist on object<Sulu\Bundle\Artic...ller\ArticleController>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
202 2
                SerializationContext::create()->setSerializeNull(true)->setGroups(['defaultPage'])
203
            )
204
        );
205
    }
206
207
    /**
208
     * Create article.
209
     *
210
     * @param Request $request
211
     *
212
     * @return Response
213
     */
214 29
    public function postAction(Request $request)
215
    {
216 29
        $action = $request->get('action');
217 29
        $document = $this->getDocumentManager()->create(self::DOCUMENT_TYPE);
218 29
        $locale = $this->getRequestParameter($request, 'locale', true);
219 29
        $data = $request->request->all();
220
221 29
        $this->persistDocument($data, $document, $locale);
222 29
        $this->handleActionParameter($action, $document, $locale);
223 19
        $this->getDocumentManager()->flush();
224
225 29
        return $this->handleView(
226
            $this->view($document)->setSerializationContext(
0 ignored issues
show
Bug introduced by
The method setSerializationContext() does not seem to exist on object<Sulu\Bundle\Artic...ller\ArticleController>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
227 29
                SerializationContext::create()->setSerializeNull(true)->setGroups(['defaultPage'])
228 29
            )
229 29
        );
230
    }
231 29
232 29
    /**
233 29
     * Update articles.
234
     *
235
     * @param Request $request
236
     * @param string $uuid
237
     *
238
     * @return Response
239
     */
240
    public function putAction(Request $request, $uuid)
241
    {
242
        $locale = $this->getRequestParameter($request, 'locale', true);
243
        $action = $request->get('action');
244
        $data = $request->request->all();
245
246 7
        $document = $this->getDocumentManager()->find(
247
            $uuid,
248 7
            $locale,
249 7
            [
250 7
                'load_ghost_content' => false,
251
                'load_shadow_content' => false,
252 7
            ]
253
        );
254
255
        $this->get('sulu_hash.request_hash_checker')->checkHash($request, $document, $document->getUuid());
256 7
257
        $this->persistDocument($data, $document, $locale);
258
        $this->handleActionParameter($action, $document, $locale);
259
        $this->getDocumentManager()->flush();
260
261 7
        return $this->handleView(
262
            $this->view($document)->setSerializationContext(
0 ignored issues
show
Bug introduced by
The method setSerializationContext() does not seem to exist on object<Sulu\Bundle\Artic...ller\ArticleController>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
263 7
                SerializationContext::create()->setSerializeNull(true)->setGroups(['defaultPage'])
264 4
            )
265
        );
266 7
    }
267
268 7
    /**
269 7
     * Deletes multiple documents.
270 7
     *
271
     * @param Request $request
272 7
     *
273 7
     * @return Response
274 7
     */
275
    public function cdeleteAction(Request $request)
276
    {
277
        $ids = array_filter(explode(',', $request->get('ids', '')));
278
279
        $documentManager = $this->getDocumentManager();
280
        foreach ($ids as $id) {
281
            $document = $documentManager->find($id);
282
            $documentManager->remove($document);
283
            $documentManager->flush();
284
        }
285
286 1
        return $this->handleView($this->view(null));
0 ignored issues
show
Documentation introduced by
$this->view(null) is of type this<Sulu\Bundle\Article...ller\ArticleController>, but the function expects a object<FOS\RestBundle\View\View>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
287
    }
288 1
289
    /**
290 1
     * Deletes multiple documents.
291 1
     *
292 1
     * @param string $id
293 1
     *
294 1
     * @return Response
295
     */
296
    public function deleteAction($id)
297 1
    {
298
        $documentManager = $this->getDocumentManager();
299
        $document = $documentManager->find($id);
300
        $documentManager->remove($document);
301
        $documentManager->flush();
302
303
        return $this->handleView($this->view(null));
0 ignored issues
show
Documentation introduced by
$this->view(null) is of type this<Sulu\Bundle\Article...ller\ArticleController>, but the function expects a object<FOS\RestBundle\View\View>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
304
    }
305
306
    /**
307 1
     * Trigger a action for given article specified over get-action parameter.
308
     *
309 1
     * @Post("/articles/{uuid}")
310 1
     *
311 1
     * @param string $uuid
312 1
     * @param Request $request
313
     *
314 1
     * @return Response
315
     */
316
    public function postTriggerAction($uuid, Request $request)
317
    {
318
        // extract parameter
319
        $action = $this->getRequestParameter($request, 'action', true);
320
        $locale = $this->getRequestParameter($request, 'locale', true);
321
322
        // prepare vars
323
        $view = null;
324
        $data = null;
325
        $userId = $this->getUser()->getId();
326
327 1
        try {
328
            switch ($action) {
329
                case 'unpublish':
330 1
                    $document = $this->getDocumentManager()->find($uuid, $locale);
331 1
                    $this->getDocumentManager()->unpublish($document, $locale);
332
                    $this->getDocumentManager()->flush();
333
334 1
                    $data = $this->getDocumentManager()->find($uuid, $locale);
335 1
                    break;
336 1
                case 'remove-draft':
337
                    $data = $this->getDocumentManager()->find($uuid, $locale);
338
                    $this->getDocumentManager()->removeDraft($data, $locale);
339
                    $this->getDocumentManager()->flush();
340 1
                    break;
341
                case 'copy-locale':
342
                    $destLocales = $this->getRequestParameter($request, 'dest', true);
343
                    $data = $this->getMapper()->copyLanguage($uuid, $userId, null, $locale, explode(',', $destLocales));
344
                    break;
345
                default:
346
                    throw new RestException('Unrecognized action: ' . $action);
347 1
            }
348
349
            // prepare view
350
            $view = $this->view($data, $data !== null ? 200 : 204);
351
            $view->setSerializationContext(SerializationContext::create()->setGroups(['defaultPage']));
0 ignored issues
show
Bug introduced by
The method setSerializationContext() does not seem to exist on object<Sulu\Bundle\Artic...ller\ArticleController>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
352 1
        } catch (RestException $exc) {
353 1
            $view = $this->view($exc->toArray(), 400);
354 1
        }
355 1
356
        return $this->handleView($view);
0 ignored issues
show
Documentation introduced by
$view is of type this<Sulu\Bundle\Article...ller\ArticleController>, but the function expects a object<FOS\RestBundle\View\View>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
357
    }
358
359
    /**
360
     * {@inheritdoc}
361 1
     */
362 1
    public function getSecurityContext()
363
    {
364
        return ArticleAdmin::SECURITY_CONTEXT;
365
    }
366
367 1
    /**
368
     * Persists the document using the given information.
369
     *
370
     * @param array $data
371
     * @param object $document
372
     * @param string $locale
373 30
     *
374
     * @throws InvalidFormException
375 30
     * @throws MissingParameterException
376
     */
377
    private function persistDocument($data, $document, $locale)
378
    {
379
        $form = $this->createForm(
380
            ArticleDocumentType::class,
381
            $document,
382
            [
383
                // disable csrf protection, since we can't produce a token, because the form is cached on the client
384
                'csrf_protection' => false,
385
            ]
386
        );
387
        $form->submit($data, false);
388 29
389
        if (!$form->isValid()) {
390 29
            throw new InvalidFormException($form);
391 29
        }
392
393
        $this->getDocumentManager()->persist(
394
            $document,
395 29
            $locale,
396
            [
397
                'user' => $this->getUser()->getId(),
398 29
                'clear_missing_content' => false,
399
                'route_path' => array_key_exists('routePath', $data) ? $data['routePath'] : null,
400 29
            ]
401
        );
402
    }
403
404 29
    /**
405
     * Returns document-manager.
406
     *
407
     * @return DocumentManagerInterface
408 29
     */
409
    protected function getDocumentManager()
410 29
    {
411
        return $this->get('sulu_document_manager.document_manager');
412
    }
413 29
414
    /**
415
     * @return ContentMapperInterface
416
     */
417
    protected function getMapper()
418
    {
419
        return $this->get('sulu.content.mapper');
420
    }
421
422 29
    /**
423
     * Delegates actions by given actionParameter, which can be retrieved from the request.
424 29
     *
425 14
     * @param string $actionParameter
426
     * @param object $document
427
     * @param string $locale
428 18
     */
429
    private function handleActionParameter($actionParameter, $document, $locale)
430
    {
431
        switch ($actionParameter) {
432
            case 'publish':
433
                $this->getDocumentManager()->publish($document, $locale);
434
                break;
435
        }
436 29
    }
437
438 29
    /**
439
     * Converts camel case string into normalized string with underscore.
440
     *
441
     * @param string $camel
442
     *
443
     * @return string
444 1
     */
445
    private function uncamelize($camel)
446 1
    {
447
        $camel = preg_replace(
448
            '/(?!^)[[:upper:]][[:lower:]]/',
449
            '$0',
450
            preg_replace('/(?!^)[[:upper:]]+/', '_$0', $camel)
451
        );
452
453
        return strtolower($camel);
454
    }
455
}
456