avris / esse
The essential CMS
Installs: 349
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Forks: 0
Type:symfony-bundle
pkg:composer/avris/esse
Requires
- php: ^7.4|^8.0
- ext-gd: *
- ext-json: *
- avris/suml: ^0.3
- symfony/dependency-injection: ^4.3|^5.0
- symfony/string: ^5.0
README
A filesystem-based, git-oriented CMS focusing only on what is (deemed by me as) "essential".
Installation
composer require avris/esse
Enable the bundle in config/bundles.php:
Avris\Esse\AvrisEsseBundle::class => ['all' => true],
config/routes.yaml:
esse_image:
path: '/image/{filename}_{size}.{extension}'
requirements: { filename:'.+' }
controller: 'Avris\Esse\Controller\EsseController::image'
esse_file:
path: '/file/{filename}.{extension}'
requirements: { filename:'.+' }
controller: 'Avris\Esse\Controller\EsseController::file'
.gitignore:
/public/image
(Optionally) overwrite default config in config/packages/avris_esse:
avris_esse:
entriesDir: '%kernel.project_dir%/content/entries'
imagesDir: '%kernel.project_dir%/content/images'
filesDir: '%kernel.project_dir%/content/files'
imageSizes:
big: { maxwidth: 960 }
small: { maxwidth: 480 }
micro: { maxwidth: 36, maxheight: 36}
Usage
Basic concepts
Content is basically a set of entries (SUML files). They can be of different types:
block- just a generic string or an arrayimagefile- any custom type you want
They are put in the /content/entries, /content/images and /content/files directories, respectively.
For instance, if you put the following content in /content/entries/about/skills.suml:
content:
en:
programming:
php: 'PHP'
js: 'JavaScript'
soft:
teamwork: 'Teamwork'
pl:
soft:
teamwork: 'Praca zespoĊowa'
Then you can fetch it like this:
public function foo(Esse $esse)
{
return $this->render('home/foo.html.twig', [
'skills' => $esse->get('about/skills'),
]);
}
You can also fetch a specific field inside of the content using $esse->getPart('about/skills.soft.teamwork'),
or in a template: {{ esse('about/skills.soft.teamwork') }}. It will be automatically translated to the current request locale,
using %locale% and then a generic "language" _ as a fallback.
You can optionally add any metadata you want
(including type which defaults to block, image or file depending on which directory the file is in,
and published which defaults to false):
type: `article`
createdAt: 2020-03-11 12:34:56
content: [] # ...
Those can be accessed with $entry->meta('createdAt').
Images
With an image put in /content/images/album.png the following content of /content/images/album.suml:
type: 'image' # optional
filename: 'album.png'
alt: 'My photo album'
source: 'https://example.com/album.png'
Esse will give you that image with $esse->getImage('album') and under https://127.0.0.1:8000/image/album_sm.png
it will serve the sm version of that image (as defined in config, under imageSizes).
Files
With an file put in /content/files/foo.txt the following content of /content/files/foo.suml:
type: 'file' # optional
filename: 'foo.txt'
published: true # optional
title: 'The Foo file'
Esse will give you that file with $esse->getFile('foo') and serve it under https://127.0.0.1:8000/file/file.txt.
Modifiers
You can implement Avris\Esse\Interfaces\EsseModifier to modify any entry before it gets served by Esse, for example:
<?php
namespace App\Article;
use App\Service\ArticleProcessor;
use Avris\Esse\Entity\Entry;
use Avris\Esse\Interfaces\EsseModifier;
final class ArticleModifier implements EsseModifier
{
private ArticleProcessor $articleProcessor;
public function __construct(ArticleProcessor $articleProcessor)
{
$this->articleProcessor = $articleProcessor;
}
public function modifyEntry(Entry $entry): ?Entry
{
if ($entry->type()->toString() !== 'article') {
return $entry;
}
if (!$entry->published() || $entry->meta('publishedAt') > new \DateTimeImmutable()) {
return null;
}
$data = $entry->allMeta();
$data['content'] = [];
foreach ($entry->versions() as $version) {
$data['content'][$version] = $this->articleProcessor->process($entry->content($version));
}
return $entry->with($data);
}
}
Indexes
You can implement Avris\Esse\Interfaces\EsseIndex to create a cached index of entries, for example:
<?php
namespace App\Article;
use Avris\Esse\Interfaces\EsseIndex;
final class TagIndex implements EsseIndex
{
public function id(): string
{
return 'tag';
}
public function build(iterable $rawFiles): array
{
$index = [];
foreach ($rawFiles as $key => $data) {
if (($data['type'] ?? null) !== 'article') {
continue;
}
foreach ($data['content'] ?? [] as $version => $content) {
foreach ($content['tags'] ?? [] as $tag) {
$tag = mb_strtolower($tag);
if (!isset($index[$tag])) {
$index[$tag] = [];
}
$index[$tag][] = $key;
}
}
}
return $index;
}
}
Example usage:
/**
* @Route("/tag/{tag}")
*/
public function tag(string $tag, Esse $esse)
{
return $this->renderFormat('tag', [
'articles' => $esse->fromIndex('tag', mb_strtolower($tag)),
]);
}
Copyright
- Author: Andre Prusinowski (Avris.it)
- Licence: MIT