Compare commits

..

13 commits
master ... v2

Author SHA1 Message Date
Simon Vieille ce4deb24f8
feat(upgrade): add compliance with symfony 6.2 2023-01-25 22:18:55 +01:00
Simon Vieille 79c799748b
feat(upgrade): add compliance with symfony 6.2 2023-01-25 22:17:28 +01:00
Simon Vieille b20d542dc3
feat(upgrade): add compliance with symfony 6.2 2023-01-25 22:14:18 +01:00
Simon Vieille c19dc624c7
feat(upgrade): add compliance with symfony 6.2 2023-01-25 22:12:16 +01:00
Simon Vieille 8e7a7e25a1
feat(upgrade): upgrade php dep 2023-01-25 21:51:47 +01:00
Simon Vieille 01622180be
feat(upgrade): add compliance with symfony 6.2 2023-01-25 21:39:37 +01:00
Simon Vieille f3f4417d7c
feat(upgrade): add compliance with symfony 6.2 2023-01-25 21:38:37 +01:00
Simon Vieille 027b7df80e
feat(upgrade): upgrade php dep 2023-01-25 21:36:17 +01:00
Simon Vieille a8ab2d3945
feat(upgrade): upgrade php dep 2023-01-25 21:34:33 +01:00
Simon Vieille 76a8cf1751
feat(upgrade): upgrade php dep 2023-01-25 21:28:38 +01:00
Simon Vieille 8ff8ec9dac
feat(upgrade): upgrade php dep 2023-01-25 20:58:38 +01:00
Simon Vieille 8518b05b8d Merge branch 'develop' into v2 2023-01-25 20:53:13 +01:00
Simon Vieille 7e8281aa8f update symfony to v6.0 2022-03-25 15:18:54 +01:00
145 changed files with 1054 additions and 1748 deletions

View file

@ -1,109 +1,5 @@
## [Unreleased]
### Added
* allow to use `window.tinymceModes` to add or override tinymce modes
* add border color on tinymce editor
### Fixed
* fix default crud sort
* fix hidden save button in file manager
* fix template of CrudController (maker)
* fix undefined `window.tinymce.murph`
## [v1.24.1] - 2024-02-01
### Fixed
* update Murph version constant
## [v1.24.0] - 2024-01-27
### Added
* add CSS class `no-wrap`
* copy the pager of the CRUD at the bottom of the list
### Fixed
* fix an issue with the file manager when editing an item opened in a modal
* fix type casting in slugifier
## [v1.23.0] - 2023-11-01
### Added
* allow to define templates show before and after a murph collection item
* add global batch actions
* add constraint `Length` in forms
* add sass classes to mange with of elements
* set searchFields option on jschoice manager (search on labels)
### Changed
* refactor services using constructor property promotions
* remove twig in the mail notifier service
* change pills colors
* change border colors of inputs when focused
* change colors on js-choices element
### Fixed
* fix regression on crud sorting
* fix test in RepositoryQuery::addForcedFilterHandler
* remove parameter $option on CrudConfiguration::setForm and fix CrudController make template
* fix the aspect of the actions's column in the crud
## [v1.22.0] - 2023-09-28
### Added
* add new options in BooleanField: `toggle|checkbox_class_when_true` and `toggle|checkbox_class_when_false`
* add `count` method in repository query
* add `addForcedFilterHandler` method in repository query
* add `inline_form_validation` option to validate inline forms with custom algo
* add crud sorting parameters in the session
* add flush option in the entity manager on create, update, remove, and persist methods
## [1.21.1] - 2023-08-17
### Added
* add form error handle in inline edit action and refill the form using the previous request content
* add form error handle in ssettings actions and refill the form using the previous request content
### Fixed
* fix tinymce reload when modal is closed and reopened
* fix modal hiding when a file is successfuly uploaded in the file manager
## [1.21.0] - 2023-08-11
### Added
* allow to use array syntax in string builder filter
* add color property in Navigation
* add badge with navigation color in admin views
* add `default_value` option in crud fields
* add `display` option in BooleanField
* add associated nodes in page form
### Fixed
* fix routes in the global settings controller
## [1.20.0] - 2023-07-27
### Added
* enable double click on cruds
* add block class name for the choice type in the page maker
* update file details view on the file manager
* add form options in the crud filter action
* add trans filter in inline form modal title
* add setter to define all fields in a defined context
* add filename generator setter in FileUploadHandler
* add variable for the sidebar size
* add twig block to override defaults actions in crud index template
* add option to remove iterable values and/or specifics keys in the twig toArray function
* add boolean field for CRUD
* add context variable in each controllers to simplify overrides
* core.site.name and core.site.logo are not longer required
* add default templates when a crud is generated
* add boolean 'is_disabled' in the menu item template options
### Fixed
* fix filemanager date ordering
* fix maker CrudController template: remove bad pasted code
* fix redirect listener: use boolean instead of integer
* fix responsive of account edit template
* fix collection widget: allow_add/allow_delete and prototype
### Changed
* user admin routes are defined in core, custom controller is not required
## [1.19.0] - 2023-04-15
### Added
* feat(page): forms for metas, opengraph and extra informations can be removed
* feat(navigation): user interface is improved
* feat(file): webp is allowed and shown in form widgets and in file manager details
* feat(file): the file manager now show the size and the modification date of a file
* feat(crud): add option `action` in field to add a link to the view page or to the edition page
* feat(crud): add option `inline_form` in field to configure to edit the data
* feat(crud): add `setDoubleClick` in the crud configuration
## [1.18.0] - 2023-01-13
### Added
* feat(dep): add symfony/runtime

View file

@ -17,55 +17,61 @@
"doctrine/doctrine-migrations-bundle": "^3.2",
"doctrine/orm": "^2.11",
"fusonic/opengraph": "^2.2",
"friendsofsymfony/jsrouting-bundle": "^2.8",
"friendsofsymfony/jsrouting-bundle": "^3.2",
"jaybizzle/crawler-detect": "^1.2",
"knplabs/doctrine-behaviors": "^2.6",
"knplabs/knp-paginator-bundle": "^5.8",
"liip/imagine-bundle": "^2.7",
"matomo/device-detector": "^5.0",
"phpdocumentor/reflection-docblock": "^5.3",
"scheb/2fa-google-authenticator": "^5.13",
"scheb/2fa-qr-code": "^5.13",
"scheb/2fa-bundle": "^6.5",
"sensio/framework-extra-bundle": "^6.2",
"sensiolabs/ansi-to-html": "^1.2",
"spe/filesize-extension-bundle": "~2.0.0",
"stof/doctrine-extensions-bundle": "^1.7",
"symfony/apache-pack": "^1.0",
"symfony/asset": "5.4.*",
"symfony/console": "5.4.*",
"symfony/dotenv": "5.4.*",
"symfony/event-dispatcher": "5.4.*",
"symfony/expression-language": "5.4.*",
"symfony/finder": "5.4.*",
"symfony/asset": "6.2.*",
"symfony/console": "6.2.*",
"symfony/dotenv": "6.2.*",
"symfony/event-dispatcher": "6.2.*",
"symfony/expression-language": "6.2.*",
"symfony/finder": "6.2.*",
"symfony/form": "6.2.*",
"symfony/framework-bundle": "6.2.*",
"symfony/http-client": "6.2.*",
"symfony/intl": "6.2.*",
"symfony/mailer": "6.2.*",
"symfony/mime": "6.2.*",
"symfony/flex": "^2.2",
"symfony/form": "5.4.*",
"symfony/framework-bundle": "5.4.*",
"symfony/http-client": "5.4.*",
"symfony/intl": "5.4.*",
"symfony/mailer": "5.4.*",
"symfony/mime": "5.4.*",
"symfony/monolog-bundle": "^3.1",
"symfony/notifier": "5.4.*",
"symfony/process": "5.4.*",
"symfony/property-access": "5.4.*",
"symfony/property-info": "5.4.*",
"symfony/proxy-manager-bridge": "5.4.*",
"symfony/security-bundle": "5.4.*",
"symfony/serializer": "5.4.*",
"symfony/string": "5.4.*",
"symfony/translation": "5.4.*",
"symfony/twig-bundle": "^5.2",
"symfony/validator": "5.4.*",
"symfony/web-link": "5.4.*",
"symfony/notifier": "6.2.*",
"symfony/process": "6.2.*",
"symfony/property-access": "6.2.*",
"symfony/property-info": "6.2.*",
"symfony/proxy-manager-bridge": "6.2.*",
"symfony/security-bundle": "6.2.*",
"symfony/serializer": "6.2.*",
"symfony/string": "6.2.*",
"symfony/translation": "6.2.*",
"symfony/twig-bundle": "^6.0",
"symfony/validator": "6.2.*",
"symfony/web-link": "6.2.*",
"symfony/webpack-encore-bundle": "^1.11",
"symfony/yaml": "5.4.*",
"symfony/yaml": "6.2.*",
"twig/extra-bundle": "^2.12|^3.3",
"twig/twig": "^2.12|^3.3",
"symfony/runtime": "^5.4"
"symfony/runtime": "6.2.*",
"scheb/2fa-totp": "^6.5"
},
"autoload": {
"psr-4": {
"App\\Core\\": "src/core/"
}
},
"config": {
"allow-plugins": {
"symfony/flex": false,
"symfony/runtime": false
}
}
}

View file

