Jump to content

Suggestions for modules in 1.5


Recommended Posts

I have not had the opportunity to check the new features of 1.5, so I don't know if these are already being development. I think these would benefit both the module developers and users.

  1. Module Updates
    An interface for updating modules would be quite useful. Sometimes an update to a module means a different table structure in the database and file changes, an update option would simplify this process.
    Installed module version should be stored in the database, when the module files are replaces with a new version this should be detected automatically in the backend modules tab and an update option should be visible. This would call the update function of the module with the earlier version so the module can make the necessary changes that might be needed for the new version, i.e. database changes. This way developers can provide a simpler way to upgrade their modules.
  2. Module Parameters
    Most of the time modules need to store some data. It would be easier for the developers if the module class had an interface for storing & retrieving module parameters. It would be similar to the Configuration::updateValue and get methods, but module specific. These parameters can be defined in the config.xml file or the module construct. And the users can change these parameters from the module configuration page. Then all the modules would have a similar interface for module parameters and users will have easier time using it. Module uninstall would automatically take care of the stored data and remove them.
  3. Module Installation Screens
    It would be easier to have the option for an install screen for the modules where users can enter some install parameters and perform manual installation instructions. This would be optional and display only when the module has it.
  4. Module Specific Class/Controller Override Methods
    Everyone is aware of the current override structure, which makes it easier for third party developers to include changes to the core methods without changing the core files. It would be better to have these in module folder. This way multiple modules can have changes to the core classes as long as they do not attempt to override the same functions.
    This could be accomplished with the use of a new special registry where modules can register overrides to the core classes and controllers. It would be loaded at the startup and used during autoloading of the modules. With some simple includes this can easily be accomplished. I should be able to provide code samples if needed.

Link to comment
Share on other sites

Hi whitelighter,

 

I'm the developer in charge of the module part in 1.5

The first and foorth points were already planned. I think I can include the two others points.

I will open a topic soon where I will descripe the main features of the new modules API :)

I hope you will answer to my topic and share ideas around the futur module part like you just did :)

 

Best regards,

Link to comment
Share on other sites

@Fabien,

 

New request API : module reactivation (sorry if it's already on the raodmap)

 

I've one case that is today not covered by the current module API.

 

I've a module that manage some new data attached to each customer :

- on installation, it creates this new information for each customer

- on customer registration, it creates the information for this customer.

 

But it may happen that the module is temporary desactivated.

In such case, new customer can register, but related information are not created : no problem while the module is desactivated.

I'd like the module to be able to create this information on module reactivation

There should be a new interface so that the module is called back on its reactivation

Link to comment
Share on other sites

New requet API (bis) : option on uninstall to destroy or not the database

 

Today, on uninstall, the module execute the sequence that is in its uninstall method : the developper has choosen either to destroy data, either to keep them.

 

For upgrade concern, it should be possible for the administrator to decide to uninstall totally (database destroyed) or partially (keeping data in database)

 

For example, between 1.3 and 1.4 some modules where not compatible : we had to uninstall them from 1.3 before upgrading to 1.4.

For module managing silders, this is not a big matter, data are reconfigured after reinstall on 1.4

But for modules managing permanent data, this is not normal to loose data (for example, data attached to each customer or to orders/invoices...). The 'reset' in 1.4 is moreover very dangerous for such modules.

Link to comment
Share on other sites

But I didn't understand the interest of have an option on destroy database. For me, unactive a module is like a uninstall without destroying the data, right ?

 

Not really. The install manages module related database creation, but also hook registration, admin tab creation, configuration values initialization (in Configuration table)....

 

1/ For the upgrade into 1.4, there was some 1.3 modules for which the code was not compatible with 1.4.

So, the 1.3 code had to be removed from the module directory before the upgrade and it's better to keep the database.

 

2/ Sometimes, the install procedure is not fully correct (troubles in registring hooks, trouble while creating AdminTab....) .It could be interesting to be able to uninstall/reinstall (reset), without loosing data.

Link to comment
Share on other sites

In other words, we should have the notion of soft reset and hard reset (or soft unistall and hard uninstall)

 

The hard version destroys all the datas

The soft version destroys only the data developper accept to destroy.

Link to comment
Share on other sites

API suggestion (ter) : Modules dependencies

 

Fabien,

I've got another suggestion regarding the module API in 1.5

 

It may happen that a functionnality is embedded over 2 or more modules.

 

For exemple, on the addons, I propose the prepaid account that is split into at least 2 modules : 1 for the core feature (i.e. prepaid accound management), and 1 per module allowing to credit the prepaid account (similar to payment modules).

 

In such case, in a module A, I'd like to be able to test/know :

1. if the module B is present on disk, so that in A, I can instanciate classes of B

2. the activation/installation status of B

 

The case also happen with a controller :

- if a module embbeds a controller, when this controller is called, it has to check if it's module is installed/activated/operationnal

Note that the 1.5 dispatcher may solve this controller point.

Link to comment
Share on other sites

Hi,

 

Ok maybe we can do something like this :

 

In the module B, we add this in the class.

public $dependancies = array('moduleA' => '1.0');

 

Then, when you will install module B, it will check if module A is installed and that the version installed is at least 1.0

When you will try to uninstall module A, if a module which have a dependancy with module A is installed, the uninstall will not complete.

 

Is that could be something good for you ?

Link to comment
Share on other sites

Looks perfect.

With this principle, we are sure that module B can use module A.

 

In 1.4 we have the method Module::isInstalled($moduleName).

We should also have Module::isEnable($moduleName) (module could be installed but desactivated).

 

I let you se how to introduce the multishop notion. I think it will be usefull in some case to detect that a module is enabled per shop or group of shop.

Link to comment
Share on other sites

1) A way for modules to pass error conditions back to module installation process. Make use of $_errors array during install/unistall

