Completed
Pull Request — master (#104)
by Mikael
01:35
created

PommProfilerController::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 11
rs 9.9
c 0
b 0
f 0
cc 1
nc 1
nop 4
1
<?php
2
/*
3
 * This file is part of the PommProject/PommBundle package.
4
 *
5
 * (c) 2018 Grégoire HUBERT <[email protected]>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
namespace PommProject\PommBundle\Controller;
11
12
use Symfony\Component\HttpFoundation\Request;
13
use Symfony\Component\HttpFoundation\Response;
14
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
15
use Symfony\Component\HttpKernel\Profiler\Profiler;
16
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
17
18
use PommProject\Foundation\Pomm;
19
20
/**
21
 * Controllers for the Pomm profiler extension.
22
 *
23
 * @package PommBundle
24
 * @copyright 2018 Grégoire HUBERT
25
 * @author Grégoire HUBERT
26
 * @license X11 {@link http://opensource.org/licenses/mit-license.php}
27
 */
28
class PommProfilerController
29
{
30
    private $generator;
31
    private $profiler;
32
    private $twig;
33
    private $pomm;
34
35
    public function __construct(
36
        UrlGeneratorInterface $generator,
37
        Profiler $profiler,
38
        \Twig_Environment $twig,
39
        Pomm $pomm
40
    ) {
41
        $this->generator = $generator;
42
        $this->profiler  = $profiler;
43
        $this->twig      = $twig;
44
        $this->pomm      = $pomm;
45
    }
46
47
    /**
48
     * Controller to explain a SQL query.
49
     *
50
     * @param $request
51
     * @param string $token
52
     * @param int $index_query
53
     *
54
     * @return Response
55
     */
56
    public function explainAction(Request $request, $token, $index_query)
57
    {
58
        $panel = 'pomm';
59
        $page  = 'home';
60
61
        if (!($profile = $this->profiler->loadProfile($token))) {
62
            return new Response(
63
                $this->twig->render(
64
                    '@WebProfiler/Profiler/info.html.twig',
65
                    array('about' => 'no_token', 'token' => $token)
66
                ),
67
                200,
68
                array('Content-Type' => 'text/html')
69
            );
70
        }
71
72
        $this->profiler->disable();
73
74
        if (!$profile->hasCollector($panel)) {
75
            throw new NotFoundHttpException(sprintf('Panel "%s" is not available for token "%s".', $panel, $token));
76
        }
77
78
        if (!array_key_exists($index_query, $profile->getCollector($panel)->getQueries())) {
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Symfony\Component\HttpKe...\DataCollectorInterface as the method getQueries() does only exist in the following implementations of said interface: PommProject\PommBundle\DatabaseDataCollector.

Let’s take a look at an example:

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

class MyUser implements 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 implementation 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 interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
79
            throw new \InvalidArgumentException(sprintf("No such query index '%s'.", $index_query));
80
        }
81
82
        $query_data = $profile->getCollector($panel)->getQueries()[$index_query];
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Symfony\Component\HttpKe...\DataCollectorInterface as the method getQueries() does only exist in the following implementations of said interface: PommProject\PommBundle\DatabaseDataCollector.

Let’s take a look at an example:

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

class MyUser implements 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 implementation 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 interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
83
84
        $explain = $this->pomm[$query_data['session_stamp']]
85
            ->getClientUsingPooler('query_manager', null)
86
            ->query(sprintf("explain %s", $query_data['sql']), $query_data['parameters']);
87
88
        return new Response($this->twig->render('@Pomm/Profiler/explain.html.twig', array(
89
            'token' => $token,
90
            'profile' => $profile,
91
            'collector' => $profile->getCollector($panel),
92
            'panel' => $panel,
93
            'page' => $page,
94
            'request' => $request,
95
            'query_index' => $index_query,
96
            'explain' => $explain,
97
        )), 200, array('Content-Type' => 'text/html'));
98
    }
99
}
100