Completed
Pull Request — master (#343)
by Leny
09:31
created

BlogController::feedAction()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 6
rs 9.4285
cc 1
eloc 3
nc 1
nop 2
1
<?php
2
3
namespace Victoire\Bundle\BlogBundle\Controller;
4
5
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
6
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
7
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
8
use Symfony\Component\HttpFoundation\JsonResponse;
9
use Symfony\Component\HttpFoundation\Request;
10
use Symfony\Component\HttpFoundation\Response;
11
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
12
use Victoire\Bundle\BlogBundle\Entity\Blog;
13
use Victoire\Bundle\BlogBundle\Form\BlogCategoryType;
14
use Victoire\Bundle\BlogBundle\Form\BlogSettingsType;
15
use Victoire\Bundle\BlogBundle\Form\BlogType;
16
use Victoire\Bundle\BlogBundle\Form\ChooseBlogType;
17
use Victoire\Bundle\BlogBundle\Repository\BlogRepository;
18
use Victoire\Bundle\BusinessPageBundle\Entity\BusinessTemplate;
19
use Victoire\Bundle\PageBundle\Controller\BasePageController;
20
use Victoire\Bundle\PageBundle\Entity\BasePage;
21
use Victoire\Bundle\ViewReferenceBundle\ViewReference\ViewReference;
22
23
/**
24
 * blog Controller.
25
 *
26
 * @Route("/victoire-dcms/blog")
27
 */
28
class BlogController extends BasePageController
29
{
30
    protected $routes;
31
32
    /**
33
     * Constructor.
34
     */
35
    public function __construct()
36
    {
37
        $this->routes = [
38
            'new'       => 'victoire_blog_new',
39
            'show'      => 'victoire_core_page_show',
40
            'settings'  => 'victoire_blog_settings',
41
            'articles'  => 'victoire_blog_articles',
42
            'category'  => 'victoire_blog_category',
43
            'delete'    => 'victoire_blog_delete',
44
        ];
45
    }
46
47
    /**
48
     * New page.
49
     *
50
     * @Route("/index/{blogId}/{tab}", name="victoire_blog_index", defaults={"blogId" = null, "tab" = "articles"})
51
     *
52
     * @param Request $request
53
     *
54
     * @return JsonResponse
55
     */
56
    public function indexAction(Request $request, $blogId = null, $tab = 'articles')
57
    {
58
        /** @var BlogRepository $blogRepo */
59
        $blogRepo = $this->get('doctrine.orm.entity_manager')->getRepository('VictoireBlogBundle:Blog');
60
        $blogs = $blogRepo->getAll()->run();
61
        $blog = reset($blogs);
62
        if (is_numeric($blogId)) {
63
            $blog = $blogRepo->find($blogId);
64
        }
65
        $options['blog'] = $blog;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$options was never initialized. Although not strictly required by PHP, it is generally a good practice to add $options = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
66
        $template = $this->getBaseTemplatePath().':index.html.twig';
67
        $chooseBlogForm = $this->createForm(ChooseBlogType::class, null, $options);
68
69
        $chooseBlogForm->handleRequest($request);
70
        if ($chooseBlogForm->isValid()) {
71
            $blog = $chooseBlogForm->getData()['blog'];
72
            $template = $this->getBaseTemplatePath().':_blogItem.html.twig';
73
            $chooseBlogForm = $this->createForm(ChooseBlogType::class, null, ['blog' => $blog]);
74
        }
75
        $businessProperties = [];
76
77
        if ($blog instanceof BusinessTemplate) {
78
            //we can use the business entity properties on the seo
79
            $businessEntity = $this->get('victoire_core.helper.business_entity_helper')->findById($blog->getBusinessEntityId());
80
            $businessProperties = $businessEntity->getBusinessPropertiesByType('seoable');
81
        }
82
83
        return new JsonResponse(
84
            [
85
                'html' => $this->container->get('victoire_templating')->render(
86
                    $template,
87
                    [
88
                        'blog'               => $blog,
89
                        'currentTab'         => $tab,
90
                        'tabs'               => ['articles', 'settings', 'category'],
91
                        'chooseBlogForm'     => $chooseBlogForm->createView(),
92
                        'businessProperties' => $businessProperties,
93
                    ]
94
                ),
95
            ]
96
        );
97
    }
98
99
    /**
100
     * New page.
101
     *
102
     * @Route("/feed/{slug}.rss", name="victoire_blog_rss", defaults={"_format" = "rss"})
103
     *
104
     * @param Request $request
105
     * @Template("VictoireBlogBundle:Blog:feed.rss.twig")
106
     * 
107
     * @return JsonResponse
108
     */
109
    public function feedAction(Request $request, Blog $blog)
0 ignored issues
show
Unused Code introduced by
The parameter $request is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
110
    {
111
        return [
112
                'blog' => $blog,
113
            ];
114
    }
115
116
    /**
117
     * New page.
118
     *
119
     * @Route("/new", name="victoire_blog_new")
120
     * @Template()
121
     *
122
     * @return JsonResponse
123
     */
124
    public function newAction($isHomepage = false)
125
    {
126
        return new JsonResponse(parent::newAction());
0 ignored issues
show
Bug Best Practice introduced by
The return type of return new \Symfony\Comp...e(parent::newAction()); (Symfony\Component\HttpFoundation\JsonResponse) is incompatible with the return type of the parent method Victoire\Bundle\PageBund...geController::newAction of type array.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
127
    }
128
129
    /**
130
     * Blog settings.
131
     *
132
     * @param Request  $request
133
     * @param BasePage $blog
134
     *
135
     * @return JsonResponse
136
     * @Route("/{id}/settings", name="victoire_blog_settings")
137
     * @ParamConverter("blog", class="VictoirePageBundle:BasePage")
138
     */
139
    public function settingsAction(Request $request, BasePage $blog)
140
    {
141
        $entityManager = $this->getDoctrine()->getManager();
142
        $form = $this->createForm($this->getPageSettingsType(), $blog);
143
        $businessProperties = [];
144
145
        $form->handleRequest($request);
146
147
        if ($form->isValid()) {
148
            $entityManager->persist($blog);
149
            $entityManager->flush();
150
151
            /** @var ViewReference $reference */
152
            $reference = $this->get('victoire_view_reference.repository')
153
            ->getOneReferenceByParameters(['viewId' => $blog->getId()]);
154
155
            return new JsonResponse([
0 ignored issues
show
Bug Best Practice introduced by
The return type of return new \Symfony\Comp...eference->getUrl())))); (Symfony\Component\HttpFoundation\JsonResponse) is incompatible with the return type of the parent method Victoire\Bundle\PageBund...troller::settingsAction of type array.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
156
                'success' => true,
157
                'url'     => $this->generateUrl(
158
                    'victoire_core_page_show', [
159
                        '_locale' => $blog->getLocale(), 'url' => $reference->getUrl(),
160
                ]),
161
            ]);
