ILIAS  release_8 Revision v8.24
ResourceBuilder.php
Go to the documentation of this file.
1<?php
2
19declare(strict_types=1);
20
22
31use ILIAS\ResourceStorage\Preloader\SecureString;
42
49{
50 use SecureString;
51
55 private \ILIAS\ResourceStorage\Information\Repository\InformationRepository $information_repository;
59 private \ILIAS\ResourceStorage\Resource\Repository\ResourceRepository $resource_repository;
63 private \ILIAS\ResourceStorage\Revision\Repository\RevisionRepository $revision_repository;
67 private \ILIAS\ResourceStorage\Stakeholder\Repository\StakeholderRepository $stakeholder_repository;
68
72 protected array $resource_cache = [];
73 protected \ILIAS\ResourceStorage\Policy\FileNamePolicy $file_name_policy;
74 protected \ILIAS\ResourceStorage\StorageHandler\StorageHandler $primary_storage_handler;
78
83 public function __construct(
85 Repositories $repositories,
89 ) {
90 $this->storage_handler_factory = $storage_handler_factory;
91 $this->lock_handler = $lock_handler;
92 $this->stream_access = $stream_access;
93 $this->primary_storage_handler = $storage_handler_factory->getPrimary();
94 $this->revision_repository = $repositories->getRevisionRepository();
95 $this->resource_repository = $repositories->getResourceRepository();
96 $this->information_repository = $repositories->getInformationRepository();
97 $this->stakeholder_repository = $repositories->getStakeholderRepository();
98 $this->file_name_policy = $file_name_policy ?? new NoneFileNamePolicy();
99 }
100
101 //
102 // Methods to create new Resources (from an Upload, a Stream od just a blank one)
103 //
107 public function new(
108 UploadResult $result,
109 InfoResolver $info_resolver
111 $resource = $this->resource_repository->blank(
112 $this->primary_storage_handler->getIdentificationGenerator()->getUniqueResourceIdentification()
113 );
114
115 return $this->append($resource, $result, $info_resolver);
116 }
117
118 public function newFromStream(
119 FileStream $stream,
120 InfoResolver $info_resolver,
121 bool $keep_original = false
123 $resource = $this->resource_repository->blank(
124 $this->primary_storage_handler->getIdentificationGenerator()->getUniqueResourceIdentification()
125 );
126
127 return $this->appendFromStream($resource, $stream, $info_resolver, $keep_original);
128 }
129
130
131 public function newBlank(): StorableResource
132 {
133 $resource = $this->resource_repository->blank(
134 $this->primary_storage_handler->getIdentificationGenerator()->getUniqueResourceIdentification()
135 );
136 $resource->setStorageID($this->primary_storage_handler->getID());
137
138 return $resource;
139 }
140
141 //
142 // Methods to append something to an existing resource
143 //
144
145 public function append(
146 StorableResource $resource,
147 UploadResult $result,
148 InfoResolver $info_resolver
150 $revision = $this->revision_repository->blankFromUpload($info_resolver, $resource, $result);
151 $revision = $this->populateRevisionInfo($revision, $info_resolver);
152
153 $resource->addRevision($revision);
154 $resource->setStorageID(
155 $resource->getStorageID() === '' ? $this->primary_storage_handler->getID() : $resource->getStorageID()
156 );
157
158 return $resource;
159 }
160
164 public function replaceWithUpload(
165 StorableResource $resource,
166 UploadResult $result,
167 InfoResolver $info_resolver
169 $revision = $this->revision_repository->blankFromUpload($info_resolver, $resource, $result);
170 $revision = $this->populateRevisionInfo($revision, $info_resolver);
171
172 foreach ($resource->getAllRevisions() as $existing_revision) {
173 $this->deleteRevision($resource, $existing_revision);
174 }
175
176 $resource->addRevision($revision);
177 $resource->setStorageID(
178 $resource->getStorageID() === '' ? $this->primary_storage_handler->getID() : $resource->getStorageID()
179 );
180
181 return $resource;
182 }
183
184 public function appendFromStream(
185 StorableResource $resource,
186 FileStream $stream,
187 InfoResolver $info_resolver,
188 bool $keep_original = false
190 $revision = $this->revision_repository->blankFromStream($info_resolver, $resource, $stream, $keep_original);
191 $revision = $this->populateRevisionInfo($revision, $info_resolver);
192
193 $resource->addRevision($revision);
194 $resource->setStorageID(
195 $resource->getStorageID() === '' ? $this->primary_storage_handler->getID() : $resource->getStorageID()
196 );
197
198 return $resource;
199 }
200
201 public function replaceWithStream(
202 StorableResource $resource,
203 FileStream $stream,
204 InfoResolver $info_resolver,
205 bool $keep_original = false
207 $revision = $this->revision_repository->blankFromStream($info_resolver, $resource, $stream, $keep_original);
208 $revision = $this->populateRevisionInfo($revision, $info_resolver);
209
210 foreach ($resource->getAllRevisions() as $existing_revision) {
211 $this->deleteRevision($resource, $existing_revision);
212 }
213
214 $resource->addRevision($revision);
215 $resource->setStorageID(
216 $resource->getStorageID() === '' ? $this->primary_storage_handler->getID() : $resource->getStorageID()
217 );
218
219 return $resource;
220 }
221
222 public function appendFromRevision(
223 StorableResource $resource,
224 int $revision_number
226 $existing_revision = $resource->getSpecificRevision($revision_number);
227 if ($existing_revision instanceof FileRevision) {
228 $info_resolver = new ClonedRevisionInfoResolver(
229 $resource->getMaxRevision() + 1,
230 $existing_revision
231 );
232
233 $cloned_revision = $this->revision_repository->blankFromClone(
234 $info_resolver,
235 $resource,
236 $existing_revision
237 );
238
239 $this->populateRevisionInfo($cloned_revision, $info_resolver);
240
241 $resource->addRevision($cloned_revision);
242 $resource->setStorageID(
243 $resource->getStorageID() === '' ? $this->primary_storage_handler->getID() : $resource->getStorageID()
244 );
245 return $resource;
246 }
247 return $resource;
248 }
249
253 public function has(ResourceIdentification $identification): bool
254 {
255 return $this->resource_repository->has($identification);
256 }
257
258
263 public function store(StorableResource $resource): void
264 {
265 foreach ($resource->getAllRevisions() as $revision) {
266 $this->file_name_policy->check($revision->getInformation()->getSuffix());
267 }
268
269 $r = $this->lock_handler->lockTables(
270 array_merge(
271 $this->resource_repository->getNamesForLocking(),
272 $this->revision_repository->getNamesForLocking(),
273 $this->information_repository->getNamesForLocking(),
274 $this->stakeholder_repository->getNamesForLocking()
275 ),
276 function () use ($resource): void {
277 $this->resource_repository->store($resource);
278
279 foreach ($resource->getAllRevisions() as $revision) {
280 $this->storeRevision($revision);
281 }
282
283 foreach ($resource->getStakeholders() as $stakeholder) {
284 $this->stakeholder_repository->register($resource->getIdentification(), $stakeholder);
285 }
286 }
287 );
288
289 $r->runAndUnlock();
290 }
291
292
296 public function clone(StorableResource $resource): StorableResource
297 {
298 $new_resource = $this->newBlank();
299 foreach ($resource->getStakeholders() as $stakeholder) {
300 $stakeholder = clone $stakeholder;
301 $new_resource->addStakeholder($stakeholder);
302 }
303
304 foreach ($resource->getAllRevisions() as $existing_revision) {
305 if (!$existing_revision instanceof FileRevision) {
306 continue;
307 }
308 $info_resolver = new ClonedRevisionInfoResolver(
309 $existing_revision->getVersionNumber(),
310 $existing_revision
311 );
312
313
314 $existing_revision = $this->stream_access->populateRevision($existing_revision);
315
316 $cloned_revision = new FileStreamRevision(
317 $new_resource->getIdentification(),
318 $existing_revision->maybeGetToken()->resolveStream(),
319 true
320 );
321
322 $this->populateRevisionInfo($cloned_revision, $info_resolver);
323 $cloned_revision->setVersionNumber($existing_revision->getVersionNumber());
324
325 $new_resource->addRevision($cloned_revision);
326 }
327 $this->store($new_resource);
328 return $new_resource;
329 }
330
335 public function storeRevision(Revision $revision): void
336 {
337 if ($revision instanceof UploadedFileRevision) {
338 // check policies
339 $this->file_name_policy->check($revision->getInformation()->getSuffix());
340 $this->primary_storage_handler->storeUpload($revision);
341 }
342 if ($revision instanceof FileStreamRevision) {
343 $this->primary_storage_handler->storeStream($revision);
344 }
345 if ($revision instanceof CloneRevision) {
346 $this->primary_storage_handler->cloneRevision($revision);
347 }
348 $this->revision_repository->store($revision);
349 $this->information_repository->store($revision->getInformation(), $revision);
350 }
351
356 public function get(ResourceIdentification $identification): StorableResource
357 {
358 if (isset($this->resource_cache[$identification->serialize()])) {
359 return $this->resource_cache[$identification->serialize()];
360 }
361 $resource = $this->resource_repository->get($identification);
362
363 $this->resource_cache[$identification->serialize()] = $this->populateNakedResourceWithRevisionsAndStakeholders(
364 $resource
365 );
366
367 return $this->resource_cache[$identification->serialize()];
368 }
369
370 public function extractStream(Revision $revision): FileStream
371 {
372 switch (true) {
373 case $revision instanceof UploadedFileRevision:
374 return Streams::ofResource(fopen($revision->getUpload()->getPath(), 'rb'));
375 case $revision instanceof CloneRevision:
376 return $revision->getRevisionToClone()->getStream();
377 case $revision instanceof FileRevision:
378 if ($revision->getStorageID() !== '') {
379 return $this->storage_handler_factory->getHandlerForRevision(
380 $revision
381 )->getStream($revision);
382 } else {
383 return $this->storage_handler_factory->getHandlerForResource(
384 $this->get($revision->getIdentification())
385 )->getStream($revision);
386 }
387 // no break
388 default:
389 throw new \LogicException('This revision type is not supported');
390 }
391 }
392
398 public function remove(StorableResource $resource, ResourceStakeholder $stakeholder = null): bool
399 {
400 $sucessful = true;
401 if ($stakeholder instanceof ResourceStakeholder) {
402 $this->stakeholder_repository->deregister($resource->getIdentification(), $stakeholder);
403 $sucessful = $stakeholder->resourceHasBeenDeleted($resource->getIdentification());
404 $resource->removeStakeholder($stakeholder);
405 if ($resource->getStakeholders() !== []) {
406 return $sucessful;
407 }
408 }
409 foreach ($resource->getStakeholders() as $s) {
410 $sucessful = $s->resourceHasBeenDeleted($resource->getIdentification()) && $sucessful;
411 }
412
413 foreach ($resource->getAllRevisions() as $revision) {
414 $this->deleteRevision($resource, $revision);
415 }
416
417 $this->storage_handler_factory->getHandlerForResource($resource)->deleteResource($resource);
418 $this->resource_repository->delete($resource);
419
420 return $sucessful;
421 }
422
423 public function removeRevision(StorableResource $resource, int $revision_number): void
424 {
425 $reveision_to_delete = $resource->getSpecificRevision($revision_number);
426 if ($reveision_to_delete !== null) {
427 $this->deleteRevision($resource, $reveision_to_delete);
428 }
429 $this->store($resource);
430 }
431
432 private function deleteRevision(StorableResource $resource, Revision $revision): void
433 {
434 try {
435 $this->storage_handler_factory->getHandlerForResource($resource)->deleteRevision($revision);
436 } catch (\Throwable $exception) {
437 }
438
439 $this->information_repository->delete($revision->getInformation(), $revision);
440 $this->revision_repository->delete($revision);
441 $resource->removeRevision($revision);
442 }
443
447 public function getAll(): \Iterator
448 {
452 foreach ($this->resource_repository->getAll() as $resource) {
453 yield $this->populateNakedResourceWithRevisionsAndStakeholders($resource);
454 }
455 }
456
458 {
459 $revisions = $this->revision_repository->get($resource);
460 $resource->setRevisions($revisions);
461
462 foreach ($revisions->getAll() as $i => $revision) {
463 $information = $this->information_repository->get($revision);
464 $revision->setInformation($information);
465 $revision->setStorageID($resource->getStorageID());
466 // $revisions->replaceSingleRevision($this->stream_access->populateRevision($revision)); // currently we do not need populating the stream every time, we will do that in consumers only
467 }
468
469 foreach ($this->stakeholder_repository->getStakeholders($resource->getIdentification()) as $s) {
470 $resource->addStakeholder($s);
471 }
472
473 return $resource;
474 }
475
476 private function populateRevisionInfo(Revision $revision, InfoResolver $info_resolver): Revision
477 {
478 $info = $revision->getInformation();
479
480 $info->setTitle($this->secure($info_resolver->getFileName()));
481 $info->setMimeType($info_resolver->getMimeType());
482 $info->setSuffix($this->secure($info_resolver->getSuffix()));
483 $info->setSize($info_resolver->getSize());
484 $info->setCreationDate($info_resolver->getCreationDate());
485
486 $revision->setInformation($info);
487 $revision->setTitle($this->secure($info_resolver->getRevisionTitle()));
488 $revision->setOwnerId($info_resolver->getOwnerId());
489
490 return $revision;
491 }
492}
static return function(ContainerConfigurator $containerConfigurator)
Definition: basic_rector.php:9
append(StorableResource $resource, UploadResult $result, InfoResolver $info_resolver)
populateRevisionInfo(Revision $revision, InfoResolver $info_resolver)
ILIAS ResourceStorage Revision Repository RevisionRepository $revision_repository
@readonly
appendFromStream(StorableResource $resource, FileStream $stream, InfoResolver $info_resolver, bool $keep_original=false)
ILIAS ResourceStorage Resource Repository ResourceRepository $resource_repository
@readonly
appendFromRevision(StorableResource $resource, int $revision_number)
ILIAS ResourceStorage Information Repository InformationRepository $information_repository
@readonly
newFromStream(FileStream $stream, InfoResolver $info_resolver, bool $keep_original=false)
populateNakedResourceWithRevisionsAndStakeholders(StorableResource $resource)
__construct(StorageHandlerFactory $storage_handler_factory, Repositories $repositories, LockHandler $lock_handler, StreamAccess $stream_access, FileNamePolicy $file_name_policy=null)
ResourceBuilder constructor.
ILIAS ResourceStorage Stakeholder Repository StakeholderRepository $stakeholder_repository
@readonly
replaceWithStream(StorableResource $resource, FileStream $stream, InfoResolver $info_resolver, bool $keep_original=false)
store(StorableResource $resource)
@description after you have modified a resource, you can store it here
has(ResourceIdentification $identification)
@description check if a resource exists
deleteRevision(StorableResource $resource, Revision $revision)
replaceWithUpload(StorableResource $resource, UploadResult $result, InfoResolver $info_resolver)
@inheritDoc
removeRevision(StorableResource $resource, int $revision_number)
storeRevision(Revision $revision)
@description Store one Revision
ILIAS ResourceStorage Policy FileNamePolicy $file_name_policy
clone(StorableResource $resource)
@description Clone anexisting resource with all it's revisions, stakeholders and information
ILIAS ResourceStorage StorageHandler StorageHandler $primary_storage_handler
setRevisions(RevisionCollection $collection)
setInformation(Information $information)
$i
Definition: metadata.php:41
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...