1 | <?php |
||||
2 | |||||
3 | namespace Dynamic\Salsify\ORM; |
||||
4 | |||||
5 | use Dynamic\Salsify\Model\Fetcher; |
||||
6 | use Dynamic\Salsify\Model\Mapper; |
||||
7 | use Dynamic\Salsify\Task\ImportTask; |
||||
8 | use Dynamic\Salsify\Traits\InstanceCreator; |
||||
9 | use GuzzleHttp\Client; |
||||
10 | use SilverStripe\Admin\LeftAndMainExtension; |
||||
0 ignored issues
–
show
|
|||||
11 | use SilverStripe\Core\Config\Config; |
||||
12 | use SilverStripe\Forms\Form; |
||||
13 | use SilverStripe\ORM\DataObject; |
||||
14 | use SilverStripe\Security\Security; |
||||
15 | |||||
16 | /** |
||||
17 | * Class LeftAndMainExtension |
||||
18 | * @package Dynamic\Salsify\ORM |
||||
19 | * @property-read \SilverStripe\Admin\LeftAndMain|\Dynamic\Salsify\ORM\SalsifyFetchExtension $owner |
||||
20 | */ |
||||
21 | class SalsifyFetchExtension extends LeftAndMainExtension |
||||
22 | { |
||||
23 | use InstanceCreator; |
||||
24 | |||||
25 | /** |
||||
26 | * @var bool |
||||
27 | */ |
||||
28 | private $noChannel = true; |
||||
0 ignored issues
–
show
|
|||||
29 | |||||
30 | /** |
||||
31 | * @var array |
||||
32 | */ |
||||
33 | private static $allowed_actions = [ |
||||
0 ignored issues
–
show
|
|||||
34 | 'salsifyFetch', |
||||
35 | ]; |
||||
36 | |||||
37 | /** |
||||
38 | * @return string |
||||
39 | */ |
||||
40 | protected function getImporterKey() |
||||
41 | { |
||||
42 | return 'single'; |
||||
43 | } |
||||
44 | |||||
45 | /** |
||||
46 | * |
||||
47 | */ |
||||
48 | public function onBeforeInit() |
||||
49 | { |
||||
50 | $this->createServices(); |
||||
51 | } |
||||
52 | |||||
53 | /** |
||||
54 | * @return boolean |
||||
55 | * @throws \Exception |
||||
56 | */ |
||||
57 | public function canFetchSalsify() |
||||
58 | { |
||||
59 | $className = $this->owner->currentPage()->getClassName(); |
||||
60 | |||||
61 | // Only allow when product has a salsify id and has a single mapping config |
||||
62 | if ( |
||||
63 | $this->owner->currentPage()->SalsifyID && |
||||
64 | $this->hasService(Mapper::class) && |
||||
65 | $this->configContainsMapping($className) && |
||||
66 | $this->getFetcher()->config()->get('organizationID') |
||||
67 | ) { |
||||
68 | return true; |
||||
69 | } |
||||
70 | return false; |
||||
71 | } |
||||
72 | |||||
73 | /** |
||||
74 | * @param string $className |
||||
75 | * |
||||
76 | * @return boolean |
||||
77 | * @throws \Exception |
||||
78 | */ |
||||
79 | private function configContainsMapping($className) |
||||
80 | { |
||||
81 | if (!$this->getMapper()->config()->get('mapping')) { |
||||
82 | return false; |
||||
83 | } |
||||
84 | |||||
85 | if (!$this->getClassMapping($className)) { |
||||
86 | return false; |
||||
87 | } |
||||
88 | |||||
89 | return true; |
||||
90 | } |
||||
91 | |||||
92 | /** |
||||
93 | * @param string $className |
||||
94 | * @return bool|array |
||||
95 | * @throws \Exception |
||||
96 | */ |
||||
97 | private function getClassMapping($className) |
||||
98 | { |
||||
99 | $mapping = $this->getMapper()->config()->get('mapping'); |
||||
100 | if (array_key_exists($className, $mapping)) { |
||||
101 | return $mapping[$className]; |
||||
102 | } |
||||
103 | if (array_key_exists('\\' . $className, $mapping)) { |
||||
104 | return $mapping['\\' . $className]; |
||||
105 | } |
||||
106 | return false; |
||||
107 | } |
||||
108 | |||||
109 | /** |
||||
110 | * @param array $data |
||||
111 | * @param Form $form |
||||
112 | * @return \SilverStripe\Control\HTTPResponse |
||||
113 | * @throws \Exception |
||||
114 | */ |
||||
115 | public function salsifyFetch($data, $form) |
||||
116 | { |
||||
117 | $className = $this->owner->currentPage()->getClassName(); |
||||
118 | |||||
119 | $id = $data['ID']; |
||||
120 | /** @var DataObject|\Dynamic\Salsify\ORM\SalsifyIDExtension $record */ |
||||
121 | $record = DataObject::get_by_id($className, $id); |
||||
122 | if ($record && !$record->canEdit()) { |
||||
123 | return Security::permissionFailure(); |
||||
124 | } |
||||
125 | |||||
126 | if (!$record || !$record->SalsifyID) { |
||||
0 ignored issues
–
show
|
|||||
127 | $this->owner->httpError(404, "Bad salsify ID: $id"); |
||||
128 | } |
||||
129 | |||||
130 | ImportTask::config()->remove('output'); |
||||
131 | $data = $this->fetchProduct($record->SalsifyID); |
||||
132 | if (array_key_exists('salsify:parent_id', $data)) { |
||||
133 | $parent = $this->fetchProduct($data['salsify:parent_id']); |
||||
134 | $data = array_merge($parent, $data); |
||||
0 ignored issues
–
show
It seems like
$parent can also be of type null ; however, parameter $arrays of array_merge() does only seem to accept array , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
135 | } |
||||
136 | |||||
137 | $this->changeToSalsifyUser(); |
||||
138 | $this->mapData($record, $data); |
||||
139 | $this->changeToPreviousUser(); |
||||
140 | |||||
141 | $this->owner->getResponse()->addHeader( |
||||
142 | 'X-Status', |
||||
143 | rawurlencode(_t(__CLASS__ . '.UPDATED', 'Updated.')) |
||||
144 | ); |
||||
145 | return $this->owner->getResponseNegotiator()->respond($this->owner->getRequest()); |
||||
146 | } |
||||
147 | |||||
148 | /** |
||||
149 | * @param string $salsifyID |
||||
150 | * @return array|NULL |
||||
151 | * @throws \Exception |
||||
152 | */ |
||||
153 | private function fetchProduct($salsifyID) |
||||
154 | { |
||||
155 | |||||
156 | $apiKey = $this->getFetcher()->config()->get('apiKey'); |
||||
157 | $timeout = $this->getFetcher()->config()->get('timeout'); |
||||
158 | $orgID = $this->getFetcher()->config()->get('organizationID'); |
||||
159 | |||||
160 | $url = "v1/orgs/{$orgID}/products/{$salsifyID}"; |
||||
161 | |||||
162 | $client = new Client([ |
||||
163 | 'base_uri' => Fetcher::API_BASE_URL, |
||||
164 | 'timeout' => $timeout, |
||||
165 | 'http_errors' => false, |
||||
166 | 'verify' => true, |
||||
167 | 'headers' => [ |
||||
168 | 'Authorization' => 'Bearer ' . $apiKey, |
||||
169 | 'Content-Type' => 'application/json', |
||||
170 | ], |
||||
171 | ]); |
||||
172 | |||||
173 | $response = $client->get($url); |
||||
174 | |||||
175 | if ($response->getStatusCode() == 404) { |
||||
176 | $this->owner->httpError(404, "Bad salsify ID: $salsifyID"); |
||||
177 | } |
||||
178 | |||||
179 | return json_decode($response->getBody(), true); |
||||
180 | } |
||||
181 | |||||
182 | /** |
||||
183 | * @param DataObject $record |
||||
184 | * @param array $data |
||||
185 | * @throws \Exception |
||||
186 | */ |
||||
187 | private function mapData($record, $data) |
||||
188 | { |
||||
189 | $forceUpdate = Config::inst()->get( |
||||
190 | $this->owner->currentPage()->getClassName(), |
||||
191 | 'refetch_force_update' |
||||
192 | ); |
||||
193 | |||||
194 | $this->getFetcher()->config()->set('useLatest', true); |
||||
195 | $this->getFetcher()->startExportRun(); |
||||
196 | $this->getFetcher()->waitForExportRunToComplete(); |
||||
197 | $file = $this->getFetcher()->getExportUrl(); |
||||
198 | |||||
199 | $this->getMapper()->extend('onBeforeMap', $file, Mapper::$SINGLE); |
||||
200 | |||||
201 | $this->getMapper()->mapToObject( |
||||
202 | $record->getClassName(), |
||||
203 | $this->getClassMapping($record->getClassName()), |
||||
0 ignored issues
–
show
It seems like
$this->getClassMapping($record->getClassName()) can also be of type boolean ; however, parameter $mappings of Dynamic\Salsify\Model\Mapper::mapToObject() does only seem to accept array , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
204 | $data, |
||||
205 | $record, |
||||
206 | false, |
||||
207 | $forceUpdate |
||||
208 | ); |
||||
209 | |||||
210 | $forceUpdateRelations = Config::inst()->get( |
||||
211 | $this->owner->currentPage()->getClassName(), |
||||
212 | 'refetch_force_update_relations' |
||||
213 | ); |
||||
214 | $this->getMapper()->mapToObject( |
||||
215 | $record->getClassName(), |
||||
216 | $this->getClassMapping($record->getClassName()), |
||||
217 | $data, |
||||
218 | $record, |
||||
219 | true, |
||||
220 | $forceUpdateRelations |
||||
221 | ); |
||||
222 | |||||
223 | $this->getMapper()->extend('onAfterMap', $file, Mapper::$SINGLE); |
||||
224 | } |
||||
225 | } |
||||
226 |
The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g.
excluded_paths: ["lib/*"]
, you can move it to the dependency path list as follows:For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths