Giter VIP home page Giter VIP logo

siduseavmodelbundle's Introduction

Sidus/EAVModelBundle Documentation

SensioLabsInsight

The canonical version of this documentation can be found here: https://vincentchalnot.github.io/SidusEAVModelBundle

Introduction

This bundle allows you to quickly set up a dynamic model in a Symfony project using Doctrine.
Model configuration is done in Yaml and everything can be easily extended.

The main feature of this model that exists nowhere else to my knowledge is the possibility to contextualize data based on as many contextualization axis you need.

All EAV model allows you to contextualize data based on the language or the country (yes: internationalization is a subset of data contextualization), some models allows you to contextualize your data based on some channels or scopes but this particular implementation allows you to manage contextualization axis to conform with your business logic, not the other way around.

Main Features:

Documentation index

Other documentation entries

Looking for something ?

Check the Q&A section and don't hesitate to ask questions in the issues.

What’s an EAV model

EAV stands for Entity-Attribute-Value

The main feature consists in storing values in a different table than the entities. Check the confusing and not-so-accurate Wikipedia article

This implementation is actually more an E(A)V model than a traditional EAV model because attributes are not stored in the database but in YAML files.

If you're not familiar with the key concepts of the EAV model, please read the following.

Why using it

  • Allowing ultra-fast model design because it's super easy to bootstrap.
  • Grouping in the same place the model and the metadata like: form configuration, validation, serialization options...
  • Managing single-value attributes and multiple-values attributes the same way and being able to change your mind after without having to do data recovery.
  • Storing contextual values per: locale, country, channel (web/print/mobile), versions.
  • Grouping and ordering attributes.
  • Easy CRUD: your forms are already configured !

Why not using it ?

Performances ? Not a real issue because MySQL is not usable for searching in a vast amount of data anyway, be it an EAV model or a more standard relational model. Solution: Elastic Search: it’s currently optionally supported through the Sidus/FilterBundle with the Sidus/ElasticaFilterBundle

Relational model

If you a have a complex relational model and you plan to use a lots of joins to retrieve data, it might be best to keep your relational model outside of the EAV model but both can coexists without any problem. However, there is a technical limitation when using this implementation of the EAV model: There is only one table for the Data entry and one table for the Values.

The implementation

We are using Doctrine as it’s the most widely supported ORM by the Symfony community and we’re aiming at a MySQL/MariaDB implementation only for data storage.

In any EAV model there are two sides

  • The model itself: Families (data types), Attributes and Attribute Types.
  • The data: The values and the class that contains the values, called here “Data”.

In some implementation the model is stored in the database but here we chose to maintain the model in Symfony service configuration for several reasons:

  • For performance reasons, you always needs to access a lots of components from your model and lazy loading will generate many unnecessary SQL requests. Symfony services are lazy loaded from PHP cache system which is very very fast compared to any other storage system.
  • For complexity reason: with services, you can always define new services, use injections, extend existing services and have complex behaviors for your entities.
  • A Symfony configuration is easy to write and to maintain and can be versioned, when your model is stored in your database along with your data you will have a very hard time to maintain the same model on your different environments.
  • Because the final users NEVER edits the model directly in production, it’s always some expert or some developer that does it on a testing environment first and we prefer simple yaml configuration files over a complex administration system that can fail.
  • It allows you to add layers of configuration for your special needs, for example you can configure directly some form options in the attribute declaration.
  • Finally, you can split your configuration and organise it in different files if needed be and you can comment it, which is a powerful feature when your model starts to grow bigger and bigger with hundreds of different attributes.

Families and attributes are services automatically generated from your configuration, attribute types are standard Symfony services.

Example

For a basic blog the configuration will look like this:

