Files
lucent-laravel/src/Record/RecordService.php
T

346 lines
10 KiB
PHP
Raw Normal View History

2023-10-02 23:10:49 +03:00
<?php
namespace Lucent\Record;
2024-08-19 17:48:10 +03:00
use Illuminate\Http\UploadedFile;
2023-10-02 23:10:49 +03:00
use Illuminate\Support\Str;
use Lucent\Account\AuthService;
use Lucent\Channel\ChannelService;
use Lucent\Edge\Edge;
2023-11-29 17:10:15 +02:00
use Lucent\Edge\EdgeService;
2023-10-02 23:10:49 +03:00
use Lucent\File\FileService;
use Lucent\Id\Id;
use Lucent\LucentException;
use Lucent\Query\Query;
2024-08-19 17:48:10 +03:00
use Lucent\Record\InputData\EdgeInputData;
use Lucent\Record\InputData\RecordInputData;
2023-10-02 23:10:49 +03:00
use Lucent\Revision\RevisionService;
use Lucent\Schema\FieldInterface;
use Lucent\Schema\Schema;
2024-08-19 17:48:10 +03:00
use Lucent\Schema\Type;
2023-10-02 23:10:49 +03:00
use Lucent\Schema\Validator\Validator;
use Lucent\Schema\Validator\ValidatorException;
readonly class RecordService
{
public function __construct(
2026-04-20 21:07:35 +03:00
private AuthService $authService,
2023-10-02 23:10:49 +03:00
private RevisionService $revisionService,
2026-04-20 21:07:35 +03:00
private ChannelService $channelService,
private Validator $recordValidator,
private Query $query,
private InputFormatter $inputFormatter,
private RecordRepo $recordRepo,
private EdgeService $edgeService,
private FileService $fileService,
) {}
2023-10-02 23:10:49 +03:00
/**
2024-08-19 17:48:10 +03:00
* @param string $url
* @param RecordInputData $data
* @param list<EdgeInputData> $edges
* @return string
2023-10-02 23:10:49 +03:00
* @throws LucentException
* @throws ValidatorException
*/
2024-08-19 17:48:10 +03:00
public function createFromUrl(
2026-04-20 21:07:35 +03:00
string $url,
2024-08-19 17:48:10 +03:00
RecordInputData $data,
2026-04-20 21:07:35 +03:00
array $edges,
): string {
2024-08-19 17:48:10 +03:00
$schema = $this->channelService->getSchema($data->schemaName)->get();
if ($schema->type !== Type::FILES) {
2026-04-20 21:07:35 +03:00
throw new LucentException(
"You can't upload a file to a regular record",
);
2024-08-19 17:48:10 +03:00
}
$fileData = $this->fileService->createFromUrl($schema, $url);
2024-08-19 17:59:08 +03:00
if ($fileData->isDuplicate) {
return $fileData->duplicateId;
}
2024-08-19 17:48:10 +03:00
return $this->create($data, $fileData->recordFile, $edges);
}
2023-10-02 23:10:49 +03:00
2024-08-19 17:48:10 +03:00
public function createFromUploadedFile(
2026-04-20 21:07:35 +03:00
UploadedFile $uploadedFile,
2024-08-19 17:48:10 +03:00
RecordInputData $data,
2026-04-20 21:07:35 +03:00
array $edges,
): string {
2024-08-19 17:48:10 +03:00
$schema = $this->channelService->getSchema($data->schemaName)->get();
if ($schema->type !== Type::FILES) {
2026-04-20 21:07:35 +03:00
throw new LucentException(
"You can't upload a file to a regular record",
);
2023-10-02 23:10:49 +03:00
}
2024-08-19 17:48:10 +03:00
$fileData = $this->fileService->upload($schema, $uploadedFile);
2024-08-19 17:59:08 +03:00
if ($fileData->isDuplicate) {
return $fileData->duplicateId;
}
2024-08-19 17:48:10 +03:00
return $this->create($data, $fileData->recordFile, $edges);
}
public function createFromFileData(
2026-04-20 21:07:35 +03:00
FileData $fileData,
2024-08-19 17:48:10 +03:00
RecordInputData $data,
2026-04-20 21:07:35 +03:00
array $edges,
): string {
2024-08-19 17:48:10 +03:00
$schema = $this->channelService->getSchema($data->schemaName)->get();
if ($schema->type !== Type::FILES) {
2026-04-20 21:07:35 +03:00
throw new LucentException(
"You can't upload a file to a regular record",
);
2023-10-02 23:10:49 +03:00
}
2024-08-19 17:48:10 +03:00
return $this->create($data, $fileData, $edges);
}
/**
* @param RecordInputData $data
* @param FileData|null $file
* @param list<EdgeInputData> $edges
* @return string
* @throws ValidatorException
*/
public function create(
RecordInputData $data,
2026-04-20 21:07:35 +03:00
?FileData $file = null,
array $edges = [],
): string {
$formattedData = $this->inputFormatter->fill(
$data->schemaName,
new RecordData($data->data),
);
2024-08-19 17:48:10 +03:00
$newRecordId = empty($data->id) ? Id::new() : $data->id;
2023-10-02 23:10:49 +03:00
$record = new Record(
2024-01-11 22:57:57 +02:00
id: $newRecordId,
2024-08-19 17:48:10 +03:00
schema: $data->schemaName,
status: $data->status,
2023-10-04 13:32:30 +03:00
_sys: System::newRecord($this->authService->currentUserId()),
2023-10-02 23:10:49 +03:00
data: $formattedData,
2024-08-19 17:48:10 +03:00
_file: !empty($file) ? FileData::fromArray(toArray($file)) : null,
2023-10-02 23:10:49 +03:00
);
2024-08-19 17:48:10 +03:00
if ($data->status === Status::PUBLISHED) {
2026-04-20 21:07:35 +03:00
$errors = $this->recordValidator->check(
$data->schemaName,
$record->data,
);
2023-10-13 21:06:23 +03:00
if ($errors->isNotEmpty()) {
$this->recordValidator->throwException($errors);
}
2023-10-02 23:10:49 +03:00
}
RecordRepo::create($record);
2026-04-20 21:07:35 +03:00
$newEdges = $this->edgeService->createManyForRecord(
$record->id,
$record->schema,
$edges,
);
2024-08-19 17:48:10 +03:00
$this->revisionService->create($record, $newEdges);
2023-10-02 23:10:49 +03:00
return $record->id;
}
/**
* @throws LucentException
* @throws ValidatorException
*/
2026-04-20 21:07:35 +03:00
public function update(string $id, array $data, Status $status): void
2023-10-02 23:10:49 +03:00
{
2026-04-20 21:07:35 +03:00
$record = $this->query
->filter(["id" => $id])
->run()
->records->first();
2023-10-02 23:10:49 +03:00
if (empty($record)) {
throw new LucentException("Record id is missing");
}
2026-04-20 21:07:35 +03:00
$formattedData = $this->inputFormatter->fill(
$record->schema,
new RecordData($data),
);
2023-10-02 23:10:49 +03:00
2024-08-19 17:48:10 +03:00
if ($status === Status::PUBLISHED) {
2026-04-20 21:07:35 +03:00
$errors = $this->recordValidator->check(
$record->schema,
$formattedData,
);
2023-10-13 21:06:23 +03:00
if ($errors->isNotEmpty()) {
$this->recordValidator->throwException($errors);
}
2024-08-19 17:48:10 +03:00
}
$newRecord = new Record(
id: $record->id,
schema: $record->schema,
status: $status,
_sys: $record->_sys->update($this->authService->currentUserId()),
data: $record->data->merge($formattedData),
_file: $record->_file,
);
RecordRepo::update($newRecord);
$newEdges = $this->edgeService->findForSource($record->id);
$this->revisionService->create($newRecord, $newEdges);
}
2023-10-13 21:06:23 +03:00
2024-08-19 17:48:10 +03:00
/**
* @throws LucentException
* @throws ValidatorException
*/
public function updateWithEdges(
string $id,
2026-04-20 21:07:35 +03:00
array $data,
2024-08-19 17:48:10 +03:00
Status $status,
2026-04-20 21:07:35 +03:00
array $edges,
): void {
$record = $this->query
->filter(["id" => $id])
->run()
->records->first();
2024-08-19 17:48:10 +03:00
if (empty($record)) {
throw new LucentException("Record id is missing");
}
2026-04-20 21:07:35 +03:00
$formattedData = $this->inputFormatter->fill(
$record->schema,
new RecordData($data),
);
2024-08-19 17:48:10 +03:00
if ($status === Status::PUBLISHED) {
2026-04-20 21:07:35 +03:00
$errors = $this->recordValidator->check(
$record->schema,
$formattedData,
);
2023-10-13 21:06:23 +03:00
if ($errors->isNotEmpty()) {
$this->recordValidator->throwException($errors);
}
2023-10-02 23:10:49 +03:00
}
$newRecord = new Record(
id: $record->id,
2023-10-04 13:32:30 +03:00
schema: $record->schema,
2024-08-19 17:48:10 +03:00
status: $status,
2023-10-04 13:32:30 +03:00
_sys: $record->_sys->update($this->authService->currentUserId()),
2023-10-02 23:10:49 +03:00
data: $record->data->merge($formattedData),
_file: $record->_file,
);
RecordRepo::update($newRecord);
2026-04-20 21:07:35 +03:00
$newEdges = $this->edgeService->replaceManyForRecord(
$record->id,
$record->schema,
$edges,
);
2024-08-19 17:48:10 +03:00
$this->revisionService->create($newRecord, $newEdges);
2023-10-02 23:10:49 +03:00
}
2026-04-20 21:07:35 +03:00
public function changeStatusBulk(string $status, array $recordsIds): void
2023-10-02 23:10:49 +03:00
{
2023-10-04 13:32:30 +03:00
RecordRepo::updateStatusBulk(Status::from($status), $recordsIds);
2023-10-02 23:10:49 +03:00
}
/**
* @throws LucentException
* @throws ValidatorException
*/
2026-04-20 21:07:35 +03:00
public function clone(string $recordId): string
2023-10-02 23:10:49 +03:00
{
2023-10-04 13:32:30 +03:00
$graph = $this->query
2023-10-02 23:10:49 +03:00
->filter(["id" => $recordId])
->limit(1)
->childrenDepth(1)
2023-10-04 13:32:30 +03:00
->run();
2023-10-02 23:10:49 +03:00
2023-10-04 13:32:30 +03:00
$record = $graph->records->first();
2023-10-02 23:10:49 +03:00
if (empty($record)) {
throw new LucentException("Record id is missing");
}
2023-10-04 13:32:30 +03:00
2026-04-20 21:07:35 +03:00
$newRecordId = (string) Str::uuid();
2023-10-02 23:10:49 +03:00
$newEdgesData = $graph->edges
->filter(fn(Edge $edge) => $edge->source == $recordId)
->values()
2026-04-20 21:07:35 +03:00
->map(
fn(Edge $edge) => new EdgeInputData(
target: $edge->target,
targetSchema: $edge->targetSchema,
field: $edge->field,
),
)
->toArray();
2023-10-02 23:10:49 +03:00
$record->id = $newRecordId;
return $this->create(
2024-08-19 17:48:10 +03:00
new RecordInputData(
schemaName: $record->schema,
id: $record->id,
data: $record->data->toArray(),
2026-04-20 21:07:35 +03:00
status: Status::DRAFT,
2024-08-19 17:48:10 +03:00
),
file: $record->_file,
2026-04-20 21:07:35 +03:00
edges: $newEdgesData,
2023-10-02 23:10:49 +03:00
);
}
2026-04-20 21:07:35 +03:00
public function deleteMany(array $recordsIds): void
2023-10-02 23:10:49 +03:00
{
2023-10-06 18:47:50 +03:00
$this->recordRepo->deleteMany($recordsIds);
2023-10-02 23:10:49 +03:00
}
2026-04-20 21:07:35 +03:00
public function emptyTrash(string $schemaName): void
2023-10-15 23:40:34 +03:00
{
$schema = $this->channelService->getSchema($schemaName)->get();
$this->recordRepo->deleteTrashedBySchema($schemaName);
}
2023-10-02 23:10:49 +03:00
/**
* @throws LucentException
* @throws ValidatorException
*/
2026-04-20 21:07:35 +03:00
public function rollback(string $recordId, int $version): void
2023-10-02 23:10:49 +03:00
{
2026-04-20 21:07:35 +03:00
$revision = $this->revisionService
->getByRecordIdAndVersion($recordId, $version)
->get();
2024-08-19 17:48:10 +03:00
$this->updateWithEdges(
2023-10-02 23:10:49 +03:00
id: $revision->recordId,
data: $revision->data->toArray(),
2024-08-19 17:48:10 +03:00
status: Status::DRAFT,
2026-04-20 21:07:35 +03:00
edges: array_map(
fn(Edge $edge) => new EdgeInputData(
$edge->target,
$edge->targetSchema,
$edge->field,
),
$revision->_edges,
),
2023-10-02 23:10:49 +03:00
);
}
2026-04-20 21:07:35 +03:00
public function createEmpty(Schema $schema): Record
2023-10-02 23:10:49 +03:00
{
2026-04-20 21:07:35 +03:00
$defaultValues = $schema->fields->reduce(function (
$carry,
FieldInterface $f,
) {
2023-10-02 23:10:49 +03:00
$carry[$f->name] = $f->default ?? null;
return $carry;
}, []);
2026-04-20 21:07:35 +03:00
$formattedData = $this->inputFormatter->fill(
$schema->name,
new RecordData($defaultValues),
);
2023-10-02 23:10:49 +03:00
return new Record(
id: Id::new(),
2023-10-04 13:32:30 +03:00
schema: $schema->name,
status: Status::DRAFT,
2023-10-13 21:06:23 +03:00
_sys: System::newRecord($this->authService->currentUserId()),
2023-10-02 23:10:49 +03:00
data: $formattedData,
_file: null,
);
}
}