PrestaShop / docs

PrestaShop technical documentation
https://devdocs.prestashop-project.org/
Other
120 stars 477 forks source link

[EPIC] All standard Back Office extension usecases #896

Open matks opened 3 years ago

matks commented 3 years ago

PrestaShop is a CMS and its richness comes from how developers use it as a foundation to build e-commerce applications. To do so, PrestaShop provides many extension capabilities: modules, themes, hooks, template overrides, raw class overrides, services decoration ...

This issue aims to gather all the standard extension usecases so we can verify that, for each of them

Examples

Add fields inside BO forms

As a Module Developer As my customer (the shop administrator) wants PrestaShop workflow to ackowledge some extra properties on products / customers / ... I want to be able to add new fields inside any forms of the Back Office and choose where in the BO page they are displayed and when shop administrator hits the "save" button, receive the submitted data so I can validate it (= verify it, and if not valid refuse the form submission and display an error message) and store it

Add BO pages reachable through the navigation menu

As a Module Developer As my customer (the shop administrator) wants to add PrestaShop BO pages I want to be able to add links inside the navigation menu in the Back Office

Remove BO pages reachable through the navigation menu

As a Module Developer As my customer (the shop administrator) wants to remove PrestaShop BO pages because they are useless for him I want to be able to remove/hide links inside the navigation menu in the Back Office

Customize navigation menu wording

As a Module Developer As my customer (the shop administrator) wants to improve the wording of the navigation menu I want to be able to customize the wordings used for the navigation menu, depending on the language

tswfi commented 3 years ago

Add fields inside BO forms

and store it

Without having to jump trough hoops (something similar to how Configuration::get works).

Something like adding a stringattribute table that has objectid, attributename, value for developers to easily add new attributes (with language and shop specific data also).

Also these attributes should be available for everybody else to use (not just this module) in themes etc.

Default grid / form for entity

As a module developer I very often have my own table that contains some data that I want to present as a grid and as a form for basic CRUD operations. Having a "default views" that I can just tell "check this entity and create a grid with filters and and edit form (nice plus: export import) from my entity please".

As an example how django admin works, just give it a django model and it figures out a basic "grid" view for it. After the basic grid / form is done one can of course start modifying it, but the modification should again be "just touch the parts you want to change".

Form validation

As a module developer form validation is a basic task that could be done just by checking the submitted data against the entity definition (or giving the form validation task to the entity with a validate() method and just handling showing the correct message to the user filling the form). This basic validation should check that the types match and then the developer can of course add their own extra validation (like min is not larger than max etc).

Referential integrety

at the moment the database has none, please add it. As far as I know doctrine has nice support for it and it would make everybodys life easier and safer.

matks commented 3 years ago

Add fields inside BO forms

and store it

Without having to jump trough hoops (something similar to how Configuration::get works).

Something like adding a stringattribute table that has objectid, attributename, value for developers to easily add new attributes (with language and shop specific data also).

If I understand correctly:

As a module developer I want to be able to easily store data by key, that can be translated and be contextualized depending on the shop context (= multistore compatible)

tswfi commented 3 years ago

I want to be able to easily store data by key, that can be translated and be contextualized depending on the shop context (= multistore compatible)

basically yes.

Somekind of structure where the the existing entity (say a product) could be extended with extra "attributes" which can be of any type. The attribute type could be a string, boolean or a file or a reference or an array of references to another entity.

Then that extended entity could be used just like a normal entity. like $product->set(('MyShinyAttribute' => 'Value')); $product->save() , and fetched in a similar way. References and arrays of references could allow developer to do something like $product->set('CompatibleProducts', ($p1, $p2, $p3) to create a new kind of crosselling for products or simpler `$product->get('AdminWhoCreatedMe') to get the user entity object of the admin.

And the attributes should be defined somehow before usage. So basically the module install method should do something like $productClass->addAttribute('MyShinyAttribute', 'String') before the attribute can be used (and uninstall can say $productClass->deleteAttribute('MyShinyAttribute') which also clears the saved data from the db).

AAND when the product is deleted the attribute values should also be cleared.

Searching and filtering with these extra attributes should also be considered somehow. I'm not that familiar with doctrine querybuilder if those can be "extended" in some nice way but it is something that should be checked.

And if the attribute is generic enough it could also be something like $product->addAttribute('MyShinyDynamicAttribute', callableSetterMethod, callableGetterMethod)

And the getters get the entity and can process the data as needed (In one project we had something similar and those were usually also marked as "readonly" attributes and used to fetch some data from an object like $product->get('IN_STOCK_TEXT') which would then call the getter method and do all the business logic tricks for so that the template logic is reduced.

and instead of product is should have written entity everywhere as this should work with all entities :)

I know this is a huge epic in itself but something like this would make the core more of a framework for everything :)

matks commented 3 years ago

Hi @tswfi I'm afraid I will stop you very quick 😅

Somekind of structure where the the existing entity (say a product) could be extended with extra "attributes" which can be of any type. The attribute type could be a string, boolean or a file or a reference or an array of references to another entity.

This is exactly what we dont want because the current possibilities of ObjectModel to customize the data structure like how you say have brought huge instability into PrestaShop and created a huge trend of issues with upgrade. I think allowing the data structure to be extended is one of the main reasons why so many upgrades fail and now there's a cliché "it's so hard to upgrade PrestaShop ! PrestaShop is so bad at upgrades! never click on upgrade button, it will destroy your shop"

We are now convinced we must prevent people to extend the core data structure and instead store their data separately in other SQL tables (like mymodule_product_extradata) as isolating the core data structure is needed to ensure it's integrity (something you even mentioned yourself 😄 ). Isolation is key for integrity.

So in the future versions of PrestaShop we will make it extremely hard to modify the core objects by introducing an anti corruption layer (but provide alternative solutions). Although since it's php code, well, you can do whatever you want with it. You can read about it here https://build.prestashop.com/news/prestashop-in-2019-and-beyond-part-3-the-future-architecture/

tswfi commented 3 years ago

I'm aware of the previous problems with extending and overriding the core entities but I think the problem with the previous way of extending was just about not having a correct way to do it and everybody did it a bit differently.

When the core has a specified method for extending and augmenting entities, for example the way I described above it should not be a problem. The configuration table works fine and this is basically just extending the same idea into all entities.

I'm all of protecting the core integrity, but it does not mean it could not be flexible at the same time.

tswfi commented 3 years ago

As per discussion on slack here: https://prestashop.slack.com/archives/C010UHP5PAR/p1616773811113300 module developers need a way for adding tabs AND keeping them up to date when module is upgraded.

At the moment it seems like $this->tabs is correctly processed (except for nested tabs https://github.com/PrestaShop/PrestaShop/issues/20908) but there is no clean way of adding new tabs during module upgrade.

Maybe a method like refreshTabs that checks module currently installed tabs against $this->tabs and adds / removes as required. Preferably this should be automatically done when version number is increased.

matks commented 3 years ago

See https://github.com/PrestaShop/example-modules/pull/59