diff --git a/app/Classes/AttachmentsManager.php b/app/Classes/AttachmentsManager.php index fd99117..a3f0d6d 100644 --- a/app/Classes/AttachmentsManager.php +++ b/app/Classes/AttachmentsManager.php @@ -55,6 +55,23 @@ public function addToHistory(string $name, array $data): string return $reference; } + /** + * Provides direct access to underlying manager for better control + */ + public function manager(): MetadataManager + { + return $this->manager; + } + + /** + * Add or replace attachment with specified reference. Will replace existing + * data + */ + public function upsert(string $reference, array $data) + { + $this->manager['files'][$reference] = $data; + } + /** * Add a single file to the bundle */ @@ -87,6 +104,14 @@ public function exists() return $this->disk->exists($this->metadataFilePath); } + /** + * Load data from disk + */ + public function load() + { + $this->manager->load(); + } + /** * Store file on disk */ diff --git a/app/Classes/Bundle.php b/app/Classes/Bundle.php index 8c91dc6..7c2fd10 100644 --- a/app/Classes/Bundle.php +++ b/app/Classes/Bundle.php @@ -18,6 +18,18 @@ public function __construct(protected string $path, protected FilesystemAdapter { $this->path = Str::start(Str::finish($this->path, '/'), '/'); $this->dataDir = $this->path . 'data/'; + + $this->registerDefaultManagers(); + } + + /** + * Load everything + */ + public function load() + { + $this->loadAttachments(); + $this->loadMetadata(); + $this->loadMarkdown(); } /** @@ -30,6 +42,19 @@ public function save() $this->saveMarkdown(); } + /** + * Register default managers + */ + private function registerDefaultManagers() + { + $this->markdown(); + $this->metadata(); + $this->metadata('metadata'); + $this->attachments(AttachmentsManager::Images); + $this->attachments(AttachmentsManager::Sounds); + $this->attachments(AttachmentsManager::Videos); + } + /** * Get a complete filename prefixed with bundle's path */ diff --git a/app/Classes/MarkdownManager.php b/app/Classes/MarkdownManager.php index 55fc960..d687370 100644 --- a/app/Classes/MarkdownManager.php +++ b/app/Classes/MarkdownManager.php @@ -29,6 +29,16 @@ public function exists() return $this->disk->exists($this->filename); } + /** + * Load markdown file + */ + public function load() + { + $content = $this->disk->get($this->filename); + + $this->set($content); + } + /** * Return current markdown content */ diff --git a/app/Classes/MetadataManager.php b/app/Classes/MetadataManager.php index df7d28f..abf8189 100644 --- a/app/Classes/MetadataManager.php +++ b/app/Classes/MetadataManager.php @@ -2,55 +2,70 @@ namespace App\Classes; -use ArrayAccess; use Illuminate\Filesystem\FilesystemAdapter; +use Illuminate\Support\Collection; -class MetadataManager implements ArrayAccess +/** + * Class MetadataManager + * + * This class is designed to handle metadata for articles or any other items that + * might have associated metadata stored in a JSON format. It uses Laravel's + * Collections for flexible data manipulation and the disk for storage. + */ +class MetadataManager { - /** - * Original metadata content - */ - private array $originalContent = []; + protected $originalContent; + + protected $content; /** - * Current metadata content + * Constructor for the MetadataManager class. + * + * @param string $filename The filename where metadata is stored. + * @param disk $disk The disk abstraction provided by Laravel. */ - private array $content = []; - public function __construct(protected string $filename, protected FilesystemAdapter $disk) { - + $this->load(); } /** - * Return a boolean value indicating if the file actually exists on disk + * Loads metadata from disk using the disk, with caching to improve performance. */ - public function exists() + public function load() { - return $this->disk->exists($this->filename); + $data = $this->readFromDisk(); + + $this->originalContent = new Collection($data); + $this->content = new Collection($data); } /** - * Set a new array of values + * Reads metadata from disk. Caches the content to reduce file system reads. + * + * @return array The data read from the file. */ - public function set(array $content): void + protected function readFromDisk() { - $this->content = $content; + $data = $this->disk->get($this->filename); + + return json_decode($data, true) ?? []; } /** - * Return a boolean indicating if the file has changed since it was loaded + * Checks if the content has been modified since it was last loaded or saved. + * + * @return bool True if the content is dirty (modified), false otherwise. */ public function isDirty(): bool { - $original = collect($this->originalContent); - $current = collect($this->content); - - return !$original->diffAssoc($current)->isEmpty() || !$current->diffAssoc($original)->isEmpty(); + return $this->originalContent->toJson() != $this->content->toJson(); } /** - * Store file on disk + * Saves the metadata to disk if it has been modified (is dirty). + * + * @return bool True if the data was saved successfully, false otherwise. */ public function save(): bool { @@ -58,40 +73,75 @@ public function save(): bool return false; } - $json = json_encode($this->content, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); + $this->writeToDisk($this->content->all()); - $this->disk->put($this->filename, $json); - - $this->originalContent = $this->content; + $this->originalContent = new Collection($this->content->all()); return true; } - public function offsetExists(mixed $offset): bool + /** + * Writes the provided data to disk as JSON. + * + * @param array $data The data to write to disk. + */ + protected function writeToDisk(array $data) { - return isset($this->content[$offset]); + $json = json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); + + $this->disk->put($this->filename, $json); } - public function &offsetGet(mixed $offset): mixed + /** + * Sets a metadata value for a specified key. + * + * @param mixed $key The key under which to store the value. + * @param mixed $value The value to store. + */ + public function set($key, $value) { - if (!isset($this->content[$offset])) { - $this->content[$offset] = null; - } - - return $this->content[$offset]; + $this->content->put($key, $value); } - public function offsetSet(mixed $offset, mixed $value): void + /** + * Sets multiple metadata at once. + */ + public function setMany(array $array) { - if (is_null($offset)) { - $this->content[] = $value; - } else { - $this->content[$offset] = $value; + foreach ($array as $key => $value) { + $this->content->put($key, $value); } } - public function offsetUnset(mixed $offset): void + /** + * Retrieves a metadata value by key. + * + * @param mixed $key The key of the value to retrieve. + * @param mixed $default The default value to return if the key does not exist. + * @return mixed The value of the specified key, or the default value. + */ + public function get($key, $default = null) { - unset($this->content[$offset]); + return $this->content->get($key, $default); + } + + /** + * Retrieves all metadata as an associative array. + * + * @return array The content of the metadata. + */ + public function all() + { + return $this->content->all(); + } + + /** + * Removes a metadata entry by key. + * + * @param mixed $key The key of the entry to remove. + */ + public function remove($key) + { + $this->content->forget($key); } } diff --git a/app/Classes/Traits/ManagesAttachments.php b/app/Classes/Traits/ManagesAttachments.php index 56e28c9..e78a19f 100644 --- a/app/Classes/Traits/ManagesAttachments.php +++ b/app/Classes/Traits/ManagesAttachments.php @@ -20,6 +20,16 @@ private function registerAttachmentsManager(string $kind): AttachmentsManager return $this->attachmentsManagers[$kind]; } + /** + * Load all attachments files + */ + private function loadAttachments() + { + foreach ($this->attachmentsManagers as $manager) { + $manager->load(); + } + } + /** * Save all attachments files that needs to be */ diff --git a/app/Classes/Traits/ManagesMarkdown.php b/app/Classes/Traits/ManagesMarkdown.php index fb31bfd..92dab22 100644 --- a/app/Classes/Traits/ManagesMarkdown.php +++ b/app/Classes/Traits/ManagesMarkdown.php @@ -22,6 +22,16 @@ private function registerMarkdownManager(string $filename): MarkdownManager return $this->markdownManagers[$filename]; } + /** + * Load all markdown files at once + */ + private function loadMarkdown() + { + foreach ($this->markdownManagers as $manager) { + $manager->load(); + } + } + /** * Save all markdown files that needs to be */ diff --git a/app/Classes/Traits/ManagesMetadata.php b/app/Classes/Traits/ManagesMetadata.php index 526035d..2ce2cdb 100644 --- a/app/Classes/Traits/ManagesMetadata.php +++ b/app/Classes/Traits/ManagesMetadata.php @@ -22,6 +22,16 @@ private function registerMetadataManager(string $filename): MetadataManager return $this->metadataManagers[$filename]; } + /** + * Load all metadata files at once + */ + private function loadMetadata() + { + foreach ($this->metadataManagers as $manager) { + $manager->load(); + } + } + /** * Save all metadata files that needs to be */ diff --git a/app/Services/BundleCreator/Creators/BlogBundleCreator.php b/app/Services/BundleCreator/Creators/BlogBundleCreator.php index afdbe30..a1c17d0 100644 --- a/app/Services/BundleCreator/Creators/BlogBundleCreator.php +++ b/app/Services/BundleCreator/Creators/BlogBundleCreator.php @@ -37,7 +37,7 @@ public function createBundle(): string } $bundle->markdown()->set(''); - $bundle->metadata()->set([ + $bundle->metadata()->setMany([ 'title' => $title, 'date' => $date->toIso8601String(), ]); diff --git a/app/Services/BundleCreator/Creators/LinkBundleCreator.php b/app/Services/BundleCreator/Creators/LinkBundleCreator.php index 9e79011..45ef7f7 100644 --- a/app/Services/BundleCreator/Creators/LinkBundleCreator.php +++ b/app/Services/BundleCreator/Creators/LinkBundleCreator.php @@ -46,10 +46,10 @@ public function createBundle(): string $ref = $bundle->attachments(AttachmentsManager::Images)->addToHistory('screenshot', [ 'contents' => $screenshot, - 'filename' => sprintf('screenshot-%s.jpg', now()->format('Y-m-d')), + 'url' => sprintf('screenshot-%s.jpg', now()->format('Y-m-d')), ]); - $bundle->metadata()->set([ + $bundle->metadata()->setMany([ 'title' => $title, 'date' => $date->toIso8601String(), 'cover' => $ref,