@ -10,12 +10,14 @@ namespace App\Core\Ab;
class AbTest implements AbTestInterface
{
protected $results;
protected string $name;
protected array $variations = [];
protected array $probabilities = [];
protected int $duration = 3600 * 24;
public function __construct(protected string $name)
public function __construct(string $name)
{
$this->name = $name;
}
public function getName(): string

View file

@ -13,16 +13,18 @@ use App\Core\Repository\Analytic\ViewRepositoryQuery;
*/
class DateRangeAnalytic
{
protected ViewRepositoryQuery $viewQuery;
protected RefererRepositoryQuery $refererQuery;
protected ?Node $node;
protected ?\DateTime $from;
protected ?\DateTime $to;
protected bool $reload = true;
protected array $cache = [];
public function __construct(
protected ViewRepositoryQuery $viewQuery,
protected RefererRepositoryQuery $refererQuery
) {
public function __construct(ViewRepositoryQuery $viewQuery, RefererRepositoryQuery $refererQuery)
{
$this->viewQuery = $viewQuery;
$this->refererQuery = $refererQuery;
}
public function getViews(): array
@ -81,7 +83,7 @@ class DateRangeAnalytic
$datas[$index]['mobileViews'] += $entity->getMobileViews();
}
uasort($datas, function ($a, $b) {
uasort($datas, function($a, $b) {
if ($a['views'] > $b['views']) {
return -1;
}
@ -128,7 +130,7 @@ class DateRangeAnalytic
$datas[$index]['uris'][$path] += $entity->getViews();
}
uasort($datas, function ($a, $b) {
uasort($datas, function($a, $b) {
if ($a['views'] > $b['views']) {
return -1;
}

View file

@ -10,10 +10,16 @@ namespace App\Core\Annotation;
#[\Attribute]
class UrlGenerator
{
public function __construct(
public string $service,
public string $method,
public array $options = []
) {
public string $service;
public string $method;
public array $options = [];
public function __construct(string $service, string $method, array $options = [])
{
$this->service = $service;
$this->method = $method;
$this->options = $options;
}
}

View file

@ -16,26 +16,53 @@ use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Csrf\CsrfToken;
use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
use Symfony\Component\Security\Guard\Authenticator\AbstractFormLoginAuthenticator;
use Symfony\Component\Security\Http\Util\TargetPathTrait;
use Symfony\Component\Security\Http\Authenticator\AbstractLoginFormAuthenticator;
use Symfony\Component\Security\Http\Authenticator\Passport\Passport;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
use Symfony\Component\Security\Http\Authenticator\Passport\Credentials\PasswordCredentials;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\CsrfTokenBadge;
class LoginFormAuthenticator extends AbstractFormLoginAuthenticator
class LoginFormAuthenticator extends AbstractLoginFormAuthenticator
{
use TargetPathTrait;
public function __construct(
private EntityManagerInterface $entityManager,
private UrlGeneratorInterface $urlGenerator,
private CsrfTokenManagerInterface $csrfTokenManager,
private UserPasswordEncoderInterface $passwordEncoder
) {
private EntityManagerInterface $entityManager;
private UrlGeneratorInterface $urlGenerator;
private CsrfTokenManagerInterface $csrfTokenManager;
private UserPasswordEncoderInterface $passwordEncoder;
public function __construct(EntityManagerInterface $entityManager, UrlGeneratorInterface $urlGenerator, CsrfTokenManagerInterface $csrfTokenManager, UserPasswordEncoderInterface $passwordEncoder)
{
$this->entityManager = $entityManager;
$this->urlGenerator = $urlGenerator;
$this->csrfTokenManager = $csrfTokenManager;
$this->passwordEncoder = $passwordEncoder;
}
public function supports(Request $request)
public function supports(Request $request): bool
{
return 'auth_login' === $request->attributes->get('_route') && $request->isMethod('POST');
}
public function authenticate(Request $request): Passport
{
$id = $request->request->get('id', '');
$request->getSession()->set(Security::LAST_USERNAME, $id);
return new Passport(
new UserBadge($id),
new PasswordCredentials($request->request->get('password', '')),
[
new CsrfTokenBadge('authenticate', $request->request->get('_csrf_token')),
]
);
}
public function getCredentials(Request $request)
{
$credentials = [
@ -72,7 +99,7 @@ class LoginFormAuthenticator extends AbstractFormLoginAuthenticator
return $this->passwordEncoder->isPasswordValid($user, $credentials['password']);
}
public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey): RedirectResponse
{
if ($targetPath = $this->getTargetPath($request->getSession(), $providerKey)) {
return new RedirectResponse($targetPath);
@ -81,7 +108,7 @@ class LoginFormAuthenticator extends AbstractFormLoginAuthenticator
return new RedirectResponse($this->urlGenerator->generate('admin_dashboard_index'));
}
protected function getLoginUrl()
protected function getLoginUrl(Request $request): string
{
return $this->urlGenerator->generate('auth_login');
}

View file

@ -12,8 +12,8 @@
namespace App\Core\Bundle;
use App\Core\DependencyInjection\CoreExtension;
use Symfony\Component\DependencyInjection\Extension\ExtensionInterface;
use Symfony\Component\HttpKernel\Bundle\Bundle;
use Symfony\Component\DependencyInjection\Extension\ExtensionInterface;
class CoreBundle extends Bundle
{

View file

@ -5,13 +5,13 @@ namespace App\Core\Cache;
use Symfony\Bundle\FrameworkBundle\Console\Application;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Output\BufferedOutput;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Finder\Finder;
use Symfony\Component\HttpClient\Exception\ClientException;
use Symfony\Component\HttpClient\Exception\TransportException;
use Symfony\Component\HttpKernel\KernelInterface;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\HttpClient\Exception\ClientException;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\HttpClient\Exception\TransportException;
/**
* class SymfonyCacheManager.
@ -20,11 +20,15 @@ use Symfony\Contracts\HttpClient\HttpClientInterface;
*/
class SymfonyCacheManager
{
public function __construct(
protected KernelInterface $kernel,
protected HttpClientInterface $httpClient,
protected UrlGeneratorInterface $urlGenerator
) {
protected KernelInterface $kernel;
protected HttpClientInterface $httpClient;
protected UrlGeneratorInterface $urlGenerator;
public function __construct(KernelInterface $kernel, HttpClientInterface $httpClient, UrlGeneratorInterface $urlGenerator)
{
$this->kernel = $kernel;
$this->httpClient = $httpClient;
$this->urlGenerator = $urlGenerator;
}
public function cleanRouting()

View file

@ -18,12 +18,19 @@ class UserCreateCommand extends Command
{
protected static $defaultName = 'murph:user:create';
protected static $defaultDescription = 'Creates a user';
protected UserFactory $userFactory;
protected EntityManager $entityManager;
protected TokenGeneratorInterface $tokenGenerator;
public function __construct(
protected UserFactory $userFactory,
protected EntityManager $entityManager,
protected TokenGeneratorInterface $tokenGenerator
UserFactory $userFactory,
EntityManager $entityManager,
TokenGeneratorInterface $tokenGenerator
) {
$this->userFactory = $userFactory;
$this->entityManager = $entityManager;
$this->tokenGenerator = $tokenGenerator;
parent::__construct();
}

View file

@ -26,7 +26,7 @@ abstract class CrudController extends AdminController
abstract protected function getConfiguration(): CrudConfiguration;
protected function doIndex(int $page, RepositoryQuery $query, Request $request, Session $session, string $context = 'index'): Response
protected function doIndex(int $page, RepositoryQuery $query, Request $request, Session $session): Response
{
$configuration = $this->getConfiguration();
@ -35,14 +35,13 @@ abstract class CrudController extends AdminController
$pager = $query
->usefilters($this->filters)
->paginate($page, $configuration->getMaxPerPage($context))
->paginate($page, $configuration->getmaxperpage('index'))
;
return $this->render($this->getConfiguration()->getView($context), [
return $this->render($this->getConfiguration()->getView('index'), [
'configuration' => $configuration,
'pager' => $pager,
'sort' => $this->sort,
'context' => $context,
'filters' => [
'show' => null !== $configuration->getForm('filter'),
'isEmpty' => empty($this->filters),
@ -50,13 +49,13 @@ abstract class CrudController extends AdminController
]);
}
protected function doNew(EntityInterface $entity, EntityManager $entityManager, Request $request, callable $beforeCreate = null, string $context = 'new'): Response
protected function doNew(EntityInterface $entity, EntityManager $entityManager, Request $request, callable $beforeCreate = null): Response
{
$configuration = $this->getConfiguration();
$this->prepareEntity($entity);
$form = $this->createForm($configuration->getForm('new'), $entity, $configuration->getFormOptions($context));
$form = $this->createForm($configuration->getForm('new'), $entity, $configuration->getFormOptions('new'));
if ($request->isMethod('POST')) {
$form->handleRequest($request);
@ -77,32 +76,30 @@ abstract class CrudController extends AdminController
$this->addFlash('warning', 'The form is not valid.');
}
return $this->render($configuration->getView($context), [
return $this->render($configuration->getView('new'), [
'form' => $form->createView(),
'configuration' => $configuration,
'context' => $context,
'entity' => $entity,
]);
}
protected function doShow(EntityInterface $entity, string $context = 'show'): Response
protected function doShow(EntityInterface $entity): Response
{
$configuration = $this->getConfiguration();
return $this->render($configuration->getView($context), [
return $this->render($configuration->getView('show'), [
'entity' => $entity,
'context' => $context,
'configuration' => $configuration,
]);
}
protected function doEdit(EntityInterface $entity, EntityManager $entityManager, Request $request, callable $beforeUpdate = null, string $context = 'edit'): Response
protected function doEdit(EntityInterface $entity, EntityManager $entityManager, Request $request, callable $beforeUpdate = null): Response
{
$configuration = $this->getConfiguration();
$this->prepareEntity($entity);
$form = $this->createForm($configuration->getForm('edit'), $entity, $configuration->getFormOptions($context));
$form = $this->createForm($configuration->getForm('edit'), $entity, $configuration->getFormOptions('edit'));
if ($request->isMethod('POST')) {
$form->handleRequest($request);
@ -115,105 +112,18 @@ abstract class CrudController extends AdminController
$entityManager->update($entity);
$this->addFlash('success', 'The data has been saved.');
return $this->redirectToRoute($configuration->getPageRoute($context), array_merge(
return $this->redirectToRoute($configuration->getPageRoute('edit'), array_merge(
['entity' => $entity->getId()],
$configuration->getPageRouteParams($context)
$configuration->getPageRouteParams('edit')
));
}
$this->addFlash('warning', 'The form is not valid.');
}
return $this->render($configuration->getView($context), [
'form' => $form->createView(),
'context' => $context,
'configuration' => $configuration,
'entity' => $entity,
]);
}
protected function doInlineEdit(string $context, string $label, EntityInterface $entity, EntityManager $entityManager, Request $request, callable $beforeUpdate = null): Response
{
$configuration = $this->getConfiguration();
$this->prepareEntity($entity);
$builder = $this->createFormBuilder($entity);
$callback = $configuration->getFields($context)[$label]['options']['inline_form'] ?? null;
$validationCallback = $configuration->getFields($context)[$label]['options']['inline_form_validation'] ?? null;
if (null === $callback) {
throw $this->createNotFoundException();
}
call_user_func_array($callback, [$builder, $entity]);
$redirectTo = $request->query->get('redirectTo');
$form = $builder->getForm();
$session = $request->getSession();
$lastRequestId = sprintf(
'inline_request_%s_%s_%s_%s',
get_class($entity),
$entity->getId(),
$context,
$label
);
$lastRequest = $session->get($lastRequestId);
if (null !== $lastRequest && !$request->isMethod('POST')) {
$fakeRequest = Request::create(
uri: $request->getUri(),
method: 'POST',
parameters: [$form->getName() => $lastRequest]
);
$form->handleRequest($fakeRequest);
if (null !== $validationCallback) {
call_user_func_array($validationCallback, [$entity, $form, $request]);
}
$session->remove($lastRequestId);
}
if ($request->isMethod('POST')) {
$form->handleRequest($request);
if (null !== $validationCallback) {
call_user_func_array($validationCallback, [$entity, $form, $request]);
}
if ($form->isValid()) {
if (null !== $beforeUpdate) {
call_user_func_array($beforeUpdate, [$entity, $form, $request]);
}
$session->remove($lastRequestId);
$entityManager->update($entity);
$this->addFlash('success', 'The data has been saved.');
return $this->redirect($redirectTo);
}
$session->set($lastRequestId, $request->request->get('form'));
$this->addFlash('warning', 'The form is not valid.');
return $this->redirect(sprintf(
'%s?data-modal=%s',
$redirectTo,
urlencode($request->getUri())
));
}
return $this->render($configuration->getView('inline_edit'), [
return $this->render($configuration->getView('edit'), [
'form' => $form->createView(),
'configuration' => $configuration,
'entity' => $entity,
'context' => $context,
'label' => $label,
'redirectTo' => $redirectTo,
]);
}
@ -284,39 +194,16 @@ abstract class CrudController extends AdminController
$query->useFilters($this->filters);
$useSelection = 'selection' === $target;
if ($batchAction['isGlobal']) {
$selection = null;
if ($useSelection) {
$queryClone = clone $query;
$pager = $queryClone->paginate($page, $configuration->getMaxPerPage($context));
$selection = [];
foreach ($pager as $key => $entity) {
if (isset($items[$key + 1])) {
$selection[] = $entity;
}
}
}
$result = $callback($query, $entityManager, $selection);
if ($result instanceof Response) {
return $result;
}
return $this->redirect($request->query->get('redirectTo'));
if ('selection' === $target) {
$isSelection = true;
$pager = $query->paginate($page, $configuration->getMaxPerPage($context));
} else {
$isSelection = false;
$pager = $query->find();
}
$pager = $useSelection
? $query->paginate($page, $configuration->getMaxPerPage($context))
: $query->find()
;
foreach ($pager as $key => $entity) {
if (($useSelection && isset($items[$key + 1])) || !$useSelection) {
if (($isSelection && isset($items[$key + 1])) || !$isSelection) {
$callback($entity, $entityManager);
}
}
@ -326,7 +213,7 @@ abstract class CrudController extends AdminController
return $this->json([]);
}
protected function doDelete(EntityInterface $entity, EntityManager $entityManager, Request $request, callable $beforeDelete = null, string $route = 'index'): Response
protected function doDelete(EntityInterface $entity, EntityManager $entityManager, Request $request, callable $beforeDelete = null): Response
{
$configuration = $this->getConfiguration();
@ -340,10 +227,10 @@ abstract class CrudController extends AdminController
$this->addFlash('success', 'The data has been removed.');
}
return $this->redirectToRoute($configuration->getPageRoute($route));
return $this->redirectToRoute($configuration->getPageRoute('index'));
}
protected function doFilter(Session $session, string $context = 'filter'): Response
protected function doFilter(Session $session): Response
{
$configuration = $this->getConfiguration();
$type = $configuration->getForm('filter');
@ -352,12 +239,11 @@ abstract class CrudController extends AdminController
throw $this->createNotFoundException();
}
$form = $this->createForm($type, null, $configuration->getFormOptions('filter'));
$form = $this->createForm($type);
$form->submit($session->get($form->getName(), []));
return $this->render($configuration->getView($context), [
return $this->render($configuration->getView('filter'), [
'form' => $form->createView(),
'context' => $context,
'configuration' => $configuration,
]);
}
@ -371,7 +257,7 @@ abstract class CrudController extends AdminController
return;
}
$form = $this->createForm($type, null, $configuration->getFormOptions('filter'));
$form = $this->createForm($type);
if ($request->query->has($form->getName())) {
$filters = $request->query->get($form->getName());
@ -418,27 +304,9 @@ abstract class CrudController extends AdminController
}
$defaultSort = $configuration->getDefaultSort($context);
$session = $request->getSession();
$sessionId = sprintf('%s_%s_sort', $context, get_called_class());
$sessionSortName = sprintf('%s_label', $sessionId);
$sessionSortDirection = sprintf('%s_direction', $sessionId);
$name = $request->query->get('_sort', $session->get($sessionSortName)) ?? $defaultSort['label'] ?? null;
$direction = strtolower(
$request->query->get(
'_sort_direction',
$session->get($sessionSortDirection)
) ?? $defaultSort['direction'] ?? 'asc'
);
$session->set($sessionSortName, $name);
$session->set($sessionSortDirection, $direction);
if (empty($name)) {
return;
}
$name = $request->query->get('_sort', $defaultSort['label'] ?? null);
$direction = strtolower($request->query->get('_sort_direction', $defaultSort['direction'] ?? 'asc'));
if (!in_array($direction, ['asc', 'desc'])) {
$direction = 'asc';

View file

@ -3,6 +3,8 @@
namespace App\Core\Controller\Dashboard;
use App\Core\Controller\Admin\AdminController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
class DashboardAdminController extends AdminController
{

View file

@ -102,11 +102,11 @@ class RedirectAdminController extends CrudController
'attr' => ['class' => 'col-6'],
])
->setField('index', 'Enabled', Field\ButtonField::class, [
'property_builder' => function (EntityInterface $entity) {
'property_builder' => function(EntityInterface $entity) {
return $entity->getIsEnabled() ? 'Yes' : 'No';
},
'attr' => ['class' => 'col-1'],
'button_attr_builder' => function (EntityInterface $entity) {
'button_attr_builder' => function(EntityInterface $entity) {
return ['class' => 'btn btn-sm btn-'.($entity->getIsEnabled() ? 'success' : 'primary')];
},
])

View file

@ -31,28 +31,11 @@ class NavigationSettingAdminController extends AdminController
$eventDispatcher->dispatch($event, NavigationSettingEvent::FORM_INIT_EVENT);
$form = $builder->getForm();
$redirectTo = $request->query->get('redirectTo');
$session = $request->getSession();
$lastRequestId = sprintf('setting_request_%s_%s', get_class($entity), $entity->getId());
$lastRequest = $session->get($lastRequestId);
if (null !== $lastRequest && !$request->isMethod('POST')) {
$fakeRequest = Request::create(
uri: $request->getUri(),
method: 'POST',
parameters: [$form->getName() => $lastRequest]
);
$form->handleRequest($fakeRequest);
$session->remove($lastRequestId);
}
if ($request->isMethod('POST')) {
$form->handleRequest($request);
if ($form->isValid()) {
$entityManager->update($entity);
$session->remove($lastRequestId);
$entityManager->update($entity);
$this->addFlash('success', 'The data has been saved.');
@ -61,21 +44,13 @@ class NavigationSettingAdminController extends AdminController
]);
}
$session->set($lastRequestId, $request->request->get('form'));
$this->addFlash('warning', 'The form is not valid.');
return $this->redirect(sprintf(
'%s?data-modal=%s',
$redirectTo,
urlencode($request->getUri())
));
}
return $this->render('@Core/setting/navigation_setting_admin/edit.html.twig', [
'form' => $form->createView(),
'entity' => $entity,
'options' => $event->getData()['options'],
'redirectTo' => $redirectTo,
]);
}

View file

@ -12,10 +12,14 @@ use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
#[Route(path: '/admin/setting')]
/**
* @Route("/admin/setting")
*/
class SettingAdminController extends AdminController
{
#[Route(path: '/{page}', name: 'admin_setting_index', requirements: ['page' => '\d+'])]
/**
* @Route("/{page}", name="admin_setting_index", requirements={"page": "\d+"})
*/
public function index(
RepositoryQuery $query,
EventDispatcherInterface $eventDispatcher,
@ -34,7 +38,9 @@ class SettingAdminController extends AdminController
]);
}
#[Route(path: '/edit/{entity}', name: 'admin_setting_edit')]
/**
* @Route("/edit/{entity}", name="admin_setting_edit")
*/
public function edit(
Entity $entity,
EntityManager $entityManager,
@ -51,53 +57,30 @@ class SettingAdminController extends AdminController
$eventDispatcher->dispatch($event, SettingEvent::FORM_INIT_EVENT);
$form = $builder->getForm();
$redirectTo = $request->query->get('redirectTo');
$session = $request->getSession();
$lastRequestId = sprintf('setting_request_%s_%s', get_class($entity), $entity->getId());
$lastRequest = $session->get($lastRequestId);
if (null !== $lastRequest && !$request->isMethod('POST')) {
$fakeRequest = Request::create(
uri: $request->getUri(),
method: 'POST',
parameters: [$form->getName() => $lastRequest]
);
$form->handleRequest($fakeRequest);
$session->remove($lastRequestId);
}
if ($request->isMethod('POST')) {
$form->handleRequest($request);
if ($form->isValid()) {
$entityManager->update($entity);
$session->remove($lastRequestId);
$entityManager->update($entity);
$this->addFlash('success', 'The data has been saved.');
return $this->redirectToRoute('admin_setting_index');
}
$session->set($lastRequestId, $request->request->get('form'));
$this->addFlash('warning', 'The form is not valid.');
return $this->redirect(sprintf(
'%s?data-modal=%s',
$redirectTo,
urlencode($request->getUri())
));
}
return $this->render('@Core/setting/setting_admin/edit.html.twig', [
'form' => $form->createView(),
'entity' => $entity,
'options' => $event->getData()['options'],
'redirectTo' => $redirectTo,
]);
}
#[Route(path: '/delete/{entity}', name: 'admin_setting_delete', methods: ['DELETE', 'POST'])]
/**
* @Route("/delete/{entity}", name="admin_setting_delete", methods={"DELETE"})
*/
public function delete(Entity $entity, EntityManager $entityManager, Request $request): Response
{
if ($this->isCsrfTokenValid('delete'.$entity->getId(), $request->request->get('_token'))) {

View file

@ -67,7 +67,7 @@ class NavigationAdminController extends CrudController
}
#[Route(path: '/admin/site/navigation/sort/{page}', name: 'admin_site_navigation_sort', methods: ['POST'], requirements: ['page' => '\d+'])]
public function sort(RepositoryQuery $query, EntityManager $entityManager, Request $request, Session $session, int $page = 1): Response
public function sort(RepositoryQuery $query, EntityManager $entityManager, Request $request, Session $session, int $page = 1, ): Response
{
return $this->doSort($page, $query, $entityManager, $request, $session);
}
@ -104,11 +104,9 @@ class NavigationAdminController extends CrudController
->setView('form', '@Core/site/navigation_admin/_form.html.twig')
->setIsSortableCollection('index', true)
->setDoubleClick('index', true)
->setField('index', 'Label', Field\TextField::class, [
'property' => 'label',
'view' => '@Core/site/navigation_admin/field/label.html.twig',
'attr' => ['class' => 'miw-200'],
])
->setField('index', 'Domain', Field\ButtonField::class, [

View file

@ -2,6 +2,7 @@
namespace App\Core\Controller\Site;
use App\Core\Controller\Admin\AdminController;
use App\Core\Entity\Site\Node;
use App\Core\Entity\Site\Node as Entity;
use App\Core\Entity\Site\Page\Page;
@ -13,15 +14,15 @@ use App\Core\Form\Site\NodeType as EntityType;
use App\Core\Manager\EntityManager;
use App\Core\Repository\Site\NodeRepository;
use App\Core\Site\ControllerLocator;
use App\Core\Site\PageLocator;
use App\Core\Site\RoleLocator;
use App\Core\Site\PageLocator;
use App\Core\Sitemap\SitemapBuilder;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Form\FormError;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
#[Route(path: '/admin/site/node')]
class NodeAdminController extends AbstractController
@ -144,7 +145,7 @@ class NodeAdminController extends AbstractController
$page = $entity->getPage();
if (null !== $page) {
if ($page !== null) {
$pageConfiguration = $pageLocator->getPages()[get_class($page)] ?? null;
} else {
$pageConfiguration = null;

View file

@ -5,19 +5,19 @@ namespace App\Core\Controller\Site;
use App\Core\Controller\Admin\Crud\CrudController;
use App\Core\Crud\CrudConfiguration;
use App\Core\Crud\Field;
use App\Core\Entity\EntityInterface;
use App\Core\Entity\Site\Page\Page as Entity;
use App\Core\Event\Page\PageEditEvent;
use App\Core\Form\Site\Page\Filter\PageFilterType as FilterType;
use App\Core\Form\Site\Page\PageType as Type;
use App\Core\Manager\EntityManager;
use App\Core\Repository\Site\Page\PageRepositoryQuery as RepositoryQuery;
use App\Core\Site\PageLocator;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\Routing\Annotation\Route;
use App\Core\Event\Page\PageEditEvent;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use App\Core\Entity\EntityInterface;
class PageAdminController extends CrudController
{
@ -95,8 +95,6 @@ class PageAdminController extends CrudController
->setAction('index', 'show', false)
->setAction('edit', 'show', false)
->setDoubleClick('index', true)
->setField('index', 'Name', Field\TextField::class, [
'property' => 'name',
'sort' => ['name', '.name'],
@ -114,7 +112,7 @@ class PageAdminController extends CrudController
}],
'attr' => ['class' => 'col-6'],
])
->setBatchAction('index', 'delete', 'Delete', function (EntityInterface $entity, EntityManager $manager) {
->setBatchAction('index', 'delete', 'Delete', function(EntityInterface $entity, EntityManager $manager) {
$manager->delete($entity);
})
;

View file

@ -8,55 +8,55 @@ use App\Core\Crud\Field;
use App\Core\Event\Account\PasswordRequestEvent;
use App\Core\Factory\UserFactory as Factory;
use App\Core\Manager\EntityManager;
use App\Core\Security\TokenGenerator;
use App\Entity\User as Entity;
use App\Form\UserType as Type;
use App\Repository\UserRepositoryQuery as RepositoryQuery;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\Routing\Annotation\Route;
use App\Core\Security\TokenGenerator;
class UserAdminController extends CrudController
{
protected ?CrudConfiguration $configuration = null;
#[Route(path: '/admin/user/{page}', name: 'admin_user_index', methods: ['GET'], requirements: ['page' => '\d+'])]
public function index(RepositoryQuery $query, Request $request, Session $session, int $page = 1): Response
{
return $this->doIndex($page, $query, $request, $session);
}
#[Route(path: '/admin/user/new', name: 'admin_user_new', methods: ['GET', 'POST'])]
public function new(Factory $factory, EntityManager $entityManager, Request $request, TokenGenerator $tokenGenerator): Response
{
return $this->doNew($factory->create(null, $tokenGenerator->generateToken()), $entityManager, $request);
}
#[Route(path: '/admin/user/show/{entity}', name: 'admin_user_show', methods: ['GET'])]
public function show(Entity $entity): Response
{
return $this->doShow($entity);
}
#[Route(path: '/admin/user/filter', name: 'admin_user_filter', methods: ['GET'])]
public function filter(Session $session): Response
{
return $this->doFilter($session);
}
#[Route(path: '/admin/user/edit/{entity}', name: 'admin_user_edit', methods: ['GET', 'POST'])]
public function edit(Entity $entity, EntityManager $entityManager, Request $request): Response
{
return $this->doEdit($entity, $entityManager, $request);
}
public function inlineEdit(string $context, string $label, Entity $entity, EntityManager $entityManager, Request $request): Response
{
return $this->doInlineEdit($context, $label, $entity, $entityManager, $request);
}
#[Route(path: '/admin/user/delete/{entity}', name: 'admin_user_delete', methods: ['DELETE', 'POST'])]
public function delete(Entity $entity, EntityManager $entityManager, Request $request): Response
{
return $this->doDelete($entity, $entityManager, $request);
}
#[Route(path: '/admin/user/resetting_request/{entity}', name: 'admin_user_resetting_request', methods: ['POST'])]
public function requestResetting(Entity $entity, EventDispatcherInterface $eventDispatcher, Request $request): Response
{
if ($this->isCsrfTokenValid('resetting_request'.$entity->getId(), $request->request->get('_token'))) {
@ -81,7 +81,6 @@ class UserAdminController extends CrudController
->setPageRoute('index', 'admin_user_index')
->setPageRoute('new', 'admin_user_new')
->setPageRoute('edit', 'admin_user_edit')
->setPageRoute('inline_edit', 'admin_user_inline_edit')
->setPageRoute('show', 'admin_user_show')
->setPageRoute('delete', 'admin_user_delete')
->setPageRoute('filter', 'admin_user_filter')
@ -97,7 +96,6 @@ class UserAdminController extends CrudController
->setView('edit', '@Core/user/user_admin/edit.html.twig')
->setDefaultSort('index', 'username')
->setDoubleClick('index', true)
->setField('index', 'E-mail', Field\TextField::class, [
'property' => 'email',
@ -108,9 +106,6 @@ class UserAdminController extends CrudController
'property' => 'displayName',
'sort' => ['displayName', '.displayName'],
'attr' => ['class' => 'miw-200'],
'inline_form' => function (FormBuilderInterface $builder) {
$builder->add('displayName', null);
},
])
;
}

View file

@ -17,7 +17,6 @@ class CrudConfiguration
protected array $actionTitles = [];
protected array $forms = [];
protected array $formOptions = [];
protected array $inlineForms = [];
protected array $views = [];
protected array $viewDatas = [];
protected array $fields = [];
@ -40,7 +39,7 @@ class CrudConfiguration
return self::$self;
}
// --
/* -- */
public function setPageTitle(string $page, string $title): self
{
@ -54,7 +53,7 @@ class CrudConfiguration
return $this->pageTitles[$page] ?? $default;
}
// --
/* -- */
public function setPageRoute(string $page, string $route): self
{
@ -80,9 +79,9 @@ class CrudConfiguration
return $this->pageRouteParams[$page] ?? [];
}
// --
/* -- */
public function setForm(string $context, string $form): self
public function setForm(string $context, string $form, array $options = []): self
{
$this->forms[$context] = $form;
@ -106,7 +105,7 @@ class CrudConfiguration
return $this->formOptions[$context] ?? [];
}
// --
/* -- */
public function setAction(string $page, string $action, bool|callable $enabled): self
{
@ -135,24 +134,8 @@ class CrudConfiguration
);
}
public function setGlobalBatchAction(
string $page,
string $action,
string $label,
callable $callback
): self {
$this->setBatchAction($page, $action, $label, $callback);
$this->batchActions[$page][$action]['isGlobal'] = true;
return $this;
}
public function setBatchAction(
string $page,
string $action,
string $label,
callable $callback
): self {
public function setBatchAction(string $page, string $action, string $label, callable $callback): self
{
if (!isset($this->batchActions[$page])) {
$this->batchActions[$page] = [];
}
@ -160,7 +143,6 @@ class CrudConfiguration
$this->batchActions[$page][$action] = [
'label' => $label,
'callback' => $callback,
'isGlobal' => false,
];
return $this;
@ -181,7 +163,7 @@ class CrudConfiguration
return !empty($this->batchActions[$page]);
}
// --
/* -- */
public function setActionTitle(string $page, string $action, string $title): self
{
@ -199,7 +181,7 @@ class CrudConfiguration
return $this->actionTitles[$page][$action] ?? $default;
}
// --
/* -- */
public function setView(string $context, string $view): self
{
@ -247,7 +229,7 @@ class CrudConfiguration
return $this->viewDatas[$context][$name] ?? $defaultValue;
}
// --
/* -- */
public function setField(string $context, string $label, string $field, array $options): self
{
@ -268,16 +250,9 @@ class CrudConfiguration
return $this->fields[$context] ?? [];
}
public function setFields(string $context, array $fields): self
{
$this->fields[$context] = $fields;
/* -- */
return $this;
}
// --
public function setMaxPerPage(string $page, int $max): self
public function setMaxPerPage(string $page, int $max)
{
$this->maxPerPage[$page] = $max;
@ -289,21 +264,7 @@ class CrudConfiguration
return $this->maxPerPage[$page] ?? $default;
}
// --
public function setDoubleClick(string $page, bool $enabled): self
{
$this->doubleClick[$page] = $enabled;
return $this;
}
public function getDoubleClick(string $page): bool
{
return $this->doubleClick[$page] ?? false;
}
// --
/* -- */
public function setI18n(array $locales, string $defaultLocale): self
{
@ -328,7 +289,7 @@ class CrudConfiguration
return !empty($this->locales);
}
// --
/* -- */
public function setDefaultSort(string $context, string $label, string $direction = 'asc'): self
{

View file

@ -1,32 +0,0 @@
<?php
namespace App\Core\Crud\Field;
use Symfony\Component\OptionsResolver\OptionsResolver;
/**
* class BooleanField.
*
* @author Simon Vieille <simon@deblan.fr>
*/
class BooleanField extends Field
{
public function configureOptions(OptionsResolver $resolver): OptionsResolver
{
parent::configureOptions($resolver);
$resolver->setDefaults([
'view' => '@Core/admin/crud/field/boolean.html.twig',
'display' => 'toggle',
'checkbox_class_when_true' => 'fa-check-square',
'checkbox_class_when_false' => 'fa-square',
'toggle_class_when_true' => 'bg-success',
'toggle_class_when_false' => 'bg-secondary',
'default_value' => false,
]);
$resolver->setAllowedTypes('display', 'string');
return $resolver;
}
}

View file

@ -28,31 +28,24 @@ abstract class Field
$resolver->setDefaults([
'property' => null,
'property_builder' => null,
'default_value' => null,
'view' => null,
'action' => null,
'raw' => false,
'sort' => null,
'href' => null,
'href_attr' => [],
'attr' => [],
'inline_form' => null,
'inline_form_validation' => null,
]);
$resolver->setRequired('view');
$resolver->setAllowedTypes('property', ['null', 'string']);
$resolver->setAllowedTypes('view', 'string');
$resolver->setAllowedTypes('action', ['null', 'string']);
$resolver->setAllowedTypes('attr', 'array');
$resolver->setAllowedTypes('href', ['null', 'string', 'callable']);
$resolver->setAllowedTypes('inline_form', ['null', 'callable']);
$resolver->setAllowedTypes('inline_form_validation', ['null', 'callable']);
$resolver->setAllowedTypes('href_attr', ['array', 'callable']);
$resolver->setAllowedTypes('href_attr', 'array', 'callable');
$resolver->setAllowedTypes('raw', 'boolean');
$resolver->setAllowedTypes('property_builder', ['null', 'callable']);
$resolver->setAllowedValues('sort', function ($value) {
if (null === $value) {
$resolver->setAllowedValues('sort', function($value) {
if ($value === null) {
return true;
}

View file

@ -15,7 +15,6 @@ class Configuration implements ConfigurationInterface
'image/jpeg',
'image/gif',
'image/svg+xml',
'image/webp',
'video/mp4',
'audio/mpeg3',
'audio/x-mpeg-3',
@ -46,100 +45,101 @@ class Configuration implements ConfigurationInterface
$treeBuilder->getRootNode()
->children()
->arrayNode('site')
->children()
->scalarNode('name')
->defaultValue('Murph')
->isRequired()
->end()
->scalarNode('logo')
->defaultValue('build/images/core/logo.svg')
->isRequired()
->end()
->arrayNode('controllers')
->prototype('array')
->children()
->scalarNode('name')
->cannotBeEmpty()
->end()
->scalarNode('action')
->cannotBeEmpty()
->end()
->end()
->end()
->end()
->arrayNode('security')
->children()
->arrayNode('roles')
->prototype('array')
->children()
->scalarNode('name')
->cannotBeEmpty()
->end()
->scalarNode('role')
->cannotBeEmpty()
->end()
->end()
->end()
->end()
->end()
->end()
->arrayNode('pages')
->prototype('array')
->children()
->scalarNode('name')
->isRequired()
->cannotBeEmpty()
->end()
->arrayNode('templates')
->prototype('array')
->children()
->scalarNode('name')
->cannotBeEmpty()
->end()
->scalarNode('file')
->cannotBeEmpty()
->end()
->end()
->end()
->end()
->end()
->end()
->end()
->end()
->end()
->arrayNode('editor_js')
->children()
->arrayNode('blocks')
->scalarPrototype()
->end()
->end()
->end()
->end()
->arrayNode('file_manager')
->children()
->arrayNode('mimes')
->scalarPrototype()
->end()
->defaultValue($defaultMimetypes)
->end()
->scalarNode('path')
->defaultValue('%kernel.project_dir%/public/uploads')
->cannotBeEmpty()
->end()
->scalarNode('path_uri')
->defaultValue('/uploads')
->cannotBeEmpty()
->end()
->arrayNode('path_locked')
->scalarPrototype()
->end()
->defaultValue($defaultLocked)
->end()
->end()
->end()
->end()
;
->arrayNode('site')
->children()
->scalarNode('name')
->defaultValue('Murph')
->isRequired()
->cannotBeEmpty()
->end()
->scalarNode('logo')
->defaultValue('build/images/core/logo.svg')
->isRequired()
->cannotBeEmpty()
->end()
->arrayNode('controllers')
->prototype('array')
->children()
->scalarNode('name')
->cannotBeEmpty()
->end()
->scalarNode('action')
->cannotBeEmpty()
->end()
->end()
->end()
->end()
->arrayNode('security')
->children()
->arrayNode('roles')
->prototype('array')
->children()
->scalarNode('name')
->cannotBeEmpty()
->end()
->scalarNode('role')
->cannotBeEmpty()
->end()
->end()
->end()
->end()
->end()
->end()
->arrayNode('pages')
->prototype('array')
->children()
->scalarNode('name')
->isRequired()
->cannotBeEmpty()
->end()
->arrayNode('templates')
->prototype('array')
->children()
->scalarNode('name')
->cannotBeEmpty()
->end()
->scalarNode('file')
->cannotBeEmpty()
->end()
->end()
->end()
->end()
->end()
->end()
->end()
->end()
->end()
->arrayNode('editor_js')
->children()
->arrayNode('blocks')
->scalarPrototype()
->end()
->end()
->end()
->end()
->arrayNode('file_manager')
->children()
->arrayNode('mimes')
->scalarPrototype()
->end()
->defaultValue($defaultMimetypes)
->end()
->scalarNode('path')
->defaultValue('%kernel.project_dir%/public/uploads')
->cannotBeEmpty()
->end()
->scalarNode('path_uri')
->defaultValue('/uploads')
->cannotBeEmpty()
->end()
->arrayNode('path_locked')
->scalarPrototype()
->end()
->defaultValue($defaultLocked)
->end()
->end()
->end()
->end();
return $treeBuilder;
}

View file

@ -2,9 +2,10 @@
namespace App\Core\Entity\Analytic;
use App\Core\Entity\EntityInterface;
use App\Core\Entity\Site\Node;
use App\Repository\Entity\Analytic\NodeViewRepository;
use Doctrine\ORM\Mapping as ORM;
use App\Core\Entity\EntityInterface;
#[ORM\Table(name: 'analytic_referer')]
#[ORM\Entity(repositoryClass: ViewRepository::class)]

View file

@ -2,9 +2,10 @@
namespace App\Core\Entity\Analytic;
use App\Core\Entity\EntityInterface;
use App\Core\Entity\Site\Node;
use App\Repository\Entity\Analytic\NodeViewRepository;
use Doctrine\ORM\Mapping as ORM;
use App\Core\Entity\EntityInterface;
#[ORM\Table(name: 'analytic_view')]
#[ORM\Entity(repositoryClass: ViewRepository::class)]

View file

@ -42,9 +42,6 @@ class Navigation implements EntityInterface
#[ORM\Column(type: 'string', length: 10)]
protected $locale = 'en';
#[ORM\Column(type: 'string', length: 7, nullable: true)]
protected $color;
#[ORM\Column(type: 'integer', nullable: true)]
protected $sortOrder;
@ -67,7 +64,7 @@ class Navigation implements EntityInterface
return $this->label;
}
public function setLabel(?string $label): self
public function setLabel(string $label): self
{
$this->label = $label;
@ -240,16 +237,4 @@ class Navigation implements EntityInterface
return false;
}
public function setColor(string $color): self
{
$this->color = $color;
return $this;
}
public function getColor(): ?string
{
return $this->color;
}
}

View file

@ -5,12 +5,13 @@ namespace App\Core\Entity\Site\Page;
use App\Core\Doctrine\Timestampable;
use App\Core\Entity\EntityInterface;
use App\Core\Entity\Site\Node;
use App\Core\File\FileAttribute;
use App\Core\Repository\Site\Page\PageRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\HttpFoundation\File\File;
use App\Core\File\FileAttribute;
#[ORM\Entity(repositoryClass: PageRepository::class)]
#[ORM\DiscriminatorColumn(name: 'class_key', type: 'string')]
@ -88,7 +89,7 @@ class Page implements EntityInterface
}
/**
* @return Block[]|Collection
* @return Collection|Block[]
*/
public function getBlocks(): Collection
{

View file

@ -15,8 +15,11 @@ class AbTestEvent extends Event
public const INIT_EVENT = 'ab_test.init';
public const RUN_EVENT = 'ab_test.run';
public function __construct(protected AbTest $test)
protected AbTest $test;
public function __construct(AbTest $test)
{
$this->test = $test;
}
public function getTest(): AbTest

View file

@ -12,10 +12,13 @@ use Symfony\Contracts\EventDispatcher\Event;
*/
class PasswordRequestEvent extends Event
{
public const EVENT = 'account_event.password_request';
const EVENT = 'account_event.password_request';
public function __construct(protected User $user)
protected User $user;
public function __construct(User $user)
{
$this->user = $user;
}
public function getUser(): User

View file

@ -12,15 +12,18 @@ use Symfony\Contracts\EventDispatcher\Event;
*/
class EntityManagerEvent extends Event
{
public const CREATE_EVENT = 'entity_manager_event.create';
public const UPDATE_EVENT = 'entity_manager_event.update';
public const DELETE_EVENT = 'entity_manager_event.delete';
public const PRE_CREATE_EVENT = 'entity_manager_event.pre_create';
public const PRE_UPDATE_EVENT = 'entity_manager_event.pre_update';
public const PRE_DELETE_EVENT = 'entity_manager_event.pre_delete';
const CREATE_EVENT = 'entity_manager_event.create';
const UPDATE_EVENT = 'entity_manager_event.update';
const DELETE_EVENT = 'entity_manager_event.delete';
const PRE_CREATE_EVENT = 'entity_manager_event.pre_create';
const PRE_UPDATE_EVENT = 'entity_manager_event.pre_update';
const PRE_DELETE_EVENT = 'entity_manager_event.pre_delete';
public function __construct(protected EntityInterface $entity)
protected EntityInterface $entity;
public function __construct(EntityInterface $entity)
{
$this->entity = $entity;
}
public function getEntity(): EntityInterface

View file

@ -2,8 +2,8 @@
namespace App\Core\Event\Page;
use App\Core\Entity\Site\Page\Page;
use Symfony\Contracts\EventDispatcher\Event;
use App\Core\Entity\Site\Page\Page;
/**
* class PageEditEvent.
@ -12,12 +12,14 @@ use Symfony\Contracts\EventDispatcher\Event;
*/
class PageEditEvent extends Event
{
public const FORM_INIT_EVENT = 'page_edit_event.form_init';
const FORM_INIT_EVENT = 'page_edit_event.form_init';
protected Page $page;
protected array $pageBuilderOptions = [];
public function __construct(protected Page $page)
public function __construct(Page $page)
{
$this->page = $page;
}
public function getPage()

View file

@ -11,11 +11,14 @@ use Symfony\Contracts\EventDispatcher\Event;
*/
class NavigationSettingEvent extends Event
{
public const INIT_EVENT = 'navigation_setting_event.init';
public const FORM_INIT_EVENT = 'navigation_setting_event.form_init';
const INIT_EVENT = 'navigation_setting_event.init';
const FORM_INIT_EVENT = 'navigation_setting_event.form_init';
public function __construct(protected $data = null)
protected $data;
public function __construct($data = null)
{
$this->data = $data;
}
public function getData()

View file

@ -11,11 +11,14 @@ use Symfony\Contracts\EventDispatcher\Event;
*/
class SettingEvent extends Event
{
public const INIT_EVENT = 'setting_event.init';
public const FORM_INIT_EVENT = 'setting_event.form_init';
const INIT_EVENT = 'setting_event.init';
const FORM_INIT_EVENT = 'setting_event.form_init';
public function __construct(protected $data = null)
protected $data;
public function __construct($data = null)
{
$this->data = $data;
}
public function getData()

View file

@ -11,7 +11,7 @@ use Symfony\Contracts\EventDispatcher\Event;
*/
class TaskInitEvent extends Event
{
public const INIT_EVENT = 'task_event.init';
const INIT_EVENT = 'task_event.init';
protected array $tasks = [];

View file

@ -14,13 +14,17 @@ use Symfony\Contracts\EventDispatcher\Event;
*/
class TaskRunRequestedEvent extends Event
{
public const RUN_REQUEST_EVENT = 'task_event.run_request';
const RUN_REQUEST_EVENT = 'task_event.run_request';
public function __construct(
protected string $task,
protected InputBag $parameters,
protected BufferedOutput $output
) {
protected string $task;
protected InputBag $parameters;
protected BufferedOutput $output;
public function __construct(string $task, InputBag $parameters, BufferedOutput $output)
{
$this->task = $task;
$this->parameters = $parameters;
$this->output = $output;
}
public function getTask(): string

View file

@ -6,6 +6,7 @@ use App\Core\Ab\AbContainer;
use App\Core\Ab\AbTest;
use App\Core\Entity\Site\Node;
use App\Core\Event\Ab\AbTestEvent;
use App\Core\Repository\Site\NodeRepository;
use App\Core\Site\SiteRequest;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\HttpFoundation\Cookie;
@ -20,13 +21,19 @@ use Symfony\Component\HttpKernel\Event\ResponseEvent;
*/
class AbListener
{
protected EventDispatcherInterface $eventDispatcher;
protected AbContainer $container;
protected SiteRequest $siteRequest;
protected ?Node $node;
public function __construct(
protected AbContainer $container,
protected EventDispatcherInterface $eventDispatcher,
protected SiteRequest $siteRequest
AbContainer $container,
EventDispatcherInterface $eventDispatcher,
SiteRequest $siteRequest
) {
$this->eventDispatcher = $eventDispatcher;
$this->container = $container;
$this->siteRequest = $siteRequest;
}
public function onKernelRequest(RequestEvent $event)
@ -63,16 +70,6 @@ class AbListener
}
}
public function onKernelResponse(ResponseEvent $event)
{
$cookies = $event->getRequest()->attributes->get('ab_test_cookies', []);
foreach ($cookies as $name => $value) {
$cookie = Cookie::create($name, $value['value'], time() + $value['duration']);
$event->getResponse()->headers->setCookie($cookie);
}
}
protected function getCookieName(): string
{
return 'ab_test_'.$this->getAbTestCode();
@ -99,4 +96,14 @@ class AbListener
return true;
}
public function onKernelResponse(ResponseEvent $event)
{
$cookies = $event->getRequest()->attributes->get('ab_test_cookies', []);
foreach ($cookies as $name => $value) {
$cookie = Cookie::create($name, $value['value'], time() + $value['duration']);
$event->getResponse()->headers->setCookie($cookie);
}
}
}

View file

@ -23,18 +23,30 @@ use Symfony\Component\HttpKernel\Event\RequestEvent;
*/
class AnalyticListener
{
protected NodeRepository $nodeRepository;
protected ViewRepositoryQuery $viewRepositoryQuery;
protected ViewFactory $viewFactory;
protected RefererRepositoryQuery $refererRepositoryQuery;
protected RefererFactory $refererFactory;
protected EntityManager $manager;
protected DeviceDetector $deviceDetector;
protected Request $request;
protected Node $node;
public function __construct(
protected NodeRepository $nodeRepository,
protected ViewRepositoryQuery $viewRepositoryQuery,
protected ViewFactory $viewFactory,
protected RefererRepositoryQuery $refererRepositoryQuery,
protected RefererFactory $refererFactory,
protected EntityManager $manager
NodeRepository $nodeRepository,
ViewRepositoryQuery $viewRepositoryQuery,
ViewFactory $viewFactory,
RefererRepositoryQuery $refererRepositoryQuery,
RefererFactory $refererFactory,
EntityManager $manager
) {
$this->nodeRepository = $nodeRepository;
$this->viewRepositoryQuery = $viewRepositoryQuery;
$this->viewFactory = $viewFactory;
$this->refererRepositoryQuery = $refererRepositoryQuery;
$this->refererFactory = $refererFactory;
$this->manager = $manager;
$this->createDeviceDetector();
}

View file

@ -3,10 +3,11 @@
namespace App\Core\EventListener;
use App\Core\Repository\RedirectRepositoryQuery;
use App\Core\Router\RedirectBuilder;
use App\Core\Router\RedirectMatcher;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpKernel\Event\ExceptionEvent;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use App\Core\Router\RedirectBuilder;
/**
* class RedirectListener.
@ -15,11 +16,15 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
*/
class RedirectListener
{
public function __construct(
protected RedirectMatcher $matcher,
protected RedirectBuilder $builder,
protected RedirectRepositoryQuery $repository
) {
protected RedirectMatcher $matcher;
protected RedirectBuilder $builder;
protected RedirectRepositoryQuery $repository;
public function __construct(RedirectMatcher $matcher, RedirectBuilder $builder, RedirectRepositoryQuery $repository)
{
$this->matcher = $matcher;
$this->builder = $builder;
$this->repository = $repository;
}
public function onKernelException(ExceptionEvent $event)
@ -32,7 +37,7 @@ class RedirectListener
$redirects = $this->repository
->orderBy('.sortOrder')
->where('.isEnabled=true')
->where('.isEnabled=1')
->find()
;

View file

@ -17,13 +17,24 @@ use Symfony\Contracts\Translation\TranslatorInterface;
*/
class PasswordRequestEventSubscriber implements EventSubscriberInterface
{
protected MailNotifier $notifier;
protected UrlGeneratorInterface $urlGenerator;
protected EntityManager $entityManager;
protected TokenGeneratorInterface $tokenGenerator;
protected TranslatorInterface $translator;
public function __construct(
protected MailNotifier $notifier,
protected UrlGeneratorInterface $urlGenerator,
protected EntityManager $entityManager,
protected TokenGeneratorInterface $tokenGenerator,
protected TranslatorInterface $translator
MailNotifier $notifier,
UrlGeneratorInterface $urlGenerator,
EntityManager $entityManager,
TokenGeneratorInterface $tokenGenerator,
TranslatorInterface $translator
) {
$this->notifier = $notifier;
$this->urlGenerator = $urlGenerator;
$this->entityManager = $entityManager;
$this->tokenGenerator = $tokenGenerator;
$this->translator = $translator;
}
public static function getSubscribedEvents()

View file

@ -16,12 +16,12 @@ use Symfony\Component\Security\Core\Exception\AccessDeniedException;
*/
class RequestSecurityEventSubscriber implements EventSubscriberInterface
{
protected NodeRepository $nodeRepository;
protected AuthorizationChecker $authorizationChecker;
public function __construct(
protected NodeRepository $nodeRepository,
ContainerInterface $container
) {
public function __construct(NodeRepository $nodeRepository, ContainerInterface $container)
{
$this->nodeRepository = $nodeRepository;
$this->authorizationChecker = $container->get('security.authorization_checker');
}

View file

@ -4,15 +4,18 @@ namespace App\Core\EventSubscriber\Site;
use App\Core\Site\SiteRequest;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\ResponseEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\HttpKernel\Event\ResponseEvent;
use Symfony\Component\HttpFoundation\Response;
use function Symfony\Component\String\u;
class ForcedDomainEventSubscriber implements EventSubscriberInterface
{
public function __construct(protected SiteRequest $siteRequest)
protected SiteRequest $siteRequest;
public function __construct(SiteRequest $siteRequest)
{
$this->siteRequest = $siteRequest;
}
public function onKernelResponse(ResponseEvent $event)
@ -35,8 +38,7 @@ class ForcedDomainEventSubscriber implements EventSubscriberInterface
->replace(
'://'.$this->siteRequest->getDomain(),
'://'.$navigation->getDomain()
)
;
);
$event->getResponse()->headers->set('Location', $uri);
$event->getResponse()->setStatusCode(Response::HTTP_MOVED_PERMANENTLY);

View file

@ -20,14 +20,27 @@ use Symfony\Contracts\Translation\TranslatorInterface;
*/
class MenuEventSubscriber extends EntityManagerEventSubscriber
{
protected NodeFactory $nodeFactory;
protected NodeRepository $nodeRepository;
protected EntityManager $entityManager;
protected CodeSlugify $slugify;
protected SymfonyCacheManager $cacheManager;
protected TranslatorInterface $translation;
public function __construct(
protected NodeFactory $nodeFactory,
protected NodeRepository $nodeRepository,
protected EntityManager $entityManager,
protected CodeSlugify $slugify,
protected SymfonyCacheManager $cacheManager,
protected TranslatorInterface $translator
NodeFactory $nodeFactory,
NodeRepository $nodeRepository,
EntityManager $entityManager,
CodeSlugify $slugify,
SymfonyCacheManager $cacheManager,
TranslatorInterface $translator
) {
$this->nodeFactory = $nodeFactory;
$this->nodeRepository = $nodeRepository;
$this->entityManager = $entityManager;
$this->slugify = $slugify;
$this->cacheManager = $cacheManager;
$this->translator = $translator;
}
public function supports(EntityInterface $entity): bool

View file

@ -17,9 +17,11 @@ use App\Core\Slugify\CodeSlugify;
class NavigationEventSubscriber extends EntityManagerEventSubscriber
{
public function __construct(
protected EntityManager $entityManager,
protected CodeSlugify $slugify
EntityManager $entityManager,
CodeSlugify $slugify
) {
$this->entityManager = $entityManager;
$this->slugify = $slugify;
}
public function supports(EntityInterface $entity): bool

View file

@ -12,6 +12,7 @@ use App\Core\Repository\Site\NodeRepository;
use App\Core\Slugify\CodeSlugify;
use App\Core\Slugify\RouteParameterSlugify;
use App\Core\Slugify\Slugify;
use Symfony\Component\HttpKernel\KernelInterface;
use function Symfony\Component\String\u;
/**
@ -21,14 +22,27 @@ use function Symfony\Component\String\u;
*/
class NodeEventSubscriber extends EntityManagerEventSubscriber
{
protected NodeFactory $nodeFactory;
protected EntityManager $entityManager;
protected KernelInterface $kernel;
protected Slugify $slugify;
protected CodeSlugify $codeSlugify;
protected RouteParameterSlugify $routeParameterSlugify;
public function __construct(
protected NodeFactory $nodeFactory,
protected NodeRepository $nodeRepository,
protected EntityManager $entityManager,
protected Slugify $slugify,
protected CodeSlugify $codeSlugify,
protected RouteParameterSlugify $routeParameterSlugify
NodeFactory $nodeFactory,
NodeRepository $nodeRepository,
EntityManager $entityManager,
Slugify $slugify,
CodeSlugify $codeSlugify,
RouteParameterSlugify $routeParameterSlugify
) {
$this->nodeFactory = $nodeFactory;
$this->nodeRepository = $nodeRepository;
$this->entityManager = $entityManager;
$this->slugify = $slugify;
$this->codeSlugify = $codeSlugify;
$this->routeParameterSlugify = $routeParameterSlugify;
}
public function supports(EntityInterface $entity): bool
@ -49,7 +63,7 @@ class NodeEventSubscriber extends EntityManagerEventSubscriber
$node = $event->getEntity();
$node->setCode($this->codeSlugify->slugify($node->getCode() ?? ''));
$node->setCode($this->codeSlugify->slugify($node->getCode()));
if ($node->getDisableUrl()) {
$node->setUrl(null);

View file

@ -17,8 +17,11 @@ use Symfony\Component\HttpFoundation\File\UploadedFile;
*/
class BlockEventSubscriber extends EntityManagerEventSubscriber
{
public function __construct(protected FileUploadHandler $fileUpload)
protected FileUploadHandler $fileUpload;
public function __construct(FileUploadHandler $fileUpload)
{
$this->fileUpload = $fileUpload;
}
public function supports(EntityInterface $entity): bool

View file

@ -16,8 +16,11 @@ use Symfony\Component\HttpFoundation\File\UploadedFile;
*/
class PageEventSubscriber extends EntityManagerEventSubscriber
{
public function __construct(protected FileUploadHandler $fileUpload)
protected FileUploadHandler $fileUpload;
public function __construct(FileUploadHandler $fileUpload)
{
$this->fileUpload = $fileUpload;
}
public function supports(EntityInterface $entity): bool

View file

@ -18,10 +18,13 @@ use Symfony\Component\HttpKernel\KernelInterface;
*/
class SiteEventSubscriber extends EntityManagerEventSubscriber
{
public function __construct(
protected KernelInterface $kernel,
protected SymfonyCacheManager $cacheManager
) {
protected KernelInterface $kernel;
protected SymfonyCacheManager $cacheManager;
public function __construct(KernelInterface $kernel, SymfonyCacheManager $cacheManager)
{
$this->kernel = $kernel;
$this->cacheManager = $cacheManager;
}
public function supports(EntityInterface $entity): bool

View file

@ -13,8 +13,11 @@ use App\Core\Event\Task\TaskRunRequestedEvent;
*/
class CacheCleanTaskEventSubscriber extends TaskEventSubscriber
{
public function __construct(protected SymfonyCacheManager $cacheManager)
protected SymfonyCacheManager $cacheManager;
public function __construct(SymfonyCacheManager $cacheManager)
{
$this->cacheManager = $cacheManager;
}
public function onInit(TaskInitEvent $event)

View file

@ -2,6 +2,7 @@
namespace App\Core\Factory;
use App\Core\Factory\FactoryInterface;
use App\Core\Entity\Redirect as Entity;
class RedirectFactory implements FactoryInterface

View file

@ -23,15 +23,22 @@ class FsFileManager
protected string $path;
protected string $pathUri;
protected array $pathLocked;
protected FileUploadHandler $uploadHandler;
protected FileInformationFactory $fileInformationFactory;
protected FileInformationRepositoryQuery $fileInformationRepositoryQuery;
public function __construct(
ParameterBagInterface $params,
protected FileUploadHandler $uploadHandler,
protected FileInformationFactory $fileInformationFactory,
protected FileInformationRepositoryQuery $fileInformationRepositoryQuery
FileUploadHandler $uploadHandler,
FileInformationFactory $fileInformationFactory,
FileInformationRepositoryQuery $fileInformationRepositoryQuery
) {
$config = $params->get('core')['file_manager'];
$this->uploadHandler = $uploadHandler;
$this->fileInformationFactory = $fileInformationFactory;
$this->fileInformationRepositoryQuery = $fileInformationRepositoryQuery;
$this->mimes = $config['mimes'];
$this->path = $config['path'];
$this->pathUri = $this->normalizePath($config['path_uri']);
@ -84,16 +91,12 @@ class FsFileManager
$this->applySort($finder, $options['sort'] ?? 'name', $options['sort_direction'] ?? 'asc');
foreach ($finder as $file) {
$splInfo = $this->getSplInfo($directory.'/'.$file->getBasename());
$data['files'][] = [
'basename' => $file->getBasename(),
'path' => $directory,
'webPath' => $this->pathUri.'/'.$directory.'/'.$file->getBasename(),
'locked' => $this->isLocked($directory.'/'.$file->getBasename()),
'mime' => mime_content_type($file->getRealPath()),
'size' => $splInfo ? $splInfo->getSize() : null,
'updated_at' => $splInfo ? date('Y-m-d H:i', $splInfo->getMTime()) : null,
];
}
@ -294,16 +297,14 @@ class FsFileManager
protected function applySort(Finder $finder, string $sort, string $direction)
{
$sorts = [
'name' => 'sortByName',
'type' => 'sortByType',
'updated_at' => 'sortByModifiedTime',
];
if ('name' === $sort) {
$finder->sortByName();
} elseif ('modification_date' === $sort) {
$finder->sortByModifiedTime();
}
if ('desc' === $direction) {
$finder->{$sorts[$sort]}()->reverseSorting();
} else {
$finder->{$sorts[$sort]}();
$finder->reverseSorting();
}
}

View file

@ -6,6 +6,7 @@ use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormView;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
class FilePickerType extends AbstractType
{
@ -29,7 +30,7 @@ class FilePickerType extends AbstractType
/**
* {@inheritdoc}
*/
public function getBlockPrefix()
public function getBlockPrefix(): string
{
return 'file_picker';
}

View file

@ -11,15 +11,6 @@ use Symfony\Component\HttpFoundation\File\UploadedFile;
*/
class FileUploadHandler
{
protected $filenameGenerator;
public function setFilenameGenerator(callable $filenameGenerator): self
{
$this->filenameGenerator = $filenameGenerator;
return $this;
}
public function handleForm(?UploadedFile $uploadedFile, string $path, ?callable $afterUploadCallback = null, bool $keepOriginalFilename = false): void
{
if (null === $uploadedFile) {
@ -30,11 +21,9 @@ class FileUploadHandler
if ($keepOriginalFilename) {
$filename = $originalFilename.'.'.$uploadedFile->guessExtension();
} elseif (!is_callable($this->filenameGenerator)) {
} else {
$safeFilename = transliterator_transliterate('Any-Latin; Latin-ASCII; [^A-Za-z0-9_] remove; Lower()', $originalFilename);
$filename = date('Ymd-his').$safeFilename.'.'.$uploadedFile->guessExtension();
} else {
$filename = call_user_func($this->filenameGenerator, $uploadedFile);
}
$uploadedFile->move($path, $filename);

View file

@ -2,11 +2,13 @@
namespace App\Core\Form\Filter;
use App\Core\Entity\Redirect;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Validator\Constraints\NotBlank;
class RedirectFilterType extends AbstractType
{

View file

@ -4,12 +4,12 @@ namespace App\Core\Form;
use App\Core\Entity\Redirect;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Validator\Constraints\NotBlank;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
class RedirectType extends AbstractType
{

View file

@ -7,7 +7,6 @@ use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Validator\Constraints\Length;
use Symfony\Component\Validator\Constraints\NotBlank;
class MenuType extends AbstractType
@ -24,7 +23,6 @@ class MenuType extends AbstractType
],
'constraints' => [
new NotBlank(),
new Length(max: 255),
],
]
);
@ -39,7 +37,6 @@ class MenuType extends AbstractType
],
'constraints' => [
new NotBlank(),
new Length(max: 255),
],
]
);

View file

@ -7,7 +7,6 @@ use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Validator\Constraints\Length;
use Symfony\Component\Validator\Constraints\NotBlank;
class NavigationAdditionalDomainType extends AbstractType
@ -25,7 +24,6 @@ class NavigationAdditionalDomainType extends AbstractType
],
'constraints' => [
new NotBlank(),
new Length(max: 255),
],
]
);

View file

@ -6,7 +6,6 @@ use App\Core\Entity\Site\Navigation;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
use Symfony\Component\Form\Extension\Core\Type\ColorType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
@ -27,7 +26,6 @@ class NavigationType extends AbstractType
],
'constraints' => [
new NotBlank(),
new Length(max: 255),
],
]
);
@ -40,21 +38,6 @@ class NavigationType extends AbstractType
'required' => true,
'attr' => [
],
'constraints' => [
new NotBlank(),
new Length(max: 255),
],
]
);
$builder->add(
'color',
ColorType::class,
[
'label' => 'Color',
'required' => true,
'attr' => [
],
'constraints' => [
new NotBlank(),
],
@ -71,7 +54,6 @@ class NavigationType extends AbstractType
],
'constraints' => [
new NotBlank(),
new Length(max: 255),
],
]
);
@ -112,7 +94,7 @@ class NavigationType extends AbstractType
],
'constraints' => [
new NotBlank(),
new Length(min: 2, max: 10),
new Length(['min' => 2, 'max' => 10]),
],
]
);

View file

@ -13,7 +13,6 @@ use Symfony\Component\Form\Extension\Core\Type\CollectionType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Validator\Constraints\Length;
use Symfony\Component\Validator\Constraints\NotBlank;
class NodeType extends AbstractType
@ -30,7 +29,6 @@ class NodeType extends AbstractType
],
'constraints' => [
new NotBlank(),
new Length(max: 255),
],
]
);
@ -45,7 +43,6 @@ class NodeType extends AbstractType
'attr' => [
],
'constraints' => [
new Length(max: 255),
],
]
);
@ -85,7 +82,6 @@ class NodeType extends AbstractType
'attr' => [
],
'constraints' => [
new Length(max: 255),
],
]
);
@ -120,9 +116,6 @@ class NodeType extends AbstractType
return $choices;
}),
'constraints' => [
new Length(max: 255),
],
]
);

View file

@ -2,11 +2,11 @@
namespace App\Core\Form\Site\Page;
use App\Core\Entity\Site\Page\Block;
use App\Core\Form\FileManager\FilePickerType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\AbstractType;
use App\Core\Entity\Site\Page\Block;
class FilePickerBlockType extends AbstractType
{

View file

@ -6,10 +6,10 @@ use App\Core\Entity\Site\Navigation;
use Doctrine\ORM\EntityRepository;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
class PageFilterType extends AbstractType
{

View file

@ -10,7 +10,6 @@ use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Validator\Constraints\Image;
use Symfony\Component\Validator\Constraints\Length;
use Symfony\Component\Validator\Constraints\NotBlank;
class PageType extends AbstractType
@ -27,7 +26,6 @@ class PageType extends AbstractType
],
'constraints' => [
new NotBlank(),
new Length(max: 255),
],
]
);
@ -41,7 +39,6 @@ class PageType extends AbstractType
'attr' => [
],
'constraints' => [
new Length(max: 255),
],
]
);
@ -55,7 +52,6 @@ class PageType extends AbstractType
'attr' => [
],
'constraints' => [
new Length(max: 255),
],
]
);
@ -69,7 +65,6 @@ class PageType extends AbstractType
'attr' => [
],
'constraints' => [
new Length(max: 255),
],
]
);
@ -83,7 +78,6 @@ class PageType extends AbstractType
'attr' => [
],
'constraints' => [
new Length(max: 255),
],
]
);

View file

@ -20,10 +20,6 @@ class CollectionType extends BaseCollectionType
'collection_name' => $options['collection_name'],
'label_add' => $options['label_add'],
'label_delete' => $options['label_delete'],
'allow_add' => $options['allow_add'],
'allow_delete' => $options['allow_delete'],
'template_before_item' => $options['template_before_item'],
'template_after_item' => $options['template_after_item'],
]);
}
@ -35,12 +31,10 @@ class CollectionType extends BaseCollectionType
'collection_name' => '',
'label_add' => 'Add',
'label_delete' => 'Delete',
'template_before_item' => null,
'template_after_item' => null,
]);
}
public function getBlockPrefix()
public function getBlockPrefix(): string
{
return 'murph_collection';
}

View file

@ -23,7 +23,7 @@ class GrapesJsType extends TextareaType
/**
* {@inheritdoc}
*/
public function getBlockPrefix()
public function getBlockPrefix(): string
{
return 'grapesjs';
}

View file

@ -11,7 +11,6 @@ use Symfony\Bundle\MakerBundle\Maker\AbstractMaker;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Filesystem\Filesystem;
use function Symfony\Component\String\u;
class MakeCrudController extends AbstractMaker
@ -104,17 +103,6 @@ class MakeCrudController extends AbstractMaker
$options
);
$views = ['_form.html.twig', '_show.html.twig'];
$directory = sprintf('templates/admin/%s_admin/', $options['route']);
$filesystem = new Filesystem();
$filesystem->mkdir($directory);
foreach ($views as $view) {
$filesystem->dumpFile(
$directory.$view,
sprintf("{{ include('@Core/admin/crud/%s') }}\n", $view)
);
}
$generator->writeChanges();
$this->writeSuccessMessage($io);

View file

@ -11,6 +11,7 @@ use Symfony\Bundle\MakerBundle\Maker\AbstractMaker;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use function Symfony\Component\String\u;
class MakeFactory extends AbstractMaker
{

View file

@ -8,11 +8,11 @@ use Symfony\Bundle\MakerBundle\DependencyBuilder;
use Symfony\Bundle\MakerBundle\Generator;
use Symfony\Bundle\MakerBundle\InputConfiguration;
use Symfony\Bundle\MakerBundle\Maker\AbstractMaker;
use Symfony\Bundle\MakerBundle\Str;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Question\Question;
use Symfony\Bundle\MakerBundle\Str;
use Symfony\Component\Filesystem\Filesystem;
class MakePage extends AbstractMaker
@ -92,8 +92,7 @@ class MakePage extends AbstractMaker
$this->writeSuccessMessage($io);
$io->text('Register the page in <comment>config/packages/app.yaml</comment>: ');
$io->text(
<<< EOF
$io->text(<<< EOF
core:
site:
@ -101,18 +100,10 @@ core:
{$pageClassNameDetails->getFullName()}:
name: {$pageClassNameDetails->getShortName()}
templates:
- {name: "Default", file: "{$templatePath}"}
- {name: "Default", file: "${templatePath}"}
EOF
);
}
public function configureDependencies(DependencyBuilder $dependencies)
{
$dependencies->addClassDependency(
Annotation::class,
'doctrine/annotations'
);
);
}
private function askForNextBlock(ConsoleStyle $io, array $blocks, bool $isFirstField)
@ -147,7 +138,7 @@ EOF
$types = [
'text' => null,
'textarea' => null,
'choice' => 'BlockEntity\\ChoiceBlock::class',
'choice' => null,
'collection' => 'BlockEntity\\CollectionBlock::class',
'editor_js_textarea' => null,
'file' => 'BlockEntity\\FileBlock::class',
@ -192,4 +183,12 @@ EOF
$io->writeln(sprintf(' * <comment>%s</comment>', $type));
}
}
public function configureDependencies(DependencyBuilder $dependencies)
{
$dependencies->addClassDependency(
Annotation::class,
'doctrine/annotations'
);
}
}

View file

@ -4,6 +4,7 @@ namespace App\Core\Manager;
use App\Core\Entity\EntityInterface;
use App\Core\Event\EntityManager\EntityManagerEvent;
use Doctrine\ORM\EntityManager as DoctrineEntityManager;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
@ -14,19 +15,23 @@ use Symfony\Component\EventDispatcher\EventDispatcherInterface;
*/
class EntityManager
{
public function __construct(
protected EventDispatcherInterface $eventDispatcher,
protected EntityManagerInterface $entityManager
) {
protected EventDispatcherInterface $eventDispatcher;
protected DoctrineEntityManager $entityManager;
public function __construct(EventDispatcherInterface $eventDispatcher, EntityManagerInterface $entityManager)
{
$this->eventDispatcher = $eventDispatcher;
$this->entityManager = $entityManager;
}
public function create(EntityInterface $entity, bool $dispatchEvent = true, bool $flush = true): self
public function create(EntityInterface $entity, bool $dispatchEvent = true): self
{
if ($dispatchEvent) {
$this->eventDispatcher->dispatch(new EntityManagerEvent($entity), EntityManagerEvent::PRE_CREATE_EVENT);
}
$this->persist($entity, $flush);
$this->persist($entity);
if ($dispatchEvent) {
$this->eventDispatcher->dispatch(new EntityManagerEvent($entity), EntityManagerEvent::CREATE_EVENT);
@ -35,13 +40,13 @@ class EntityManager
return $this;
}
public function update(EntityInterface $entity, bool $dispatchEvent = true, bool $flush = true): self
public function update(EntityInterface $entity, bool $dispatchEvent = true): self
{
if ($dispatchEvent) {
$this->eventDispatcher->dispatch(new EntityManagerEvent($entity), EntityManagerEvent::PRE_UPDATE_EVENT);
}
$this->persist($entity, $flush);
$this->persist($entity);
if ($dispatchEvent) {
$this->eventDispatcher->dispatch(new EntityManagerEvent($entity), EntityManagerEvent::UPDATE_EVENT);
@ -50,17 +55,14 @@ class EntityManager
return $this;
}
public function delete(EntityInterface $entity, bool $dispatchEvent = true, bool $flush = true): self
public function delete(EntityInterface $entity, bool $dispatchEvent = true): self
{
if ($dispatchEvent) {
$this->eventDispatcher->dispatch(new EntityManagerEvent($entity), EntityManagerEvent::PRE_DELETE_EVENT);
}
$this->entityManager->remove($entity);
if ($flush) {
$this->flush();
}
$this->flush();
if ($dispatchEvent) {
$this->eventDispatcher->dispatch(new EntityManagerEvent($entity), EntityManagerEvent::DELETE_EVENT);
@ -88,12 +90,9 @@ class EntityManager
return $this->entityManager;
}
protected function persist(EntityInterface $entity, bool $flush = true)
protected function persist(EntityInterface $entity)
{
$this->entityManager->persist($entity);
if ($flush) {
$this->flush();
}
$this->flush();
}
}

View file

@ -11,13 +11,10 @@ use App\Core\Entity\EntityInterface;
*/
class TranslatableEntityManager extends EntityManager
{
protected function persist(EntityInterface $entity, bool $flush = true)
protected function persist(EntityInterface $entity)
{
$this->entityManager->persist($entity, $flush);
$this->entityManager->persist($entity);
$entity->mergeNewTranslations();
if ($flush) {
$this->flush();
}
$this->flush();
}
}

View file

@ -3,7 +3,7 @@
namespace App\Core;
if (!defined('MURPH_VERSION')) {
define('MURPH_VERSION', 'v1.24.1');
define('MURPH_VERSION', 'v1.18.0');
}
/**

View file

@ -2,10 +2,10 @@
namespace App\Core\Notification;
use App\Entity\User;
use Symfony\Bridge\Twig\Mime\TemplatedEmail;
use Symfony\Component\Mailer\MailerInterface;
use Twig\Environment as TwigEnvironment;
use App\Entity\User;
/**
* class MailNotifier.
@ -14,6 +14,7 @@ use Twig\Environment as TwigEnvironment;
*/
class MailNotifier
{
protected MailerInterface $mailer;
protected array $attachments = [];
protected array $recipients = [];
protected array $bccRecipients = [];
@ -21,8 +22,10 @@ class MailNotifier
protected ?string $from = null;
protected ?string $replyTo = null;
public function __construct(protected MailerInterface $mailer)
public function __construct(TwigEnvironment $twig, MailerInterface $mailer)
{
$this->mailer = $mailer;
$this->twig = $twig;
}
public function setMailer(Swift_Mailer $mailer): self

View file

@ -7,8 +7,8 @@ use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* @method null|Referer find($id, $lockMode = null, $lockVersion = null)
* @method null|Referer findOneBy(array $criteria, array $orderBy = null)
* @method Referer|null find($id, $lockMode = null, $lockVersion = null)
* @method Referer|null findOneBy(array $criteria, array $orderBy = null)
* @method Referer[] findAll()
* @method Referer[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
*/

View file

@ -3,9 +3,9 @@
namespace App\Core\Repository\Analytic;
use App\Core\Repository\Analytic\RefererRepository as Repository;
use App\Core\Repository\RepositoryQuery;
use Knp\Component\Pager\PaginatorInterface;
use Symfony\Component\HttpFoundation\Request;
use App\Core\Repository\RepositoryQuery;
class RefererRepositoryQuery extends RepositoryQuery
{

View file

@ -7,8 +7,8 @@ use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* @method null|View find($id, $lockMode = null, $lockVersion = null)
* @method null|View findOneBy(array $criteria, array $orderBy = null)
* @method View|null find($id, $lockMode = null, $lockVersion = null)
* @method View|null findOneBy(array $criteria, array $orderBy = null)
* @method View[] findAll()
* @method View[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
*/

View file

@ -3,9 +3,9 @@
namespace App\Core\Repository\Analytic;
use App\Core\Repository\Analytic\ViewRepository as Repository;
use App\Core\Repository\RepositoryQuery;
use Knp\Component\Pager\PaginatorInterface;
use Symfony\Component\HttpFoundation\Request;
use App\Core\Repository\RepositoryQuery;
class ViewRepositoryQuery extends RepositoryQuery
{

View file

@ -7,8 +7,8 @@ use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* @method null|FileInformation find($id, $lockMode = null, $lockVersion = null)
* @method null|FileInformation findOneBy(array $criteria, array $orderBy = null)
* @method FileInformation|null find($id, $lockMode = null, $lockVersion = null)
* @method FileInformation|null findOneBy(array $criteria, array $orderBy = null)
* @method FileInformation[] findAll()
* @method FileInformation[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
*/

View file

@ -7,8 +7,8 @@ use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* @method null|NavigationSetting find($id, $lockMode = null, $lockVersion = null)
* @method null|NavigationSetting findOneBy(array $criteria, array $orderBy = null)
* @method NavigationSetting|null find($id, $lockMode = null, $lockVersion = null)
* @method NavigationSetting|null findOneBy(array $criteria, array $orderBy = null)
* @method NavigationSetting[] findAll()
* @method NavigationSetting[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
*/

View file

@ -7,8 +7,8 @@ use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* @method null|Redirect find($id, $lockMode = null, $lockVersion = null)
* @method null|Redirect findOneBy(array $criteria, array $orderBy = null)
* @method Redirect|null find($id, $lockMode = null, $lockVersion = null)
* @method Redirect|null findOneBy(array $criteria, array $orderBy = null)
* @method Redirect[] findAll()
* @method Redirect[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
*/

View file

@ -2,8 +2,9 @@
namespace App\Core\Repository;
use App\Core\Repository\RedirectRepository as Repository;
use App\Core\Repository\RepositoryQuery;
use Knp\Component\Pager\PaginatorInterface;
use App\Core\Repository\RedirectRepository as Repository;
class RedirectRepositoryQuery extends RepositoryQuery
{

View file

@ -98,26 +98,6 @@ abstract class RepositoryQuery
return $this;
}
public function count()
{
return $this
->select(sprintf('COUNT(%s.id) as total', $this->id))
->query
->getQuery()
->setMaxResults(1)
->getOneOrNullResult()['total']
;
}
protected function addForcedFilterHandler(string $name): self
{
if (!in_array($name, $this->forcedFilterHandlers)) {
$this->forcedFilterHandlers[] = $name;
}
return $this;
}
protected function populateDqlId(&$data)
{
if (is_string($data)) {

View file

@ -7,8 +7,8 @@ use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* @method null|Setting find($id, $lockMode = null, $lockVersion = null)
* @method null|Setting findOneBy(array $criteria, array $orderBy = null)
* @method Setting|null find($id, $lockMode = null, $lockVersion = null)
* @method Setting|null findOneBy(array $criteria, array $orderBy = null)
* @method Setting[] findAll()
* @method Setting[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
*/

View file

@ -32,9 +32,9 @@ class NodeRepository extends NestedTreeRepository
;
}
return null !== $query->getQuery()
return $query->getQuery()
->setMaxResults(1)
->getOneOrNullResult()
->getOneOrNullResult() !== null
;
}
}

View file

@ -10,19 +10,6 @@ $pagination-bg: #ffffff !default;
$pagination-active-color: #ffffff !default;
$pagination-active-bg: #343a40 !default;
$sidebar-width: 260px !default;
$input-border-color: map-get($theme-colors, 'dark-blue');
$input-btn-focus-color: $input-border-color;
$component-active-color: map-get($theme-colors, 'dark-blue');
$nav-tabs-link-active-bg: map-get($theme-colors, 'dark-blue');
$nav-pills-link-active-bg: map-get($theme-colors, 'dark-blue');
$nav-tabs-link-active-color: lighten(map-get($theme-colors, 'dark-blue'), 100%);
$nav-pills-link-active-color: lighten(map-get($theme-colors, 'dark-blue'), 100%);
$input-focus-border-color: lighten(map-get($theme-colors, 'dark-blue'), 80%);
@import "~choices.js/src/styles/choices.scss";
@import "~bootstrap/scss/bootstrap.scss";
@import "~@fortawesome/fontawesome-free/css/all.css";
@ -30,29 +17,9 @@ $input-focus-border-color: lighten(map-get($theme-colors, 'dark-blue'), 80%);
@import '~grapesjs/dist/css/grapes.min.css';
@import '~grapesjs-component-code-editor/dist/grapesjs-component-code-editor.min.css';
@for $i from 1 through 400 {
.miw-#{$i}, .min-width-#{$i} {
min-width: #{$i}px;
}
.min-width-#{$i}p {
min-width: #{$i}#{"%"};
}
.maw-#{$i}, .max-width-#{$i} {
max-width: #{$i}px;
}
.max-width-#{$i}p {
max-width: #{$i}#{"%"};
}
.width-#{$i} {
width: #{$i}px;
}
.width-#{$i}p {
width: #{$i}#{"%"};
@for $i from 1 through 100 {
.miw-#{$i*5} {
min-width: $i * 5px;
}
}
@ -82,11 +49,6 @@ body {
display: block;
}
.choices__inner, .is-focused .choices__inner, .is-open .choices__inner {
border: 1px solid map-get($theme-colors, 'dark-blue');
background: #fff;
}
.dropdown-toggle-hide-after {
&::after {
display: none;
@ -146,7 +108,6 @@ body {
.table .thead-light {
a, th {
color: map-get($theme-colors, 'dark-blue');
background: lighten(map-get($theme-colors, 'dark-blue'), 80%);
}
}
@ -212,7 +173,7 @@ tr.table-primary-light {
.sidebar {
width: $sidebar-width;
width: 260px;
display: inline-block;
.sidebar-toggler {
@ -292,8 +253,8 @@ tr.table-primary-light {
.body {
padding-top: 60px;
width: calc(100% - $sidebar-width);
margin-left: $sidebar-width;
width: calc(100% - 260px);
margin-left: 260px;
display: inline-block;
.nav {
@ -439,21 +400,6 @@ th {
margin-right: 4px;
}
.form-color {
display: inline-block;
line-height: 0;
border-radius: 25%;
input {
padding: 0;
border: 0;
height: auto;
width: 30px;
aspect-ratio: 1/1;
display: inline-block;
}
}
#form-main {
> .tab-content {
@media screen and (min-width: 500px) {
@ -619,11 +565,7 @@ fieldset.form-group {
&-filter {
padding-right: 20px;
padding-bottom: 15px;
.pagination {
margin-bottom: 0;
}
padding-bottom: 20px;
@media screen and (max-width: 769px) {
padding-right: 10px;
@ -654,20 +596,8 @@ fieldset.form-group {
}
}
.table {
.crud-batch-column {
width: 1%;
}
.crud-action-column {
text-align: right;
white-space: nowrap;
width: 1px;
}
}
.no-wrap {
white-space: nowrap;
.table .crud-batch-column {
width: 1%;
}
form {
@ -725,16 +655,6 @@ form {
}
}
label.required::after {
content: '*';
margin-left: 3px;
color: #b41215;
}
.invalid-feedback {
margin-top: -3px;
}
.gjs-editor-cont {
border-radius: 10px;
overflow: hidden !important;
@ -744,18 +664,6 @@ label.required::after {
background: map-get($theme-colors, 'dark-blue');
}
.tox {
&.tox-silver-sink.tox-tinymce-aux {
z-index: 3000 !important;
}
&.tox-tinymce {
border-color: $input-border-color;
border-radius: 5px;
}
}
.field-boolean {
color: #49555b;
font-size: 20px;
.tox.tox-silver-sink.tox-tinymce-aux {
z-index: 3000 !important;
}

View file

@ -1,7 +1,6 @@
import '../../../../../../../../assets/css/admin.scss';
require('../../../../../../../../node_modules/bootstrap/dist/js/bootstrap.min.js')
require('./modules/sidebar.js')()
require('./modules/table-fixed.js')()
require('./modules/form-confirm.js')()
require('./modules/form-file.js')()
@ -28,4 +27,5 @@ require('./modules/file-manager.js')()
require('./modules/file-picker.js')()
require('./modules/analytics.js')()
require('./modules/page.js')()
require('./modules/sidebar.js')()
require('./modules/node.js')()

View file

@ -19,7 +19,7 @@ Routing.setRoutingData(routes)
const map = {
'fa fa-file-pdf': ['application/pdf'],
'fa fa-file-image': ['image/png', 'image/jpg', 'image/jpeg', 'image/gif', 'image/webp'],
'fa fa-file-image': ['image/png', 'image/jpg', 'image/jpeg', 'image/gif'],
'fa fa-file-audio': ['application/ogg', 'audio/mp3', 'audio/mpeg', 'audio/wav'],
'fa fa-file-archive': ['application/zip', 'multipart/x-zip', 'application/rar', 'application/x-rar-compressed', 'application/x-zip-compressed', 'application/tar', 'application/x-tar'],
'fa fa-file-alt': ['application/rtf'],
@ -53,7 +53,7 @@ export default {
return
}
if (['image/png', 'image/jpg', 'image/jpeg', 'image/gif', 'image/webp'].indexOf(this.mime) === -1) {
if (['image/png', 'image/jpg', 'image/jpeg', 'image/gif'].indexOf(this.mime) === -1) {
this.thumbnail = null
return
}

View file

@ -25,8 +25,7 @@
<div class="breadcrumb mb-0 file-manager-views">
<select v-model="sort" class="form-control form-control-sm d-inline w-auto ml-1">
<option value="name">Name</option>
<option value="updated_at">Date</option>
<option value="type">Type</option>
<option value="modification_date">Date</option>
</select>
<select v-model="sortDirection" class="form-control form-control-sm d-inline w-auto ml-1">
<option value="asc">ASC</option>
@ -107,7 +106,7 @@
<td width="10">
<span class="fa fa-folder text-warning"></span>
</td>
<td colspan="2">
<td>
..
</td>
</tr>
@ -116,7 +115,7 @@
<td width="10">
<span class="fa fa-folder text-warning"></span>
</td>
<td colspan="2">
<td>
<div v-if="item.locked" class="float-right">
<span class="btn btn-sm btn-light">
<span class="fa fa-lock"></span>
@ -139,12 +138,6 @@
<span v-html="item.basename"></span>
</td>
<td class="text-right">
<span class="d-none d-sm-block">
<span class="btn btn-sm btn-light border-light mr-1 mb-1" v-text="readableFilesize(item.size)"></span>
<span class="btn btn-sm btn-light border-light mr-1 mb-1" v-text="item.updated_at"></span>
</span>
</td>
</tr>
</table>
</div>
@ -330,26 +323,6 @@ export default {
.catch((e) => {
alert('An error occured')
})
},
readableFilesize (size) {
if (size <= 0) {
return '0 KB'
}
if (size === 1) {
return '1 byte'
}
const mod = 1024
const units = ['bytes', 'KB', 'MB', 'GB', 'TB', 'PB']
let i = 0
while (size > mod && i < units.length - 1) {
size /= mod
++i
}
return `${size.toFixed(2)} ${units[i]}`
}
},
mounted () {
@ -385,7 +358,7 @@ export default {
$(events).each((k, event) => {
body.on(event + '.success', () => {
$('div[id^=modal-container-]').modal('hide')
$('div[id^=modal-container]').modal('hide')
that.refresh()
})
})
@ -393,10 +366,6 @@ export default {
body.on('file_manager.info.update.success', () => {
$('*[data-modal="' + that.modalUrl + '"]').click()
})
body.on('file_manager.info.directory.request_open', () => {
$('*[data-modal="' + that.modalUrl + '"]').click()
})
},
watch: {
directory (directory) {

View file

@ -8,28 +8,16 @@ module.exports = () => {
const form = $('#form-batch')
form.submit((e) => {
const select = document.querySelector('#form-batch-action')
const options = select.querySelectorAll('#form-batch-action option')
let doPrevent = true
e.preventDefault()
options.forEach((option) => {
if (option.value === select.value && option.getAttribute('data-isglobal') === 'true') {
doPrevent = false
}
})
const route = form.attr('action')
const datas = form.serialize()
if (doPrevent) {
e.preventDefault()
form.addClass('is-loading')
const route = form.attr('action')
const datas = form.serialize()
form.addClass('is-loading')
$.post(route, datas)
.always(() => {
document.location.reload()
})
}
$.post(route, datas)
.always(() => {
document.location.reload()
})
})
}

View file

@ -1,9 +1,8 @@
const Choices = require('choices.js')
const $ = require('jquery')
module.exports = () => {
document.querySelectorAll('*[data-jschoice]').forEach((item) => {
return new Choices(item, {
searchFields: ['label'],
})
module.exports = function () {
$('*[data-jschoice]').each(function (key, item) {
return new Choices(item)
})
}

View file

@ -36,9 +36,8 @@ const fileManagerBrowser = function (callback) {
const clickCallback = (e) => {
callback($(e.target).attr('data-value'), {})
$('#fm-modal').next('.modal-backdrop').remove()
$('#fm-modal').next('div[id^="modal-container-"]').modal('hide')
$('#fm-modal').modal('hide')
$('div[id^="modal-container-"]').modal('hide')
container.modal('hide')
$('body').off('click', '#file-manager-insert', clickCallback)
}

View file

@ -1,34 +1,9 @@
const $ = require('jquery')
const Sidebar = () => {
const menu = document.querySelector('.sidebar')
if (!menu) {
return
}
const stickyMenu = menu.querySelector('.sidebar-sticky')
const items = stickyMenu.querySelectorAll('a.nav-link')
const currentItem = menu.querySelector('.nav-link.active')
items.forEach((item) => {
item.addEventListener('click', () => {
localStorage.setItem('sidebar-item-top', stickyMenu.scrollTop)
})
const SidebarOpener = () => {
$('.sidebar-toggler .btn').click(() => {
$('.sidebar').toggleClass('is-open')
})
const toggler = menu.querySelector('.sidebar-toggler .btn')
toggler.addEventListener('click', () => {
menu.classList.toggle('is-open')
})
if (currentItem) {
stickyMenu.scrollTo({
top: Math.min(currentItem.offsetTop, localStorage.getItem('sidebar-item-top') ?? 0),
behavior: 'smooth'
})
}
}
module.exports = Sidebar
module.exports = SidebarOpener

View file

@ -36,7 +36,7 @@ const fileManagerBrowser = function (callback) {
const clickCallback = (e) => {
callback($(e.target).attr('data-value'), {})
$('div[id^="modal-container-"]').modal('hide')
$('div[id^="modal-container"]').modal('hide')
container.modal('hide')
$('body').off('click', '#file-manager-insert', clickCallback)
@ -53,7 +53,7 @@ const fileManagerBrowser = function (callback) {
})
}
const createTinymceConfig = function () {
if (typeof window.tinymce !== 'undefined') {
window.tinymce.murph = window.tinymce.murph || {}
window.tinymce.murph.selector = window.tinymce.murph.selector || '*[data-tinymce]'
window.tinymce.murph.configurationBase = window.tinymce.murph.configurationBase || {
@ -80,7 +80,6 @@ const createTinymceConfig = function () {
}
window.tinymce.murph.modes = window.tinymce.murph.modes || {}
window.tinymceModes = window.tinymceModes || {}
window.tinymce.murph.modes.default = window.tinymce.murph.modes.default || {
plugins: 'print preview importcss searchreplace visualblocks visualchars fullscreen template table charmap hr pagebreak nonbreaking toc insertdatetime advlist lists wordcount textpattern noneditable help charmap quickbars link image code autoresize',
@ -96,11 +95,6 @@ const createTinymceConfig = function () {
toolbar: 'undo redo | bold italic underline'
}
window.tinymce.murph.modes = {
...window.tinymce.murph.modes,
...window.tinymceModes
}
tinymce.addI18n('fr_FR', {
Redo: 'R\u00e9tablir',
Undo: 'Annuler',
@ -618,20 +612,15 @@ const doInitEditor = () => {
}
module.exports = function () {
if (typeof tinymce === 'undefined') {
return
}
const observer = new MutationObserver(doInitEditor)
const config = { attributes: false, childList: true, subtree: true }
observer.observe(document.querySelector('body'), config)
$(() => {
createTinymceConfig()
doInitEditor()
const observer = new MutationObserver(doInitEditor)
const config = { attributes: false, childList: true, subtree: true }
observer.observe(document.querySelector('body'), config)
$('body').on('hidden.bs.modal', '.modal', (e) => {
if (!$('.tox-dialog').length) {
$(e.target).find('.tox-tinymce').each(() => {
window.tinymce.remove($(this).prev().attr('id'))
})
}
})
})
}

View file

@ -1,79 +1,68 @@
<?php echo "<?php\n"; ?>
<?= "<?php\n" ?>
namespace <?php echo $namespace; ?>;
namespace <?= $namespace; ?>;
use App\Core\Controller\Admin\Crud\CrudController;
use App\Core\Crud\CrudConfiguration;
use App\Core\Crud\Field;
use App\Core\Entity\EntityInterface;
use App\Core\Manager\EntityManager;
use <?php echo $entity; ?> as Entity;
use <?php echo $factory; ?> as Factory;
use <?php echo $form; ?> as Type;
use <?php echo $repository_query; ?> as RepositoryQuery;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\IsGranted;
use <?= $entity ?> as Entity;
use <?= $factory ?> as Factory;
use <?= $form ?> as Type;
use <?= $repository_query ?> as RepositoryQuery;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\Routing\Annotation\Route;
class <?php echo $class_name; ?> extends CrudController
class <?= $class_name; ?> extends CrudController
{
protected ?CrudConfiguration $configuration = null;
#[Route(path: '/admin/user/edit/{entity}', name: 'admin_user_edit', methods: ['GET', 'POST'])]
#[Route(path: '/admin/<?php echo $route; ?>/{page}', name: 'admin_<?php echo $route; ?>_index', methods: ['GET'], requirements: ['page' => '\d+'])]
#[Route(path: "/admin/<?= $route; ?>/{page}", name: "admin_<?= $route; ?>_index", methods: ['GET'], requirements: ['page' => '\d+'])]
public function index(RepositoryQuery $query, Request $request, Session $session, int $page = 1): Response
{
return $this->doIndex($page, $query, $request, $session);
}
#[Route(path: '/admin/<?php echo $route; ?>/new', name: 'admin_<?php echo $route; ?>_new', methods: ['GET', 'POST'])]
#[Route(path: "/admin/<?= $route; ?>/new", name: "admin_<?= $route; ?>_new", methods: ['GET', 'POST'])]
public function new(Factory $factory, EntityManager $entityManager, Request $request): Response
{
return $this->doNew($factory->create(), $entityManager, $request);
}
#[Route(path: '/admin/<?php echo $route; ?>/show/{entity}', name: 'admin_<?php echo $route; ?>_show', methods: ['GET'])]
#[IsGranted('show', 'entity')]
#[Route(path: "/admin/<?= $route; ?>/show/{entity}", name: "admin_<?= $route; ?>_show", methods: ['GET'])]
public function show(Entity $entity): Response
{
return $this->doShow($entity);
}
#[Route(path: '/admin/<?php echo $route; ?>/filter', name: 'admin_<?php echo $route; ?>_filter', methods: ['GET'])]
#[Route(path: "/admin/<?= $route; ?>/filter", name: "admin_<?= $route; ?>_filter", methods: ['GET'])]
public function filter(Session $session): Response
{
return $this->doFilter($session);
}
#[Route(path: '/admin/<?php echo $route; ?>/edit/{entity}', name: 'admin_<?php echo $route; ?>_edit', methods: ['GET', 'POST'])]
#[IsGranted('edit', 'entity')]
#[Route(path: "/admin/<?= $route; ?>/edit/{entity}", name: "admin_<?= $route; ?>_edit", methods: ['GET', 'POST'])]
public function edit(Entity $entity, EntityManager $entityManager, Request $request): Response
{
return $this->doEdit($entity, $entityManager, $request);
}
#[Route(path: '/admin/<?php echo $route; ?>/inline_edit/{entity}/{context}/{label}', name: 'admin_<?php echo $route; ?>_inline_edit', methods: ['GET', 'POST'])]
#[IsGranted('edit', 'entity')]
public function inlineEdit(string $context, string $label, Entity $entity, EntityManager $entityManager, Request $request): Response
{
return $this->doInlineEdit($context, $label, $entity, $entityManager, $request);
}
#[Route(path: '/admin/<?php echo $route; ?>/sort/{page}', name: 'admin_<?php echo $route; ?>_sort', methods: ['POST'], requirements: ['page' => '\d+'])]
#[Route(path: "/admin/<?= $route; ?>/sort/{page}", name: "admin_<?= $route; ?>_sort", methods: ['POST'], requirements: ['page' => '\d+'])]
public function sort(RepositoryQuery $query, EntityManager $entityManager, Request $request, Session $session, int $page = 1): Response
{
return $this->doSort($page, $query, $entityManager, $request, $session);
}
#[Route(path: '/admin/<?php echo $route; ?>/batch/{page}', name: 'admin_<?php echo $route; ?>_batch', methods: ['POST'], requirements: ['page' => '\d+'])]
#[Route(path: "/admin/<?= $route; ?>/batch/{page}", name: "admin_<?= $route; ?>_batch", methods: ['POST'], requirements: ['page' => '\d+'])]
public function batch(RepositoryQuery $query, EntityManager $entityManager, Request $request, Session $session, int $page = 1): Response
{
return $this->doBatch($page, $query, $entityManager, $request, $session);
}
#[Route(path: '/admin/<?php echo $route; ?>/delete/{entity}', name: 'admin_<?php echo $route; ?>_delete', methods: ['DELETE', 'POST'])]
#[IsGranted('delete', 'entity')]
#[Route(path: "/admin/<?= $route; ?>/delete/{entity}", name: "admin_<?= $route; ?>_delete", methods: ['DELETE', 'POST'])]
public function delete(Entity $entity, EntityManager $entityManager, Request $request): Response
{
return $this->doDelete($entity, $entityManager, $request);
@ -81,32 +70,23 @@ class <?php echo $class_name; ?> extends CrudController
protected function getConfiguration(): CrudConfiguration
{
if ($this->configuration) {
return $this->configuration;
}
return $this->configuration = CrudConfiguration::create()
->setPageTitle('index', 'List of <?php echo $entity; ?>')
return CrudConfiguration::create()
->setPageTitle('index', 'List of <?= $entity; ?>')
->setPageTitle('edit', 'Edition of {id}')
->setPageTitle('new', 'New <?php echo $entity; ?>')
->setPageTitle('new', 'New <?= $entity; ?>')
->setPageTitle('show', 'View of {id}')
->setPageRoute('index', 'admin_<?php echo $route; ?>_index')
->setPageRoute('new', 'admin_<?php echo $route; ?>_new')
->setPageRoute('edit', 'admin_<?php echo $route; ?>_edit')
->setPageRoute('inline_edit', 'admin_<?php echo $route; ?>_inline_edit')
->setPageRoute('show', 'admin_<?php echo $route; ?>_show')
->setPageRoute('sort', 'admin_<?php echo $route; ?>_sort')
->setPageRoute('batch', 'admin_<?php echo $route; ?>_batch')
->setPageRoute('delete', 'admin_<?php echo $route; ?>_delete')
->setPageRoute('filter', 'admin_<?php echo $route; ?>_filter')
->setPageRoute('index', 'admin_<?= $route; ?>_index')
->setPageRoute('new', 'admin_<?= $route; ?>_new')
->setPageRoute('edit', 'admin_<?= $route; ?>_edit')
->setPageRoute('show', 'admin_<?= $route; ?>_show')
->setPageRoute('sort', 'admin_<?= $route; ?>_sort')
->setPageRoute('batch', 'admin_<?= $route; ?>_batch')
->setPageRoute('delete', 'admin_<?= $route; ?>_delete')
->setPageRoute('filter', 'admin_<?= $route; ?>_filter')
->setForm('edit', Type::class)
->setForm('edit', Type::class, [])
->setForm('new', Type::class)
->setView('form', 'admin/<?php echo $route; ?>_admin/_form.html.twig')
->setView('show_entity', 'admin/<?php echo $route; ?>_admin/_show.html.twig')
// ->setForm('filter', Type::class)
// ->setMaxPerPage('index', 20)
@ -118,7 +98,6 @@ class <?php echo $class_name; ?> extends CrudController
// ->setAction('index', 'show', true)
// ->setAction('index', 'edit', true)
// ->setAction('index', 'delete', true)
// ->setDoubleClick('index', false)
// ->setAction('edit', 'back', true)
// ->setAction('edit', 'show', true)
@ -149,6 +128,6 @@ class <?php echo $class_name; ?> extends CrudController
protected function getSection(): string
{
return '<?php echo $route; ?>';
return '<?= $route; ?>';
}
}

View file

@ -1,11 +1,11 @@
<?php echo "<?php\n"; ?>
<?= "<?php\n" ?>
namespace <?php echo $namespace; ?>;
namespace <?= $namespace; ?>;
use App\Core\Factory\FactoryInterface;
use <?php echo $entity; ?> as Entity;
use <?= $entity ?> as Entity;
class <?php echo $class_name; ?> implements FactoryInterface
class <?= $class_name; ?> implements FactoryInterface
{
public function create(): Entity
{

View file

@ -1,6 +1,6 @@
<?php echo "<?php\n"; ?>
<?= "<?php\n" ?>
namespace <?php echo $namespace; ?>;
namespace <?= $namespace; ?>;
use App\Core\Entity\Site\Page\Page;
use App\Core\Entity\Site\Page as BlockEntity;
@ -9,28 +9,28 @@ use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Form\FormBuilderInterface;
#[ORM\Entity]
class <?php echo $class_name; ?> extends Page
class <?= $class_name; ?> extends Page
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
<?php if (count($blocks)) { ?> $builder
<?php foreach ($blocks as $block) { ?>
->add('<?php echo $block['name']; ?>', <?php echo $block['type']; ?>)
<?php } ?>
<?php if (count($blocks)): ?> $builder
<?php foreach ($blocks as $block): ?>
->add('<?= $block['name'] ?>', <?= $block['type'] ?>)
<?php endforeach; ?>
;
<?php } ?>
<?php endif; ?>
}
<?php foreach ($blocks as $block) { ?>
public function set<?php echo $block['camelCase']; ?>(BlockEntity\Block $block)
<?php foreach ($blocks as $block): ?>
public function set<?= $block['camelCase'] ?>(BlockEntity\Block $block)
{
return $this->setBlock($block);
}
public function get<?php echo $block['camelCase']; ?>()
public function get<?= $block['camelCase'] ?>()
{
return $this->getBlock('<?php echo $block['name']; ?>'<?php if ($block['class']) { ?>, <?php echo $block['class']; ?><?php } ?>);
return $this->getBlock('<?= $block['name'] ?>'<?php if ($block['class']): ?>, <?= $block['class'] ?><?php endif; ?>);
}
<?php } ?>
<?php endforeach; ?>
}

View file

@ -1,15 +1,15 @@
<?php echo "<?php\n"; ?>
<?= "<?php\n" ?>
namespace <?php echo $namespace; ?>;
namespace <?= $namespace; ?>;
use App\Core\Repository\RepositoryQuery;
use Knp\Component\Pager\PaginatorInterface;
use <?php echo $repository; ?> as Repository;
use <?= $repository; ?> as Repository;
class <?php echo $class_name; ?> extends RepositoryQuery
class <?= $class_name; ?> extends RepositoryQuery
{
public function __construct(Repository $repository, PaginatorInterface $paginator)
{
parent::__construct($repository, '<?php echo $id; ?>', $paginator);
parent::__construct($repository, '<?= $id; ?>', $paginator);
}
}

View file

@ -64,7 +64,7 @@
"Display name": "Nom d'affichage"
"Administrator": "Administrateur⋅trice"
"Writer": "Rédacteur⋅trice"
"Reference": "Référence"
"Reference": "Élement de référence"
"My account": "Mon compte"
"Logout": "Déconnexion"
"Dashboard": "Tableau de bord"
@ -144,7 +144,7 @@
"Username or e-mail": "Identifiant ou e-mail"
"Submit": "Soumettre"
"If the information submitted corresponds to a user account, you will receive an e-mail with the link to initiate the password change procedure.": "Si les informations soumises correspondent à un compte utilisateur, vous allez recevoir un e-mail avec en lien pour enclancher la procédure de changement de mot de passe."
"Enter your account username or email address. An e-mail will be sent to you to initiate the password change procedure.": "Saisissez le nom d'utilisateur ou l'adresse e-mail de votre compte. Un e-mail vous sera envoyé pour enclancher la procédure de changement de mot de passe."
"Enter your account username or email address. An e-mail will be sent to you to initiate the password change procedure. ": "Saisissez le nom d'utilisateur ou l'adresse e-mail de votre compte. Un e-mail vous sera envoyé pour enclancher la procédure de changement de mot de passe."
"Show the login page": "Afficher la page de connexion"
"A password reset request has been made. If you are the source of this request, click on the link below or copy and paste the address if the link does not work.": "Une demande de réinitialisation de mot de passe a été réalisée. Si vous êtes à l'origine de cette demande, cliquer sur le lien ci-dessous ou copier et coller l'adresse si le lien ne fonctionne pas."
"Edit the routing": "Éditez le routage"
@ -163,7 +163,7 @@
"Filter": "Filtrer"
"Force this domain": "Forcer ce nom de domaine"
"Additional domains": "Domaines additionnels"
"Regular expression: do not add the delimiter": "Expression régulière : ne pas ajouter de délimiteur"
"Regular expression: do not add the delimiter": "Expréssion régulière : ne pas ajouter de délimiteur"
"Content type": "Type de contenu"
'Leave blank equals "text/html"': 'Laissez vide équivaut à "text/html"'
"Close": "Fermer"
@ -223,4 +223,3 @@
"At least one role": "Au moins un rôle"
"All roles": "Tous les rôles"
"Enable A/B Testing": "Activer le test A/B"
"Color": "Couleur"

View file

@ -2,7 +2,7 @@
{% import _self as macros %}
{% block title %}{{ 'My account'|trans }} {{ parent() ? ('- ' ~ parent()) : '' }}{% endblock %}
{% block title %}{{ 'My account'|trans }} - {{ parent() }}{% endblock %}
{% block body %}
<div class="bg-light">
@ -12,7 +12,7 @@
</div>
<div class="row">
<div class="col-12 col-md-6">
<div class="col-6">
<form action="{{ path('admin_account_password') }}" method="post">
<div class="tab-content">
<div class="tab-pane active">
@ -102,7 +102,7 @@
</form>
</div>
<div class="col-12 col-md-6">
<div class="col-6">
<form action="{{ path('admin_account_2fa') }}" method="post">
<div class="tab-content">
<div class="tab-pane active">

View file

@ -9,3 +9,4 @@
{% endfor %}
</div>
</div>

View file

@ -1,6 +1,6 @@
<div class="row">
<div class="col-md-12 p-3">
{% for item in entity_to_array(entity, false, ['id']) %}
{% for item in entity_to_array(entity) %}
<div class="font-weight-bold">{{ item.name|trans }}</div>
<div class="mb-3">{{ item.value }}</div>
{% endfor %}

View file

@ -4,7 +4,7 @@
{% block body_class %}has-form{% endblock %}
{% block title %}{{ configuration.pageTitle(context)|trans|build_string(entity) }} {{ parent() ? ('- ' ~ parent()) : '' }}{% endblock %}
{% block title %}{{ configuration.pageTitle(context)|trans|build_string(entity) }} - {{ parent() }}{% endblock %}
{% block body %}
{% block header %}

View file

@ -1,22 +0,0 @@
{%- block value -%}
{% set value = value|default(options.default_value) %}
<span class="field-boolean">
{% if options.display == 'checkbox' %}
{% block checkbox %}
<span class="fa {{ value ? options.checkbox_class_when_true : options.checkbox_class_when_false }}"></span>
{% endblock %}
{% elseif options.display == 'toggle' %}
{% block toggle %}
{% if value %}
<span class="rounded-pill pl-3 pr-1 text-white {{ options.toggle_class_when_true }}">
<span class="fa fa-circle"></span>
</span>
{% else %}
<span class="rounded-pill pr-3 pl-1 text-white {{ options.toggle_class_when_false }}">
<span class="fa fa-circle"></span>
</span>
{% endif %}
{% endblock %}
{% endif %}
</span>
{%- endblock -%}

View file

@ -2,7 +2,7 @@
{%- if value -%}
<span class="btn btn-sm btn-light">
<span class="fa fa-calendar-alt text-black-50 mr-2"></span>
{{- value|default(options.default_value)|date(options.format) -}}
{{- value|date(options.format) -}}
</span>
{%- endif -%}
{%- endblock -%}

Some files were not shown because too many files have changed in this diff Show more