diff --git a/front/js/entry/FieldEditEntry/FieldEditEntry.svelte b/front/js/entry/FieldEditEntry/FieldEditEntry.svelte
index c53c274..c34439d 100644
--- a/front/js/entry/FieldEditEntry/FieldEditEntry.svelte
+++ b/front/js/entry/FieldEditEntry/FieldEditEntry.svelte
@@ -1,6 +1,7 @@
+
+
diff --git a/front/js/entry/RecordEditEntry/RecordForm.svelte b/front/js/entry/RecordEditEntry/RecordForm.svelte
index 8a186aa..e125c76 100644
--- a/front/js/entry/RecordEditEntry/RecordForm.svelte
+++ b/front/js/entry/RecordEditEntry/RecordForm.svelte
@@ -1,5 +1,6 @@
{#each fields as field}
{#if field.type === "text"}
- f.fieldId === field.id && f.locale === "main",
- )}
- schemaField={field}
- locale="main"
- dataField={fieldData.find(
- (f) => f.id === field.id && f.locale === "main",
- )}
- >
+ {@render textField(field, "main")}
{#if field.translatable}
{#each selectedLocales as locale (locale)}
-
- f.fieldId === field.id && f.locale === locale,
- )}
- schemaField={field}
- {locale}
- dataField={fieldData.find(
- (f) => f.id === field.id && f.locale === locale,
- )}
- >
+ {@render textField(field, locale)}
+ {/each}
+ {/if}
+ {/if}
+ {#if field.type === "relation"}
+ {@render relationField(field, "main")}
+ {#if field.translatable}
+ {#each selectedLocales as locale (locale)}
+ {@render relationField(field, locale)}
{/each}
{/if}
{/if}
{/each}
+
+{#snippet textField(field, locale)}
+
+{/snippet}
+
+{#snippet relationField(field, locale)}
+
+{/snippet}
diff --git a/front/js/entry/RecordEditEntry/fields/RelationField.svelte b/front/js/entry/RecordEditEntry/fields/RelationField.svelte
new file mode 100644
index 0000000..c088bbb
--- /dev/null
+++ b/front/js/entry/RecordEditEntry/fields/RelationField.svelte
@@ -0,0 +1,86 @@
+
+
+
+
+
diff --git a/front/js/entry/SchemaEntry/SchemaEntry.svelte b/front/js/entry/SchemaEntry/SchemaEntry.svelte
index afb67e5..0ba614e 100644
--- a/front/js/entry/SchemaEntry/SchemaEntry.svelte
+++ b/front/js/entry/SchemaEntry/SchemaEntry.svelte
@@ -8,7 +8,8 @@
let newSchemaAlias = $state("");
let fields = $state(data.fields);
const app = getApp();
-
+ const createFieldUrl = (schema, type) =>
+ app.url(`fields/create?schema=${schema.id}&type=${type}`);
function handleSchemaCreate(e) {
e.preventDefault();
post(
@@ -113,24 +114,16 @@
Add field
diff --git a/src/Core/Data/Record.php b/src/Core/Data/Record.php
index f1b9911..b6addb1 100644
--- a/src/Core/Data/Record.php
+++ b/src/Core/Data/Record.php
@@ -7,6 +7,7 @@ class Record
public function __construct(
public string $id,
public string $schemaId,
+ public string $titleFieldId,
public Carbon $createdAt,
public string $createdBy,
public ?Carbon $publishedAt,
diff --git a/src/Core/Data/RecordField.php b/src/Core/Data/RecordField.php
index 3a9771b..3318bf5 100644
--- a/src/Core/Data/RecordField.php
+++ b/src/Core/Data/RecordField.php
@@ -5,8 +5,9 @@ use Carbon\Carbon;
class RecordField
{
public function __construct(
- public string $recordId,
public string $id,
+ public string $recordId,
+ public string $fieldId,
public string $locale,
public RecordMode $mode,
public mixed $value,
diff --git a/src/Core/Data/RecordPreview.php b/src/Core/Data/RecordPreview.php
new file mode 100644
index 0000000..0e3a522
--- /dev/null
+++ b/src/Core/Data/RecordPreview.php
@@ -0,0 +1,10 @@
+ $field->recordId,
"id" => $field->id,
+ "record_id" => $field->recordId,
+ "field_id" => $field->fieldId,
"locale" => $field->locale,
"mode" => $field->mode->value,
"value" => $field->value,
diff --git a/src/Core/Record/RecordModule.php b/src/Core/Record/RecordModule.php
index 7647f48..8449632 100644
--- a/src/Core/Record/RecordModule.php
+++ b/src/Core/Record/RecordModule.php
@@ -2,7 +2,7 @@
use Carbon\Carbon;
use Lucent\Core\Data\Record;
-use Lucent\Core\Data\RecordField;
+use Lucent\Core\Data\RecordPreview;
use Lucent\Core\Data\RecordStatus;
use stdClass;
@@ -27,6 +27,7 @@ class RecordModule
return [
"id" => $record->id,
"schema_id" => $record->schemaId,
+ "title_field_id" => $record->titleFieldId,
"created_at" => $record->createdAt->toJSON(),
"created_by" => $record->createdBy,
"published_at" => empty($record->publishedAt)
@@ -49,6 +50,7 @@ class RecordModule
return new Record(
id: data_get($data, "id"),
schemaId: data_get($data, "schema_id"),
+ titleFieldId: data_get($data, "title_field_id"),
createdAt: Carbon::parse(data_get($data, "created_at")),
createdBy: data_get($data, "created_by"),
publishedAt: empty(data_get($data, "published_at"))
@@ -65,4 +67,13 @@ class RecordModule
trashedBy: data_get($data, "trashed_by"),
);
}
+
+ public static function recordPreviewFromDb(stdClass $data): RecordPreview
+ {
+ return new RecordPreview(
+ id: data_get($data, "id"),
+ schemaId: data_get($data, "schema_id"),
+ title: data_get($data, "title"),
+ );
+ }
}
diff --git a/src/Core/Record/RecordValidationModule.php b/src/Core/Record/RecordValidationModule.php
index 1fe74f2..5bde0d6 100644
--- a/src/Core/Record/RecordValidationModule.php
+++ b/src/Core/Record/RecordValidationModule.php
@@ -157,7 +157,7 @@ class RecordValidationModule
string $locale,
): ?RecordField {
return collect($recordFields)->first(
- fn(RecordField $field) => $field->id === $schemaField->id &&
+ fn(RecordField $field) => $field->fieldId === $schemaField->id &&
$field->locale === $locale &&
$field->mode === RecordMode::DRAFT,
);
diff --git a/src/Core/Repository/RecordFieldRepo.php b/src/Core/Repository/RecordFieldRepo.php
index f237668..aa5c6a6 100644
--- a/src/Core/Repository/RecordFieldRepo.php
+++ b/src/Core/Repository/RecordFieldRepo.php
@@ -34,7 +34,7 @@ class RecordFieldRepo
public static function delete(RecordField $field): void
{
DB::table(self::TABLE_NAME)
- ->where("id", $field->id)
+ ->where("field_id", $field->fieldId)
->where("locale", $field->locale)
->where("mode", $field->mode->value)
->where("record_id", $field->recordId)
@@ -44,7 +44,7 @@ class RecordFieldRepo
public static function findOne(string $id): ?RecordField
{
return DB::table(self::TABLE_NAME)
- ->where("id", $id)
+ ->where("field_id", $id)
->get()
->map(RecordFieldModule::fromDb(...))
->first();
diff --git a/src/Core/Repository/RecordRepo.php b/src/Core/Repository/RecordRepo.php
index 1778ce0..c9e9b77 100644
--- a/src/Core/Repository/RecordRepo.php
+++ b/src/Core/Repository/RecordRepo.php
@@ -2,6 +2,7 @@
use Illuminate\Support\Facades\DB;
use Lucent\Core\Data\Record;
+use Lucent\Core\Data\RecordPreview;
use Lucent\Core\Record\RecordModule;
class RecordRepo
@@ -28,4 +29,33 @@ class RecordRepo
->map(RecordModule::fromDb(...))
->first();
}
+
+ /*
+ * @return RecordPreview[]
+ */
+ public static function findBySchemas(array $schemas): array
+ {
+ return DB::table(self::TABLE_NAME)
+ ->select(
+ "records.id",
+ "records.schema_id",
+ "records_data.value as title",
+ )
+ ->whereIn("schema_id", $schemas)
+ ->join("records_data", function ($join) {
+ $join
+ ->on("records.id", "=", "records_data.record_id")
+ ->on(
+ "records.title_field_id",
+ "=",
+ "records_data.field_id",
+ );
+ })
+ ->orderBy("created_at", "desc")
+ ->limit(5)
+ ->get()
+
+ ->map(RecordModule::recordPreviewFromDb(...))
+ ->toArray();
+ }
}
diff --git a/src/Core/Schema/Data/FieldProp/FieldProp.php b/src/Core/Schema/Data/FieldProp/FieldProp.php
index 9a352b0..27022c8 100644
--- a/src/Core/Schema/Data/FieldProp/FieldProp.php
+++ b/src/Core/Schema/Data/FieldProp/FieldProp.php
@@ -6,6 +6,7 @@ class FieldProp
{
return match ($type) {
"text" => new TextFieldProp(min: 0, max: 0, default: ""),
+ "relation" => new RelationFieldProp(schemas: [], min: 0, max: 0),
default => new InvalidFieldProp(),
};
}
@@ -24,6 +25,11 @@ class FieldProp
max: $props["max"] ?? 0,
default: $props["default"] ?? "",
),
+ "relation" => new RelationFieldProp(
+ schemas: $props["schemas"] ?? [],
+ min: $props["min"] ?? 0,
+ max: $props["max"] ?? 0,
+ ),
default => new InvalidFieldProp(),
};
}
diff --git a/src/Core/Schema/Data/FieldProp/RelationFieldProp.php b/src/Core/Schema/Data/FieldProp/RelationFieldProp.php
new file mode 100644
index 0000000..8ab7aa3
--- /dev/null
+++ b/src/Core/Schema/Data/FieldProp/RelationFieldProp.php
@@ -0,0 +1,10 @@
+edgeService->createMany(
- source: $request->input("source"),
- sourceSchema: $request->input("sourceSchema"),
- targetSchema: $request->input("targetSchema"),
- field: $request->input("field"),
- targets: $request->input("targets"),
- );
- $graph = $this->query
- ->filter(["id" => $request->input("source")])
- ->limit(1)
- ->skip(0)
- ->childrenDepth(2)
- ->childrenLimit(200)
- ->parentsDepth(1)
- ->parentsLimit(200)
- ->run();
-
- return [
- "graph" => toArray($graph),
- ];
- }
-
+ public function postCreate(Request $request) {}
}
diff --git a/src/Http/Controller/RecordController.php b/src/Http/Controller/RecordController.php
index c14687a..18c50fb 100644
--- a/src/Http/Controller/RecordController.php
+++ b/src/Http/Controller/RecordController.php
@@ -136,96 +136,6 @@ class RecordController
);
}
- public function exportCSV(Request $request)
- {
- $schemaName = $request->route("schemaName");
- $schema = $this->channelService->channel->schemas
- ->where("name", $schemaName)
- ->first();
-
- $urlParams = $request->all();
-
- $sort = data_get($urlParams, "sort") ?? "-_sys.updatedAt";
- $filter = data_get($urlParams, "filter") ?? [];
- $arguments = array_merge(
- [
- "schema" => $schema->name,
- "status_in" => "draft,published",
- ],
- $filter,
- );
-
- $records = $this->query
- ->filter($arguments)
- ->limit(-1)
- ->status(explode(",", $arguments["status_in"]))
- ->childrenDepth(1)
- // ->skip($skip)
- ->sort($sort)
- ->run()
- ->tree();
-
- header("Content-Type: application/csv");
- header(
- 'Content-Disposition: attachment; filename="' .
- $schemaName .
- '.csv";',
- );
- $handle = fopen("php://output", "w");
- $relationColumns = $this->makeCsvRelationColumns($schema);
- $csvRow = [
- "id",
- ...array_keys($records[0]->data->toArray()),
- ...$relationColumns,
- ];
- fputcsv($handle, $csvRow, ",");
- foreach ($records as $record) {
- $csvRow = [$record->id, ...$record->data->toArray()];
- $csvRow = array_merge(
- $csvRow,
- $this->makeCsvRelationColumnValues($schema, $record->_children),
- );
- $csvRow = array_values($csvRow);
- fputcsv($handle, $csvRow, ",");
- }
- fclose($handle);
- echo $handle;
- exit();
- }
-
- private function makeCsvRelationColumns($schema): array
- {
- return $schema->fields
- ->filter(fn($f) => get_class($f) === Reference::class)
- ->reduce(function ($c, $f) {
- $c[] = $f->name . " id";
- $c[] = $f->name . " name";
- return $c;
- }, []);
- }
-
- private function makeCsvRelationColumnValues($schema, $children): array
- {
- return $schema->fields
- ->filter(fn($f) => get_class($f) === Reference::class)
- ->reduce(function ($c, $f) use ($children) {
- $fieldRecords = data_get($children, $f->name);
- if (empty($fieldRecords)) {
- $c[] = "";
- $c[] = "";
- } elseif (count($fieldRecords) === 1) {
- $c[] = data_get($fieldRecords, "0.id");
- $c[] = $this->viewModel->getRecordName($fieldRecords[0]);
- } else {
- $c[] = collect($fieldRecords)->pluck("id")->join("::");
- $c[] = collect($fieldRecords)
- ->pluck("data.name")
- ->join("::");
- }
- return $c;
- }, []);
- }
-
public function edit(Request $request)
{
$recordId = $request->route("id");
@@ -291,34 +201,11 @@ class RecordController
);
}
- public function suggestions(Request $request)
+ public function suggest(Request $request)
{
- $arguments = [
- "schema" => $request->input("schema"),
- ];
-
- if ($request->input("value")) {
- if (in_array($request->input("ui"), ["text", "date"])) {
- $arguments[
- "data." . $request->input("field") . "_regex"
- ] = $request->input("value");
- } elseif ($request->input("ui") == "number") {
- $arguments[
- "data." . $request->input("field") . "_eqnum"
- ] = floatval($request->input("value"));
- } elseif ($request->input("ui") == "date") {
- } elseif ($request->input("ui") == "search") {
- $arguments["search_regex"] = $request->input("value");
- }
- }
-
- $records = $this->query->filter($arguments)->limit(10)->tree();
-
- if ($records->isEmpty()) {
- return ok([]);
- }
-
- return ok($records->toArray());
+ $schemas = $request->input("schemas");
+ $records = RecordRepo::findBySchemas($schemas);
+ return ok(toArray($records));
}
public function postCreate(Request $request)
@@ -328,10 +215,11 @@ class RecordController
$title = $request->input("title");
$now = Carbon::now();
$userId = AuthModule::getCurrentUserId();
-
+ $titleField = collect($fields)->where("alias", "_title")->first();
$record = new Record(
id: Id::new(),
schemaId: $schemaId,
+ titleFieldId: $titleField->id,
createdAt: $now,
createdBy: $userId,
publishedAt: null,
@@ -344,11 +232,10 @@ class RecordController
RecordRepo::insert($record);
- $titleField = collect($fields)->where("alias", "_title")->first();
-
$titleFieldData = new RecordField(
+ id: Id::new(),
recordId: $record->id,
- id: $titleField->id,
+ fieldId: $titleField->id,
locale: "main",
mode: RecordMode::DRAFT,
value: $title,
@@ -364,15 +251,16 @@ class RecordController
public function saveField(Request $request)
{
$recordId = $request->input("recordId");
- $id = $request->input("id");
+ $fieldId = $request->input("id");
$locale = $request->input("locale");
$value = $request->input("value") ?? "";
$now = Carbon::now();
- $field = FieldRepo::findOne($id);
+ $field = FieldRepo::findOne($fieldId);
$userId = AuthModule::getCurrentUserId();
$recordField = new RecordField(
+ id: Id::new(),
recordId: $recordId,
- id: $field->id,
+ fieldId: $field->id,
locale: $locale,
mode: RecordMode::DRAFT,
value: $value,
@@ -396,49 +284,6 @@ class RecordController
]);
}
- public function save(Request $request)
- {
- $recordId = $request->input("record.id");
- try {
- if ($request->input("isCreateMode")) {
- $recordId = $this->recordService->create(
- data: new RecordInputData(
- $request->input("record.schema"),
- $recordId ?? "",
- $request->input("record.data"),
- Status::from($request->input("record.status")),
- ),
- edges: array_map(
- EdgeInputData::fromArray(...),
- $request->input("edges") ?? [],
- ),
- );
- } else {
- $this->recordService->updateWithEdges(
- id: $request->input("record.id"),
- data: $request->input("record.data"),
- status: Status::from($request->input("record.status")),
- edges: array_map(
- EdgeInputData::fromArray(...),
- $request->input("edges") ?? [],
- ),
- );
- }
-
- $newGraph = $this->query
- ->filter(["id" => $recordId])
- ->limit(10)
- ->childrenDepth(1)
- ->parentsDepth(1)
- ->run();
- } catch (ValidatorException $th) {
- return fail($th->getValidatorErrors());
- } catch (LucentException $th) {
- return fail($th);
- }
- return ok(toArray($newGraph));
- }
-
public function clone(Request $request)
{
try {
@@ -596,4 +441,94 @@ class RecordController
return ok(toArray($record));
}
+
+ public function exportCSV(Request $request)
+ {
+ $schemaName = $request->route("schemaName");
+ $schema = $this->channelService->channel->schemas
+ ->where("name", $schemaName)
+ ->first();
+
+ $urlParams = $request->all();
+
+ $sort = data_get($urlParams, "sort") ?? "-_sys.updatedAt";
+ $filter = data_get($urlParams, "filter") ?? [];
+ $arguments = array_merge(
+ [
+ "schema" => $schema->name,
+ "status_in" => "draft,published",
+ ],
+ $filter,
+ );
+
+ $records = $this->query
+ ->filter($arguments)
+ ->limit(-1)
+ ->status(explode(",", $arguments["status_in"]))
+ ->childrenDepth(1)
+ // ->skip($skip)
+ ->sort($sort)
+ ->run()
+ ->tree();
+
+ header("Content-Type: application/csv");
+ header(
+ 'Content-Disposition: attachment; filename="' .
+ $schemaName .
+ '.csv";',
+ );
+ $handle = fopen("php://output", "w");
+ $relationColumns = $this->makeCsvRelationColumns($schema);
+ $csvRow = [
+ "id",
+ ...array_keys($records[0]->data->toArray()),
+ ...$relationColumns,
+ ];
+ fputcsv($handle, $csvRow, ",");
+ foreach ($records as $record) {
+ $csvRow = [$record->id, ...$record->data->toArray()];
+ $csvRow = array_merge(
+ $csvRow,
+ $this->makeCsvRelationColumnValues($schema, $record->_children),
+ );
+ $csvRow = array_values($csvRow);
+ fputcsv($handle, $csvRow, ",");
+ }
+ fclose($handle);
+ echo $handle;
+ exit();
+ }
+
+ private function makeCsvRelationColumns($schema): array
+ {
+ return $schema->fields
+ ->filter(fn($f) => get_class($f) === Reference::class)
+ ->reduce(function ($c, $f) {
+ $c[] = $f->name . " id";
+ $c[] = $f->name . " name";
+ return $c;
+ }, []);
+ }
+
+ private function makeCsvRelationColumnValues($schema, $children): array
+ {
+ return $schema->fields
+ ->filter(fn($f) => get_class($f) === Reference::class)
+ ->reduce(function ($c, $f) use ($children) {
+ $fieldRecords = data_get($children, $f->name);
+ if (empty($fieldRecords)) {
+ $c[] = "";
+ $c[] = "";
+ } elseif (count($fieldRecords) === 1) {
+ $c[] = data_get($fieldRecords, "0.id");
+ $c[] = $this->viewModel->getRecordName($fieldRecords[0]);
+ } else {
+ $c[] = collect($fieldRecords)->pluck("id")->join("::");
+ $c[] = collect($fieldRecords)
+ ->pluck("data.name")
+ ->join("::");
+ }
+ return $c;
+ }, []);
+ }
}
diff --git a/src/Http/web.php b/src/Http/web.php
index 8453a01..afe4359 100644
--- a/src/Http/web.php
+++ b/src/Http/web.php
@@ -70,6 +70,7 @@ Route::group(
Route::get("content/{id}", [RecordController::class, "index"]);
// RECORD
+ Route::get("records/suggest", [RecordController::class, "suggest"]);
Route::get("records/{id}", [RecordController::class, "edit"]);
Route::post("records", [RecordController::class, "postCreate"]);
Route::post("records/fields", [
diff --git a/src/Record/Record.php b/src/Record/Record.php
index bcc1947..46cdd25 100644
--- a/src/Record/Record.php
+++ b/src/Record/Record.php
@@ -8,30 +8,37 @@ use Illuminate\Support\Str;
class Record implements JsonSerializable
{
-
-
function __construct(
- public string $id,
- public string $schema,
- public Status $status,
- public System $_sys,
+ public string $id,
+ public string $schema,
+ public Status $status,
+ public System $_sys,
public RecordData $data,
- public ?FileData $_file = null,
- )
+ public ?FileData $_file = null,
+ ) {}
+
+ private function indexValues(array $arrObject)
{
- }
-
-
- private function indexValues(array $arrObject){
-
- return trim(Str::lower(collect($arrObject)
- ->map(function($value){
- if(is_array($value)){
- return $this->indexValues($value ?? []);
- }
- return str_replace(array("\r", "\n"), '', strip_tags((string)$value));
- })
- ->values()->join(" ")." ". $this->_file?->originalName ?? ""));
+ return trim(
+ Str::lower(
+ collect($arrObject)
+ ->map(function ($value) {
+ if (is_array($value)) {
+ return $this->indexValues($value ?? []);
+ }
+ return str_replace(
+ ["\r", "\n"],
+ "",
+ strip_tags((string) $value),
+ );
+ })
+ ->values()
+ ->join(" ") .
+ " " .
+ $this->_file?->originalName ??
+ "",
+ ),
+ );
}
public function toDB(): array
@@ -50,10 +57,8 @@ class Record implements JsonSerializable
public static function fromDB(stdClass $data): Record
{
-
$file = json_decode($data->_file, true);
if (!empty($file)) {
-
$file = FileData::fromArray($file);
} else {
$file = null;
@@ -69,11 +74,8 @@ class Record implements JsonSerializable
);
}
-
public function jsonSerialize(): static
{
return $this;
}
-
-
}