commit 41455d8e390f51be802dbfcc555a162fef1cb235 Author: Simon Vieille Date: Sun May 30 20:36:00 2021 +0200 init diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ac70d56 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/site/ +/Makefile diff --git a/docs/crud.md b/docs/crud.md new file mode 100644 index 0000000..e08882c --- /dev/null +++ b/docs/crud.md @@ -0,0 +1,2 @@ +# Welcome to Murph FR + diff --git a/docs/img/settings/01.png b/docs/img/settings/01.png new file mode 100644 index 0000000..5535d2c Binary files /dev/null and b/docs/img/settings/01.png differ diff --git a/docs/img/settings/02.png b/docs/img/settings/02.png new file mode 100644 index 0000000..3183bd9 Binary files /dev/null and b/docs/img/settings/02.png differ diff --git a/docs/img/settings/03.png b/docs/img/settings/03.png new file mode 100644 index 0000000..54bb20c Binary files /dev/null and b/docs/img/settings/03.png differ diff --git a/docs/img/settings/04.png b/docs/img/settings/04.png new file mode 100644 index 0000000..d0e4924 Binary files /dev/null and b/docs/img/settings/04.png differ diff --git a/docs/img/tasks/01.png b/docs/img/tasks/01.png new file mode 100644 index 0000000..5b7a9b7 Binary files /dev/null and b/docs/img/tasks/01.png differ diff --git a/docs/img/tasks/02.png b/docs/img/tasks/02.png new file mode 100644 index 0000000..f500372 Binary files /dev/null and b/docs/img/tasks/02.png differ diff --git a/docs/img/tree/01.png b/docs/img/tree/01.png new file mode 100644 index 0000000..192b2c2 Binary files /dev/null and b/docs/img/tree/01.png differ diff --git a/docs/img/tree/02.png b/docs/img/tree/02.png new file mode 100644 index 0000000..1dccffa Binary files /dev/null and b/docs/img/tree/02.png differ diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..0f4aea8 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,11 @@ +# Welcome to Murph + +Muprh is an open-source CMF built on **top of Symfony** that helps you to **build your +own CMS** with several domains and languages. It comes with a fully implemented +and customizable tree manager, a CRUD generator, a 2FA authentication, settings and tasks +managers. + +Symfony developers will love build on Murph 💪 +End users will be fond of the interface and the powerful tools 💜 + + diff --git a/docs/install.md b/docs/install.md new file mode 100644 index 0000000..26ad304 --- /dev/null +++ b/docs/install.md @@ -0,0 +1,44 @@ +# Installation + +## Technical Requirements + +* Install PHP 7.3 or higher and these PHP extensions (which are installed and enabled by default in most PHP 7 installations): Ctype, iconv, JSON, PCRE, Session, SimpleXML, and Tokenizer; +* [Install Composer](https://getcomposer.org/download/), which is used to install PHP packages. +* [Install NodeJS](https://nodejs.org/en/download/) 12 or higher, [Yarn](https://classic.yarnpkg.com/en/docs/install/#debian-stable) and [Webpack](https://webpack.js.org/guides/installation/) +* A created database (MySQL, PostgreSQL or SQLite) +* build-essential to run `make` + +## Setting up the skeleton + +Depending of you environment, PHP and composer could be located in specific paths. +Defines theme with environment vars: + +``` +export PHP=/path/to/php +export COMPOSER=/path/to/composer +``` + +Create your project: + +``` +composer create-project murph/murph-skeleton my_project -s dev +``` + +An error occured because of the unconfigured database. + +* Copy `.env` into `.env.local` +* Edit `.env.local` ([documentation](https://symfony.com/doc/current/configuration.html#configuring-environment-variables-in-env-files)) +* Run `php bin/doctrine-migrate` (or `make doctrine-migrate`) + +And finally, build assets with `make asset`. + +## Create an admin user + +Run `php bin/console murph:user:create` and answer questions. + +## Configure a web server + +Read the documentation of Symfony to [configure a web server](https://symfony.com/doc/current/setup/web_server_configuration.html). + +In case of a local server, you can use the [Symfony Local Web Server](https://symfony.com/doc/current/setup/symfony_server.html). +Then go to [https://127.0.0.1:8000/admin](https://127.0.0.1:8000/admin). diff --git a/docs/settings.md b/docs/settings.md new file mode 100644 index 0000000..d9909fb --- /dev/null +++ b/docs/settings.md @@ -0,0 +1,259 @@ +# Settings + +## Global settings + +![](/img/settings/02.png) + +### Create settings + +The creation of settings is based on events. + +Using an event subscriber, you can create settings and define how to edit them. +A setting's value is stored in json so a value could be a string, a boolean, an array, etc. + +See the example below. + +``` +// src/EventSuscriber/SettingEventSubscriber.php +namespace App\EventSuscriber; + +use App\Core\Event\Setting\SettingEvent; +use App\Core\EventSuscriber\SettingEventSubscriber as EventSubscriber; +use App\Core\Setting\SettingManager; +use Symfony\Component\Form\Extension\Core\Type\CheckboxType; +use Symfony\Component\Form\Extension\Core\Type\ColorType; + +class SettingEventSubscriber extends EventSubscriber +{ + protected SettingManager $manager; + + public function __construct(SettingManager $manager) + { + $this->manager = $manager; + } + + public function onInit(SettingEvent $event) + { + $this->manager->init('app_font_color', 'Font color', 'Design', '#fff'); + $this->manager->init('app_background_color', 'Background color', 'Design', '#333'); + $this->manager->init('app_maintenance_enabled', 'Maintenance', 'System', false); + } + + public function onFormInit(SettingEvent $event) + { + $data = $event->getData(); + $builder = $data['builder']; + $entity = $data['entity']; + + if (in_array($entity->getCode(), ['app_font_color', 'app_background_color'])) { + $builder->add( + 'value', + ColorType::class, + [ + 'label' => $entity->getLabel(), + ] + ); + } + + if (in_array($entity->getCode(), ['app_maintenance_enabled'])) { + $builder->add( + 'value', + CheckboxType::class, + [ + 'label' => $entity->getLabel(), + ] + ); + } + } +} +``` + +### Access settings + +Settings are accessible using `App\Core\Setting\SettingManager` which is a service. + +``` +// src/Controller/FooController.php +namespace App\Controller; + +use App\Core\Setting\SettingManager; +use Symfony\Component\HttpFoundation\Response; + +class FooController +{ + public function foo(SettingManager $settingManager): Response + { + $fontColor = $settingManager->get('app_font_color'); + $backgroundColor = $settingManager->get('app_background_color'); + $maintenanceEnabled = $settingManager->get('app_maintenance_enabled'); + + // ... + } +} +``` + +In a template, you can use the function `setting`: + +``` +Font color: {{ setting('app_font_color') }}
+Background color: {{ setting('app_background_color') }}
+Maintenance enabled: {{ setting('app_maintenance_enabled') ? 'Yes' : 'No' }}
+``` + + +### Update settings + +Settings are accessible using `App\Core\Setting\SettingManager` which is a service. + +``` +// src/Controller/FooController.php +namespace App\Controller; + +use App\Core\Setting\SettingManager; +use Symfony\Component\HttpFoundation\Response; + +class FooController +{ + public function foo(SettingManager $settingManager): Response + { + $settingManager->set('app_font_color', '#f00'); + $settingManager->set('app_background_color', '#00f'); + $settingManager->set('app_maintenance_enabled', true); + + // ... + } +} +``` + +You can also edit them from UI: + +![](/img/settings/01.png) + + +## Navigation settings + +![](/img/settings/03.png) + +### Create settings + +The creation of settings is based on events. + +Using an event subscriber, you can create settings and define how to edit them. +A setting's value is stored in json so a value could be a string, a boolean, an array, etc. + +See the example below. + +``` +// src/EventSuscriber/NavigationSettingEventSubscriber.php +namespace App\EventSuscriber; + +use App\Core\Event\Setting\NavigationSettingEvent; +use App\Core\EventSuscriber\NavigationSettingEventSubscriber as EventSubscriber; +use App\Core\Setting\NavigationSettingManager; +use Symfony\Component\Form\Extension\Core\Type\TextType; +use Symfony\Component\Form\Extension\Core\Type\EmailType; + +class NavigationSettingEventSubscriber extends EventSubscriber +{ + protected NavigationSettingManager $manager; + + public function __construct(NavigationSettingManager $manager) + { + $this->manager = $manager; + } + + public function onInit(NavigationSettingEvent $event) + { + $data = $event->getData(); + $navigation = $data['navigation']; + + $this->manager->init($navigation, 'nav_tracker_code', 'Stats', 'Tracker', ''); + $this->manager->init($navigation, 'nav_contact_email', 'Contact', 'Email', 'foo@example.com'); + } + + public function onFormInit(NavigationSettingEvent $event) + { + $data = $event->getData(); + $builder = $data['builder']; + $entity = $data['entity']; + + if (in_array($entity->getCode(), ['nav_tracker_code'])) { + $builder->add( + 'value', + TextType::class, + [ + 'label' => $entity->getLabel(), + ] + ); + } + + if (in_array($entity->getCode(), ['nav_contact_email'])) { + $builder->add( + 'value', + EmailType::class, + [ + 'label' => $entity->getLabel(), + ] + ); + } + } +} +``` + +### Access settings + +Settings are accessible using `App\Core\Setting\NavigationSettingManager` which is a service. + +``` +// src/Controller/FooController.php +namespace App\Controller; + +use App\Core\Setting\NavigationSettingManager; +use App\Core\Site\SiteRequest; +use Symfony\Component\HttpFoundation\Response; + +class FooController +{ + public function foo(NavigationSettingManager $settingManager, SiteRequest $siteRequest): Response + { + $trackerCode = $settingManager->get($siteRequest->getNavigation(), 'nav_tracker_code'); + $contactEmail = $settingManager->get($siteRequest->getNavigation(), 'nav_contact_email'); + + // ... + } +} +``` + +In a template, you can use the function `navigation_setting`: + +``` +Tracker code: {{ navigation_setting(_navigation, 'nav_tracker_code') }}
+Contact email: {{ navigation_setting('my_nav', 'nav_contact_email') }}
+``` +### Update settings + +Settings are accessible using `App\Core\Setting\NavigationSettingManager` which is a service. + +``` +// src/Controller/FooController.php +namespace App\Controller; + +use App\Core\Setting\NavigationSettingManager; +use App\Core\Site\SiteRequest; +use Symfony\Component\HttpFoundation\Response; + +class FooController +{ + public function foo(NavigationSettingManager $settingManager, SiteRequest $siteRequest): Response + { + $settingManager->set($siteRequest->getNavigation(), 'nav_tracker_code', '...'); + $settingManager->set('my_nav', 'nav_contact_email', '...'); + + // ... + } +} +``` + +You can also edit them from UI: + +![](/img/settings/04.png) diff --git a/docs/tasks.md b/docs/tasks.md new file mode 100644 index 0000000..a15d5b0 --- /dev/null +++ b/docs/tasks.md @@ -0,0 +1,37 @@ +# Tasks + +![](/img/tasks/01.png) + +Tasks are executable from UI. The creation of tasks is based on events. + +``` +// src/EventSuscriber/MyTaskEventSubscriber.php +namespace App\EventSuscriber; + +use App\Core\Event\Task\TaskInitEvent; +use App\Core\Event\Task\TaskRunRequestedEvent; +use App\Core\EventSuscriber\Task\TaskEventSubscriber; + +class MyTaskEventSubscriber extends TaskEventSubscriber +{ + public function onInit(TaskInitEvent $event) + { + $event->addTask('my_task', 'Example', 'My task'); + } + + public function onRunRequest(TaskRunRequestedEvent $event) + { + if ('my_task' !== $event->getTask()) { + return; + } + + $event->getOutput()->writeln('My task is started'); + + // ... + + $event->getOutput()->writeln('My task is finished'); + } +} +``` + +![](/img/tasks/02.png) diff --git a/docs/tree.md b/docs/tree.md new file mode 100644 index 0000000..a914572 --- /dev/null +++ b/docs/tree.md @@ -0,0 +1,38 @@ +# Tree manager + +Murph manages contents this way: + +* You define navigations +* For each navigation, you define menus +* For each menu, you define elements (nodes) +* and for each element, you define: + - an optional page + - the routing + - some attributes + - a sitemap configuration + +## Navigation + +To create a navigation, go to `Navigations` and click on `New`. Then fill the form and save. + +* The `label` is the label displayed whenever necessary (eg: `Example`) +* The `locale` is the language used in the content (eg: `en`) +* The `code` is a unique technical identifier useful in templating, routing and settings (eg: `example_en`) +* The `domain` defines the main domain used to access the navigation (eg: `example.com`) +* `Additional domains` are additional domains used to access the navigation (eg: `www.example.com`). You can specify regular expression to match all that you want + +If several navigations share the same domain, then the locale will by used to prefix routes. +But if a navigation uses a single domain then the local will not prefix routes. + +![](/img/tree/01.png) + +## Menu + +To create a menu, go to `Trees`, select the navigation and click on `Add a menu`. Then fill the form and save. + +* The `label` is the label displayed whenever necessary (eg: `Top menu`) +* The `code` is an unique technical identifier (in the given navigation) and it is useful in templating, routing and settings (eg: `top`) + +When a menu is created then an element is automatically generated. + +![](/img/tree/02.png) diff --git a/docs/users.md b/docs/users.md new file mode 100644 index 0000000..e08882c --- /dev/null +++ b/docs/users.md @@ -0,0 +1,2 @@ +# Welcome to Murph FR + diff --git a/mkdocs.yml b/mkdocs.yml new file mode 100644 index 0000000..f09be14 --- /dev/null +++ b/mkdocs.yml @@ -0,0 +1,10 @@ +site_name: Murph documentation +theme: readthedocs +nav: + - Overview: index.md + - Installation: install.md + - Tree manager: tree.md + - CRUD: crud.md + - Settings: settings.md + - Users: users.md + - Tasks: tasks.md