depot/README.md
2023-10-05 02:28:17 +02:00

14 KiB

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:

  1. 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.
  2. 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.

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

  1. When the component is installed for the first time, the file install.mysql.utf8.sql is executed.
  2. 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:

  1. load() to load the existing record from the database, passing the primary key of the record.
  2. bind() to set the new values for the fields.
  3. check() to perform any validation.
  4. store() to save the new values to the database.
  5. 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>