Completed
Push — master ( a937a1...6472ae )
by Christophe
03:46
created

GoogleChartsExtension::end()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 14
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
dl 0
loc 14
rs 9.2
c 1
b 0
f 0
cc 4
eloc 8
nc 3
nop 1
1
<?php
2
3
namespace CMEN\GoogleChartsBundle\Twig;
4
5
use CMEN\GoogleChartsBundle\Exception\GoogleChartsException;
6
use CMEN\GoogleChartsBundle\GoogleCharts\Chart;
7
8
/**
9
 * @author Christophe Meneses
10
 */
11
class GoogleChartsExtension extends \Twig_Extension
12
{
13
    /**
14
     * Version of Google Charts used.
15
     *
16
     * @var string
17
     */
18
    private $version;
19
20
    /**
21
     * Locale to customize currencies, dates, and numbers.
22
     *
23
     * @var string
24
     */
25
    private $language;
26
27
28
    /**
29
     * GoogleChartsExtension constructor.
30
     *
31
     * @param string $version
32
     * @param string $language
33
     */
34
    public function __construct($version, $language)
35
    {
36
        $this->version = $version;
37
        $this->language = $language;
38
    }
39
40
41
    /**
42
     * @inheritdoc
43
     */
44
    public function getFunctions()
45
    {
46
        return array(
47
            new \Twig_SimpleFunction('gc_draw', array($this, 'draw'), array('is_safe' => array('html'))),
48
            new \Twig_SimpleFunction('gc_start', array($this, 'start'), array('is_safe' => array('html'))),
49
            new \Twig_SimpleFunction('gc_end', array($this, 'end'), array('is_safe' => array('html'))),
50
            new \Twig_SimpleFunction('gc_event', array($this, 'event'), array('is_safe' => array('html'))),
51
            new \Twig_SimpleFunction('gc_language', array($this, 'language')),
52
        );
53
    }
54
55
    /**
56
     * Returns the Javascript for the beginning of one or more charts.
57
     *
58
     * @param Chart|Chart[] $charts Chart instance or array of Chart instance
59
     * @param string|string[]|null $elementsID HTML element ID or array of HTML elements IDs. Can be null
60
     *
61
     * @return string
62
     */
63
    public function start($charts, $elementsID = null)
64
    {
65
        return $this->checkAndCallGoodMethod('startCharts', $charts, $elementsID);
66
    }
67
68
    /**
69
     * Returns the Javascript for the end of one or more charts.
70
     *
71
     * @param Chart|Chart[] $charts Chart instance or array of Chart instance
72
     *
73
     * @return string
74
     *
75
     * @throws GoogleChartsException
76
     */
77
    public function end($charts)
78
    {
79
        if ($charts instanceof Chart) {
80
            return $this->endCharts(array($charts));
81
82
        } elseif (is_array($charts) && !empty($charts)) {
83
            $this->checkChartType($charts);
84
85
            return $this->endCharts($charts);
86
87
        } else {
88
            throw new GoogleChartsException('An instance of Chart or an array of Chart is expected.');
89
        }
90
    }
91
92
    /**
93
     * Returns the full Javascript to draw one or more charts.
94
     *
95
     * @param Chart|Chart[] $charts Chart instance or array of Chart instance
96
     * @param string|string[]|null $elementsID HTML element ID or array of HTML elements IDs. Can be null
97
     *
98
     * @return string
99
     */
100
    public function draw($charts, $elementsID = null)
101
    {
102
        return $this->checkAndCallGoodMethod('drawCharts', $charts, $elementsID);
103
    }
104
105
    /**
106
     * Add an event to a chart.
107
     *
108
     * @param Chart $chart A Chart instance
109
     * @param string $type Type of event
110
     * @param string $functionName Name of Javascript function
111
     */
112
    public function event(Chart $chart, $type, $functionName)
113
    {
114
        $chart->getEvents()->addListener($type, $functionName);
115
    }
116
117
    /**
118
     * Set the locale. Must be called before drawing charts.
119
     *
120
     * @link https://developers.google.com/chart/interactive/docs/basic_load_libs#loadwithlocale
121
     *
122
     * @param string $language Locale, for example : "fr"
123
     */
124
    public function language($language)
125
    {
126
        $this->language = $language;
127
    }
128
129
    /**
130
     * Returns Javascript according to the called method.
131
     *
132
     * @param string $name Method's name to be called
133
     * @param Chart|Chart[] $charts Chart instance or array of Chart instance
134
     * @param string|string[]|null $elementsID HTML element ID or array of HTML elements IDs. Can be null
135
     *
136
     * @return string
137
     *
138
     * @throws GoogleChartsException
139
     */
140
    private function checkAndCallGoodMethod($name, $charts, $elementsID = null)
141
    {
142
        if ($charts instanceof Chart) {
143
            if ($elementsID) {
144
                if (!is_string($elementsID)) {
145
                    throw new GoogleChartsException('A string is expected for HTML element ID.');
146
                }
147
148
                return $this->$name(array($charts), array($elementsID));
149
150
            } else {
151
                return $this->$name(array($charts));
152
            }
153
154
        } elseif (is_array($charts) && !empty($charts)) {
155
            if ($elementsID !== null) {
156
                if (count($charts) != count($elementsID)) {
157
                    throw new GoogleChartsException(
158
                        'Array charts and array HTML elements ID do not have the same number of element.'
159
                    );
160
                }
161
162
                $callback = function ($item) {
163
                    if (!is_string($item)) {
164
                        throw new GoogleChartsException('A string is expected for HTML element ID.');
165
                    }
166
                };
167
                array_map($callback, $elementsID);
168
            }
169
170
            $this->checkChartType($charts);
171
172
            return $this->$name($charts, $elementsID);
173
174
        } else {
175
            throw new GoogleChartsException('An instance of Chart or an array of Chart is expected.');
176
        }
177
    }
178
179
    /**
180
     * Checks if all elements of an array are instances of Chart. Throws an exception if not.
181
     *
182
     * @param Chart[] $charts
183
     *
184
     * @throws GoogleChartsException
185
     */
186
    private function checkChartType($charts)
187
    {
188
        $callback = function ($item) {
189
            if (!$item instanceof Chart) {
190
                throw new GoogleChartsException('An instance of Chart or an array of Chart is expected.');
191
            }
192
        };
193
        array_map($callback, $charts);
194
    }
195
196
    /**
197
     * Returns Javascript to load libraries.
198
     *
199
     * @param string[] $packages List of packages to load
200
     *
201
     * @return string
202
     */
203
    private function loadLibraries($packages)
204
    {
205
        array_walk($packages, function (&$item) {
206
            $item = '"' . $item . '"';
207
        });
208
209
        ($this->language) ? $language = ', language: "' . $this->language . '"' : $language = '';
210
211
        $load = '"' . $this->version . '", {packages:[' . implode(',', $packages) . ']' . $language . '}';
212
213
        if ($this->version == '1' || $this->version == '1.1') {
214
            return 'google.load("visualization", ' . $load . ');';
215
216
        } else {
217
            return 'google.charts.load(' . $load . ');';
218
        }
219
    }
220
221
    /**
222
     * Returns the Javascript for the beginning of the callback.
223
     *
224
     * @param string $name Name of callback
225
     *
226
     * @return string
227
     */
228
    private function startCallback($name)
229
    {
230
        return "google.setOnLoadCallback($name);
231
            function $name() {";
232
    }
233
234
    /**
235
     * Returns the Javascript for the end of the callback.
236
     *
237
     * @return string
238
     */
239
    private function endCallback()
240
    {
241
        return '}';
242
    }
243
244
    /**
245
     * Returns the Javascript for the beginning of the charts.
246
     *
247
     * @param Chart[] $charts Array of Chart instance
248
     * @param string[]|null $elementsID Array of HTML elements IDs. Can be null
249
     *
250
     * @return string
251
     */
252
    public function startCharts($charts, $elementsID = null)
253
    {
254
        $packages = array();
255
        $drawChartName = '';
256
        for ($i = 0; $i < count($charts); $i++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
257
            if ($elementsID) {
258
                $charts[$i]->setElementID($elementsID[$i]);
259
            }
260
261
            if (!in_array($charts[$i]->getPackage(), $packages)) {
262
                $packages[] = $charts[$i]->getPackage();
263
            }
264
            $drawChartName .= $charts[$i]->getElementID();
265
        }
266
267
        $js = $this->loadLibraries($packages);
268
269
        $js .= $this->startCallback('drawChart' . ucfirst(md5($drawChartName)));
270
271
        foreach ($charts as $chart) {
272
            $js .= $chart->startDraw();
273
        }
274
275
        return $js;
276
    }
277
278
    /**
279
     * Returns the Javascript for the end of the charts.
280
     *
281
     * @param Chart[] $charts Array of Chart instance
282
     *
283
     * @return string
284
     */
285
    public function endCharts($charts)
286
    {
287
        $js = '';
288
289
        foreach ($charts as $chart) {
290
            $js .= $chart->endDraw();
291
        }
292
293
        $js .= $this->endCallback();
294
295
        return $js;
296
    }
297
298
    /**
299
     * Returns the full Javascript to draw charts.
300
     *
301
     * @param Chart[] $charts Array of Chart instance
302
     * @param string[]|null $elementsID Array of HTML elements IDs. Can be null
303
     *
304
     * @return string
305
     */
306
    public function drawCharts($charts, $elementsID = null)
307
    {
308
        return $this->startCharts($charts, $elementsID) . $this->endCharts($charts);
309
    }
310
311
    /**
312
     * @inheritdoc
313
     */
314
    public function getName()
315
    {
316
        return 'cmen_google_charts_extension';
317
    }
318
}
319