Completed
Push — master ( b6ee28...2840be )
by Paul
10s
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\ChooseBlogType;
14
use Victoire\Bundle\BlogBundle\Repository\BlogRepository;
15
use Victoire\Bundle\BusinessPageBundle\Entity\BusinessTemplate;
16
use Victoire\Bundle\PageBundle\Controller\BasePageController;
17
use Victoire\Bundle\PageBundle\Entity\BasePage;
18
use Victoire\Bundle\ViewReferenceBundle\ViewReference\ViewReference;
19
20
/**
21
 * blog Controller.
22
 *
23
 * @Route("/victoire-dcms/blog")
24
 */
25
class BlogController extends BasePageController
26
{
27
    protected $routes;
28
29
    /**
30
     * Constructor.
31
     */
32
    public function __construct()
33
    {
34
        $this->routes = [
35
            'new'       => 'victoire_blog_new',
36
            'show'      => 'victoire_core_page_show',
37
            'settings'  => 'victoire_blog_settings',
38
            'articles'  => 'victoire_blog_articles',
39
            'category'  => 'victoire_blog_category',
40
            'delete'    => 'victoire_blog_delete',
41
        ];
42
    }
43
44
    /**
45
     * New page.
46
     *
47
     * @Route("/index/{blogId}/{tab}", name="victoire_blog_index", defaults={"blogId" = null, "tab" = "articles"})
48
     *
49
     * @param Request $request
50
     *
51
     * @return JsonResponse
52
     */
53
    public function indexAction(Request $request, $blogId = null, $tab = 'articles')
54
    {
55
        /** @var BlogRepository $blogRepo */
56
        $blogRepo = $this->get('doctrine.orm.entity_manager')->getRepository('VictoireBlogBundle:Blog');
57
        $blogs = $blogRepo->getAll()->run();
58
        $blog = reset($blogs);
59
        if (is_numeric($blogId)) {
60
            $blog = $blogRepo->find($blogId);
61
        }
62
        $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...
63
        $template = $this->getBaseTemplatePath().':index.html.twig';
64
        $chooseBlogForm = $this->createForm(new ChooseBlogType(), null, $options);
65
66
        $chooseBlogForm->handleRequest($request);
67
        if ($chooseBlogForm->isValid()) {
68
            $blog = $chooseBlogForm->getData()['blog'];
69
            $template = $this->getBaseTemplatePath().':_blogItem.html.twig';
70
            $chooseBlogForm = $this->createForm(new ChooseBlogType(), null, ['blog' => $blog]);
71
        }
72
        $businessProperties = [];
73
74
        if ($blog instanceof BusinessTemplate) {
75
            //we can use the business entity properties on the seo
76
            $businessEntity = $this->get('victoire_core.helper.business_entity_helper')->findById($blog->getBusinessEntityId());
77
            $businessProperties = $businessEntity->getBusinessPropertiesByType('seoable');
78
        }
79
80
        return new JsonResponse(
81
            [
82
                'html' => $this->container->get('victoire_templating')->render(
83
                    $template,
84
                    [
85
                        'blog'               => $blog,
86
                        'currentTab'         => $tab,
87
                        'tabs'               => ['articles', 'settings', 'category'],
88
                        'chooseBlogForm'     => $chooseBlogForm->createView(),
89
                        'businessProperties' => $businessProperties,
90
                    ]
91
                ),
92
            ]
93
        );
94
    }
95
96
    /**
97
     * New page.
98
     *
99
     * @Route("/feed/{slug}.rss", name="victoire_blog_rss", defaults={"_format" = "rss"})
100
     *
101
     * @param Request $request
102
     * @Template("VictoireBlogBundle:Blog:feed.rss.twig")
103
     * 
104
     * @return JsonResponse
105
     */
106
    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...
107
    {
108
        return [
109
                'blog' => $blog,
110
            ];
111
    }
112
113
    /**
114
     * New page.
115
     *
116
     * @Route("/new", name="victoire_blog_new")
117
     * @Template()
118
     *
119
     * @return JsonResponse
120
     */
121
    public function newAction($isHomepage = false)
122
    {
123
        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...
124
    }
125
126
    /**
127
     * Blog settings.
128
     *
129
     * @param Request  $request
130
     * @param BasePage $blog
131
     *
132
     * @return JsonResponse
133
     * @Route("/{id}/settings", name="victoire_blog_settings")
134
     * @ParamConverter("blog", class="VictoirePageBundle:BasePage")
135
     */
136
    public function settingsAction(Request $request, BasePage $blog)
137
    {
138
        $entityManager = $this->getDoctrine()->getManager();
139
        $form = $this->createForm($this->getPageSettingsType(), $blog);
140
        $businessProperties = [];
141
142
        $form->handleRequest($request);
143
144
        if ($form->isValid()) {
145
            $entityManager->persist($blog);
146
            $entityManager->flush();
147
148
            /** @var ViewReference $reference */
149
            $reference = $this->get('victoire_view_reference.repository')
150
            ->getOneReferenceByParameters(['viewId' => $blog->getId()]);
151
152
            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...
153
                'success' => true,
154
                'url'     => $this->generateUrl(
155
                    'victoire_core_page_show', [
156
                        '_locale' => $blog->getLocale(), 'url' => $reference->getUrl(),
157
                ]),
158
            ]);
159
        }
