Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve file sorting performance #6112

Merged
merged 10 commits into from
Feb 5, 2024
104 changes: 104 additions & 0 deletions src/Cms/Blueprint.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ class Blueprint
protected $sections = [];
protected $tabs = [];

protected array|null $fileTemplates = null;

/**
* Magic getter/caller for any blueprint prop
*/
Expand Down Expand Up @@ -96,6 +98,108 @@ public function __debugInfo(): array
return $this->props ?? [];
}

/**
* Gathers what file templates are allowed in
* this model based on the blueprint
*/
public function acceptedFileTemplates(string $inSection = null): array
{
// get cached results for the current file model
// (except when collecting for a specific section)
if ($inSection === null && $this->fileTemplates !== null) {
return $this->fileTemplates; // @codeCoverageIgnore
}

$templates = [];

// collect all allowed file templates from blueprint…
foreach ($this->sections() as $section) {
// if collecting for a specific section, skip all others
if ($inSection !== null && $section->name() !== $inSection) {
continue;
}

$templates = match ($section->type()) {
'files' => [...$templates, $section->template() ?? 'default'],
'fields' => [
...$templates,
...$this->acceptedFileTemplatesFromFields($section->fields())
],
default => $templates
};
}

// no caching for when collecting for specific section
if ($inSection !== null) {
return $templates; // @codeCoverageIgnore
}

return $this->fileTemplates = $templates;
}

/**
* Gathers the allowed file templates from model's fields
*/
protected function acceptedFileTemplatesFromFields(array $fields): array
{
$templates = [];

foreach ($fields as $field) {
// fields with uploads settings
if (isset($field['uploads']) === true && is_array($field['uploads']) === true) {
$templates = array_merge($templates, $this->acceptedFileTemplatesFromFieldUploads($field['uploads']));
continue;
}

// structure and object fields
if (isset($field['fields']) === true && is_array($field['fields']) === true) {
$fields = $this->acceptedFileTemplatesFromFields($field['fields']);
$templates = array_merge($templates, $fields);
continue;
}

// layout and blocks fields
if (isset($field['fieldsets']) === true && is_array($field['fieldsets']) === true) {
$fieldsets = $this->acceptedFileTemplatesFromFieldsets($field['fieldsets']);
$templates = array_merge($templates, $fieldsets);
bastianallgeier marked this conversation as resolved.
Show resolved Hide resolved
continue;
}
}

return $templates;
}

/**
* Gathers the allowed file templates from fieldsets
*/
protected function acceptedFileTemplatesFromFieldsets(array $fieldsets): array
{
$templates = [];

foreach ($fieldsets as $fieldset) {
foreach (($fieldset['tabs'] ?? []) as $tab) {
$templates = array_merge($templates, $this->acceptedFileTemplatesFromFields($tab['fields'] ?? []));
}
}

return $templates;
}

/**
* Extracts templates from field uploads settings
*/
protected function acceptedFileTemplatesFromFieldUploads(array $uploads): array
{
// only if the `uploads` parent is this model
if ($target = $uploads['parent'] ?? null) {
if ($this->model->id() !== $target) {
return [];
}
}

return [($uploads['template'] ?? 'default')];
}

/**
* Converts all column definitions, that
* are not wrapped in a tab, into a generic tab
Expand Down
67 changes: 6 additions & 61 deletions src/Cms/File.php
Original file line number Diff line number Diff line change
Expand Up @@ -157,72 +157,17 @@ public function blueprint(): FileBlueprint
*/
public function blueprints(string $inSection = null): array
{
// get cached results for the current file model
// (except when collecting for a specific section)
if ($inSection === null && $this->blueprints !== null) {
return $this->blueprints; // @codeCoverageIgnore
}

// always include the current template as option
$template = $this->template() ?? 'default';
$templates = [$template];
$parent = $this->parent();

// what file templates/blueprints should be considered is
// defined bythe parent's blueprint: which templates it allows
// in files sections as well as files fields
$blueprint = $parent->blueprint();

$fromFields = function ($fields) use (&$fromFields, $parent) {
$templates = [];

foreach ($fields as $field) {
// files or textare field
if (
$field['type'] === 'files' ||
$field['type'] === 'textarea'
) {
$uploads = $field['uploads'] ?? null;

// only if the `uploads` parent is the actual parent
if ($target = $uploads['parent'] ?? null) {
if ($parent->id() !== $target) {
continue;
}
}

$templates[] = $uploads['template'] ?? 'default';
continue;
}

// structure field
if ($field['type'] === 'structure') {
$fields = $fromFields($field['fields']);
$templates = array_merge($templates, $fields);
continue;
}
}

return $templates;
};

// collect all allowed templates…
foreach ($blueprint->sections() as $section) {
// if collecting for a specific section, skip all others
if ($inSection !== null && $section->name() !== $inSection) {
continue;
}

// …from files sections
if ($section->type() === 'files') {
$templates[] = $section->template() ?? 'default';
continue;
}

// …from fields
if ($section->type() === 'fields') {
$fields = $fromFields($section->fields());
$templates = array_merge($templates, $fields);
}
}
$templates = [
$this->template() ?? 'default',
...$this->parent()->blueprint()->acceptedFileTemplates($inSection)
];

// make sure every template is only included once
$templates = array_unique(array_filter($templates));
Expand Down
5 changes: 5 additions & 0 deletions src/Cms/FileActions.php
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,11 @@ public function changeName(
*/
public function changeSort(int $sort): static
{
// skip if the sort number stays the same
if ($this->sort()->value() === $sort) {
return $this;
}

return $this->commit(
'changeSort',
['file' => $this, 'position' => $sort],
Expand Down
Loading
Loading