Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 58
0.00% covered (danger)
0.00%
0 / 4
CRAP
0.00% covered (danger)
0.00%
0 / 1
ApiTrait
0.00% covered (danger)
0.00%
0 / 58
0.00% covered (danger)
0.00%
0 / 4
240
0.00% covered (danger)
0.00%
0 / 1
 onDispatch
0.00% covered (danger)
0.00%
0 / 13
0.00% covered (danger)
0.00%
0 / 1
6
 determineOutputMode
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
6
 isAccessDenied
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
6
 output
0.00% covered (danger)
0.00%
0 / 24
0.00% covered (danger)
0.00%
0 / 1
90
1<?php
2
3/**
4 * Additional functionality for API controllers.
5 *
6 * PHP version 8
7 *
8 * Copyright (C) The National Library 2015-2016.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2,
12 * as published by the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
22 *
23 * @category VuFind
24 * @package  Controller
25 * @author   Ere Maijala <ere.maijala@helsinki.fi>
26 * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
27 * @link     https://vufind.org/wiki/development:plugins:controllers Wiki
28 */
29
30namespace VuFindApi\Controller;
31
32use Exception;
33use Laminas\Http\Exception\InvalidArgumentException;
34use Laminas\Mvc\Exception\DomainException;
35
36/**
37 * Additional functionality for API controllers.
38 *
39 * @category VuFind
40 * @package  Controller
41 * @author   Ere Maijala <ere.maijala@helsinki.fi>
42 * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
43 * @link     https://vufind.org/wiki/development:plugins:controllers Wiki
44 */
45trait ApiTrait
46{
47    /**
48     * Callback function in JSONP mode
49     *
50     * @var string
51     */
52    protected $jsonpCallback = null;
53
54    /**
55     * Whether to pretty-print JSON
56     *
57     * @var bool
58     */
59    protected $jsonPrettyPrint = false;
60
61    /**
62     * Type of output to use
63     *
64     * @var string
65     */
66    protected $outputMode = 'json';
67
68    /**
69     * Execute the request
70     *
71     * @param \Laminas\Mvc\MvcEvent $e Event
72     *
73     * @return mixed
74     * @throws DomainException|InvalidArgumentException|Exception
75     */
76    public function onDispatch(\Laminas\Mvc\MvcEvent $e)
77    {
78        // Add CORS headers and handle OPTIONS requests. This is a simplistic
79        // approach since we allow any origin. For more complete CORS handling
80        // a module like zfr-cors could be used.
81        $response = $this->getResponse();
82        $headers = $response->getHeaders();
83        $headers->addHeaderLine('Access-Control-Allow-Origin: *');
84        $request = $this->getRequest();
85        if ($request->getMethod() == 'OPTIONS') {
86            // Disable session writes
87            $this->disableSessionWrites();
88            $headers->addHeaderLine(
89                'Access-Control-Allow-Methods',
90                'GET, POST, OPTIONS'
91            );
92            $headers->addHeaderLine('Access-Control-Max-Age', '86400');
93
94            return $this->output(null, 204);
95        }
96        return parent::onDispatch($e);
97    }
98
99    /**
100     * Determine the correct output mode based on content negotiation or the
101     * view parameter
102     *
103     * @return void
104     */
105    protected function determineOutputMode()
106    {
107        $request = $this->getRequest();
108        $this->jsonpCallback
109            = $request->getQuery('callback', $request->getPost('callback', null));
110        $this->jsonPrettyPrint = filter_var(
111            $request->getQuery(
112                'prettyPrint',
113                $request->getPost('prettyPrint', false)
114            ),
115            FILTER_VALIDATE_BOOLEAN
116        );
117        $this->outputMode = empty($this->jsonpCallback) ? 'json' : 'jsonp';
118    }
119
120    /**
121     * Check whether access is denied and return the appropriate message or false.
122     *
123     * @param string $permission Permission to check
124     *
125     * @return \Laminas\Http\Response|boolean
126     */
127    protected function isAccessDenied($permission)
128    {
129        $auth = $this->serviceLocator
130            ->get(\LmcRbacMvc\Service\AuthorizationService::class);
131        if (!$auth->isGranted($permission)) {
132            return $this->output(
133                [],
134                ApiInterface::STATUS_ERROR,
135                403,
136                'Permission denied'
137            );
138        }
139        return false;
140    }
141
142    /**
143     * Send output data and exit.
144     *
145     * @param mixed  $data     The response data
146     * @param string $status   Status of the request
147     * @param int    $httpCode A custom HTTP Status Code
148     * @param string $message  Status message
149     *
150     * @return \Laminas\Http\Response
151     * @throws Exception
152     */
153    protected function output($data, $status, $httpCode = null, $message = '')
154    {
155        $response = $this->getResponse();
156        $headers = $response->getHeaders();
157        if ($httpCode !== null) {
158            $response->setStatusCode($httpCode);
159        }
160        if (null === $data) {
161            return $response;
162        }
163        $output = $data;
164        if (!isset($output['status'])) {
165            $output['status'] = $status;
166        }
167        if ($message && !isset($output['statusMessage'])) {
168            $output['statusMessage'] = $message;
169        }
170        $jsonOptions = $this->jsonPrettyPrint ? JSON_PRETTY_PRINT : 0;
171        if ($this->outputMode == 'json') {
172            $headers->addHeaderLine('Content-type', 'application/json');
173            $response->setContent(json_encode($output, $jsonOptions));
174            return $response;
175        } elseif ($this->outputMode == 'jsonp') {
176            $headers->addHeaderLine('Content-type', 'application/javascript');
177            $response->setContent(
178                $this->jsonpCallback . '(' . json_encode($output, $jsonOptions)
179                . ');'
180            );
181            return $response;
182        } else {
183            throw new Exception('Invalid output mode');
184        }
185    }
186}