Completed
Push — master ( 759a3c...0a5dc9 )
by Mohamed
04:06
created

RestApiController   A

Complexity

Total Complexity 17

Size/Duplication

Total Lines 205
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 6

Test Coverage

Coverage 93.75%

Importance

Changes 5
Bugs 1 Features 0
Metric Value
wmc 17
c 5
b 1
f 0
lcom 1
cbo 6
dl 0
loc 205
ccs 60
cts 64
cp 0.9375
rs 10

5 Methods

Rating   Name   Duplication   Size   Complexity  
A getRequestFormat() 0 4 2
B getCardsAction() 0 36 4
B getCardAction() 0 35 4
B getCardsRandomAction() 0 28 4
A createResponse() 0 15 3
1
<?php
2
3
/*
4
 * This file is part of the Moo\FlashCardBundle package.
5
 *
6
 * (c) Mohamed Alsharaf <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Moo\FlashCardBundle\Controller;
13
14
use FOS\RestBundle;
15
use FOS\RestBundle\Controller\FOSRestController;
16
use Moo\FlashCardBundle\Response\RestResponse;
17
use Nelmio\ApiDocBundle\Annotation\ApiDoc;
18
use Symfony\Component\HttpFoundation\Request;
19
20
/**
21
 * RestApiController is the default REST API controller.
22
 *
23
 * @author Mohamed Alsharaf <[email protected]>
24
 */