sidus_eav_model:
    families:
        Post:
            attributeAsLabel: title
            attributes:
                title: # Default type is string
                    required: true

                content:
                    type: html # This type is available through the EAVBootstrapBundle

                publicationDate:
                    type: datetime

                publicationStatus:
                    type: choice
                    form_options: # Symfony form options are passed directly
                        choices:
                            draft: Draft
                            published: Published
                            archived: Archived

                author:
                    type: data_selector # This type allows to select an other entity inside the EAV model
                    options:
                        autoload: true # Autoload author when loading Post
                        allowed_families:
                            - Author

                tags:
                    multiple: true
                    form_options:
                        collection_options:
                            sortable: true

                isFeatured:
                    type: boolean

        Author:
            attributeAsLabel: name
            attributes:
                name:
                    required: true

                email:
                    validation_rules: # Validation rules can be applied directly in the model
                        - Email: ~

Note that by convention we declare the families in UpperCamelCase and the attributes as lowerCamelCase and we encourage you to do so.

siduseavmodelbundle's People

Contributors

bghosts avatar cjprinse avatar dom18fr avatar fabiensalles avatar fjarnet avatar johnkrovitch avatar shavounet avatar vincentchalnot avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

siduseavmodelbundle's Issues

Installation Failed

When I'm trying to install SidusEAV Bundle then, Symfony flex version incompatibility error comes up.

Please have a look at the screenshot.
image

Les tooltips ne sont pas générées

Les tooltips ne sont pas générées quand le form est chargé en ajax. Pour pouvoir le faire sur le layout "normal", j'ai ajouté le script ci dessous dans kedge.js
$('[data-toggle="tooltip"]').tooltip();

EAV event recompute changeset

Recomputing changeset for attributes with removed values does not work.

Exemple:

foreach (array_unique($data->getRefererDatas()->toArray()) as $activity){
                if (self::ACTIVITY_FAMILY !== $activity->getFamilyCode()){
                    continue;
                }
                if(!in_array($activity, $actualActivities)){
                    $activity->removeSubscribers($data);
                    $activityAttribute = $activity->getFamily()->getAttribute('subscribers');
                    $event->recomputeAttributeChangeset($activity, $activityAttribute);
                }
            }
        }

how to use EAV model with normal entity?

I am using EAV with normal entities.

Use case

user has many roles, roles can belong to many users. Let's assume User is an EAV model, but Role is a normal entity.

Question 1 : how to design the User EAV model.

sidus_eav_model:
    families:
        Project:
            attributeAsLabel: username
            attributes:
                username:
                    required: true
                    type: string
               roles:
                    type: integer
                    collection: true
<entity name="Acme\Component\User\Model\Role" table="acme_role">
        <id name="id" type="integer">
            <generator strategy="AUTO"/>
        </id>
        <field name="role" type="string" unique="true" length="30" nullable="false"/>
        <field name="label" type="string" length="30"/>
        <field name="description" type="text" nullable="true"/>
    </entity>

Question 2: What is the effecient way to get a list of users with associated roles?

action filtrer

  • lorsqu'on filtre, le layout (surchargé) n'est pas repris.

The option "sortable" does not exist

tags:
    multiple: true
    form_options:
        sortable: true

The option "sortable" does not exist. Defined options are: "action", "allow_extra_fields", "attr", "auto_initialize", "block_name", "by_reference", "cascade_validation", "compound", "constraints", "csrf_field_name", "csrf_message", "csrf_protection", "csrf_provider", "csrf_token_id", "csrf_token_manager", "data", "data_class", "disabled", "embed_form", "empty_data", "error_bubbling", "error_delay", "error_mapping", "error_type", "extra_fields_message", "help_block", "help_block_popover", "help_block_tooltip", "help_label", "help_label_popover", "help_label_tooltip", "help_widget_popover", "horizontal", "horizontal_input_wrapper_class", "horizontal_label_class", "horizontal_label_div_class", "horizontal_label_offset_class", "inherit_data", "intention", "invalid_message", "invalid_message_parameters", "label", "label_attr", "label_format", "label_render", "legend_tag", "mapped", "max_length", "method", "omit_collection_item", "pattern", "post_max_size_message", "property_path", "prototype_names", "read_only", "render_fieldset", "render_optional_text", "render_required_asterisk", "required", "show_child_legend", "show_legend", "static_text", "tabs_class", "translation_domain", "trim", "upload_max_size_message", "validation_groups", "virtual", "widget_add_btn", "widget_addon_append", "widget_addon_prepend", "widget_btn_append", "widget_btn_prepend", "widget_checkbox_label", "widget_form_control_class", "widget_form_group", "widget_form_group_attr", "widget_items_attr", "widget_prefix", "widget_remove_btn", "widget_suffix", "widget_type".

