ComposerJsonController   A
last analyzed

Complexity

Total Complexity 6

Size/Duplication

Total Lines 145
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 6

Importance

Changes 5
Bugs 0 Features 0
Metric Value
wmc 6
lcom 1
cbo 6
dl 0
loc 145
rs 10
c 5
b 0
f 0

3 Methods

Rating   Name   Duplication   Size   Complexity  
A getComposerJsonAction() 0 4 1
B putComposerJsonAction() 0 24 3
B checkComposerJson() 0 27 2
1
<?php
2
3
/**
4
 * This file is part of tenside/core-bundle.
5
 *
6
 * (c) Christian Schiffler <[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
 * This project is provided in good faith and hope to be usable by anyone.
12
 *
13
 * @package    tenside/core-bundle
14
 * @author     Christian Schiffler <[email protected]>
15
 * @copyright  2015 Christian Schiffler <[email protected]>
16
 * @license    https://github.com/tenside/core-bundle/blob/master/LICENSE MIT
17
 * @link       https://github.com/tenside/core-bundle
18
 * @filesource
19
 */
20
21
namespace Tenside\CoreBundle\Controller;
22
23
use Composer\IO\BufferIO;
24
use Composer\Util\ConfigValidator;
25
use Nelmio\ApiDocBundle\Annotation\ApiDoc;
26
use Symfony\Component\HttpFoundation\JsonResponse;
27
use Symfony\Component\HttpFoundation\Request;
28
use Symfony\Component\HttpFoundation\Response;
29
use Tenside\CoreBundle\Annotation\ApiDescription;
30
31
/**
32
 * Controller for manipulating the composer.json file.
33
 */
34
class ComposerJsonController extends AbstractController
35
{
36
    /**
37
     * Retrieve the composer.json.
38
     *
39
     * @return Response
40
     *
41
     * @ApiDoc(
42
     *   section="files",
43
     *   statusCodes = {
44
     *     200 = "When everything worked out ok"
45
     *   },
46
     *   authentication = true,
47
     *   authenticationRoles = {
48
     *     "ROLE_EDIT_COMPOSER_JSON"
49
     *   }
50
     * )
51
     */
52
    public function getComposerJsonAction()
53
    {
54
        return new Response($this->get('tenside.composer_json'));
55
    }
56
57
    /**
58
     * Update the composer.json with the given data if it is valid.
59
     *
60
     * The whole submitted data is used as file.
61
     *
62
     * @param Request $request The request to process.
63
     *
64
     * @return JsonResponse
65
     *
66
     * @ApiDoc(
67
     *   section="files",
68
     *   statusCodes = {
69
     *     200 = "When everything worked out ok"
70
     *   },
71
     *   authentication = true,
72
     *   authenticationRoles = {
73
     *     "ROLE_EDIT_COMPOSER_JSON"
74
     *   }
75
     * )
76
     * @ApiDescription(
77
     *   response={
78
     *     "status" = {
79
     *       "dataType" = "string",
80
     *       "description" = "Either OK or ERROR"
81
     *     },
82
     *     "errors" = {
83
     *       "description" = "List of contained errors",
84
     *       "subType" = "object",
85
     *       "actualType" = "collection",
86
     *       "children" = {
87
     *         "line" = {
88
     *           "dataType" = "string",
89
     *           "description" = "The line number containing the error",
90
     *           "required" = true
91
     *         },
92
     *         "msg" = {
93
     *           "dataType" = "string",
94
     *           "description" = "The error message",
95
     *           "required" = true
96
     *         }
97
     *       }
98
     *     },
99
     *     "warnings" = {
100
     *       "description" = "List of contained warnings",
101
     *       "subType" = "object",
102
     *       "actualType" = "collection",
103
     *       "children" = {
104
     *         "line" = {
105
     *           "dataType" = "string",
106
     *           "description" = "The line number containing the warning",
107
     *           "required" = true
108
     *         },
109
     *         "msg" = {
110
     *           "dataType" = "string",
111
     *           "description" = "The error message",
112
     *           "required" = true
113
     *         }
114
     *       }
115
     *     }
116
     *   }
117
     * )
118
     */
119
    public function putComposerJsonAction(Request $request)
120
    {
121
        $content = $request->getContent();
122
        try {
123
            $errors = $this->checkComposerJson($content);
0 ignored issues
show
Bug introduced by
It seems like $content defined by $request->getContent() on line 121 can also be of type resource; however, Tenside\CoreBundle\Contr...er::checkComposerJson() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
124
        } catch (\Exception $e) {
125
            $errors = [
126
                'errors'   => [['line' => 0, 'msg' => 'Invalid payload']],
127
                'warnings' => [],
128
            ];
129
        }
130
131
        if (!empty($errors['errors'])) {
132
            $errors['status'] = 'ERROR';
133
        } else {
134
            $errors['status'] = 'OK';
135
136
            $file = $this->get('tenside.composer_json');
137
            $file->load($content);
138
            $file->save();
139
        }
140
141
        return new JsonResponse($errors);
142
    }
143
144
    /**
145
     * Check the json contents and return the error array.
146
     *
147
     * @param string $content The Json content.
148
     *
149
     * @return array<string,string[]>
0 ignored issues
show
Documentation introduced by
Should the return type not be array<string,array>?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
150
     */
151
    private function checkComposerJson($content)
152
    {
153
        $tempFile = $this->getTensideDataDir() . '/composer.json.tmp';
154
        file_put_contents($tempFile, $content);
155
156
        $validator = new ConfigValidator(new BufferIO());
157
158
        list($errors, $publishErrors, $warnings) = $validator->validate($tempFile);
159
        unlink($tempFile);
160
161
        $errors = array_merge($errors, $publishErrors);
162
163
        $errors   = str_replace(dirname($tempFile), '', $errors);
164
        $warnings = str_replace(dirname($tempFile), '', $warnings);
165
166
        $lineMapper = function ($str) {
167
            if (preg_match('#Parse error on line (\d+)#', $str, $match)) {
168
                return ['line' => $match[1], 'msg' => $str];
169
            }
170
            return ['line' => 0, 'msg' => $str];
171
        };
172
173
        return [
174
            'errors'   => array_map($lineMapper, $errors),
175
            'warnings' => array_map($lineMapper, $warnings),
176
        ];
177
    }
178
}
179