I want to create a module that would add a new table to the database. (The purpose would be to store information about product videos.) I know how to do the SQL coding. Does OpenCart allow modules to do this?
Looking through the source I see there's a controller folder for modules (catalog/controller/module) and a view folder (catalog/view/theme/default/template/module), but I can't find a model folder for modules.
Thanks,
Richard
Looking through the source I see there's a controller folder for modules (catalog/controller/module) and a view folder (catalog/view/theme/default/template/module), but I can't find a model folder for modules.
Thanks,
Richard
yes modules can do that. The model folder for modules doesn't exist, but you can create it. If you look at the tag cloud module you can see how I created and call a model file for a module.
OpenCart commercial mods and development http://spotonsolutions.net
Layered Navigation
Shipment Tracking
Vehicle Year/Make/Model Filter
Thanks!
Do you know where there's any good documentation online for developing for OpenCart? There's really no comments in the code and the documentation at opencart.com doesn't go into any detail beyond the barest basics (MVC, etc).
Rich
Do you know where there's any good documentation online for developing for OpenCart? There's really no comments in the code and the documentation at opencart.com doesn't go into any detail beyond the barest basics (MVC, etc).
Rich
Thanks Qphoria! I saw Xsecrets using it in his module.
Do you know if there's any kind of "install" and "uninstall" action that's run on the module when it's installed, so I can set up the new database table? Or should I provide an "install" button in the admin panel view and do it there?
Thanks,
Rich
Do you know if there's any kind of "install" and "uninstall" action that's run on the module when it's installed, so I can set up the new database table? Or should I provide an "install" button in the admin panel view and do it there?
Thanks,
Rich
Up to 1.4.8b, the only way to install extra stuff is to put an additional function that gets triggered when the index() function is called that will check the db and make the changes if necessary each time the edit page is loaded.
In 1.4.9, I've added an automatic call to check if the module has its own install/uninstall function. If so, then it will be called during the install / uninstall steps instead of having to put it at the edit step
In 1.4.9, I've added an automatic call to check if the module has its own install/uninstall function. If so, then it will be called during the install / uninstall steps instead of having to put it at the edit step
Awesome, I'll be using it when it's available. For now I thought of putting the check in the 'index' action, but instead I think I'll create an "install" action usable from the Admin panel (an "Install" button called from the module's control panel page).Qphoria wrote:In 1.4.9, I've added an automatic call to check if the module has its own install/uninstall function. If so, then it will be called during the install / uninstall steps instead of having to put it at the edit step
One of the implications of your "uninstall" function is that dropping the extra table from the database means permanently deleting everything the module created. In my plugin all product videos would be wiped clean from the database. We might not want to do that without some sort of big flashing warning first. Or maybe you could prompt the user to ask if they want to run the uninstall step (deleting all its data), or if they just want to temporarily disable it (not deleting the data)?
cool.. very awesome Q..Qphoria wrote:In 1.4.9, I've added an automatic call to check if the module has its own install/uninstall function. If so, then it will be called during the install / uninstall steps instead of having to put it at the edit step
is there any information about next 1.49 feature?
I started developing my own modules in 2.x, with that I am not sure which version the install/uninstall functions were available by default.
What i want to address here is the concern that the uninstall function would automatically erase data. While removing a module does remove its data from the settings table, if the uninstall function is available and triggered it does only what you tell it to.
install: You create and populate tables even alter and populate existing tables.
Uninstall: You can optionally revert all of your changes, using install does not mean you have to use uninstall. That said, if a module is to be uninstalled then the data should really be removed, a user may not want to use the module any longer and so wants to remove it from their store entirely. You should accommodate this.
If you use neither of these options (and don't handle the install elsewhere) then all of the saved data about the module go into the settings database:
This line in the controllers (again I know only of oc[2.0 -> 2.1]) is what saves your settings when you click save in a module using the default setup.
To break that line down:
'your_module' goes into the code column
The post data is a key => value pair for each form element and is entered into the key and value columns of the database respectively with the key being the name of the form input it came from and value being the user input it contained.
When getting information back for the form you load it back into the $data array.
Personally I do the following because its easier than writing line after line for each form element, its a bug in my bonnet when building modules, masses of repetition.
I do similar for form error checking and language loading too but as its getting in depth and a little off topic I am going to leave it here. If anybody would like to know more feel free to drop me a message on the forum, I will be happy to share an example of how i do these too.
What i want to address here is the concern that the uninstall function would automatically erase data. While removing a module does remove its data from the settings table, if the uninstall function is available and triggered it does only what you tell it to.
install: You create and populate tables even alter and populate existing tables.
Uninstall: You can optionally revert all of your changes, using install does not mean you have to use uninstall. That said, if a module is to be uninstalled then the data should really be removed, a user may not want to use the module any longer and so wants to remove it from their store entirely. You should accommodate this.
If you use neither of these options (and don't handle the install elsewhere) then all of the saved data about the module go into the settings database:
This line in the controllers (again I know only of oc[2.0 -> 2.1]) is what saves your settings when you click save in a module using the default setup.
Code: Select all
$this->model_setting_setting->editSetting('your_module', $this->request->post);
'your_module' goes into the code column
The post data is a key => value pair for each form element and is entered into the key and value columns of the database respectively with the key being the name of the form input it came from and value being the user input it contained.
When getting information back for the form you load it back into the $data array.
Personally I do the following because its easier than writing line after line for each form element, its a bug in my bonnet when building modules, masses of repetition.
Code: Select all
// I add this into the constructor if i've used one otherwise its in which ever method im populating form data from
$this->settings = $this->model_setting_setting->getSetting('module_name');
// now i Lazy Load the settings for the form in the index method (or whichever method is using it).
foreach ($this->settings as $key => $val) {
$data[$key] = $val;
}
The drawback of doing so, is that when you load the new extension the first time, no default values are given.Chris_UK wrote: ↑Sun Aug 11, 2019 6:25 pmCode: Select all
$this->settings = $this->model_setting_setting->getSetting('module_name');
Code: Select all
foreach ($this->settings as $key => $val) { $data[$key] = $val; }
Nor the fields are filled with default values.
Also, if you add later additional variables and values, the extension will produce errors.
What I do always is like that:
Code: Select all
$vars = array(
'status' => 0,
'sort_order' => 0,
'var1' => 'val1',
'var1 => 'val2',
'var3' => array(),
'var4 => array( 'subvar1' => 1, 'subvar2' => 'whateveryouwant' ),
and so on ..
And after that something like:
Code: Select all
foreach( $vars as $k => $v ) {
if( !is_null( $this->config->get( $this->_name . '_' . $k ) ) ) {
if( is_array( $v ) ) {
$data['cfg_' . $k] = $this->config->get( $this->_name . '_' . $k ) + $v;
}else{
$data['cfg_' . $k] = $this->config->get( $this->_name . '_' . $k );
}
}else{
$data['cfg_' . $k] = $v;
}
}
And I do not have to take care on the extensions name (which es defined prior > see _name above), because inside the template (no matter which type), the values wil have all a prefix cfg_ which will be replaced when storing the settings.
Also adding new variables at any time will produce a correct result.
Full Stack Web Developer :: Dedicated OpenCart Development & Support DACH Region
Contact for Custom Work / Fast Support.
Thank you for your response, I don't make many modules and when i do it tends to be for a specific purpose for my own website so its not something I have run into yet, however I can see your reasoning and portable code is always a bonus in my book.OSWorX wrote: ↑Sun Aug 11, 2019 8:10 pmThis kind of code is highly portable (can be used with any type of extension).
And I do not have to take care on the extensions name (which es defined prior > see _name above), because inside the template (no matter which type), the values wil have all a prefix cfg_ which will be replaced when storing the settings.
Also adding new variables at any time will produce a correct result.
I am going to look into some of my modules and update them. I may never release them into the wild but if I do I don't want silly bugs causing issues when they can be prevented.
After several years of developing extensions (modules, plugins, etc.) for OC, I know that some time the extension has to be updated.
Updated in a way that I have to add one ore more variables.
Doing like I described, such a task is just a matter of 1,2 minutes.
Also, I do not assign each and every language variable as the core does.
Get them all with 1 line - and if (in rare cases) a language variable has to overriden or assigned specially, this will be also jut 1 line (more).
Additonally - what a some of the (better) OC devs are doing (some of them doing it , but not in a good way!), is to 'summarize' common tasks and functions.
If you have once 40, 50 or more extensions, you will have all those in a serperate, own library - from where they can be called at simply any time (without writing again and again and again the same stuff).
There are maybe a few more tips, maybe one of the others here have some?
Updated in a way that I have to add one ore more variables.
Doing like I described, such a task is just a matter of 1,2 minutes.
Also, I do not assign each and every language variable as the core does.
Get them all with 1 line - and if (in rare cases) a language variable has to overriden or assigned specially, this will be also jut 1 line (more).
Additonally - what a some of the (better) OC devs are doing (some of them doing it , but not in a good way!), is to 'summarize' common tasks and functions.
If you have once 40, 50 or more extensions, you will have all those in a serperate, own library - from where they can be called at simply any time (without writing again and again and again the same stuff).
There are maybe a few more tips, maybe one of the others here have some?
Full Stack Web Developer :: Dedicated OpenCart Development & Support DACH Region
Contact for Custom Work / Fast Support.
OSWorX wrote: ↑Sun Aug 11, 2019 8:10 pmWhat I do always is like that:Code: Select all
$vars = array( 'status' => 0, 'sort_order' => 0, 'var1' => 'val1', 'var1 => 'val2', 'var3' => array(), 'var4 => array( 'subvar1' => 1, 'subvar2' => 'whateveryouwant' ), and so on ..
I just knocked up this little method to extract the field names directly from the template, in doing so no manually edited arrays.
Code: Select all
function fieldExtractor($input) {
$dom = new DOMDocument;
$dom->preserveWhiteSpace = false;
/** DOMDocument::loadHTML warnings suppressed with @
* A html 4 DTD is used by loadHTML as a fallback when no DTD is present in the input.
*
* OC uses html5 which has no DTD and so produces lots of notices.
*/
@$dom->loadHTML($input);
$x_path = new DOMXPath($dom);
// The form fields from the template in the input.
$fields = $x_path->query('//input|//textarea|//select');
if (is_object($fields)) {
foreach ($fields as $field) {
$form_fields[] = $field->getAttribute('name');
}
}
return $form_fields;
}
Code: Select all
$this->load->model('setting/setting');
$this->settings = $this->model_setting_setting->getSetting('module_code');
// parse the same template as will be called used for the response output.
$form_fields = fieldExtractor($this->load->view('directory/template.tpl'));
foreach ($form_fields as $iteration => $field) {
if (array_key_exists($field, $this->settings)) {
$data[$field] = $this->settings[$field];
} else {
$data[$field] = '';
}
}
As these are just fallback values I see no reason currently to type cast or even give a real default value but if there is a case for it, the query and foreach within the function could be split to handle it.
Hopefully its quite portable too.
Not a bad Idea ..
Full Stack Web Developer :: Dedicated OpenCart Development & Support DACH Region
Contact for Custom Work / Fast Support.
I have just revised the code to reduce the code in the controller and renamed it to clarify its function. If anybody wants to use it, that's totally fine with me.
Also by combining it all into one function I was able to drop the second foreach, its pointless doing two when the whole thing can be wrapped into a single foreach.
UPDATE: Although the notices are suppressed at loadHTML, the previous version used the OpenCart's view loader to supply the html we needed. This was an error on my part, I had not considered that the view loader was the point in the application where the notices were being sent in the first place.
To remedy this issue we now make use of file_get_contents instead of using output from the view loader, this change means the first parameter of the function will now be the path to the template file. We still need the error suppression within the function as the template is not a fully formed html document.
Also by combining it all into one function I was able to drop the second foreach, its pointless doing two when the whole thing can be wrapped into a single foreach.
Code: Select all
/**
* @param string $input Path to template file
* @param array $settings Extension settings from the database
* @return array our template vars
*/
function formVarCreator($input, $settings) {
$dom = new DOMDocument;
$dom->preserveWhiteSpace = false;
// Used instead of the load->view method of OpenCart.
$content = file_get_contents($input);
/**
* loadHTML relies on DTD to determine if a html document is
* formed correctly and falls back on 4.0 transitional when no
* DTD is found in the document.
*
* You may make use of "internal errors" if you prefer to handle
* errors in some way.
*
* In this case, the template isn't a fully formed HTML document
* being just one part of the full view and will always result in
* many notices from loadHTML.
*
* Here errors are suppress with @.
*/
@$dom->loadHTML($content);
$x_path = new DOMXPath($dom);
$paths = $x_path->query('//input|//select|//textarea');
if (is_object($paths)) {
foreach ($paths as $node) {
$field = $node->getAttribute('name');
if (array_key_exists($field, $settings)) {
$form_fields[$field] = $settings[$field];
} else {
$form_fields[$field] = '';
}
}
}
return $form_fields;
}
// place this before the view loader line.
$data = array_merge($data, formVarCreator(DIR_TEMPLATE . 'shipping/parcel2go.tpl', $this->settings));
To remedy this issue we now make use of file_get_contents instead of using output from the view loader, this change means the first parameter of the function will now be the path to the template file. We still need the error suppression within the function as the template is not a fully formed html document.
Who is online
Users browsing this forum: No registered users and 77 guests