162
        }
163
        //we display the form
164
        $errors = $this->get('victoire_form.error_helper')->getRecursiveReadableErrors($form);
165
        if ($errors != '') {
166
            return new JsonResponse(['html' => $this->container->get('victoire_templating')->render(
0 ignored issues
show
Bug Best Practice introduced by
The return type of return new \Symfony\Comp...'message' => $errors)); (Symfony\Component\HttpFoundation\JsonResponse) is incompatible with the return type of the parent method Victoire\Bundle\PageBund...troller::settingsAction of type array.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
167
                        $this->getBaseTemplatePath().':Tabs/_settings.html.twig',
168
                            [
169
                                'blog'               => $blog,
170
                                'form'               => $form->createView(),
171
                                'businessProperties' => $businessProperties,
172
                            ]
173
                        ),
174
                        'message' => $errors,
175
                    ]
176
                );
177
        }
178
179
        return new Response($this->container->get('victoire_templating')->render(
0 ignored issues
show
Bug Best Practice introduced by
The return type of return new \Symfony\Comp...$businessProperties))); (Symfony\Component\HttpFoundation\Response) is incompatible with the return type of the parent method Victoire\Bundle\PageBund...troller::settingsAction of type array.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
180
                    $this->getBaseTemplatePath().':Tabs/_settings.html.twig',
181
                    [
182
                        'blog'               => $blog,
183
                        'form'               => $form->createView(),
184
                        'businessProperties' => $businessProperties,
185
                    ]
186
                )
187
        );
188
    }
189
190
    /**
191
     * Blog settings.
192
     *
193
     * @param Request  $request
194
     * @param BasePage $blog
195
     *
196
     * @return Response
197
     * @Route("/{id}/category", name="victoire_blog_category")
198
     * @ParamConverter("blog", class="VictoirePageBundle:BasePage")
199
     */
200
    public function categoryAction(Request $request, BasePage $blog)
