1 | <?php |
||||||
2 | |||||||
3 | /** |
||||||
4 | * @author Russell Michell 2018 <[email protected]> |
||||||
5 | * @package silverstripe-verifiable |
||||||
6 | */ |
||||||
7 | |||||||
8 | namespace PhpTek\Verifiable\Control; |
||||||
9 | |||||||
10 | use SilverStripe\ORM\DataObject; |
||||||
11 | use SilverStripe\Control\HTTPRequest; |
||||||
12 | use SilverStripe\ORM\DB; |
||||||
13 | use SilverStripe\Core\ClassInfo; |
||||||
14 | use SilverStripe\Control\Controller; |
||||||
15 | use SilverStripe\Core\Injector\Injector; |
||||||
16 | use SilverStripe\Control\Director; |
||||||
17 | use SilverStripe\Versioned\Versioned; |
||||||
18 | use SilverStripe\Security\Permission; |
||||||
19 | use PhpTek\Verifiable\ORM\FieldType\ChainpointProof; |
||||||
20 | use PhpTek\Verifiable\Extension\VerifiableExtension; |
||||||
21 | use PhpTek\Verifiable\Exception\VerifiableValidationException; |
||||||
22 | |||||||
23 | /** |
||||||
24 | * Controller available to CLI or XHR requests for updating all or selected versionable |
||||||
25 | * object versions with full-proofs. |
||||||
26 | * |
||||||
27 | * @todo Check with Chainpoint API docs: How many nodes should be submitted to? |
||||||
28 | * @todo Only fetch versions that have unique proof values |
||||||
29 | * @todo Declare a custom Monolog\Formatter\FormatterInterface and refactor log() method |
||||||
30 | */ |
||||||
31 | class UpdateProofController extends Controller |
||||||
32 | { |
||||||
33 | /** |
||||||
34 | * Entry point. |
||||||
35 | * |
||||||
36 | * @param HTTPRequest $request |
||||||
37 | * @throws Exception |
||||||
38 | */ |
||||||
39 | public function index(HTTPRequest $request = null) |
||||||
40 | { |
||||||
41 | if (!$backend = $this->service->name() === 'chainpoint') { |
||||||
0 ignored issues
–
show
The property
service does not exist on PhpTek\Verifiable\Control\UpdateProofController . Since you implemented __get , consider adding a @property annotation.
![]() |
|||||||
42 | throw new \Exception(sprintf('Cannot use %s backend with %s!', $backend, __CLASS__)); |
||||||
0 ignored issues
–
show
$backend of type false is incompatible with the type string expected by parameter $args of sprintf() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
43 | } |
||||||
44 | |||||||
45 | if (!Director::is_cli() && !Permission::check('ADMIN')) { |
||||||
46 | throw new \Exception('You do not have permission to access this controller'); |
||||||
47 | } |
||||||
48 | |||||||
49 | $class = $request->getVar('Class') ?? ''; |
||||||
0 ignored issues
–
show
The method
getVar() does not exist on null .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces. This is most likely a typographical error or the method has been renamed. ![]() |
|||||||
50 | $recordId = $request->getVar('ID') ?? 0; |
||||||
51 | $version = $request->getVar('Version') ?? 0; |
||||||
52 | |||||||
53 | // Process one specific record + version |
||||||
54 | if ($class && $recordId && $version) { |
||||||
55 | $this->log('NOTICE', 'Start: Processing single proof...', 2); |
||||||
56 | $this->updateVersion($class, $recordId, $version); |
||||||
57 | // Process everything |
||||||
58 | } else { |
||||||
59 | $this->log('NOTICE', 'Start: Processing all proofs...', 2); |
||||||
60 | |||||||
61 | // Get all records with partial proofs. Attempt to fetch their full proofs |
||||||
62 | // from Tierion, then write them back to local DB |
||||||
63 | $this->updateVersions(); |
||||||
64 | } |
||||||
65 | |||||||
66 | $this->log('NOTICE', 'End.', 2); |
||||||
67 | } |
||||||
68 | |||||||
69 | /** |
||||||
70 | * Process a single version for a single record. Fetch partial proof, ready to |
||||||
71 | * make them whole again by re-writing to the xxx_Versions table's "Proof" field. |
||||||
72 | * |
||||||
73 | * @param string $class |
||||||
74 | * @param int $id |
||||||
75 | * @param int $version |
||||||
76 | * @return void |
||||||
77 | * @throws Exception |
||||||
78 | */ |
||||||
79 | protected function updateVersion($class, $id, $version) |
||||||
80 | { |
||||||
81 | if (!$record = $class::get()->byID($id)) { |
||||||
82 | throw new \Exception(sprintf('Cannot find %s record for #%d', $class, $id)); |
||||||
83 | } |
||||||
84 | |||||||
85 | if (!$record->hasExtension(VerifiableExtension::class)) { |
||||||
86 | throw new \Exception(sprintf('%s does not have verifiable extension applied', $class)); |
||||||
87 | } |
||||||
88 | |||||||
89 | $record = Versioned::get_version($class, $id, $version); |
||||||
90 | |||||||
91 | $this->process($record); |
||||||
0 ignored issues
–
show
The call to
PhpTek\Verifiable\Contro...ofController::process() has too few arguments starting with proof .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check compares calls to functions or methods with their respective definitions. If the call has less arguments than are defined, it raises an issue. If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above. ![]() |
|||||||
92 | } |
||||||
93 | |||||||
94 | /** |
||||||
95 | * Process all versions for all applicable records. Fetch partial proofs, ready to |
||||||
96 | * make them whole again by re-writing to the xxx_Versions table's "Proof" field. |
||||||
97 | * |
||||||
98 | * @return void |
||||||
99 | */ |
||||||
100 | protected function updateVersions() |
||||||
101 | { |
||||||
102 | // Get decorated classes |
||||||
103 | $dataObjectSublasses = ClassInfo::getValidSubClasses(DataObject::class); |
||||||
104 | |||||||
105 | foreach ($dataObjectSublasses as $class) { |
||||||
106 | $obj = Injector::inst()->create($class); |
||||||
107 | |||||||
108 | if (!$obj->hasExtension(VerifiableExtension::class)) { |
||||||
109 | continue; |
||||||
110 | } |
||||||
111 | |||||||
112 | $this->log('NOTICE', "Processing class: $class"); |
||||||
113 | $classFlag = false; |
||||||
114 | |||||||
115 | foreach ($class::get() as $item) { |
||||||
116 | $versions = Versioned::get_all_versions($class, $item->ID)->sort('Version ASC'); |
||||||
117 | |||||||
118 | foreach ($versions as $record) { |
||||||
119 | try { |
||||||
120 | if (!$proof = $record->dbObject('Proof')) { |
||||||
121 | $this->log('NOTICE', "Skipping proof for record #{$item->ID} (None found)"); |
||||||
122 | continue; |
||||||
123 | } |
||||||
124 | } catch (\Exception $e) { |
||||||
125 | $this->log('NOTICE', "Skipping proof for record #{$item->ID} (Bad data)"); |
||||||
126 | continue; |
||||||
127 | } |
||||||
128 | |||||||
129 | if ($proof->isInitial()) { |
||||||
130 | $classFlag = true; |
||||||
131 | $this->log( |
||||||
132 | 'NOTICE', |
||||||
133 | "\tInitial proof found for ID #{$record->RecordID} and version {$record->Version}" |
||||||
134 | ); |
||||||
135 | $this->log( |
||||||
136 | 'NOTICE', |
||||||
137 | "\tRequesting proof via UUID {$proof->getHashIdNode()[0]}" |
||||||
138 | ); |
||||||
139 | $this->process($record, $proof); |
||||||
140 | } |
||||||
141 | } |
||||||
142 | } |
||||||
143 | |||||||
144 | if (!$classFlag) { |
||||||
145 | $this->log('NOTICE', "Nothing to do."); |
||||||
146 | } |
||||||
147 | } |
||||||
148 | } |
||||||
149 | |||||||
150 | /** |
||||||
151 | * Make the call to the backend, return a full-proof if it's available and |
||||||
152 | * update the local version(s) with it. |
||||||
153 | * |
||||||
154 | * @param DataObject $record |
||||||
155 | * @param string $proof |
||||||
156 | * @return void |
||||||
157 | */ |
||||||
158 | protected function process($record, $proof) |
||||||
159 | { |
||||||
160 | $uuid = $proof->getHashIdNode()[0]; |
||||||
161 | // Pre-seed the service with the saved nodes...unless it's only verified proofs that get propagated..?? |
||||||
162 | $nodes = $record->dbObject('Extra')->getStoreAsArray(); |
||||||
163 | $this->service->setExtra($nodes); |
||||||
0 ignored issues
–
show
The property
service does not exist on PhpTek\Verifiable\Control\UpdateProofController . Since you implemented __get , consider adding a @property annotation.
![]() |
|||||||
164 | |||||||
165 | $this->log('NOTICE', sprintf("\tCalling cached node: %s/proofs/%s", $nodes[0], $uuid)); |
||||||
166 | |||||||
167 | // Don't attempt to write anything that isn't a full proof |
||||||
168 | try { |
||||||
169 | $response = $this->service->call('read', $uuid); |
||||||
170 | } catch (VerifiableValidationException $e) { |
||||||
171 | $this->log('ERROR', $e->getMessage()); |
||||||
172 | |||||||
173 | return; |
||||||
174 | } |
||||||
175 | |||||||
176 | $proof = ChainpointProof::create() |
||||||
177 | ->setValue($response); |
||||||
178 | |||||||
179 | if ($proof && $proof->isFull()) { |
||||||
180 | $this->log( |
||||||
181 | 'NOTICE', |
||||||
182 | "Full proof fetched. Updating record ID #{$record->RecordID} and version {$record->Version}" |
||||||
183 | ); |
||||||
184 | $this->doUpdate($record, $record->Version, $response); |
||||||
185 | } else { |
||||||
186 | $this->log( |
||||||
187 | 'WARN', |
||||||
188 | "\t\tNo full proof found yet for record ID #{$record->RecordID} and version {$record->Version}" |
||||||
189 | ); |
||||||
190 | } |
||||||
191 | } |
||||||
192 | |||||||
193 | /** |
||||||
194 | * Use the lowest level of the ORM to update the xxx_Versions table directly |
||||||
195 | * with a proof. |
||||||
196 | * |
||||||
197 | * @param type $id |
||||||
198 | * @param type $version |
||||||
0 ignored issues
–
show
The type
PhpTek\Verifiable\Control\type was not found. Maybe you did not declare it correctly or list all dependencies?
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. filter:
dependency_paths: ["lib/*"]
For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths ![]() |
|||||||
199 | */ |
||||||
200 | protected function doUpdate($object, $version, $proof) |
||||||
201 | { |
||||||
202 | $table = sprintf('%s_Versions', $object->baseTable()); |
||||||
203 | $sql = sprintf( |
||||||
204 | 'UPDATE "%s" SET "Proof" = \'%s\' WHERE "RecordID" = %d AND "Version" = %d', |
||||||
205 | $table, |
||||||
206 | $proof, |
||||||
207 | $object->ID, |
||||||
208 | $version |
||||||
209 | ); |
||||||
210 | |||||||
211 | DB::query($sql); |
||||||
212 | |||||||
213 | $this->log('NOTICE', "Version #$version of record #{$object->ID} updated."); |
||||||
214 | } |
||||||
215 | |||||||
216 | /** |
||||||
217 | * Simple colourised logging for CLI operation only. |
||||||
218 | * |
||||||
219 | * @param string $type |
||||||
220 | * @param string $msg |
||||||
221 | * @param int $newLine |
||||||
222 | * @return void |
||||||
223 | */ |
||||||
224 | protected function log(string $type, string $msg, int $newLines = 1) |
||||||
225 | { |
||||||
226 | if (!Director::is_cli()) { |
||||||
227 | return; |
||||||
228 | } |
||||||
229 | |||||||
230 | $lb = Director::is_cli() ? PHP_EOL : '<br/>'; |
||||||
231 | $colours = [ |
||||||
232 | 'default' => "\033[0m", |
||||||
233 | 'red' => "\033[31m", |
||||||
234 | 'green' => "\033[32m", |
||||||
235 | 'yellow' => "\033[33m", |
||||||
236 | 'blue' => "\033[34m", |
||||||
237 | 'magenta' => "\033[35m", |
||||||
238 | ]; |
||||||
239 | |||||||
240 | switch ($type) { |
||||||
241 | case 'ERROR': |
||||||
242 | $colour = $colours['red']; |
||||||
243 | break; |
||||||
244 | case 'WARN': |
||||||
245 | $colour = $colours['yellow']; |
||||||
246 | break; |
||||||
247 | default: |
||||||
248 | case 'WARN': |
||||||
249 | $colour = $colours['green']; |
||||||
250 | break; |
||||||
251 | } |
||||||
252 | |||||||
253 | echo sprintf( |
||||||
254 | '%s[%s] %s%s%s', |
||||||
255 | $colour, |
||||||
256 | $type, |
||||||
257 | $msg, |
||||||
258 | str_repeat($lb, $newLines), |
||||||
259 | $colours['default'] |
||||||
260 | ); |
||||||
261 | } |
||||||
262 | } |
||||||
263 |
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.
This is most likely a typographical error or the method has been renamed.