designtopack/public/kirby/src/Content/Content.php
2024-07-10 16:10:33 +02:00

248 lines
4.6 KiB
PHP

<?php
namespace Kirby\Content;
use Kirby\Cms\Blueprint;
use Kirby\Cms\ModelWithContent;
use Kirby\Form\Form;
/**
* The Content class handles all fields
* for content from pages, the site and users
*
* @package Kirby Content
* @author Bastian Allgeier <bastian@getkirby.com>
* @link https://getkirby.com
* @copyright Bastian Allgeier
* @license https://getkirby.com/license
*/
class Content
{
/**
* The raw data array
*/
protected array $data = [];
/**
* Cached field objects
* Once a field is being fetched
* it is added to this array for
* later reuse
*/
protected array $fields = [];
/**
* A potential parent object.
* Not necessarily needed. Especially
* for testing, but field methods might
* need it.
*/
protected ModelWithContent|null $parent;
/**
* Magic getter for content fields
*/
public function __call(string $name, array $arguments = []): Field
{
return $this->get($name);
}
/**
* Creates a new Content object
*
* @param bool $normalize Set to `false` if the input field keys are already lowercase
*/
public function __construct(
array $data = [],
ModelWithContent $parent = null,
bool $normalize = true
) {
if ($normalize === true) {
$data = array_change_key_case($data, CASE_LOWER);
}
$this->data = $data;
$this->parent = $parent;
}
/**
* Same as `self::data()` to improve
* `var_dump` output
* @codeCoverageIgnore
*
* @see self::data()
*/
public function __debugInfo(): array
{
return $this->toArray();
}
/**
* Converts the content to a new blueprint
*/
public function convertTo(string $to): array
{
// prepare data
$data = [];
$content = $this;
// blueprints
$old = $this->parent->blueprint();
$subfolder = dirname($old->name());
$new = Blueprint::factory(
$subfolder . '/' . $to,
$subfolder . '/default',
$this->parent
);
// forms
$oldForm = new Form([
'fields' => $old->fields(),
'model' => $this->parent
]);
$newForm = new Form([
'fields' => $new->fields(),
'model' => $this->parent
]);
// fields
$oldFields = $oldForm->fields();
$newFields = $newForm->fields();
// go through all fields of new template
foreach ($newFields as $newField) {
$name = $newField->name();
$oldField = $oldFields->get($name);
// field name and type matches with old template
if ($oldField?->type() === $newField->type()) {
$data[$name] = $content->get($name)->value();
} else {
$data[$name] = $newField->default();
}
}
// preserve existing fields
return array_merge($this->data, $data);
}
/**
* Returns the raw data array
*/
public function data(): array
{
return $this->data;
}
/**
* Returns all registered field objects
*/
public function fields(): array
{
foreach ($this->data as $key => $value) {
$this->get($key);
}
return $this->fields;
}
/**
* Returns either a single field object
* or all registered fields
*/
public function get(string $key = null): Field|array
{
if ($key === null) {
return $this->fields();
}
$key = strtolower($key);
return $this->fields[$key] ??= new Field(
$this->parent,
$key,
$this->data()[$key] ?? null
);
}
/**
* Checks if a content field is set
*/
public function has(string $key): bool
{
return isset($this->data[strtolower($key)]) === true;
}
/**
* Returns all field keys
*/
public function keys(): array
{
return array_keys($this->data());
}
/**
* Returns a clone of the content object
* without the fields, specified by the
* passed key(s)
*/
public function not(string ...$keys): static
{
$copy = clone $this;
$copy->fields = [];
foreach ($keys as $key) {
unset($copy->data[strtolower($key)]);
}
return $copy;
}
/**
* Returns the parent
* Site, Page, File or User object
*/
public function parent(): ModelWithContent|null
{
return $this->parent;
}
/**
* Set the parent model
*
* @return $this
*/
public function setParent(ModelWithContent $parent): static
{
$this->parent = $parent;
return $this;
}
/**
* Returns the raw data array
*
* @see self::data()
*/
public function toArray(): array
{
return $this->data();
}
/**
* Updates the content and returns
* a cloned object
*
* @return $this
*/
public function update(
array $content = null,
bool $overwrite = false
): static {
$content = array_change_key_case((array)$content, CASE_LOWER);
$this->data = $overwrite === true ? $content : array_merge($this->data, $content);
// clear cache of Field objects
$this->fields = [];
return $this;
}
}