GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

TwigExtensionPlugin   A
last analyzed

Complexity

Total Complexity 23

Size/Duplication

Total Lines 223
Duplicated Lines 7.17 %

Coupling/Cohesion

Components 1
Dependencies 6

Test Coverage

Coverage 92.59%

Importance

Changes 0
Metric Value
wmc 23
lcom 1
cbo 6
dl 16
loc 223
ccs 75
cts 81
cp 0.9259
rs 10
c 0
b 0
f 0

10 Methods

Rating   Name   Duplication   Size   Complexity  
A getSubscribedEvents() 0 7 1
A onItemPreParse() 0 18 1
A onItemPostParse() 0 22 1
A renderString() 0 10 1
A addTwigGlobals() 0 14 2
A registerExtensions() 0 14 1
A fileFunction() 8 24 5
B fragmentFunction() 8 36 9
A itemTocFunction() 0 4 1
A itemTocInternalFunction() 0 17 1

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php
2
/*
3
 * This file is part of the trefoil application.
4
 *
5
 * (c) Miguel Angel Gabriel <[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 Trefoil\Plugins\Optional;
11
12
use Easybook\Events\EasybookEvents;
13
use Easybook\Events\ParseEvent;
14
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
15
use Trefoil\Plugins\BasePlugin;
16
use Trefoil\Util\Toolkit;
17
18
/**
19
 * This plugin extends Twig to provide some useful functionalities:
20
 *
21
 * <li>
22
 * <b>Use configuration options in book contents</b> (instead of only in templates).
23
 * For example, in "chapter1.md" you can write "The title is {{ book.title }}".
24
 * This is mainly useful with user-defined configuration options.
25
 *
26
 * <li>
27
 * <b>itemtoc()</b> function automatically generates the Table of Contents of the current item.
28
 * The deep of the itemtoc can be tweaked by the configuration option <i>edition.itemtoc.deep</i>,
29
 * which defaults to one less than the main TOC deep <i>edition.toc.deep</i>.
30
 * It uses de <i>itemtoc.twig</i> template that must be available either as local or global template.
31
 *
32
 * <li>
33
 * <b>file()</b> function (deprecated, use fragment()) works like PHP's <i>include()</i>,
34
 * allowing the inclusion of another file into the current item.
35
 * The syntax is <i>file(filename, variables, options)</i> where "variables" and "options" are
36
 * optional hash tables where you can pass variables {'variable': 'value'} or
37
 * options {'nopagebreak': true} to the included file.
38
 *
39
 * <li>
40
 * <b>fragment()</b> function works like PHP's <i>include()</i>, allowing the inclusion of
41
 * another file into the current item.
42
 *
43
 * is a simplified version of <i>file()</i> without any variables or options.
44
 * The syntax is <i>fragment(filename)</i>. No page break will be inserted after the file contents.
45
 *
46
 *
47
 */