I am a module, I need PS v1.5, in install() method I check the current installation version, I find 1.4. I can only return false with no meaningful feedback to user. "This module failed to install", but why? OK I can log but does user know to check the log?

 

2) Publish table naming conventions and add it to module developers guide, make 3rd party modules use unique prefixes

I am a module, I create table customization, nuking a native table. OK, I should know native table names but how about another 3rd party module that may use the same table name?

 

3) Do not simply remove module on delete, ask module to remove itself by calling module->uninstall()

I am a module with multiple tables, installed but currently disabled. User deletes me without first uninstalling, Prestashop nukes my files leaving my tables in place.

 

4) Module::__construct

public function __construct($name = NULL) {...

Either use that $name parameter or remove from method signature

Link to comment
Share on other sites

Hi Phrasespot,

 

1) I was thinking to add the variable :

public $installMessage;

This two variables will be use during install or uninstall, and you will be able to define in the module the message displayed in case of success or failure.

Is that sound like a good idea to you ?

 

2) The naming convention for table could be something like

_DB_PREFIX_.$this->name.'_'.$tableName;

$this->name is the same name used for the module directory (and you can't have two module directory with the same name). This way you will be sure that the table will be unique (in the case of every module is respecting the naming convention :P).

 

3) We can add the call of the method uninstall when delete method is called.

 

4) Wow, I never saw that. I'm wondering what the point of such parameter.

I will check in the solution if this parameter is used and will remove it if it's not.

Link to comment
Share on other sites

Hi Fabien

 

1) I was thinking to add the variable :

public $installMessage;

Yes that would do, we could also use the already defined $_errors fields of the class.

 

Another (trivial) thing is static $_db field of Module class. I cannot find any reference to this field searching for Module::$_db or self::$_db in the codebase. What is the purpose of this field?

 

And please, uniform class fields naming (capitalization, underscores etc), for example in Module class (not only in there though) we have:

 

public $displayName

public $limited_countries

 

protected $_lang

protected $table

 

protected static $modulesCache

protected static $l_cache

protected static $_hookModulesCache

protected static $_INSTANCE

Link to comment
Share on other sites

2) The naming convention for table could be something like

_DB_PREFIX_.$this->name.'_'.$tableName;

$this->name is the same name used for the module directory (and you can't have two module directory with the same name). This way you will be sure that the table will be unique (in the case of every module is respecting the naming convention :P).

That sounds good. I don't think any module author would have a problem following a convention. It is for every module's benefit.

Link to comment
Share on other sites

For the message part, I won't use $_errors because the field $installMessage will be used for failure and success.

The name $_errors could only be used for failure.

 

I will check on every field, remove the one which are not used anymore (maybe there were here for retrocompatibility). I will check this with the team.

 

For the naming of field, do not worry. We created an internal convention for the naming of variables and functions.

So I hope in a near futur, all name will respect the convention :)

Link to comment
Share on other sites

For the message part, I won't use $_errors because the field $installMessage will be used for failure and success.

The name $_errors could only be used for failure.

Of course, you are right. Makes more sense.

 

in a near futur, all name will respect the convention

Great news :)

Link to comment
Share on other sites

It's possible to have a summary of module API ?

Raphale should have ask this

http://www.prestashop.com/forums/topic/135340-few-questions-about-15/page__fromsearch__1

 

Fabien,

Another point about modules API.

In the admin folder, there is some controllers, specific to the administration.

Will it be possible for a module to create such controller ?

Today, it is quiete impossible for a module to manage such controller.

For exemple, I create an AdminTab located in a module that need to call a myGetFile.php (returning a specific PDF for ex).

