admin | ||
.editorconfig | ||
CODING_STANDARDS.md | ||
depot.xml | ||
LICENSE.md | ||
README.md |
Depot
Introduction
This project is also based on the desperation to sort and find my electronic components. Some integrated circuits (ICs) accumulated in various boxes and the question of whether I own that or the other IC, had to be painstakingly researched. Above all, there were at one time several places where components were stored or partly kept at a plant. The idea was born, but it took long time to implement it. Klosterneuburg, October 2023 Thomas Kuschel KW4NZ.
Workflow (since 0.0.1)
In git we start to make a new branch named b1_basic_backend, where we start developing our project. The first run with simply renaming entries from a copy of the component com_banners did not work as expected. So let us start at the very beginning:
Adding basic files for component (b1_basic_backend)
With the git branch b1_basic_backend Add the following basic six files:
-
admin
- src/Extension/DepotComponent.php: The main extension file for the component.
- services/provider.php: It tells Joomla how to initialize or boot the component.
- src/Controller/DisplayController.php: The default Controller for the component.
- src/View/Parts/HtmlView.php: The Html View for the "Parts" page.
- tmpl/parts/default.php: The layout file for the "Parts" page.
-
depot.xml: XML manifest file that tells Joomla! how to install the component.
Description of each file:
1. DepotComponent.php
This file contains class for the extension. The class extends MVCComponent. Compare this version with the original at Tech Fry Tutorium.
namespace KW4NZ\Component\Depot\Administrator\Extension;
use Joomla\CMS\Extension\MVCComponent;
class DepotComponent extends MVCComponent
{
}
2. provider.php
This is a special file that tells Joomla how to initialize the component - which services it requires and how they should be provided.
The service provider file registers dependencies the component will use. Here, we have included two dependencies:
-
DispatcherFactory is needed to create the Dispatcher class instance, and then Joomla will call dispatch() on this Dispatcher object, as the next step in running the component.
-
MVCFactory is needed to create the Controller, View, Model and Table class instances on behalf of the component.
3. DisplayController.php
This is a default controller for the component. It simply sets its default view and leaves the rest to its parent.
When you view the component through URL, Joomla uses the controller to execute the task. The task is the name of method in the controller file. If you do not pass the controller or task in the URL, it defaults to Display Controller and display Task.
The default view is the name of the component. So, here we need to override the
default view to parts
.
4. HtmlView.php
This file contains class HtmlView that extends BaseHtmlView. The BaseHtmlView is the base class for a Joomla View.
The view gets the data from the model to be output by the layout file.
For example:
$this->msg = $this->get('Msg');
This method converts the get('Msg') call into a getMsg() call on the model, which is the method which you have to provide in the model.
The view file displays data using the template layout file - $tpl, which defaults to default.php.
5. default.php
This file holds the template for the page. When no specific layout is requested for a view, Joomla will load the template in the default.php file.
<h2>Welcome to Depot Component!</h2>
6. depot.xml
This file tells Joomla how to install the component and what file are included.
In the administration part, we include a link to the menu and include files and folders (services, src, tmpl and so on) which are in the parent folder admin of the component. While installing the component, these will get copied to the Joomla administrator/components/com_depot.
Installation the component
Create a .zip file of the com_depot directory. Then inside the Joomla Administration upload this .zip package.
Now you should see a new link "Depot" in the "Compnents" section of the menu. If you click it, you should see the default "Depot" page.
Language files
We create two language files for the system and the component Depot at the directory /admin/language/en-GB/ naming it
- com_depot.ini
- com_depot.sys.ini
Creating and managing Joomla database (b2_database)
With the new git branch b2_database we continue our workflow.
Joomla usually manage its content with a database. In our component, we use a MariaDB database. At the time of development of this component we have PHP8.2, and we use Mariadb database with version from 11.1, client 15.2 for Linux (x86_64) using readline 5.1 We support MySQL and MariaDB; not tested support for PostgreSQL.
In the manifest file <component_name>.xml, here the file depot.xml, there are installation instructions to "install", "uninstall", and "update" the Joomla extension/component.
The SQL plain text files are stored in and as:
-
admin/sql/
- install.mysql.utf8.sql
- uninstall.mysql.utf8.sql
-
admin/sql/updates/mysql/
- 0.0.1.sql
- 0.0.4.sql
- 0.0.5.sql
Database table installation
- When the component is installed for the first time, the file install.mysql.utf8.sql is executed.
- If the component is already installed, the update
scenario comes into play, the folder admin/sql/updates/mysql/: Only the files with higher version
numbers than the installed version of the component will be
executed in ascending order.
Hint: The version of the installed component is stored in the Joomla's table "#__schemas".
The "#__"-prefix is substituted automatically with the database prefix, (e.g. "jm_") which is defined in the configuration file (configuration.php) of the installed Joomla version as parameter $dbprefix.
install.mysql.utf8.sql
DROP TABLE IF EXISTS `#__depot`;
CREATE TABLE `#__depot`(
`id` SERIAL,
`component_name` VARCHAR(1024) CHARACTER SET ascii COLLATE ascii_general_ci NULL DEFAULT NULL
COMMENT 'unique component name (ASCII characters only)',
`alias` VARCHAR(1024) NOT NULL DEFAULT '',
`description` VARCHAR(4000) NOT NULL DEFAULT '',
`quantity` INT(10) UNSIGNED NOT NULL DEFAULT 0,
`quantity_exp` INT(11) NOT NULL DEFAULT 0
COMMENT 'Exponent of the quantity (10^x of the number, usually 0 i.e. 10⁰)',
`asset_id` INT(10) UNSIGNED NOT NULL DEFAULT 0 COMMENT 'FK to the #__assets table.',
`created` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00',
`created_by` INT(10) UNSIGNED NOT NULL DEFAULT 0,
`checked_out` INT(11) NOT NULL DEFAULT 0,
`checked_out_time` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00',
`modified` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00',
`modified_by` INT(10) UNSIGNED NOT NULL DEFAULT 0,
`path` VARCHAR(400) NOT NULL DEFAULT '',
`state` TINYINT(4) NOT NULL DEFAULT 0
COMMENT 'Published=1,Unpublished=0,Archived=2,Trashed=-2',
`access` TINYINT(4) NOT NULL DEFAULT 0,
`params` VARCHAR(1024) NOT NULL DEFAULT '',
`image` VARCHAR(1024) NOT NULL DEFAULT '',
`ordering` INT(11) NOT NULL DEFAULT 0,
`version` int unsigned NOT NULL DEFAULT 1,
-- references to other tables:
`category_id` INT(11) NOT NULL DEFAULT 0,
`datasheet_id` INT(11) NOT NULL DEFAULT 0,
`datasheet_alt` VARCHAR(1024) NOT NULL DEFAULT '',
`manufacturer_id` INT(11) NOT NULL DEFAULT 0,
`stock_id` INT(11) NOT NULL DEFAULT 0,
PRIMARY KEY (`id`),
KEY `idx_state` (`state`),
KEY `idx_stock_id` (`stock_id`),
KEY `idx_manufacturer` (`manufacturer_id`),
UNIQUE KEY `aliasindex` (`alias`,`manufacturer_id`,`stock_id`)
) ENGINE=InnoDB
AUTO_INCREMENT=0
DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
INSERT INTO `#__depot` (`component_name`,`alias`,`description`,`quantity`,`created`,
`ordering`,`state`,`manufacturer_id`) VALUES
('1N5404','1n5404','diode, rectifier 3A',9,'2023-09-25 15:00:00',1,1,1),
('1N4148','1n4148','diode, general purpose',1234,'2023-09-25 15:15:15',2,1,2);
The table is created in the database when the component is installed. Also two lines of sample data are inserted into the table "#__depot".
Database table uninstallation
When the component is uninstalled the uninstall.mysql.utf8 sql is executed. We drop the used tables from the database.
install.mysql.utf8.sql
DROP TABLE IF EXISTS `#__depot`;
Database table update
When the component is updated the admin/sql/updates/mysql folder with its files is executed.
Even if you do not need a database update, you can add an empty file in admin/sql/updates/mysql/0.0.2.sql to initialize the schema version.
In future versions, if you plan to use database tables, the update can be performed automatically. We create an empty file, just with a comment "-- version 0.0.2" admin/sql/updates/mysql/0.0.2.sql
-- version 0.0.2
Manifest file for extensions
The sql files are only executed if they exist in the <component_name>.xml manifest file. We add this after the namespace tag, just before the files information tag:
<install> <!-- Runs on install -->
<sql>
<file driver="mysql" charset="utf8">sql/install.mysql.utf8.sql</file>
</sql>
</install>
<uninstall> <!-- Runs on uninstall -->
<sql>
<file driver="mysql" charset="utf8">sql/uninstall.mysql.utf8.sql</file>
</sql>
</uninstall>
<update>
<schemas>
<schemapath type="mysql">sql/updates/mysql</schemapath>
</schemas>
</update>
The <version> tag of the manifest must be updated to 0.0.2 and also add the sql folder in the administration files section.
Table class
src/table/DepotTable.php
For each database table, you have to define a table class. The model asks the table to get information or perform database operations.
This table class has to be defined in admin/src/Table/DepotTable.php file.
<?php
namespace KW4NZ\Component\Depot\Administrator\Table;
use Joomla\CMS\Table\Table;
use Joomla\Database\DatabaseDriver;
\defined('_JEXEC') or die;
class DepotTable extends Table
{
function __contruct(DatabaseDriver $db)
{
parent::__contruct('#__depot', 'id', $db);
}
}
Joomla uses the Table Object to get item or record, insert records, update or delete records for the database operations.
Methods in the table objects are:
- load() to load the existing record from the database, passing the primary key of the record.
- bind() to set the new values for the fields.
- check() to perform any validation.
- store() to save the new values to the database.
- delete() to delete the record from the database.
Get a Form in Joomla component
The Form class of Joomla is used to create complex forms with flexible layouts and dynamic properties. First, the form fields are defined in the XML file. Then the view file gets the form from the model and layout file displays the form.
XML Form file
admin/forms/part.xml
<?xml version="1.0" encoding="UTF-8"?>
<form>
<field
name="title"
type="text"
label="JGLOBAL_TITLE"
required="true"
/>
</form>
Similarly you can add other fields to the XML file.
View file
admin/src/View/Part/HtmlView.php
This file is similar to the view file added earlier for the "Parts" view. The view file gets the form from the model in the display() method.
<?php
namespace KW4NZ\Component\Depot\Administrator\View\Part;
use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;
\defined('_JEDEC') or die;
class HtmlView extends BaseHtmlView
{
protected $form;
protected $item;
public function display($tpl = null)
{
$this->form = $this->get('Form');
$this->item = $this->get('Item');
parent::display($tpl);
}
}
The code will look for the method getForm() and getItem() in the model file. We need to get the item to get the ID of the record in case of editing the existing record.
Model file
admin/src/Model/PartModel.php
We need to extend the model class with the AdminModel. The AdminModel class extends FormModel class. The getForm() method gets the Form object for the edit form.
namespace KW4NZ\Component\Depot\Administrator\Model;
use Joomla\CMS\MVC\Model\AdminModel;
\defined('_JEXEC') or die;
class PartModel extends AdminModel
{
public function getForm($data = array(), $loadData = true)
{
$form = $this->loadForm('com_depot.part',
'part', array('control' => 'jform',
'load_data' => $loadData));
if (empty($form)) {
return false;
}
return $form;
}
}
The loadForm() and preprocessForm() methods are defined in the FromModel class and the bind() method is defined in the Form class. The first argument (name) of loadForm() is set to "com_depot.part". The second argument (form xml source) is "part", and the third argument is the associative array for options.
The form is defined in the source file: forms/part.xml
After you have set the $form variable with the Form object, you check to see if you are loading data to the form. If you want to pre-load data for the form, you include an element called "load_data" that is set to a boolean true. Then, the method calls the loadFormData() method to get the data for the form. This method gets any previously loaded data from the session or database.
Modifying Form dynamically
Inside the getForm() method, before returning the $form, you can modify the form with many methods of the Form class. You can easily fine-tune your forms dynamically before they are rendered.
Layout file - rendering Form
tmpl/part/edit.php
After you get the form in the view file ($this->form), the form is rendered in the layout file (edit.php).
<?php
use Joomla\CMS\HTML\HTMLHelper;
$wa = $this->document->getWebAssetManager();
$wa->useScript('keepalive');
$wa->useScript('form.validate');
?>
<form action="<?= Route::_('index.php?option=com_depot&layout=edit&id=' .
(int) $this->item->id); ?>"
method="post" name="adminForm" id="item-form" class="form-validate">
<?= $this->form->renderField('title'); ?>
<input type="hidden" name="task" value="part.edit" />
<?= HTMLHelper::_('form.token'); ?>
</form>
The form validate script is required to submit the for. The renderField() method of the Form class displays the field - both label and input.
We can access the form using following URL:
administrator/index.php?option=com_depot&view=part&layout=edit
It displays edit.php layout file of the Part View. When the form is submitted, the data is sent to the controller depending upon the action buttons in the toolbar.
Please remember to add the additional folder form
to the Manifest file "depot.xml", i.e.
just a line before <folder>services</folder>
:
<folder>form</folder>