48
class TwigExtensionPlugin extends BasePlugin implements EventSubscriberInterface
49
{
50 1
    public static function getSubscribedEvents()
51
    {
52 1
        return array(
53 1
            EasybookEvents::PRE_PARSE  => 'onItemPreParse',
54 1
            EasybookEvents::POST_PARSE => array('onItemPostParse', -1010)
55 1
        );
56
    }
57
58 1
    public function onItemPreParse(ParseEvent $event)
59
    {
60 1
        $this->init($event);
61
62 1
        $content = $event->getItemProperty('original');
63
64
        // replace "{#" to avoid problems with markdown extra syntax for ids in headers
65 1
        $content = str_replace('{#', '@%@&', $content);
66
67
        // replace configuration options on PreParse to take care of normal replacements
68
        // and the first pass of "itemtoc()"
69 1
        $content = $this->renderString($content);
70
71
        # replace back "{#"
72 1
        $content = str_replace('@%@&', '{#', $content);
73
74 1
        $event->setItemProperty('original', $content);
75 1
    }
76
77 1
    public function onItemPostParse(ParseEvent $event)
78
    {
79 1
        $this->init($event);
80
81 1
        $content = $event->getItemProperty('content');
82
83
        // ensure the Twig function call is not enclosed into a '<p>..</p>' tag
84
        // as it will result in epub checking erros
85 1
        $content = preg_replace('/<p>\s*{{/', '{{', $content);
86 1
        $content = preg_replace('/}}\s*<\/p>/', '}}', $content);
87
88
        // replace "{#" to avoid problems with markdown extra syntax for ids in headers
89 1
        $content = str_replace('{#', '@%@&', $content);
90
91
        // replace also in PostParse to process the second pass of "itemtoc()" ("itemtoc_internal()")
92 1
        $content = $this->renderString($content);
93
94
        # replace back "{#"
95 1
        $content = str_replace('@%@&', '{#', $content);
96
97 1
        $event->setItemProperty('content', $content);
98 1
    }
99
100 1
    protected function renderString($string, $variables = array())
101
    {
102
        // we need a new Twig String Renderer environment
103 1
        $twig = new \Twig_Environment(new \Twig_Loader_String(), $this->app['twig.options']);
104
105 1
        $this->addTwigGlobals($twig);
106 1
        $this->registerExtensions($twig);
107
108 1
        return $twig->render($string, $variables);
109
    }
110
111 1
    protected function addTwigGlobals(\Twig_Environment $twig)
112
    {
113 1
        $twig->addGlobal('app', $this->app);
114
115 1
        if (null !== $this->app['publishing.book.config']['book']) {
116 1
            $twig->addGlobal('book', $this->app['publishing.book.config']['book']);
117
118 1
            $publishingEdition = $this->edition;
119 1
            $editions = $this->app->book('editions');
120 1
            $twig->addGlobal('edition', $editions[$publishingEdition]);
121 1
        }
122
123 1
        $twig->addGlobal('item', $this->item);
124 1
    }
125
126
    /**
127
     * Register all the extensions here.
128
     */
129 1
    protected function registerExtensions(\Twig_Environment $twig)
130
    {
131
        // file()
132 1
        $twig->addFunction(new \Twig_SimpleFunction('file', array($this, 'fileFunction')));
133
134
        // fragment()
135 1
        $twig->addFunction(new \Twig_SimpleFunction('fragment', array($this, 'fragmentFunction')));
136
137
        // itemtoc() and its internal counterpart
138 1
        $twig->addFunction(new \Twig_SimpleFunction('itemtoc', array($this, 'itemTocFunction')));
139 1
        $twig->addFunction(
140 1
            new \Twig_SimpleFunction('_itemtoc_internal', array($this, 'itemTocInternalFunction'))
141 1
        );
142 1
    }
143
144
    /**
145
     * Twig function: <b>file(filename, variables, options)</b>
146
     *
147
     * @deprecated
148
     *
149
     * @param string $filename  to be included (relative to book Contents dir)
150
     * @param array  $variables to be passed to the template
151
     * @param array  $options   (default: 'nopagebreak: false' => add a page break after the included text)
152
     *
153
     * @return string included text with all the replacements done.
154
     */
155
    public function fileFunction($filename, $variables = array(), $options = array())
156
    {
157
        $dir = $this->app['publishing.dir.contents'];
158
        $file = $dir . '/' . $filename;
159
160 View Code Duplication
        if (!file_exists($file)) {
161
            $this->writeLn(
162
                sprintf('Included content file "%s" not found in "%s"', $filename, $this->item['config']['content']),
163
                'error'
164
            );
165
166
            return $filename;
167
        }
168
169
        $rendered = $this->renderString(file_get_contents($file), $variables);
170
171
        // pagebreak is added by default
172
        $addPageBreak = !isset($options['nopagebreak']) || (isset($options['nopagebreak']) && !$options['nopagebreak']);
173
        if ($addPageBreak) {
174
            $rendered .= '<div class="page-break"></div>';
175
        }
176
177
        return $rendered;
178
    }
179
180
    /**
181
     * Twig function: <b>fragment(filename)</b>
182
     *
183
     * @param string $filename  to be included (relative to book Contents dir)
184
     *
185
     * @param array  $variables to be passed to the template (example: {'name': 'John'} )
186
     * @param array  $options   (example {'pagebreak' => true} will add a page break after the included text)
187
     *
188
     * @return string included text with all the replacements done.
189
     */
190 1
    public function fragmentFunction($filename, $variables = array(), $options = array())
191
    {
192 1
        $dir = $this->app['publishing.dir.contents'];
193 1
        $file = $dir . '/' . $filename;
194
195 1 View Code Duplication
        if (!file_exists($file)) {
196
            $this->writeLn(
197
                sprintf('Fragment file "%s" not found in "%s"', $filename, $this->item['config']['content']),
198
                'error'
199
            );
200
201
            return $filename;
202
        }
203
204 1
        $rendered = $this->renderString(file_get_contents($file), $variables);
205
206
        // surround contents with the (optional) tag and class
207 1
        $tag = isset($options['tag']) ? $options['tag'] : '';
208 1
        $attributes = array('markdown' => 1);
209 1
        $attributes['class'] = isset($options['class']) ? $options['class'] : '';
210 1
        if ($attributes['class'] && empty($tag)) {
211 1
            $tag = 'div';
212 1
        }
213
214 1
        if ($tag) {
215 1
            $attributes['class'] = 'fragment ' . $attributes['class'];
216 1
            $rendered = Toolkit::renderHTMLTag($tag, $rendered, $attributes);
217 1
        }
218
        
219
        // add pagebreak if asked
220 1
        if (isset($options['pagebreak']) && $options['pagebreak']) {
221
            $rendered .= '<div class="page-break"></div>';
222
        }
223
        
224 1
        return $rendered;
225
    }
226
227
    /**
228
     * Twig function: <b>itemtoc()</b>
229
     *
230
     * @return string The _itemtoc_internal() function call
231
     *
232
     * Generating the item toc requires two phases to ensure that included files got parsed after being
233
     * included (with file()). The second phase does the actual rendering of the itemtoc
234
     * template.
235
     */
236 1
    public function itemTocFunction()
237
    {
238 1
        return '{{ _itemtoc_internal() }}';
239
    }
240
241
    /**
242
     * Twig function: <b>_itemtoc_internal()</b>
243
     * <b>This is an internal function so is not to be used directly in content files.</b>
244
     * It will be invoked on itemPostParse, after all the file() functions have been resolved and all
245
     * the included item contents have been parsed.
246
     *
247
     * @uses Configuration option <i>edition.plugins.TwigExtension.itemtoc.deep</i>
248
     *       (default: <i>edition.toc.deep + 1 </i>
249
     *
250
     * @return string The item toc rendered
251
     *
252
     */
253 1
    public function itemTocInternalFunction()
254
    {
255 1
        $template = 'itemtoc.twig';
256
257
        // note that we need to use the normal Twig template renderer, not our Twig string renderer
258 1
        $twig = $this->app['twig'];
259 1
        $this->addTwigGlobals($twig);
260
261 1
        $itemtoc_deep = $this->getEditionOption(
262 1
            'plugins.options.TwigExtension.itemtoc.deep',
263 1
            $this->getEditionOption('toc.deep') + 1
264 1
        );
265
266 1
        $rendered = $twig->render($template, array('itemtoc_deep' => $itemtoc_deep));
267
268 1
        return $rendered;
269
    }
270
}
271