In vendor/sidus/eav-model-bundle/Sidus/EAVModelBundle/Form/Type/DataType.php at line 292, there are twice the sortable option in the $collectionOptions:

  • the first declared in $collectionOptions;
  • the second is taken from the .yml declaration and comes from $options['entry_options’]

Fixed currently on my project with the Z.O.B. Design Pattern

    protected function addMultipleAttribute(
        FormInterface $form,
        AttributeInterface $attribute,
        FamilyInterface $family,
        DataInterface $data = null,
        array $options = []
    ) {
        $formOptions = [];
        if (array_key_exists('form_options', $options)) {
            $formOptions = $options['form_options'];
        }

        $formOptions = array_merge($formOptions, $attribute->getFormOptions($data));
        $label = $this->getFieldLabel($family, $attribute);

        $formOptions['label'] = false; // Removing label
        
        $sortable = isset($formOptions['sortable']) ? $formOptions['sortable'] : false;
        unset($formOptions['sortable']);
        
        $collectionOptions = [
            'label' => $label,
            'type' => $attribute->getType()->getFormType(),
            'entry_options' => $formOptions,
            'allow_add' => true,
            'allow_delete' => true,
            'required' => $attribute->isRequired(),
            'sortable' => $sortable,
            'prototype_name' => '__'.$attribute->getCode().'__',
        ];
        if (!empty($formOptions['collection_options'])) {
            $collectionOptions = array_merge($collectionOptions, $formOptions['collection_options']);
        }
        unset($collectionOptions['entry_options']['collection_options']);
        $form->add($attribute->getCode(), $this->collectionType, $collectionOptions);
    }

rendu embed multiple

Il y a un un décalage dans l'affichage entre les embed multiple déjà enregistré et les nouveaux embed.
Il manque une div dans le prototype JS, entre le label et l'input.

Compatibility of Families with ACL

I want to know whether the families created using this Bundle are compatible with the Symfony's ACL or not. If it is compatible, let me know how to use them together.

traduction du titre des listes datagrid

  • titre liste tableau n'est plus traduit. La trad "list_of %family%" est traduite, mais n'a pas une traduction tout à fait correcte. Je pense que c'est une régression car avant la clé family.list prenait l'avantage (exemple programmeCourt.list).

ContextErrorException Warning: Illegal offset type in isset or empty

When creating the services for families, this error happens.

The problem is the way the services for families are created: the use of the Parameter class is the problem.

Fetching the class name directly from the container fixes the problem:

   $definition = new Definition(
        $container->getParameter('sidus_eav_model.family.class'),
        [
            $code,
            new Reference('sidus_eav_model.attribute.registry'),
            new Reference('sidus_eav_model.family.registry'),
            new Reference('sidus_eav_model.context.manager'),
            $familyConfiguration,
        ]
    );

attributeasIdentifier does not seems to work with the API Platform bridge

When declaring an attribute as identifier is the model configuration, an 500 error is thrown saying that "attributeAsIdentifier" can not be duplicate. But in my configuration, only one attribute is declared as identifier.

It's look like the issue is related with the API Platform bridge, but this is not sure.

Unable to replace alias "sidus_eav_model.denormalizer.data" with actual definition "Sidus\EAVModelBundle\Serializer\Denormalizer\EAVDataDenormalizer".

I am getting an error after installation.

I am getting this error

Unable to replace alias "sidus_eav_model.denormalizer.data" with actual definition "Sidus\EAVModelBundle\Serializer\Denormalizer\EAVDataDenormalizer".

with:
You have requested a non-existent service "Sidus\EAVModelBundle\Serializer\Denormalizer\EAVDataDenormalizer".

I do not see what I have done wrong, I have configured the bundle in config.yaml and also registered in AppKernel class

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.