160
        //we display the form
161
        $errors = $this->get('victoire_form.error_helper')->getRecursiveReadableErrors($form);
162
        if ($errors != '') {
163
            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...
164
                        $this->getBaseTemplatePath().':Tabs/_settings.html.twig',
165
                            [
166
                                'blog'               => $blog,
167
                                'form'               => $form->createView(),
168
                                'businessProperties' => $businessProperties,
169
                            ]
170
                        ),
171
                        'message' => $errors,
172
                    ]
173
                );
174
        }
175
176
        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...
177
                    $this->getBaseTemplatePath().':Tabs/_settings.html.twig',
178
                    [
179
                        'blog'               => $blog,
180
                        'form'               => $form->createView(),
181
                        'businessProperties' => $businessProperties,
182
                    ]
183
                )
184
        );
185
    }
186
187
    /**
188
     * Blog settings.
189
     *
190
     * @param Request  $request
191
     * @param BasePage $blog
192
     *
193
     * @return Response
194
     * @Route("/{id}/category", name="victoire_blog_category")
195
     * @ParamConverter("blog", class="VictoirePageBundle:BasePage")
196
     */
197
    public function categoryAction(Request $request, BasePage $blog)
198
    {
199
        $entityManager = $this->getDoctrine()->getManager();
200
        $form = $this->createForm($this->getPageCategoryType(), $blog);
201
        $businessProperties = [];
202
203
        //if the page is a business entity page
204
        if ($blog instanceof BusinessTemplate) {
205
            //we can use the business entity properties on the seo
206
            $businessEntity = $this->get('victoire_core.helper.business_entity_helper')->findById($blog->getBusinessEntityId());
207
            $businessProperties = $businessEntity->getBusinessPropertiesByType('seoable');
208
        }
209
210
        $form->handleRequest($request);
211
212
        if ($form->isValid()) {
213
            $entityManager->persist($blog);
214
            $entityManager->flush();
215
216
            return new JsonResponse([
217
                'success' => true,
218
                'url'     => $this->generateUrl('victoire_core_page_show', ['_locale' => $blog->getLocale(), 'url' => $blog->getUrl()]), ]);
219
        }
220
        //we display the form
221
        $errors = $this->get('victoire_form.error_helper')->getRecursiveReadableErrors($form);
222
        if ($errors != '') {
223
            return new JsonResponse(['html' => $this->container->get('victoire_templating')->render(
224
                        $this->getBaseTemplatePath().':Tabs/_category.html.twig',
225
                            [
226
                                'blog'               => $blog,
227
                                'form'               => $form->createView(),
228
                                'businessProperties' => $businessProperties,
229
                            ]
230
                        ),
231
                        'message' => $errors,
232
                    ]
233
                );
234
        }
235
236
        return new Response($this->container->get('victoire_templating')->render(
237
                    $this->getBaseTemplatePath().':Tabs/_category.html.twig',
238
                    [
239
                        'blog'               => $blog,
240
                        'form'               => $form->createView(),
241
                        'businessProperties' => $businessProperties,
242
                    ]
243
                )
244
        );
245
    }
246
247
    /**
248
     * Blog settings.
249
     *
250
     * @param Request  $request
251
     * @param BasePage $blog
252
     *
253
     * @return Response
254
     * @Route("/{id}/articles", name="victoire_blog_articles")
255
     * @ParamConverter("blog", class="VictoirePageBundle:BasePage")
256
     */
257
    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...
258
    {
259
        return new Response($this->container->get('victoire_templating')->render(
260
                    $this->getBaseTemplatePath().':Tabs/_articles.html.twig',
261
                    [
262
                        'blog' => $blog,
263
                    ]
264
                )
265
        );
266
    }
267
268
    /**
269
     * Page delete.
270
     *
271
     * @param Blog $blog
272
     *
273
     * @return JsonResponse
274
     * @Route("/{id}/delete", name="victoire_blog_delete")
275
     * @Template()
276
     * @ParamConverter("blog", class="VictoirePageBundle:BasePage")
277
     */
278
    public function deleteAction(BasePage $blog)
279
    {
280
        if (!$this->get('security.authorization_checker')->isGranted('ROLE_VICTOIRE', $blog)) {
281
            throw new AccessDeniedException("Nop ! you can't do such an action");
282
        }
283
284
        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...
285
            $bep = $this->get('victoire_page.page_helper')->findPageByParameters(
286
                [
287
                    'templateId' => $_article->getTemplate()->getId(),
288
                    'entityId'   => $_article->getId(),
289
                ]
290
            );
291
            $this->get('victoire_blog.manager.article')->delete($_article, $bep);
292
        }
293
294
        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.

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