25
class RestApiController extends FOSRestController
26
{
27
    /**
28
     * Returns a paginated list of cards.
29
     *
30
     * @ApiDoc(
31
     *  section="Public API (RESTful)",
32
     *  resource=true,
33
     *   statusCodes={
34
     *      200="Returned when successful",
35
     *      404="Returned when the cards are not found"
36
     *   },
37
     *   filters={
38
     *      {"name"="limit",    "dataType"="integer", "required"=false, "description"="Max number of cards to return."},
39
     *      {"name"="page",     "dataType"="integer", "required"=false, "description"="Page number."},
40
     *      {"name"="query",    "dataType"="string",  "required"=false, "description"="Limit result by query."},
41
     *      {"name"="category", "dataType"="integer", "required"=false, "description"="Limit result by a category ID."}
42
     *   }
43
     * )
44
     *
45
     * @param Request $request
46
     *
47
     * @return \Symfony\Component\HttpFoundation\Response
48
     */
49 3
    public function getCardsAction(Request $request)
50
    {
51 3
        $cardService = $this->get('moo_flashcard.card.repository');
52
53 3
        $data = $cardService->fetchCardsBy(
54
            [
55 3
                'query'    => $request->get('query', ''),
56 3
                'category' => $request->query->getInt('category', 0),
57
            ],
58 3
            $request->query->getInt('page', 1),
59 3
            $request->query->getInt('limit', 20)
60
        );
61 3
        $total = $data->getTotalItemCount();
62
63 3
        $response = $this->createResponse($data->getItems(), 'No flash cards found.');
64 3
        $response->extra = ['total' => $total];
65
66
        $view = $this
67 3
            ->view($response, $response->code)
68 3
            ->setTemplate('MooFlashCardBundle:Card:list.html.twig');
69
70 3
        if ('html' === $this->getRequestFormat($view, $request)) {
71 1
            $view->setData([
72 1
                'cards' => $response->content,
73
            ]);
74
        }
75
76 3
        $return = $this->handleView($view);
77
78
        // for html request, return the error message
79 3
        if (!$total && 'html' === $this->getRequestFormat($view, $request)) {
80 1
            return $return->setContent($response->errorMessage);
81
        }
82
83 3
        return $return;
84
    }
85
86
    /**
87
     * Search for a card.
88
     *
89
     * @ApiDoc(
90
     *  section="Public API (RESTful)",
91
     *  resource=true,
92
     *   statusCodes={
93
     *      200="Returned when successful",
94
     *      404="Returned when the card is not found"
95
     *   },
96
     *   filters={
97
     *      {"name"="query",     "dataType"="string",  "required"=false, "description"="Search query"},
98
     *      {"name"="pageLink",  "dataType"="boolean", "required"=false, "description"="To indicate whether to include a link to the card page (html format only)."},
99
     *      {"name"="shareLink", "dataType"="boolean", "required"=false, "description"="To indicate whether to include the share buttons (twitter & google+) (html format only)."},
100
     *      {"name"="popup",     "dataType"="boolean", "required"=false, "description"="To indicate whether to the html is to be displayed as a popup box. This will include 'popup class name and close button' (html format only)."}
101
     *   }
102
     * )
103
     *
104
     * @param Request $request
105
     *
106
     * @return \Symfony\Component\HttpFoundation\Response
107
     */
108 3
    public function getCardAction(Request $request)
109
    {
110 3
        $query = $request->get('query', '');
111 3
        $pageLink = (boolean) $request->query->getInt('pageLink', true);
0 ignored issues
show
Documentation introduced by
true is of type boolean, but the function expects a integer.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
112 3
        $shareLink = (boolean) $request->query->getInt('shareLink', true);
0 ignored issues
show
Documentation introduced by
true is of type boolean, but the function expects a integer.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
113 3
        $popup = (boolean) $request->query->getInt('popup', true);
0 ignored issues
show
Documentation introduced by
true is of type boolean, but the function expects a integer.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
114
115 3
        $cardService = $this->get('moo_flashcard.card.repository');
116 3
        $data = $cardService->searchForOne($query);
117
118 3
        $response = $this->createResponse($data, 'The flash card you are looking for does not exist.');
119
120
        $view = $this
121 3
            ->view($response, $response->code)
122 3
            ->setTemplate('MooFlashCardBundle:Card:details.html.twig');
123
124
        // FOSRestBundle, see https://github.com/FriendsOfSymfony/FOSRestBundle/issues/299
125 3
        if ('html' === $this->getRequestFormat($view, $request)) {
126 2
            $view->setData([
127 2
                'card'       => $data,
128 2
                'page_link'  => (boolean) $pageLink,
129 2
                'share_link' => (boolean) $shareLink,
130 2
                'popup'      => (boolean) $popup,
131
            ]);
132
        }
133
134 3
        $return = $this->handleView($view);
135
136
        // for html request, return the error message
137 3
        if (!$data && 'html' === $this->getRequestFormat($view, $request)) {
138 1
            return $return->setContent($response->errorMessage);
139
        }
140
141 3
        return $return;
142
    }
143
144
    /**
145
     * Returns a random selection of cards.
146
     *
147
     * @ApiDoc(
148
     *  section="Public API (RESTful)",
149
     *  resource=true,
150
     *   statusCodes={
151
     *      200="Returned when successful",
152
     *      404="Returned when the cards are not found"
153
     *   },
154
     *   filters={
155
     *      {"name"="limit",    "dataType"="integer", "required"=false, "description"="Max number of cards to return."}
156
     *   }
157
     * )
158
     *
159
     * @param Request $request
160
     *
161
     * @return \Symfony\Component\HttpFoundation\Response
162
     */
163 1
    public function getCardsRandomAction(Request $request)
164
    {
165 1
        $limit = $request->get('limit', 30);
166 1
        $cardService = $this->get('moo_flashcard.card.repository');
167 1
        $data = $cardService->fetchRadomCards($limit);
168
169 1
        $response = $this->createResponse($data, 'No flash cards found.');
170
171
        $view = $this
172 1
            ->view($response, $response->code)
173 1
            ->setTemplate('MooFlashCardBundle:Card:list.html.twig');
174
175
        // FOSRestBundle, see https://github.com/FriendsOfSymfony/FOSRestBundle/issues/299
176 1
        if ('html' === $this->getRequestFormat($view, $request)) {
177
            $view->setData([
178
                'cards' => $response->content,
179
            ]);
180
        }
181
182 1
        $return = $this->handleView($view);
183
184
        // for html request, return the error message
185 1
        if (!$data && 'html' === $this->getRequestFormat($view, $request)) {
186
            return $return->setContent($response->errorMessage);
187
        }
188
189 1
        return $return;
190
    }
191
192
    /**
193
     * Return request format 'e.g. html, json)
194
     *
195
     * @param RestBundle\View\View $view
196
     * @param Request              $request
197
     *
198
     * @return string
199
     */
200 7
    protected function getRequestFormat(RestBundle\View\View $view, Request $request)
201
    {
202 7
        return ($view->getFormat() ?: $request->getRequestFormat());
203
    }
204
205
    /**
206
     * Create the web service response
207
     *
208
     * @param array|null|object $content
209
     * @param string            $errorMessage
210
     * @param int               $code
211
     *
212
     * @return \Moo\FlashCardBundle\Response\RestResponse
213
     */
214 7
    protected function createResponse($content, $errorMessage = '', $code = null)
215
    {
216 7
        $response = new RestResponse();
217 7
        $response->content = $content;
0 ignored issues
show
Documentation Bug introduced by
It seems like $content can also be of type array or object. However, the property $content is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
218 7
        if (!$content) {
219 2
            $response->code = 404;
220 2
            $response->errorMessage = $errorMessage;
221
        }
222
223 7
        if (null !== $code) {
224
            $response->code = $code;
225
        }
226
227 7
        return $response;
228
    }
229
}
230