Completed
Pull Request — master (#333)
by Elan
01:46
created

XHGuiTwigExtension   A

Complexity

Total Complexity 20

Size/Duplication

Total Lines 142
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 4

Importance

Changes 0
Metric Value
wmc 20
lcom 1
cbo 4
dl 0
loc 142
rs 10
c 0
b 0
f 0

13 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
A getName() 0 4 1
A getFunctions() 0 10 1
A getFilters() 0 10 1
A truncate() 0 8 2
A url() 0 12 2
A staticUrl() 0 6 1
A formatBytes() 0 4 1
A formatTime() 0 4 1
A formatDiff() 0 13 3
A makePercent() 0 6 2
A formatPercent() 0 4 1
A pathPrefix() 0 17 3
1
<?php
2
3
namespace XHGui\Twig;
4
5
use Slim\App;
6
use Slim\Router;
7
use Twig_Extension;
8
use Twig_Filter_Method;
9
use Twig_Function_Method;
10
11
class XHGuiTwigExtension extends Twig_Extension
12
{
13
    /** @var App */
14
    protected $_app;
15
    /** @var Router */
16
    private $router;
17
    /** @var string */
18
    private $pathPrefix;
19
20
    public function __construct(App $app)
21
    {
22
        $this->_app = $app;
23
        $this->router = $app->router();
0 ignored issues
show
Bug introduced by
The method router() does not exist on Slim\App. Did you maybe mean dispatchRouterAndPrepareRoute()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
24
        $this->pathPrefix = $app->config('path.prefix');
25
    }
26
27
    public function getName()
28
    {
29
        return 'xhgui';
30
    }
31
32
    public function getFunctions()
33
    {
34
        return [
0 ignored issues
show
Bug Best Practice introduced by
The return type of return array('url' => ne...e' => array('html')))); (array<string,Twig_Function_Method>) is incompatible with the return type declared by the interface Twig\Extension\ExtensionInterface::getFunctions of type Twig\TwigFunction[].

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...
35
            'url' => new Twig_Function_Method($this, 'url'),
0 ignored issues
show
Deprecated Code introduced by
The class Twig_Function_Method has been deprecated with message: since 1.12 (to be removed in 2.0)

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...
36
            'static' => new Twig_Function_Method($this, 'staticUrl'),
0 ignored issues
show
Deprecated Code introduced by
The class Twig_Function_Method has been deprecated with message: since 1.12 (to be removed in 2.0)

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...
37
            'percent' => new Twig_Function_Method($this, 'makePercent', [
0 ignored issues
show
Deprecated Code introduced by
The class Twig_Function_Method has been deprecated with message: since 1.12 (to be removed in 2.0)

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...
38
                'is_safe' => ['html'],
39
            ]),
40
        ];
41
    }
42
43
    public function getFilters()
44
    {
45
        return [
0 ignored issues
show
Bug Best Practice introduced by
The return type of return array('as_bytes' ...od($this, 'truncate')); (array<string,Twig_Filter_Method>) is incompatible with the return type declared by the interface Twig\Extension\ExtensionInterface::getFilters of type Twig\TwigFilter[].

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...
46
            'as_bytes' => new Twig_Filter_Method($this, 'formatBytes', ['is_safe' => ['html']]),
0 ignored issues
show
Deprecated Code introduced by
The class Twig_Filter_Method has been deprecated with message: since 1.12 (to be removed in 2.0)

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...
47
            'as_time' => new Twig_Filter_Method($this, 'formatTime', ['is_safe' => ['html']]),
0 ignored issues
show
Deprecated Code introduced by
The class Twig_Filter_Method has been deprecated with message: since 1.12 (to be removed in 2.0)

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...
48
            'as_diff' => new Twig_Filter_Method($this, 'formatDiff', ['is_safe' => ['html']]),
0 ignored issues
show
Deprecated Code introduced by
The class Twig_Filter_Method has been deprecated with message: since 1.12 (to be removed in 2.0)

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...
49
            'as_percent' => new Twig_Filter_Method($this, 'formatPercent', ['is_safe' => ['html']]),
0 ignored issues
show
Deprecated Code introduced by
The class Twig_Filter_Method has been deprecated with message: since 1.12 (to be removed in 2.0)

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...
50
            'truncate' => new Twig_Filter_Method($this, 'truncate'),
0 ignored issues
show
Deprecated Code introduced by
The class Twig_Filter_Method has been deprecated with message: since 1.12 (to be removed in 2.0)

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...
51
        ];
52
    }
53
54
    public function truncate($input, $length = 50)
55
    {
56
        if (strlen($input) < $length) {
57
            return $input;
58
        }
59
60
        return substr($input, 0, $length) . "\xe2\x80\xa6";
61
    }
62
63
    /**
64
     * Get a URL for xhgui.
65
     *
66
     * @param string $name The file/path you want a link to
67
     * @param array $queryargs additional querystring arguments
68
     * @return string url
69
     */
70
    public function url($name, $queryargs = [])
71
    {
72
        $query = '';
73
        if (!empty($queryargs)) {
74
            $query = '?' . http_build_query($queryargs);
75
        }
76
77
        // this is copy of \Slim\Slim::urlFor() to mix path prefix in
78
        // \Slim\Slim::urlFor
79
80
        return rtrim($this->pathPrefix(), '/') . $this->router->urlFor($name) . $query;
81
    }
82
83
    /**
84
     * Get the URL for static content relative to webroot
85
     *
86
     * @param string $path The file/path you want a link to
87
     * @return string url
88
     */
89
    public function staticUrl($path)
90
    {
91
        $rootUri = $this->pathPrefix();
92
93
        return rtrim($rootUri, '/') . '/' . $path;
94
    }
95
96
    public function formatBytes($value)
97
    {
98
        return number_format((float)$value) . '&nbsp;<span class="units">bytes</span>';
99
    }
100
101
    public function formatTime($value)
102
    {
103
        return number_format((float)$value) . '&nbsp;<span class="units">µs</span>';
104
    }
105
106
    public function formatDiff($value)
107
    {
108
        $class = $value > 0 ? 'diff-up' : 'diff-down';
109
        if ($value == 0) {
110
            $class = 'diff-same';
111
        }
112
113
        return sprintf(
114
            '<span class="%s">%s</span>',
115
            $class,
116
            number_format((float)$value)
117
        );
118
    }
119
120
    public function makePercent($value, $total)
121
    {
122
        $value = (false === empty($total)) ? $value / $total : 0;
123
124
        return $this->formatPercent($value);
125
    }
126
127
    public function formatPercent($value)
128
    {
129
        return number_format((float)$value * 100, 0) . ' <span class="units">%</span>';
130
    }
131
132
    /**
133
     * @return string
134
     */
135
    private function pathPrefix()
136
    {
137
        if ($this->pathPrefix !== null) {
138
            return $this->pathPrefix;
139
        }
140
141
        $request = $this->_app->request();
0 ignored issues
show
Bug introduced by
The method request() does not exist on Slim\App. Did you maybe mean isHeadRequest()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
142
        $rootUri = $request->getRootUri();
143
144
        // Get URL part prepending index.php
145
        $indexPos = strpos($rootUri, 'index.php');
146
        if ($indexPos > 0) {
147
            return substr($rootUri, 0, $indexPos);
148
        }
149
150
        return $rootUri;
151
    }
152
}
153