umanit / block-bundle
Doctrine Block management made easy
Installs: 3 372
Dependents: 1
Suggesters: 0
Security: 0
Stars: 6
Watchers: 7
Forks: 4
Open Issues: 3
Type:symfony-bundle
Requires
- php: ^7.1
- doctrine/doctrine-bundle: ^1.6|^2.1
- doctrine/orm: ^2.5
- symfony/contracts: ^1.1
- symfony/form: ^4.4
- symfony/framework-bundle: ^4.4
- symfony/validator: ^4.4
Suggests
- umanit/translation-bundle: Allow your panel to be translated.
README
Doctrine Block managment made easy.
- Simple implementation
- Flexible
- Orderable Blocks
- Database consistent
- User friendly
- Dev friendly
Philosophy
Usually when dealing with blocks, developers lose their database consistency because they have to store many block types in a single table. The most common way of storing many types of blocks in one single table is to store them in a json column.
We think json is bad for database consistency and performances. Searching, indexing, managing relations, primary and unique keys... You name it, none of them is possible with json.
UmanitBlockBundle intends to solve this problem by giving back their entities to the developers.
Front requirements
When using SonataAdmin
- jQuery
- jQueryUI sortable
- FontAwesome
- jQuery Select2 (best have)
When using Sylius
- Nothing!
Install
Register the bundle to your 'config/bundles.php'
<?php return [ // ... Umanit\BlockBundle\UmanitBlockBundle::class => ['all' => true], ];
Add one of the Twig's form theme
# config/packages/twig.yaml twig: form_themes: # When using SonataAdmin - '@UmanitBlock/sonata/form/panel.html.twig' # When using Sylius - '@UmanitBlock/sylius/form/panel.html.twig'
Add assets in your layout
<!-- When using SonataAdmin --> <link rel="stylesheet" href="{{ asset('bundles/umanitblock/sonata/panel.css') }}"> <script src="{{ asset('bundles/umanitblock/sonata/panel.js') }}" defer="defer"></script> <!-- When using Sylius --> <script src="{{ asset('bundles/umanitblock/sylius/panel.js') }}" defer="defer"></script>
Usage
Terminology
- A
Block
is a simple Doctrine entity that implementsUmanit\BlockBundle\Model\BlockInterface
. - A
Block Manager
is a service used to administrate and render aBlock
. - A
Panel
is a Doctrine entity that contains a collection of orderedBlock
instances.
Create an entity containing the Panel
Usually, you'll have a content entity (here we'll call it Page
) having one or more Panels
.
<?php namespace AppBundle\Entity; use Doctrine\ORM\Mapping as ORM; use Umanit\BlockBundle\Entity\Panel; /** * @ORM\Entity() */ class Page { // Your other fields... /** * @var Panel * * @ORM\ManyToOne(targetEntity="Umanit\BlockBundle\Entity\Panel", cascade={"persist"}) * @ORM\JoinColumn(name="panel_id", referencedColumnName="id") */ protected $content; // Getters and Setters... }
Next, use the provided PanelType
form to administrate the Page
content.
use Umanit\BlockBundle\Form\PanelType; $builder->add('content', PanelType::class);
Every block manager is available by default, if you want to filter them, you can give an option authorized_blocks
, an
array of all the block types allowed to be selected, or unauthorized_blocks
, an array of all the block types not
allowed to be selected.
use Umanit\BlockBundle\Form\PanelType; $builder->add('content', PanelType::class, [ 'authorized_blocks' => [MyBlock::class] ]); $builder->add('content', PanelType::class, [ 'unauthorized_blocks' => [MyBlock::class] ]);
Create a Block entity and its Block Manager
Start by creating your Block
entity which should extends the bundle Block
entity, like the following example:
<?php namespace AppBundle\Entity; use Doctrine\ORM\Mapping as ORM; use Umanit\BlockBundle\Entity\Block; /** * @ORM\Entity() */ class TitleAndText extends Block { /** * @var string * * @ORM\Column(name="title", type="string") */ private $title; /** * @var string * * @ORM\Column(name="text", type="text") */ private $text; // getters and setters ... /** * */ public function __toString() { return $this->getTitle() ? : 'New TitleAndText'; } }
Then, create a Block Manager
service and it's FormType
which should extend AbstractBlockType
.
This service will define the form used to administrate your Block
.
It will also allow you to define the rendering of the Block
in the front end.
<?php namespace AppBundle\BlockManager; use AppBundle\Entity\TitleAndText; use AppBundle\Form\TitleAndTextType; use Umanit\BlockBundle\Block\AbstractBlockManager; use Umanit\BlockBundle\Model\BlockInterface; use Twig\Environment; use \Twig\Error\LoaderError; use \Twig\Error\RuntimeError; use \Twig\Error\SyntaxError; class TitleAndTextManager extends AbstractBlockManager { /** @var Environment */ private $twig; /** * QuoteBlockManager constructor. * * @param Environment $twig */ public function __construct(Environment $twig) { $this->twig = $twig; } /** * Define which Block type is managed by this Manager * * @return string */ public function getManagedBlockType(): string { return TitleAndText::class; } /** * This method must return the form typemanaged by this block manager. * * @return string */ public function getManagedFormType(): string { return TitleAndTextType::class; } /** * Define how the block should be rendered on the front end. * * @param BlockInterface $block * @param array $parameters * * @return string * @throws LoaderError * @throws RuntimeError * @throws SyntaxError */ public function render(BlockInterface $block, array $parameters = []): string { return $this->twig->render('blocks/title-and-text.html.twig', ['block' => $block]); } }
<?php namespace AppBundle\Form\TitleAndTextType; use Umanit\BlockBundle\Form\AbstractBlockType; use Symfony\Component\Form\Extension\Core\Type\TextareaType; use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Validator\Constraints\NotBlank; class TitleAndTextType extends AbstractBlockType { /** * Define the form used by the back end to administrate the block. * * @param FormBuilderInterface $builder * @param array $options */ public function buildForm(FormBuilderInterface $builder, array $options): void { $builder ->add('title', TextType::class, [ 'constraints' => [ new NotBlank(), ], ]) ->add('text', TextareaType::class, [ 'constraints' => [ new NotBlank(), ], ]) ; } }
Finally, tag your Block Manager
with umanit_block.manager
.
# config/services.yml services: app.block_manager.title_and_text_manager: class: AppBundle\BlockManager\TitleAndTextManager arguments: ['@twig'] tags: ['umanit_block.manager']
Render your blocks
Use the twig function umanit_block_render
to render each of your blocks.
{# page.html.twig #} {% for block in page.content.blocks %} {{ umanit_block_render(block) }} {% endfor %}
umanit_block_render
will find the right BlockManager
and call its render
method.
You can pass an array of parameters to umanit_block_render
. This parameters will be passed to the render
method of
the BlockManager
.
Integration with UmanitTranslationBundle
This bundle is fully compatible with UmanitTranslationBundle.
Once translating a Panel
, all the Block
instances and their properties will also be translated.
If you need a locale parameter in you BlockManager
form (to filter an EntityType
for example), pass the parameter
to the PanelType
like so:
$builder->add('content', PanelType::class, ['locale' => 'be']);