How can the myGetFile.php be sure that it is called from the back office context ? (I have trouble to intanciate the psAmin cookie from such file

Link to comment
Share on other sites

Definatly needed loads asking on forum posts from what i can see including myself.

 

1. Option for customer to prepay for products by toping up there account through my account area.Like a little savings or piggy bank

 

2. Option to buy now pay later like the bank wire but instead buy now pay later text is there stating order etc. in on hold pending acceptance with bo customasizable text on the page customer sees etc.

 

3. Allopass intergration for phone payments http://www.allopass.com and 123 ticket system which is the same http://www.123ticket.com

 

4. Paypoint payment module http://www.paypoint.com

 

5. Option for customer to print invoices out.

 

6. Customer comments on BO login page (once logged in index.php) for easier browsing and use

 

7. Manufacturers module showing in blocks etc. images i.e. company logos to the manufacturers.

 

8. Direct debit payment options

 

Thank you.

Link to comment
Share on other sites

Hi Ladyred, thanks for your propositions.

But you're not in the right topic :)

Here we are talking about the modules API (technical part for modules conceptor / developer only) and you are asking about new modules and new functionnalities. You should open your own topic for that point ;)

 

Yeah thanks. Sorry din't realise that. However i must admit i do require what olea is asking above

 

Link to comment
Share on other sites

@Fabien & @Olivier : There is PaymentModule but i would like have ShippingModule with an unik method "getShippingCost".

 

For exemple :

 

<?php
class \PersonalShipping extends \ShippingModule
{
    public $displayName = 'My Personal Shipping'; // Auto translate
    public $displayDescription = 'This is my first personal shipping module'; // Auto translate
    public $version = '1.0.0'; // Three level version
    public $requiredCoreVersions = array('1.4', '1.5.'); // Required core versions
    public $requiredModules = array( // Required modules with versions
		    'JbxTools' => array('1.', '2.'),
    );
    public $menu = array( // Attach this module on (multi) "menu"
		    'tab'   => 'shipping' // Original "tab"
    );
    public $carrier = array(
		    'name'		  => 'PersonalShipping',
		    'active'	    => 1,
		    // ...
    );
    public function getShippingCost(Cart $cart, Array $products)
    {
		    $shippingCost = 0.0;
		    // Computational logic
		    return $shippingCost;
    }
}

 

It's just an exemple with my ideas...

(Sorry for use global namespacing but it's now a habit.)

Link to comment
Share on other sites

Say a module needs a new global page in the root of the site, and a controller for that page. Being able to include these type of pages in site's other functionality would be great, for example including it in .htaccess generate or being able to specify its default rewrite. The current afterCreateHtaccess hook fails short of being able to add it in the correct position. Does this make sense?

Link to comment
Share on other sites

Also a major improvement would be to increase the number of the methods and split their responsibilities in classes. Take the preProcess method of AuthController class as an example. There is just too much going on in that method and dies in the middle if errors found, without any consideration for a child class that may be overriding the method. Assume I want to remove the check for the phone number. There is no easy way of doing this; I have to replicate the remaining 400+ lines in an overriding class preProcess method just to be able to remove those two lines. This is just one example and if the 'overridable' is not just to be fashionable phrase, class methods must be made more specialized and have a contract they present to the callers of the method. Otherwise modules will just have to keep re-writing the code that has already been written in the core parent classes.

  • Like 1
Link to comment
Share on other sites

@phrasespot, this is not really related to modules part.

But I agree with the fast this is important. I'll tell this to others developers.

 

In other hand, I made my first commit on Branches 1.5

Here are the changes I made :

- Module::hookExec became Hook::exec

- Module::hookExecPayment became a standard hook::exec and currency restriction are made in the method preCall (in Module class and PaymentModule class) which can evolve (if you want to create restriction for CarrierModule for example)

- Module::registerHook will create the hook if it does not exist

- All the alias method of Hook::exec are now deprecated

- All hooks have been renamed display / action to know if the hook is used for a view or for an action

- A hook_alias table has been created to get retrocompatibility to older module :)

- Dynamic hooks are now present in the code :

Hook::exec('actionObject'.$objectName.$actionName.$locationName);

$objectName : Object name (Product, Category, ...)

$actionName : Action name (Add, Update, Delete, ...)

$location : Before ou After

You can now hook module on object action.

Example : Module::registerHook('actionObjectProductAddBefore');

Link to comment
Share on other sites

@phrasespot, this is not really related to modules part.1

I understand, this is not directly related to the modules, but for any 3rd party code which interact with PS, i.e. modules mainly, this is vital.

 

But I agree with the fast this is important. I'll tell this to others developers.

