1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace CMEN\GoogleChartsBundle\Output\Javascript; |
4
|
|
|
|
5
|
|
|
use CMEN\GoogleChartsBundle\Exception\GoogleChartsException; |
6
|
|
|
use CMEN\GoogleChartsBundle\GoogleCharts\Chart; |
7
|
|
|
use CMEN\GoogleChartsBundle\GoogleCharts\Charts\Diff\DiffChart; |
8
|
|
|
use CMEN\GoogleChartsBundle\Output\AbstractChartOutput; |
9
|
|
|
use CMEN\GoogleChartsBundle\Output\DataOutputInterface; |
10
|
|
|
use CMEN\GoogleChartsBundle\Output\EventsOutputInterface; |
11
|
|
|
use CMEN\GoogleChartsBundle\Output\OptionsOutputInterface; |
12
|
|
|
|
13
|
|
|
/** |
14
|
|
|
* @author Christophe Meneses |
15
|
|
|
*/ |
16
|
|
|
class ChartOutput extends AbstractChartOutput |
17
|
|
|
{ |
18
|
|
|
/** @var OptionsOutputInterface */ |
19
|
|
|
private $optionsOutput; |
20
|
|
|
|
21
|
|
|
/** @var DataOutputInterface */ |
22
|
|
|
private $dataOutput; |
23
|
|
|
|
24
|
|
|
/** @var EventsOutputInterface */ |
25
|
|
|
private $eventsOutput; |
26
|
|
|
|
27
|
|
|
/** |
28
|
|
|
* ChartOutput constructor. |
29
|
|
|
* |
30
|
|
|
* @param string $version |
31
|
|
|
* @param string $language |
32
|
|
|
* @param OptionsOutputInterface $optionsOutput |
33
|
|
|
* @param DataOutputInterface $dataOutput |
34
|
|
|
* @param EventsOutputInterface $eventsOutput |
35
|
|
|
*/ |
36
|
|
|
public function __construct( |
37
|
|
|
$version, |
38
|
|
|
$language, |
39
|
|
|
OptionsOutputInterface $optionsOutput, |
40
|
|
|
DataOutputInterface $dataOutput, |
41
|
|
|
EventsOutputInterface $eventsOutput |
42
|
|
|
) { |
43
|
|
|
parent::__construct($version, $language); |
44
|
|
|
|
45
|
|
|
$this->optionsOutput = $optionsOutput; |
46
|
|
|
$this->dataOutput = $dataOutput; |
47
|
|
|
$this->eventsOutput = $eventsOutput; |
48
|
|
|
} |
49
|
|
|
|
50
|
|
|
/** |
51
|
|
|
* {@inheritdoc} |
52
|
|
|
*/ |
53
|
|
|
public function startChart(Chart $chart) |
54
|
|
|
{ |
55
|
|
|
if (null === $chart->getElementID()) { |
56
|
|
|
throw new GoogleChartsException('Container is not defined.'); |
57
|
|
|
} |
58
|
|
|
|
59
|
|
|
$js = 'var '.$chart->getName().' = new google.'.$chart->getLibrary().'.'.$chart->getType(). |
60
|
|
|
'(document.getElementById("'.$chart->getElementID().'"));'; |
61
|
|
|
|
62
|
|
|
if (!$chart instanceof DiffChart) { |
63
|
|
|
$js .= $this->dataOutput->draw($chart->getData(), $chart->getDataName()); |
64
|
|
|
} else { |
65
|
|
|
$js .= $this->dataOutput->draw($chart->getOldChart()->getData(), 'old_'.$chart->getDataName()). |
66
|
|
|
$this->dataOutput->draw($chart->getNewChart()->getData(), 'new_'.$chart->getDataName()). |
67
|
|
|
'var '.$chart->getDataName().' = '.$chart->getName(). |
68
|
|
|
'.computeDiff(old_'.$chart->getDataName().', |
69
|
|
|
new_'.$chart->getDataName().');'; |
70
|
|
|
} |
71
|
|
|
|
72
|
|
|
$js .= $this->optionsOutput->draw($chart->getOptions(), $chart->getOptionsName()); |
73
|
|
|
|
74
|
|
|
return $js; |
75
|
|
|
} |
76
|
|
|
|
77
|
|
|
/** |
78
|
|
|
* {@inheritdoc} |
79
|
|
|
*/ |
80
|
|
|
public function endChart(Chart $chart) |
81
|
|
|
{ |
82
|
|
|
if ('visualization' == $chart->getLibrary()) { |
83
|
|
|
$options = $chart->getOptionsName(); |
84
|
|
|
} else { |
85
|
|
|
/* Options conversion for material charts */ |
86
|
|
|
$options = 'google.'.$chart->getLibrary().'.'.$chart->getType(). |
87
|
|
|
'.convertOptions('.$chart->getOptionsName().')'; |
88
|
|
|
} |
89
|
|
|
|
90
|
|
|
return $this->eventsOutput->draw($chart->getEvents(), $chart->getName()).$chart->getName(). |
91
|
|
|
'.draw('.$chart->getDataName().', '.$options.');'; |
92
|
|
|
} |
93
|
|
|
|
94
|
|
|
/** |
95
|
|
|
* {@inheritdoc} |
96
|
|
|
*/ |
97
|
|
|
public function startCharts($charts, $elementsID = null) |
98
|
|
|
{ |
99
|
|
|
if ($charts instanceof Chart) { |
100
|
|
|
$charts = [$charts]; |
101
|
|
|
|
102
|
|
|
if ($elementsID) { |
103
|
|
|
if (!is_string($elementsID)) { |
104
|
|
|
throw new GoogleChartsException('A string is expected for HTML element ID.'); |
105
|
|
|
} |
106
|
|
|
|
107
|
|
|
$elementsID = [$elementsID]; |
108
|
|
|
} |
109
|
|
|
} elseif (is_array($charts) && !empty($charts)) { |
110
|
|
|
$this->checkChartsTypes($charts); |
111
|
|
|
|
112
|
|
|
if (null !== $elementsID) { |
113
|
|
|
$this->checkElementsId($charts, $elementsID); |
|
|
|
|
114
|
|
|
} |
115
|
|
|
} else { |
116
|
|
|
throw new GoogleChartsException('An instance of Chart or an array of Chart is expected.'); |
117
|
|
|
} |
118
|
|
|
|
119
|
|
|
$packages = []; |
120
|
|
|
$drawChartName = ''; |
121
|
|
|
for ($i = 0; $i < count($charts); ++$i) { |
|
|
|
|
122
|
|
|
if ($elementsID) { |
123
|
|
|
$charts[$i]->setElementID($elementsID[$i]); |
124
|
|
|
} |
125
|
|
|
|
126
|
|
|
if (!in_array($charts[$i]->getPackage(), $packages)) { |
127
|
|
|
$packages[] = $charts[$i]->getPackage(); |
128
|
|
|
} |
129
|
|
|
$drawChartName .= $charts[$i]->getElementID(); |
130
|
|
|
} |
131
|
|
|
|
132
|
|
|
$js = $this->loadLibraries($packages); |
133
|
|
|
|
134
|
|
|
$js .= $this->startCallback('drawChart'.ucfirst(md5($drawChartName))); |
135
|
|
|
|
136
|
|
|
foreach ($charts as $chart) { |
137
|
|
|
$js .= $this->startChart($chart); |
138
|
|
|
} |
139
|
|
|
|
140
|
|
|
return $js; |
141
|
|
|
} |
142
|
|
|
|
143
|
|
|
/** |
144
|
|
|
* {@inheritdoc} |
145
|
|
|
*/ |
146
|
|
|
public function endCharts($charts) |
147
|
|
|
{ |
148
|
|
|
if ($charts instanceof Chart) { |
149
|
|
|
$js = $this->endChart($charts).$this->endCallback(); |
150
|
|
|
} elseif (is_array($charts) && !empty($charts)) { |
151
|
|
|
$this->checkChartsTypes($charts); |
152
|
|
|
|
153
|
|
|
$js = ''; |
154
|
|
|
foreach ($charts as $chart) { |
155
|
|
|
$js .= $this->endChart($chart); |
156
|
|
|
} |
157
|
|
|
|
158
|
|
|
$js .= $this->endCallback(); |
159
|
|
|
} else { |
160
|
|
|
throw new GoogleChartsException('An instance of Chart or an array of Chart is expected.'); |
161
|
|
|
} |
162
|
|
|
|
163
|
|
|
return $js; |
164
|
|
|
} |
165
|
|
|
|
166
|
|
|
/** |
167
|
|
|
* {@inheritdoc} |
168
|
|
|
*/ |
169
|
|
|
public function fullCharts($charts, $elementsID = null) |
170
|
|
|
{ |
171
|
|
|
return $this->startCharts($charts, $elementsID).$this->endCharts($charts); |
172
|
|
|
} |
173
|
|
|
|
174
|
|
|
/** |
175
|
|
|
* {@inheritdoc} |
176
|
|
|
*/ |
177
|
|
|
public function loadLibraries($packages) |
178
|
|
|
{ |
179
|
|
|
array_walk($packages, function (&$item) { |
180
|
|
|
$item = "'".$item."'"; |
181
|
|
|
}); |
182
|
|
|
|
183
|
|
|
($this->language) ? $language = ", language: '".$this->language."'" : $language = ''; |
184
|
|
|
|
185
|
|
|
$load = "'".$this->version."', {packages:[".implode(',', $packages).']'.$language.'}'; |
186
|
|
|
|
187
|
|
|
return "google.charts.load($load);"; |
188
|
|
|
} |
189
|
|
|
|
190
|
|
|
/** |
191
|
|
|
* {@inheritdoc} |
192
|
|
|
*/ |
193
|
|
|
public function startCallback($name) |
194
|
|
|
{ |
195
|
|
|
return "google.charts.setOnLoadCallback($name); function $name() {"; |
196
|
|
|
} |
197
|
|
|
|
198
|
|
|
/** |
199
|
|
|
* {@inheritdoc} |
200
|
|
|
*/ |
201
|
|
|
public function endCallback() |
202
|
|
|
{ |
203
|
|
|
return '}'; |
204
|
|
|
} |
205
|
|
|
} |
206
|
|
|
|
This check looks at variables that have been passed in as parameters and are passed out again to other methods.
If the outgoing method call has stricter type requirements than the method itself, an issue is raised.
An additional type check may prevent trouble.