1<?php
2
3namespace ls\ajax;
4
5/**
6 * Ajax helper
7 * This class will help to standardize the Ajax communication
8 * between server and client.
9 * See the manual page for more info: https://manual.limesurvey.org/Backend_Ajax_protocol
10 *
11 * @since 2016-09-27
12 * @author Olle Härstedt
13 */
14class AjaxHelper
15{
16    /**
17     * As Yii createUrl, but appends param ajax = 1 to url
18     * Use when creating Ajax action links, like button clicks that
19     * will open modals or save data.
20     * @param string $route
21     * @param array $params
22     * @return string
23     */
24    public static function createUrl($route, array $params = array())
25    {
26        $params['ajax'] = 1;
27        return App()->createUrl($route, $params);
28    }
29    /**
30     * Echoes json with result set as $msg
31     * This is the custom json, that expects to be
32     * handled manually.
33     * @param string $msg message
34     * @return void
35     */
36    public static function output($msg)
37    {
38        $output = new JsonOutput($msg);
39        self::echoString($output); // Encoded to json format when converted to string
40    }
41
42    /**
43     * Success popup
44     * @param string $msg
45     * @return void
46     */
47    public static function outputSuccess($msg)
48    {
49        $output = new JsonOutputSuccess($msg);
50        self::echoString($output);
51    }
52
53    /**
54     * Error popup
55     * @param string $msg
56     * @param int $code
57     * @return void
58     */
59    public static function outputError($msg, $code = 0)
60    {
61        $output = new JsonOutputError($msg, $code);
62        self::echoString($output);
63    }
64
65    /**
66     * No permission popup
67     * @return void
68     */
69    public static function outputNoPermission()
70    {
71        $output = new JsonOutputNoPermission();
72        self::echoString($output);
73    }
74
75    /**
76     * @return void
77     */
78    public static function outputNotLoggedIn()
79    {
80        $output = new JsonOutputNotLoggedIn();
81        self::echoString($output);
82    }
83
84    /**
85     * @param string $target
86     * @return void
87     */
88    public static function outputHtml($html, $target)
89    {
90        $output = new JsonOutputHtml($html, $target);
91        self::echoString($output);
92    }
93
94    /**
95     * Echo $str with json header
96     * @param string $str
97     * @return void
98     */
99    private static function echoString($str)
100    {
101        header('Content-Type: application/json');
102        echo $str;
103        \Yii::app()->end();
104    }
105}
106
107/**
108 * Base class for json output
109 * @since 2016-09-27
110 * @author Olle Härstedt
111 */
112class JsonOutput
113{
114    /**
115     * @var mixed
116     */
117    public $result;
118
119    /**
120     * Array like array('code' => 123, 'message' => 'Something went wrong.')
121     * @var array|null
122     */
123    public $error;
124
125    /**
126     * Success message pop-up
127     * @var string|null
128     */
129    public $success;
130
131    /**
132     * True if user is logged in
133     * @var boolean
134     */
135    public $loggedIn;
136
137    /**
138     * True if user has permission
139     * @var boolean
140     */
141    public $hasPermission;
142
143    /**
144     * Translated text of 'No permission'
145     * @var string
146     */
147    public $noPermissionText;
148
149    /**
150     *
151     * @param string|null $result
152     */
153    public function __construct($result)
154    {
155        $this->result = $result;
156
157        // Defaults
158        $this->loggedIn = true;
159        $this->hasPermission = true;
160
161        // TODO: Check if user is logged in
162    }
163
164    /**
165     * @return string Json encoded object
166     */
167    public function __toString()
168    {
169        return json_encode(array(
170            'ajaxHelper'       => true, // To help JS parse in some cases.
171            'success'          => $this->success,
172            'result'           => $this->result,
173            'error'            => $this->error,
174            'loggedIn'         => $this->loggedIn,
175            'hasPermission'    => $this->hasPermission,
176            'noPermissionText' => gT('No permission')
177        ));
178    }
179}
180
181/**
182 * Permission set to false
183 * @since 2016-09-27
184 * @author Olle Härstedt
185 */
186class JsonOutputNoPermission extends JsonOutput
187{
188    public function __construct()
189    {
190        parent::__construct(null);
191        $this->hasPermission = false;
192    }
193}
194
195/**
196 * Set error in constructor, which will be
197 * shown as a pop-up on client.
198 * @since 2016-09-27
199 * @author Olle Härstedt
200 */
201class JsonOutputError extends JsonOutput
202{
203    /**
204     * @param string $msg
205     * @param int $code
206     * @return JsonOutputError
207     */
208    public function __construct($msg, $code = 0)
209    {
210        parent::__construct(null);
211        $this->error = array(
212            'message' => $msg,
213            'code' => $code
214        );
215    }
216}
217
218/**
219 * Set success message in constructor, which
220 * will be shown as a pop-up on client.
221 * @since 2016-09-27
222 * @author Olle Härstedt
223 */
224class JsonOutputSuccess extends JsonOutput
225{
226    /**
227     * @param string $msg
228     * @return JsonOutputError
229     */
230    public function __construct($msg)
231    {
232        parent::__construct(null);
233        $this->success = $msg;
234    }
235}
236
237/**
238 *
239 */
240class JsonOutputModal extends JsonOutput
241{
242
243    /**
244     * @var string
245     */
246    public $html;
247
248    /**
249     *
250     */
251    public function __construct($html)
252    {
253        parent::__construct(null);
254        $this->html = $html;
255    }
256
257    /**
258     *
259     * @return
260     */
261    public function __toString()
262    {
263        return json_encode(array(
264            'html' => $this->html,
265            'hasPermission' => $this->hasPermission,
266            'loggedIn' => $this->loggedIn
267        ));
268    }
269}
270
271/**
272 * Echo html for log in form modal body
273 * This is a special case of JsonOutputModal, but with fixed html
274 * Only used through JsonOutputNotLoggedIn in AdminController::run.
275 */
276class JsonOutputNotLoggedIn extends JsonOutputModal
277{
278    /**
279     *
280     */
281    public function __construct()
282    {
283        parent::__construct(null);
284
285        \Yii::import('application.controllers.admin.authentication', true);
286
287        // Return success, failure or template data
288        $result = \Authentication::prepareLogin();
289
290        // This should not be possible here
291        if (isset($result[0]) && $result[0] == 'success') {
292            throw new \CException('Internal error: login form submitted');
293        } else if (isset($result[0]) && $result[0] == 'failed') {
294            throw new \CException('Internal error: login form submitted');
295        }
296
297        $data = $result;
298        $this->html = \Yii::app()->getController()->renderPartial('/admin/authentication/ajaxLogin', $data, true);
299
300        $this->hasPermission = true;
301        $this->loggedIn = false;
302    }
303}
304
305/**
306 * Echo HTML and put it in a <div> with id $target.
307 */
308class JsonOutputHtml extends JsonOutput
309{
310
311    /**
312     * Content.
313     * @var string
314     */
315    public $html;
316
317    /**
318     * ID of element to put HTML in.
319     * @var string
320     */
321    public $target;
322
323    /**
324     * @param string $html
325     * @param string $target ID of element to put HTML in.
326     */
327    public function __construct($html, $target)
328    {
329        $this->html    = $html;
330        $this->target  = $target;
331    }
332
333    public function __toString()
334    {
335        return json_encode(
336            array(
337                'loggedIn'      => true,
338                'hasPermission' => true,
339                'success'       => true,
340                'html'          => $this->html,
341                'outputType'    => 'jsonoutputhtml',
342                'target'        => $this->target
343            )
344        );
345    }
346}
347