Passed
Pull Request — master (#182)
by Alex
05:02
created

createUpdateDeleteProcessOutput()   B

Complexity

Conditions 7
Paths 7

Size

Total Lines 19
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 11
c 1
b 0
f 0
dl 0
loc 19
rs 8.8333
cc 7
nc 7
nop 1
1
<?php
2
/**
3
 * Created by PhpStorm.
4
 * User: alex
5
 * Date: 29/09/19
6
 * Time: 6:08 PM
7
 */
8
9
namespace AlgoWeb\PODataLaravel\Query;
10
11
use Illuminate\Database\Eloquent\Model;
12
use Illuminate\Support\Facades\App;
13
use POData\Common\InvalidOperationException;
14
use POData\Common\ODataException;
15
use POData\Providers\Metadata\ResourceSet;
16
17
class LaravelWriteQuery extends LaravelBaseQuery
18
{
19
20
21
    /**
22
     * @param $data
23
     * @param $paramList
24
     * @param Model|null $sourceEntityInstance
25
     * @return array
26
     */
27
    public function createUpdateDeleteProcessInput($data, $paramList, Model $sourceEntityInstance)
28
    {
29
        $parms = [];
30
31
        foreach ($paramList as $spec) {
32
            $varType = isset($spec['type']) ? $spec['type'] : null;
33
            $varName = $spec['name'];
34
            if (null == $varType) {
35
                $parms[] = ('id' == $varName) ? $sourceEntityInstance->getKey() : $sourceEntityInstance->$varName;
36
                continue;
37
            }
38
            // TODO: Give this smarts and actively pick up instantiation details
39
            $var = new $varType();
40
            if ($spec['isRequest']) {
41
                $var->setMethod('POST');
42
                $var->request = new \Symfony\Component\HttpFoundation\ParameterBag($data);
43
            }
44
            $parms[] = $var;
45
        }
46
        return $parms;
47
    }
48
49
50
    /**
51
     * @param $result
52
     * @throws ODataException
53
     * @return array|mixed
54
     */
55
    public function createUpdateDeleteProcessOutput($result)
56
    {
57
        if (!($result instanceof \Illuminate\Http\JsonResponse)) {
58
            throw ODataException::createInternalServerError('Controller response not well-formed json.');
59
        }
60
        $outData = $result->getData();
61
        if (is_object($outData)) {
62
            $outData = (array) $outData;
63
        }
64
65
        if (!is_array($outData)) {
66
            throw ODataException::createInternalServerError('Controller response does not have an array.');
67
        }
68
        if (!(key_exists('id', $outData) && key_exists('status', $outData) && key_exists('errors', $outData))) {
69
            throw ODataException::createInternalServerError(
70
                'Controller response array missing at least one of id, status and/or errors fields.'
71
            );
72
        }
73
        return $outData;
74
    }
75
76
    /**
77
     * @param ResourceSet $sourceResourceSet
78
     * @param $data
79
     * @param                            $verb
80
     * @param  Model|null                $source
81
     * @throws InvalidOperationException
82
     * @throws ODataException
83
     * @throws \Exception
84
     * @return Model|null
85
     */
86
    public function createUpdateCoreWrapper(ResourceSet $sourceResourceSet, $data, $verb, Model $source = null)
87
    {
88
        $lastWord = 'update' == $verb ? 'updated' : 'created';
89
        $class = $sourceResourceSet->getResourceType()->getInstanceType()->getName();
90
        if (!$this->getAuth()->canAuth($this->getVerbMap()[$verb], $class, $source)) {
91
            throw new ODataException('Access denied', 403);
92
        }
93
94
        $payload = $this->createUpdateDeleteCore($source, $data, $class, $verb);
95
96
        $success = isset($payload['id']);
97
98
        if ($success) {
99
            try {
100
                return $class::findOrFail($payload['id']);
101
            } catch (\Exception $e) {
102
                throw new ODataException($e->getMessage(), 500);
103
            }
104
        }
105
        throw new ODataException('Target model not successfully ' . $lastWord, 422);
106
    }
107
108
109
    /**
110
     * @param $sourceEntityInstance
111
     * @param $data
112
     * @param $class
113
     * @param string $verb
114
     *
115
     * @throws ODataException
116
     * @throws InvalidOperationException
117
     * @return array|mixed
118
     */
119
    public function createUpdateDeleteCore($sourceEntityInstance, $data, $class, $verb)
120
    {
121
        $raw = $this->getControllerContainer();
122
        $map = $raw->getMetadata();
123
124
        if (!array_key_exists($class, $map)) {
125
            throw new InvalidOperationException('Controller mapping missing for class ' . $class . '.');
126
        }
127
        $goal = $raw->getMapping($class, $verb);
128
        if (null == $goal) {
129
            throw new InvalidOperationException(
130
                'Controller mapping missing for ' . $verb . ' verb on class ' . $class . '.'
131
            );
132
        }
133
134
        if (null === $data) {
135
            $msg = 'Data must not be null';
136
            throw new InvalidOperationException($msg);
137
        }
138
        if (is_object($data)) {
139
            $arrayData = (array) $data;
140
        } else {
141
            $arrayData = $data;
142
        }
143
        if (!is_array($arrayData)) {
144
            throw ODataException::createPreConditionFailedError(
145
                'Data not resolvable to key-value array.'
146
            );
147
        }
148
149
        $controlClass = $goal['controller'];
150
        $method = $goal['method'];
151
        $paramList = $goal['parameters'];
152
        $controller = App::make($controlClass);
153
        $parms = $this->createUpdateDeleteProcessInput($arrayData, $paramList, $sourceEntityInstance);
154
        unset($data);
155
156
        $result = call_user_func_array(array($controller, $method), $parms);
157
158
        return $this->createUpdateDeleteProcessOutput($result);
159
    }
160
}
161