Thanks, I wish developers responsible from other parts of prestashop also started a dialog similar to this thread. I, and I am sure others too, appreciate greatly this thread and the time you spend here.

Link to comment
Share on other sites

  • 2 weeks later...
Open a topic about it,

I did open several, simultaneously, but the forum died on me, and was not responsive for several hours, wasting a couple of hours work. :( Maybe I will get to it again.

 

On another note, please look at this issue report. http://forge.prestas...owse/PSCFI-4101

 

This is one major problem with the hooks. Most of the time there is no state passed to hook method from the calling process and when there is then it is worse than useless; it is misleading.

 

After a duplicate product call, hook is called, so in my hookAddProduct($params) method I would expect the $params['product'] to be a faithful duplicate of the original, duplicated product. Not so in this case so not really useful to me as an argument passed. You may as well just pass the product's id as I will have to query DB to get anything useful out of that argument anyway.

Link to comment
Share on other sites

  • 4 weeks later...

@Phrasespot

I let Vincent see the bug with you on the forge.

 

Just to keep update this post. You can now exec a hook directly in the tpl like this :

{hook h='displayRightColumn'}

If you combine this with the new hook system in 1.5, you can create and execute new hook very easily.

 

In your module : $this->registerHook('myNewHook')

If the hook does not exist, it is created.

And execute it where you want in your tpl : {hook h='myNewHook'}

 

I also added dynamic hook in AdminControllers, so there is no a hook before and after each action of each controller :

Hook::exec('action'.get_class($this).ucfirst($this->action).'Before', array('controller' => $this));
$return = $this->{'process'.Tools::toCamelCase($this->action)}($token);
Hook::exec('action'.get_class($this).ucfirst($this->action).'After', array('controller' => $this, 'return' => $return));
return $return;

 

Last thing, I added the param $this in the dynamic hooks of Object Model.

If some of you want to run some tests on Dynamic Hooks and tell me if some params are missing to make them great, do not hesitate :)

Link to comment
Share on other sites

HI,

 

Can I ask the PrestaShop developers if it is possible to implement a new parameter (checkbox) "turn off auto estimates" into the "Shipping Estimation" module ?

 

If the parameter == false then every time when user adds any item into the cart or update totals the Shipping Cost will be automatically recalculated (current PrestaShop 1.4.6.2 algorithm).

If the parameter == true then estimate the shipping cost only when user pressed the Update button.

 

I explained why I need it in this post:

http://www.prestasho...-seconds-delay/

 

 

Regards

Link to comment
Share on other sites

@Phrasespot

I let Vincent see the bug with you on the forge.

Thanks

 

Just to keep update this post. You can now exec a hook directly in the tpl like this :

{hook h='displayRightColumn'}

If you combine this with the new hook system in 1.5, you can create and execute new hook very easily.

 

In your module : $this->registerHook('myNewHook')

If the hook does not exist, it is created.

And execute it where you want in your tpl : {hook h='myNewHook'}

This sounds really great. I cannot wait to play with this though later. Spent all evening wresting with an installation using latest SVN :/

 

I also added dynamic hook in AdminControllers, so there is no a hook before and after each action of each controller :

I don't really understand the purpose of this but I will read the class to get a better idea. I will need to go back an re-read your hook name convention post in his thread too. I am a little confused with something like 'actionObjectAttributeAddBefore'

Link to comment
Share on other sites

OK, I still don't get how I could reach to the state in which the hook is being executed even in the new hook system.

 

For example, take extraLeft hook. In ProductController you are executing

 

HookExec::('extraLeft');

 

as well as a number of other hooks. In my module's hookExtraLeft() method I cannot reach to the product context in which the hook is being executed. Now in 1.5 I don't have access to the product in any of the hook... methods executed in ProductController. Every Hook::exec method should forward parameters to the hooking methods, like for example as in OOS hook:

 

Hook::exec('productOutOfStock', array('product' => $this->product))

Link to comment
Share on other sites

Yes!, now I can sleep well. Really, thanks!

 

In 1.4 the solution was to hook another method (usually productActions) and save the passed in parameter to a local variable to use in other hooks, which is kind of hackish.

 

I am really looking forward to 1.5, e.g. new "Cart Rules" rule :)

Link to comment
Share on other sites

One other thing I would like to see is some logistic facilities being made available for modules. For example modules very often need to list, edit. delete, sort, paginate instances of sub classes of ObjectModel. This is currently possible only if I were to extend Tab and AdminTab in my module. I am against that as I think BO UI madness lies down that road. So if you could make things like $fieldsDisplay available to a module without needing to add tabs, that would be great.

 

Edit: Or a way to insert a tab view to the module configuration view only would do too.

Link to comment
Share on other sites

×
×
  • Create New...