201
    {
202
        $entityManager = $this->getDoctrine()->getManager();
203
        $form = $this->createForm($this->getPageCategoryType(), $blog);
204
        $businessProperties = [];
205
206
        //if the page is a business entity page
207
        if ($blog instanceof BusinessTemplate) {
208
            //we can use the business entity properties on the seo
209
            $businessEntity = $this->get('victoire_core.helper.business_entity_helper')->findById($blog->getBusinessEntityId());
210
            $businessProperties = $businessEntity->getBusinessPropertiesByType('seoable');
211
        }
212
213
        $form->handleRequest($request);
214
215
        if ($form->isValid()) {
216
            $entityManager->persist($blog);
217
            $entityManager->flush();
218
219
            return new JsonResponse([
220
                'success' => true,
221
                'url'     => $this->generateUrl('victoire_core_page_show', ['_locale' => $blog->getLocale(), 'url' => $blog->getUrl()]), ]);
222
        }
223
        //we display the form
224
        $errors = $this->get('victoire_form.error_helper')->getRecursiveReadableErrors($form);
225
        if ($errors != '') {
226
            return new JsonResponse(['html' => $this->container->get('victoire_templating')->render(
227
                        $this->getBaseTemplatePath().':Tabs/_category.html.twig',
228
                            [
229
                                'blog'               => $blog,
230
                                'form'               => $form->createView(),
231
                                'businessProperties' => $businessProperties,
232
                            ]
233
                        ),
234
                        'message' => $errors,
235
                    ]
236
                );
237
        }
238
239
        return new Response($this->container->get('victoire_templating')->render(
240
                    $this->getBaseTemplatePath().':Tabs/_category.html.twig',
241
                    [
242
                        'blog'               => $blog,
243
                        'form'               => $form->createView(),
244
                        'businessProperties' => $businessProperties,
245
                    ]
246
                )
247
        );
248
    }
249
250
    /**
251
     * Blog settings.
252
     *
253
     * @param Request  $request
254
     * @param BasePage $blog
255
     *
256
     * @return Response
257
     * @Route("/{id}/articles", name="victoire_blog_articles")
258
     * @ParamConverter("blog", class="VictoirePageBundle:BasePage")
259
     */
260
    public function articlesAction(Request $request, BasePage $blog)
0 ignored issues
show
Unused Code introduced by
The parameter $request is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
261
    {
262
        return new Response($this->container->get('victoire_templating')->render(
263
                    $this->getBaseTemplatePath().':Tabs/_articles.html.twig',
264
                    [
265
                        'blog' => $blog,
266
                    ]
267
                )
268
        );
269
    }
270
271
    /**
272
     * Page delete.
273
     *
274
     * @param Blog $blog
275
     *
276
     * @return JsonResponse
277
     * @Route("/{id}/delete", name="victoire_blog_delete")
278
     * @Template()
279
     * @ParamConverter("blog", class="VictoirePageBundle:BasePage")
280
     */
281
    public function deleteAction(BasePage $blog)
282
    {
283
        if (!$this->get('security.authorization_checker')->isGranted('ROLE_VICTOIRE', $blog)) {
284
            throw new AccessDeniedException("Nop ! you can't do such an action");
285
        }
286
287
        foreach ($blog->getArticles() as $_article) {
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Victoire\Bundle\PageBundle\Entity\BasePage as the method getArticles() does only exist in the following sub-classes of Victoire\Bundle\PageBundle\Entity\BasePage: Victoire\Bundle\BlogBundle\Entity\Blog. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
288
            $bep = $this->get('victoire_page.page_helper')->findPageByParameters(
289
                [
290
                    'templateId' => $_article->getTemplate()->getId(),
291
                    'entityId'   => $_article->getId(),
292
                ]
293
            );
294
            $this->get('victoire_blog.manager.article')->delete($_article, $bep);
295
        }
296
297
        return new JsonResponse(parent::deleteAction($blog));
0 ignored issues
show
Bug Best Practice introduced by
The return type of return new \Symfony\Comp...::deleteAction($blog)); (Symfony\Component\HttpFoundation\JsonResponse) is incompatible with the return type of the parent method Victoire\Bundle\PageBund...ontroller::deleteAction of type array<string,boolean|string>.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
298
    }
299
300
    /**
301
     * @return string
302
     */
303
    protected function getPageSettingsType()
304
    {
305
        return BlogSettingsType::class;
306
    }
307
308
    /**
309
     * @return string
310
     */
311
    protected function getPageCategoryType()
312
    {
313
        return BlogCategoryType::class;
314
    }
315
316
    /**
317
     * @return string
318
     */
319
    protected function getNewPageType()
320
    {
321
        return BlogType::class;
322
    }
323
324
    /**
325
     * @return \Victoire\Bundle\BlogBundle\Entity\Blog
326
     */
327
    protected function getNewPage()
328
    {
329
        return new Blog();
330
    }
331
332
    /**
333
     * @return string
334
     */
335
    protected function getBaseTemplatePath()
336
    {
337
        return 'VictoireBlogBundle:Blog';
338
    }
339
340
    /**
341
     * @param unknown $action
342
     */
343
    protected function getRoutes($action)
344
    {
345
        return $this->routes[$action];
346
    }
347
}
348