~xibo-maintainers/xibo/tempel

428.1.10 by Dan Garner
Namespaced Modules
1
<?php
2
/*
3
 * Xibo - Digital Signage - http://www.xibo.org.uk
4
 * Copyright (C) 2006-2015 Daniel Garner
5
 *
6
 * This file is part of Xibo.
7
 *
8
 * Xibo is free software: you can redistribute it and/or modify
9
 * it under the terms of the GNU Affero General Public License as published by
10
 * the Free Software Foundation, either version 3 of the License, or
11
 * any later version. 
12
 *
13
 * Xibo is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 * GNU Affero General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU Affero General Public License
19
 * along with Xibo.  If not, see <http://www.gnu.org/licenses/>.
20
 *
21
 */
22
namespace Xibo\Widget;
428.1.45 by Dan Garner
Module Installation Routines
23
454.1.107 by Dan Garner
Switched to Guzzle
24
use GuzzleHttp\Client;
25
use GuzzleHttp\Exception\RequestException;
428.1.45 by Dan Garner
Module Installation Routines
26
use Xibo\Entity\Media;
428.1.57 by Dan Garner
Convert forecastio
27
use Xibo\Exception\NotFoundException;
28
use Xibo\Factory\DisplayFactory;
428.1.45 by Dan Garner
Module Installation Routines
29
use Xibo\Factory\MediaFactory;
428.1.10 by Dan Garner
Namespaced Modules
30
use Xibo\Helper\Cache;
31
use Xibo\Helper\Config;
32
use Xibo\Helper\Date;
33
use Xibo\Helper\Log;
428.1.46 by Dan Garner
Module Settings Form (tested with ForecastIO).
34
use Xibo\Helper\Sanitize;
428.1.10 by Dan Garner
Namespaced Modules
35
use Xibo\Helper\Theme;
36
454.1.87 by Dan Garner
Rename Widget\Module to Widget\ModuleWidget to prevent name already in use.
37
class ForecastIo extends ModuleWidget
428.1.10 by Dan Garner
Namespaced Modules
38
{
428.1.40 by Dan Garner
Get theme's working again, including the option to override Twig Views.
39
    const API_ENDPOINT = 'https://api.forecast.io/forecast/';
40
441.1.6 by Dan Garner
Maintenance Script.
41
    private $resourceFolder;
428.1.45 by Dan Garner
Module Installation Routines
42
    protected $codeSchemaVersion = 1;
428.1.10 by Dan Garner
Namespaced Modules
43
441.1.6 by Dan Garner
Maintenance Script.
44
    public function __construct()
45
    {
46
        $this->resourceFolder = PROJECT_ROOT . '/web/modules/forecastio';
447.1.3 by Dan Garner
Fix forecast module forms.
47
48
        parent::__construct();
441.1.6 by Dan Garner
Maintenance Script.
49
    }
50
428.1.10 by Dan Garner
Namespaced Modules
51
    /**
52
     * Install or Update this module
53
     */
428.1.45 by Dan Garner
Module Installation Routines
54
    public function installOrUpdate()
428.1.10 by Dan Garner
Namespaced Modules
55
    {
428.1.45 by Dan Garner
Module Installation Routines
56
        if ($this->module == null) {
428.1.10 by Dan Garner
Namespaced Modules
57
            // Install
428.1.45 by Dan Garner
Module Installation Routines
58
            $module = new \Xibo\Entity\Module();
59
            $module->name = 'Forecast IO';
60
            $module->type = 'forecastio';
454.1.59 by Dan Garner
Supplied Class name on Module table to load in Widget classes correctly
61
            $module->class = 'Xibo\Widget\ForecastIo';
428.1.45 by Dan Garner
Module Installation Routines
62
            $module->description = 'Weather forecasting from Forecast IO';
63
            $module->imageUri = 'forms/library.gif';
64
            $module->enabled = 1;
65
            $module->previewEnabled = 1;
66
            $module->assignable = 1;
67
            $module->regionSpecific = 1;
68
            $module->renderAs = 'html';
69
            $module->schemaVersion = $this->codeSchemaVersion;
70
            $module->settings = [];
454.4.111 by Dan Garner
Complete implementation of "set duration" on all forms.
71
            $module->defaultDuration = 60;
428.1.45 by Dan Garner
Module Installation Routines
72
73
            $this->setModule($module);
74
            $this->installModule();
428.1.10 by Dan Garner
Namespaced Modules
75
        }
76
77
        // Check we are all installed
428.1.45 by Dan Garner
Module Installation Routines
78
        $this->installFiles();
79
    }
80
81
    public function installFiles()
82
    {
454.4.41 by Dan Garner
FQP for creating module system files.
83
        MediaFactory::createModuleSystemFile(PROJECT_ROOT . '/web/modules/vendor/jquery-1.11.1.min.js')->save();
84
        MediaFactory::createModuleSystemFile(PROJECT_ROOT . '/web/modules/xibo-layout-scaler.js')->save();
428.1.45 by Dan Garner
Module Installation Routines
85
86
        foreach (MediaFactory::createModuleFileFromFolder($this->resourceFolder) as $media) {
87
            /* @var Media $media */
88
            $media->save();
89
        }
428.1.10 by Dan Garner
Namespaced Modules
90
    }
91
92
    /**
93
     * Form for updating the module settings
94
     */
428.1.45 by Dan Garner
Module Installation Routines
95
    public function settingsForm()
428.1.10 by Dan Garner
Namespaced Modules
96
    {
428.1.46 by Dan Garner
Module Settings Form (tested with ForecastIO).
97
        return 'forecastio-form-settings';
428.1.10 by Dan Garner
Namespaced Modules
98
    }
99
100
    /**
101
     * Process any module settings
102
     */
428.1.45 by Dan Garner
Module Installation Routines
103
    public function settings()
428.1.10 by Dan Garner
Namespaced Modules
104
    {
105
        // Process any module settings you asked for.
428.1.46 by Dan Garner
Module Settings Form (tested with ForecastIO).
106
        $apiKey = Sanitize::getString('apiKey');
428.1.10 by Dan Garner
Namespaced Modules
107
108
        if ($apiKey == '')
428.1.46 by Dan Garner
Module Settings Form (tested with ForecastIO).
109
            throw new \InvalidArgumentException(__('Missing API Key'));
428.1.10 by Dan Garner
Namespaced Modules
110
111
        $this->module->settings['apiKey'] = $apiKey;
428.1.46 by Dan Garner
Module Settings Form (tested with ForecastIO).
112
        $this->module->settings['cachePeriod'] = Sanitize::getInt('cachePeriod', 300);
428.1.10 by Dan Garner
Namespaced Modules
113
    }
114
115
    /**
116
     * Loads templates for this module
117
     */
447.1.3 by Dan Garner
Fix forecast module forms.
118
    private function loadTemplates()
428.1.10 by Dan Garner
Namespaced Modules
119
    {
120
        // Scan the folder for template files
447.1.4 by Dan Garner
Fix twitter module forms.
121
        foreach (glob(PROJECT_ROOT . '/modules/forecastio/*.template.json') as $template) {
428.1.10 by Dan Garner
Namespaced Modules
122
            // Read the contents, json_decode and add to the array
123
            $this->module->settings['templates'][] = json_decode(file_get_contents($template), true);
124
        }
125
126
        Log::debug(count($this->module->settings['templates']));
127
    }
128
129
    /**
447.1.3 by Dan Garner
Fix forecast module forms.
130
     * Templates available
131
     * @return array
132
     */
133
    public function templatesAvailable()
134
    {
135
        if (!isset($this->module->settings['templates']))
136
            $this->loadTemplates();
137
138
        return $this->module->settings['templates'];
139
    }
140
454.1.56 by Dan Garner
Set the date locale correctly for localized dates (responding to language parameter in config). Unfortunately they character encoding is messed up on the short date....
141
    public function validate()
142
    {
454.4.111 by Dan Garner
Complete implementation of "set duration" on all forms.
143
        if ($this->getUseDuration() == 1 && $this->getDuration() == 0)
454.1.56 by Dan Garner
Set the date locale correctly for localized dates (responding to language parameter in config). Unfortunately they character encoding is messed up on the short date....
144
            throw new \InvalidArgumentException(__('Please enter a duration'));
145
    }
146
447.1.3 by Dan Garner
Fix forecast module forms.
147
    /**
428.1.10 by Dan Garner
Namespaced Modules
148
     * Add Media to the Database
149
     */
428.1.45 by Dan Garner
Module Installation Routines
150
    public function add()
428.1.10 by Dan Garner
Namespaced Modules
151
    {
428.1.57 by Dan Garner
Convert forecastio
152
        $this->setDuration(Sanitize::getInt('duration', $this->getDuration()));
454.4.111 by Dan Garner
Complete implementation of "set duration" on all forms.
153
        $this->setUseDuration(Sanitize::getCheckbox('useDuration'));
428.1.57 by Dan Garner
Convert forecastio
154
        $this->setOption('name', Sanitize::getString('name'));
155
        $this->setOption('useDisplayLocation', Sanitize::getCheckbox('useDisplayLocation'));
156
        $this->setOption('color', Sanitize::getString('color'));
157
        $this->setOption('longitude', Sanitize::getDouble('longitude'));
158
        $this->setOption('latitude', Sanitize::getDouble('latitude'));
447.1.3 by Dan Garner
Fix forecast module forms.
159
        $this->setOption('templateId', Sanitize::getString('templateId'));
428.1.57 by Dan Garner
Convert forecastio
160
        $this->setOption('icons', Sanitize::getString('icons'));
161
        $this->setOption('overrideTemplate', Sanitize::getCheckbox('overrideTemplate'));
162
        $this->setOption('size', Sanitize::getInt('size'));
163
        $this->setOption('units', Sanitize::getString('units'));
164
        $this->setOption('updateInterval', Sanitize::getInt('updateInterval', 60));
165
        $this->setOption('lang', Sanitize::getString('lang'));
166
        $this->setOption('dayConditionsOnly', Sanitize::getCheckbox('dayConditionsOnly'));
167
168
        $this->setRawNode('styleSheet', Sanitize::getParam('styleSheet', null));
169
        $this->setRawNode('currentTemplate', Sanitize::getParam('currentTemplate', null));
170
        $this->setRawNode('dailyTemplate', Sanitize::getParam('dailyTemplate', null));
428.1.10 by Dan Garner
Namespaced Modules
171
172
        // Save the widget
454.1.56 by Dan Garner
Set the date locale correctly for localized dates (responding to language parameter in config). Unfortunately they character encoding is messed up on the short date....
173
        $this->validate();
428.1.10 by Dan Garner
Namespaced Modules
174
        $this->saveWidget();
175
    }
176
177
    /**
178
     * Edit Media in the Database
179
     */
428.1.45 by Dan Garner
Module Installation Routines
180
    public function edit()
428.1.10 by Dan Garner
Namespaced Modules
181
    {
428.1.57 by Dan Garner
Convert forecastio
182
        $this->setDuration(Sanitize::getInt('duration', $this->getDuration()));
454.4.111 by Dan Garner
Complete implementation of "set duration" on all forms.
183
        $this->setUseDuration(Sanitize::getCheckbox('useDuration'));
428.1.57 by Dan Garner
Convert forecastio
184
        $this->setOption('name', Sanitize::getString('name'));
185
        $this->setOption('useDisplayLocation', Sanitize::getCheckbox('useDisplayLocation'));
186
        $this->setOption('color', Sanitize::getString('color'));
187
        $this->setOption('longitude', Sanitize::getDouble('longitude'));
188
        $this->setOption('latitude', Sanitize::getDouble('latitude'));
447.1.3 by Dan Garner
Fix forecast module forms.
189
        $this->setOption('templateId', Sanitize::getString('templateId'));
428.1.57 by Dan Garner
Convert forecastio
190
        $this->setOption('icons', Sanitize::getString('icons'));
191
        $this->setOption('overrideTemplate', Sanitize::getCheckbox('overrideTemplate'));
192
        $this->setOption('size', Sanitize::getInt('size'));
193
        $this->setOption('units', Sanitize::getString('units'));
194
        $this->setOption('updateInterval', Sanitize::getInt('updateInterval', 60));
195
        $this->setOption('lang', Sanitize::getString('lang'));
196
        $this->setOption('dayConditionsOnly', Sanitize::getCheckbox('dayConditionsOnly'));
197
198
        $this->setRawNode('styleSheet', Sanitize::getParam('styleSheet', null));
199
        $this->setRawNode('currentTemplate', Sanitize::getParam('currentTemplate', null));
200
        $this->setRawNode('dailyTemplate', Sanitize::getParam('dailyTemplate', null));
428.1.10 by Dan Garner
Namespaced Modules
201
202
        // Save the widget
454.1.56 by Dan Garner
Set the date locale correctly for localized dates (responding to language parameter in config). Unfortunately they character encoding is messed up on the short date....
203
        $this->validate();
428.1.10 by Dan Garner
Namespaced Modules
204
        $this->saveWidget();
428.1.56 by Dan Garner
Add module tab route. Fix disappearing user after edit.
205
    }
206
207
    public function iconsAvailable()
428.1.10 by Dan Garner
Namespaced Modules
208
    {
209
        // Scan the forecast io folder for icons
210
        $icons = array();
211
212
        foreach (array_diff(scandir($this->resourceFolder), array('..', '.')) as $file) {
213
            if (stripos($file, '.png'))
214
                $icons[] = array('id' => $file, 'value' => ucfirst(str_replace('-', ' ', str_replace('.png', '', $file))));
215
        }
216
217
        return $icons;
218
    }
219
220
    /**
221
     * Units supported by Forecast.IO API
222
     * @return array The Units Available
223
     */
428.1.56 by Dan Garner
Add module tab route. Fix disappearing user after edit.
224
    public function unitsAvailable()
428.1.10 by Dan Garner
Namespaced Modules
225
    {
226
        return array(
227
            array('id' => 'auto', 'value' => 'Automatically select based on geographic location', 'tempUnit' => ''),
228
            array('id' => 'ca', 'value' => 'Canada', 'tempUnit' => 'F'),
229
            array('id' => 'si', 'value' => 'Standard International Units', 'tempUnit' => 'C'),
230
            array('id' => 'uk', 'value' => 'United Kingdom', 'tempUnit' => 'C'),
231
            array('id' => 'us', 'value' => 'United States', 'tempUnit' => 'F'),
232
        );
233
    }
234
235
    /**
236
     * Languages supported by Forecast.IO API
237
     * @return array The Supported Language
238
     */
428.1.56 by Dan Garner
Add module tab route. Fix disappearing user after edit.
239
    public function supportedLanguages()
428.1.10 by Dan Garner
Namespaced Modules
240
    {
241
        return array(
242
            array('id' => 'en', 'value' => __('English')),
243
            array('id' => 'bs', 'value' => __('Bosnian')),
244
            array('id' => 'de', 'value' => __('German')),
245
            array('id' => 'es', 'value' => __('Spanish')),
246
            array('id' => 'fr', 'value' => __('French')),
247
            array('id' => 'it', 'value' => __('Italian')),
248
            array('id' => 'nl', 'value' => __('Dutch')),
249
            array('id' => 'pl', 'value' => __('Polish')),
250
            array('id' => 'pt', 'value' => __('Portuguese')),
251
            array('id' => 'ru', 'value' => __('Russian')),
252
            array('id' => 'tet', 'value' => __('Tetum')),
454.1.111 by Dan Garner
Turkish support for ForecastIO
253
            array('id' => 'tr', 'value' => __('Turkish')),
428.1.10 by Dan Garner
Namespaced Modules
254
            array('id' => 'x-pig-latin', 'value' => __('lgpay Atinlay'))
255
        );
256
    }
257
428.1.57 by Dan Garner
Convert forecastio
258
    /**
259
     * Get Tab
260
     */
261
    public function getTab($tab)
428.1.10 by Dan Garner
Namespaced Modules
262
    {
263
        if (!$data = $this->getForecastData(0))
428.1.57 by Dan Garner
Convert forecastio
264
            throw new NotFoundException(__('No data returned, please check error log.'));
428.1.10 by Dan Garner
Namespaced Modules
265
266
        $rows = array();
267
        foreach ($data['currently'] as $key => $value) {
268
            if (stripos($key, 'time')) {
269
                $value = Date::getLocalDate($value);
270
            }
271
272
            $rows[] = array('forecast' => __('Current'), 'key' => $key, 'value' => $value);
273
        }
274
275
        foreach ($data['daily']['data'][0] as $key => $value) {
276
            if (stripos($key, 'time')) {
277
                $value = Date::getLocalDate($value);
278
            }
279
280
            $rows[] = array('forecast' => __('Daily'), 'key' => $key, 'value' => $value);
281
        }
282
428.1.57 by Dan Garner
Convert forecastio
283
        return ['forecast' => $rows];
428.1.10 by Dan Garner
Namespaced Modules
284
    }
285
428.1.57 by Dan Garner
Convert forecastio
286
    /**
287
     * Get the forecast data for the provided display id
288
     * @param int $displayId
289
     * @return array
290
     */
428.1.10 by Dan Garner
Namespaced Modules
291
    private function getForecastData($displayId)
292
    {
428.1.57 by Dan Garner
Convert forecastio
293
        $defaultLat = Config::getSetting('DEFAULT_LAT');
294
        $defaultLong = Config::getSetting('DEFAULT_LONG');
428.1.10 by Dan Garner
Namespaced Modules
295
454.1.56 by Dan Garner
Set the date locale correctly for localized dates (responding to language parameter in config). Unfortunately they character encoding is messed up on the short date....
296
        if ($this->getOption('useDisplayLocation') == 1) {
428.1.10 by Dan Garner
Namespaced Modules
297
            // Use the display ID or the default.
298
            if ($displayId != 0) {
299
428.1.57 by Dan Garner
Convert forecastio
300
                $display = DisplayFactory::getById($displayId);
428.1.10 by Dan Garner
Namespaced Modules
301
                $defaultLat = $display->latitude;
302
                $defaultLong = $display->longitude;
303
            }
304
        } else {
454.1.56 by Dan Garner
Set the date locale correctly for localized dates (responding to language parameter in config). Unfortunately they character encoding is messed up on the short date....
305
            $defaultLat = $this->getOption('latitude', $defaultLat);
306
            $defaultLong = $this->getOption('longitude', $defaultLong);
428.1.10 by Dan Garner
Namespaced Modules
307
        }
308
428.1.57 by Dan Garner
Convert forecastio
309
        $apiKey = $this->getSetting('apiKey');
428.1.10 by Dan Garner
Namespaced Modules
310
        if ($apiKey == '')
311
            die(__('Incorrectly configured module'));
312
313
        // Query the API and Dump the Results.
454.1.56 by Dan Garner
Set the date locale correctly for localized dates (responding to language parameter in config). Unfortunately they character encoding is messed up on the short date....
314
        $apiOptions = array('units' => $this->getOption('units', 'auto'), 'lang' => $this->getOption('lang', 'en'), 'exclude' => 'flags,minutely,hourly');
428.1.10 by Dan Garner
Namespaced Modules
315
        $key = md5($defaultLat . $defaultLong . 'null' . implode('.', $apiOptions));
316
317
        if (!Cache::has($key)) {
318
            Log::notice('Getting Forecast from the API', $this->getModuleType(), __FUNCTION__);
428.1.40 by Dan Garner
Get theme's working again, including the option to override Twig Views.
319
            if (!$data = $this->get($defaultLat, $defaultLong, null, $apiOptions)) {
428.1.10 by Dan Garner
Namespaced Modules
320
                return false;
321
            }
322
323
            // If the response is empty, cache it for less time
428.1.57 by Dan Garner
Convert forecastio
324
            $cacheDuration = $this->getSetting('cachePeriod');
428.1.10 by Dan Garner
Namespaced Modules
325
326
            // Cache
327
            Cache::put($key, $data, $cacheDuration);
328
        } else {
329
            Log::notice('Getting Forecast from the Cache with key: ' . $key, $this->getModuleType(), __FUNCTION__);
330
            $data = Cache::get($key);
331
        }
332
333
        //Debug::Audit('Data: ' . var_export($data, true));
334
335
        // Icon Mappings
336
        $icons = array(
337
            'unmapped' => 'wi-alien',
338
            'clear-day' => 'wi-day-sunny',
339
            'clear-night' => 'wi-night-clear',
340
            'rain' => 'wi-rain',
341
            'snow' => 'wi-snow',
342
            'sleet' => 'wi-hail',
343
            'wind' => 'wi-windy',
344
            'fog' => 'wi-fog',
345
            'cloudy' => 'wi-cloudy',
346
            'partly-cloudy-day' => 'wi-day-cloudy',
347
            'partly-cloudy-night' => 'wi-night-partly-cloudy',
348
        );
349
350
        // Temperature Unit Mappings
351
        $temperatureUnit = '';
352
        foreach ($this->unitsAvailable() as $unit) {
454.1.56 by Dan Garner
Set the date locale correctly for localized dates (responding to language parameter in config). Unfortunately they character encoding is messed up on the short date....
353
            if ($unit['id'] == $this->getOption('units', 'auto')) {
428.1.10 by Dan Garner
Namespaced Modules
354
                $temperatureUnit = $unit['tempUnit'];
355
                break;
356
            }
357
        }
358
359
        // Are we set to only show daytime weather conditions?
454.1.56 by Dan Garner
Set the date locale correctly for localized dates (responding to language parameter in config). Unfortunately they character encoding is messed up on the short date....
360
        if ($this->getOption('dayConditionsOnly') == 1) {
428.1.10 by Dan Garner
Namespaced Modules
361
            if ($data->currently->icon == 'partly-cloudy-night')
362
                $data->currently->icon = 'clear-day';
363
        }
364
365
        $data->currently->wicon = (isset($icons[$data->currently->icon]) ? $icons[$data->currently->icon] : $icons['unmapped']);
366
        $data->currently->temperatureFloor = (isset($data->currently->temperature) ? floor($data->currently->temperature) : '--');
367
        $data->currently->summary = (isset($data->currently->summary) ? $data->currently->summary : '--');
368
        $data->currently->weekSummary = (isset($data->daily->summary) ? $data->daily->summary : '--');
369
        $data->currently->temperatureUnit = $temperatureUnit;
370
371
        // Convert a stdObject to an array
372
        $data = json_decode(json_encode($data), true);
373
374
        // Process the icon for each day
375
        for ($i = 0; $i < 7; $i++) {
376
            // Are we set to only show daytime weather conditions?
454.1.56 by Dan Garner
Set the date locale correctly for localized dates (responding to language parameter in config). Unfortunately they character encoding is messed up on the short date....
377
            if ($this->getOption('dayConditionsOnly') == 1) {
428.1.10 by Dan Garner
Namespaced Modules
378
                if ($data['daily']['data'][$i]['icon'] == 'partly-cloudy-night')
379
                    $data['daily']['data'][$i]['icon'] = 'clear-day';
380
            }
381
382
            $data['daily']['data'][$i]['wicon'] = (isset($icons[$data['daily']['data'][$i]['icon']]) ? $icons[$data['daily']['data'][$i]['icon']] : $icons['unmapped']);
383
            $data['daily']['data'][$i]['temperatureMaxFloor'] = (isset($data['daily']['data'][$i]['temperatureMax'])) ? floor($data['daily']['data'][$i]['temperatureMax']) : '--';
384
            $data['daily']['data'][$i]['temperatureMinFloor'] = (isset($data['daily']['data'][$i]['temperatureMin'])) ? floor($data['daily']['data'][$i]['temperatureMin']) : '--';
385
            $data['daily']['data'][$i]['temperatureFloor'] = ($data['daily']['data'][$i]['temperatureMinFloor'] != '--' && $data['daily']['data'][$i]['temperatureMaxFloor'] != '--') ? floor((($data['daily']['data'][$i]['temperatureMinFloor'] + $data['daily']['data'][$i]['temperatureMaxFloor']) / 2)) : '--';
386
            $data['daily']['data'][$i]['temperatureUnit'] = $temperatureUnit;
387
        }
388
389
        return $data;
390
    }
391
392
    private function makeSubstitutions($data, $source)
393
    {
394
        // Replace all matches.
395
        $matches = '';
396
        preg_match_all('/\[.*?\]/', $source, $matches);
397
398
        // Substitute
399
        foreach ($matches[0] as $sub) {
400
            $replace = str_replace('[', '', str_replace(']', '', $sub));
401
402
            // Handling for date/time
403
            if (stripos($replace, 'time|') > -1) {
404
                $timeSplit = explode('|', $replace);
405
406
                $time = Date::getLocalDate($data['time'], $timeSplit[1]);
407
454.1.56 by Dan Garner
Set the date locale correctly for localized dates (responding to language parameter in config). Unfortunately they character encoding is messed up on the short date....
408
                Log::info('Time: ' . $time);
409
428.1.10 by Dan Garner
Namespaced Modules
410
                // Pull time out of the array
411
                $source = str_replace($sub, $time, $source);
412
            } else {
413
                // Match that in the array
414
                if (isset($data[$replace]))
415
                    $source = str_replace($sub, $data[$replace], $source);
416
            }
417
        }
418
419
        return $source;
420
    }
421
422
    /**
423
     * Get Resource
424
     * @param int $displayId
425
     * @return mixed
426
     */
428.1.57 by Dan Garner
Convert forecastio
427
    public function getResource($displayId = 0)
428.1.10 by Dan Garner
Namespaced Modules
428
    {
429
        // Behave exactly like the client.
447.1.3 by Dan Garner
Fix forecast module forms.
430
        if (!$foreCast = $this->getForecastData($displayId))
428.1.10 by Dan Garner
Namespaced Modules
431
            return '';
432
454.1.56 by Dan Garner
Set the date locale correctly for localized dates (responding to language parameter in config). Unfortunately they character encoding is messed up on the short date....
433
        // Do we need to override the language?
454.1.57 by Dan Garner
Set the date locale correctly for localized dates (responding to language parameter in config). Unfortunately they character encoding is messed up on the short date....
434
        // TODO: I don't like this date fix, the library should really check the file exists?
435
        if ($this->getOption('lang', 'en') != 'en' && file_exists(PROJECT_ROOT . '/vendor/jenssegers/date/src/Lang/' . $this->getOption('lang') . '.php')) {
454.1.56 by Dan Garner
Set the date locale correctly for localized dates (responding to language parameter in config). Unfortunately they character encoding is messed up on the short date....
436
            \Jenssegers\Date\Date::setLocale($this->getOption('lang'));
437
        }
438
428.1.57 by Dan Garner
Convert forecastio
439
        $data = [];
440
        $isPreview = (Sanitize::getCheckbox('preview') == 1);
441
442
        // Replace the View Port Width?
443
        $data['viewPortWidth'] = ($isPreview) ? $this->region->width : '[[ViewPortWidth]]';
444
428.1.10 by Dan Garner
Namespaced Modules
445
        $headContent = '
428.1.60 by Dan Garner
Convert text module. Missing displayGroup route.
446
            <link href="' . $this->getResourceUrl('forecastio/weather-icons.min.css') . '" rel="stylesheet" media="screen">
428.1.10 by Dan Garner
Namespaced Modules
447
            <style type="text/css">
454.1.56 by Dan Garner
Set the date locale correctly for localized dates (responding to language parameter in config). Unfortunately they character encoding is messed up on the short date....
448
                .container { color: ' . $this->getOption('color', '000') . '; }
449
                #content { zoom: ' . $this->getOption('size', 1) . '; }
454.4.14 by Dan Garner
Parse Library references in modules with templates that don't current do it
450
                ' . $this->parseLibraryReferences($isPreview, $this->getRawNode('styleSheet', null)) . '
428.1.10 by Dan Garner
Namespaced Modules
451
            </style>
452
        ';
453
454
        // Add our fonts.css file
454.4.46 by Dan Garner
Fixed font reference in generated fonts.css and provided a way to regenerate from module settings.
455
        $headContent .= '<link href="' . $this->getResourceUrl('fonts.css') . '" rel="stylesheet" media="screen">';
428.1.42 by Dan Garner
Embedded Module Conversion
456
        $headContent .= '<style type="text/css">' . file_get_contents(Theme::uri('css/client.css', true)) . '</style>';
428.1.10 by Dan Garner
Namespaced Modules
457
428.1.57 by Dan Garner
Convert forecastio
458
        // Replace any icon sets
454.1.56 by Dan Garner
Set the date locale correctly for localized dates (responding to language parameter in config). Unfortunately they character encoding is messed up on the short date....
459
        $data['head'] = str_replace('[[ICONS]]', $this->getResourceUrl('forecastio/' . $this->getOption('icons')), $headContent);
428.1.10 by Dan Garner
Namespaced Modules
460
461
        // Make some body content
454.4.14 by Dan Garner
Parse Library references in modules with templates that don't current do it
462
        $body = $this->parseLibraryReferences($isPreview, $this->getRawNode('currentTemplate', null));
463
        $dailyTemplate = $this->parseLibraryReferences($isPreview, $this->getRawNode('dailyTemplate', null));
428.1.10 by Dan Garner
Namespaced Modules
464
465
        // Handle the daily template (if its here)
466
        if (stripos($body, '[dailyForecast]')) {
467
            // Pull it out, and run substitute over it for each day
468
            $dailySubs = '';
469
            // Substitute for every day (i.e. 7 times).
470
            for ($i = 0; $i < 7; $i++) {
447.1.3 by Dan Garner
Fix forecast module forms.
471
                $dailySubs .= $this->makeSubstitutions($foreCast['daily']['data'][$i], $dailyTemplate);
428.1.10 by Dan Garner
Namespaced Modules
472
            }
473
474
            // Substitute the completed template
475
            $body = str_replace('[dailyForecast]', $dailySubs, $body);
476
        }
477
478
        // Run replace over the main template
447.1.3 by Dan Garner
Fix forecast module forms.
479
        $data['body'] = $this->makeSubstitutions($foreCast['currently'], $body);
428.1.10 by Dan Garner
Namespaced Modules
480
481
482
        // JavaScript to control the size (override the original width and height so that the widget gets blown up )
483
        $options = array(
428.1.42 by Dan Garner
Embedded Module Conversion
484
            'previewWidth' => Sanitize::getDouble('width', 0),
485
            'previewHeight' => Sanitize::getDouble('height', 0),
428.1.10 by Dan Garner
Namespaced Modules
486
            'originalWidth' => $this->region->width,
487
            'originalHeight' => $this->region->height,
428.1.42 by Dan Garner
Embedded Module Conversion
488
            'scaleOverride' => Sanitize::getDouble('scale_override', 0)
428.1.10 by Dan Garner
Namespaced Modules
489
        );
490
428.1.42 by Dan Garner
Embedded Module Conversion
491
        $javaScriptContent = '<script type="text/javascript" src="' . $this->getResourceUrl('vendor/jquery-1.11.1.min.js') . '"></script>';
492
        $javaScriptContent .= '<script type="text/javascript" src="' . $this->getResourceUrl('xibo-layout-scaler.js') . '"></script>';
428.1.10 by Dan Garner
Namespaced Modules
493
        $javaScriptContent .= '<script>
494
495
            var options = ' . json_encode($options) . '
496
497
            $(document).ready(function() {
498
                $("body").xiboLayoutScaler(options);
499
            });
500
        </script>';
501
502
        // Replace the After body Content
428.1.42 by Dan Garner
Embedded Module Conversion
503
        $data['javaScript'] = $javaScriptContent;
428.1.10 by Dan Garner
Namespaced Modules
504
454.4.14 by Dan Garner
Parse Library references in modules with templates that don't current do it
505
        // Update and save widget if we've changed our assignments.
506
        if ($this->hasMediaChanged())
507
            $this->widget->save(['saveWidgetOptions' => false]);
508
428.1.10 by Dan Garner
Namespaced Modules
509
        // Return that content.
428.1.57 by Dan Garner
Convert forecastio
510
        return $this->renderTemplate($data);
511
    }
512
513
    public function isValid()
428.1.10 by Dan Garner
Namespaced Modules
514
    {
515
        // Using the information you have in your module calculate whether it is valid or not.
516
        // 0 = Invalid
517
        // 1 = Valid
518
        // 2 = Unknown
519
        return 1;
520
    }
428.1.40 by Dan Garner
Get theme's working again, including the option to override Twig Views.
521
454.1.107 by Dan Garner
Switched to Guzzle
522
    public function get($latitude, $longitude, $time = null, $options = array())
428.1.40 by Dan Garner
Get theme's working again, including the option to override Twig Views.
523
    {
524
        $request_url = self::API_ENDPOINT
525
            . '[APIKEY]'
526
            . '/'
527
            . $latitude
528
            . ','
529
            . $longitude
530
            . ((is_null($time)) ? '' : ','. $time);
531
532
        if (!empty($options)) {
533
            $request_url .= '?'. http_build_query($options);
534
        }
535
428.1.57 by Dan Garner
Convert forecastio
536
        Log::debug('Calling API with: ' . $request_url);
428.1.40 by Dan Garner
Get theme's working again, including the option to override Twig Views.
537
428.1.57 by Dan Garner
Convert forecastio
538
        $request_url = str_replace('[APIKEY]', $this->getSetting('apiKey'), $request_url);
428.1.40 by Dan Garner
Get theme's working again, including the option to override Twig Views.
539
454.1.107 by Dan Garner
Switched to Guzzle
540
        // Request
541
        $client = new Client();
542
543
        try {
454.1.171 by Dan Garner
Fix typo Guzzel to Guzzle
544
            $response = $client->get($request_url, Config::getGuzzleProxy(['connect_timeout' => 20]));
454.1.107 by Dan Garner
Switched to Guzzle
545
546
            // Success?
547
            if ($response->getStatusCode() != 200) {
548
                Log::error('ForecastIO API returned %d status. Unable to proceed. Headers = %s', $response->getStatusCode(), var_export($response->getHeaders(), true));
549
550
                // See if we can parse the error.
551
                $body = json_decode($response->getBody());
552
553
                Log::error('ForecastIO Error: ' . ((isset($body->errors[0])) ? $body->errors[0]->message : 'Unknown Error'));
554
555
                return false;
556
            }
557
558
            // Parse out header and body
559
            $body = json_decode($response->getBody());
560
561
            return $body;
562
        }
563
        catch (RequestException $e) {
564
            Log::error('Unable to reach Forecast API: %s', $e->getMessage());
565
            return false;
566
        }
428.1.40 by Dan Garner
Get theme's working again, including the option to override Twig Views.
567
    }
428.1.10 by Dan Garner
Namespaced Modules
568
}