diff --git a/README.md b/README.md
index 760aec2..4c43517 100644
--- a/README.md
+++ b/README.md
@@ -17,7 +17,7 @@ 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)
+## Adding basic files for component (b1_basic_backend)
With the git branch **b1_basic_backend**
Add the following basic six files:
@@ -124,7 +124,7 @@ the directory /admin/language/en-GB/ naming it
---
-### Creating and managing Joomla database (b2_database)
+## Creating and managing Joomla database (b2_database)
With the new git branch **b2_database** we continue our workflow.
@@ -295,7 +295,7 @@ Methods in the table objects are:
---
-### Get a Form in Joomla component
+## Get a Form in Joomla component (b3_form)
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
@@ -440,7 +440,7 @@ just a line before `services` :
---
-### Adding administrator's actions (Back-end) - Save and Cancel
+## Adding administrator's actions (Back-end) - Save and Cancel (b4_actions)
In the form View, you can add action buttons like "Save" and "Cancel" to submit the form
or cancel the editing respectively. These buttons are added to the toolbar.
@@ -526,3 +526,189 @@ So, you either have data from the database, which you can get with `getItem()`,
data from the session, which you can get with `getUserSate()`.
---
+## Automatic handling of fields (b5_field_manipulation)
+Values of some fields in the form can be automatically handled. There is no need to fill in
+the values while creating or editing a record.
+
+For example, `alias` can be generated from the `title` (or here, from the component's name),
+dates can be set to the current date or to `null`, user id can be obtained from current
+logged in user. Further may you also need to check validity of some fields like "should not
+be empty", `alias` should be unique, etc.
+
+The data submitted by the form needs to be modified before saving. This can be done at
+various places:
+
+- in the **Model class** by oeverriding the `save()` method or `preparetable()` method.
+- in the **Table class** by overriding the `bind()`, `check()`, or `store()` methods.
+
+#### 1. Model file
+**admin/src/Model/PartModel.php
+```php
+public function save($data)
+{
+ /* Add code to modify data before saving */
+
+ return parent:save($data);
+}
+```
+It is better to perform automatic handling of fields in the Table class as the data can be
+saved not only from administration, but also from frontend, API or by any other means.
+
+##### Example generating Alias
+Alias is generated from the `component_name` (or any other field) using **OutputFilter** class
+method.
+```php
+if (empty($data['alias']))
+{
+ if (Factory::getConfig()->get('unicodeslugs') == 1) {
+ $data['alias'] = OutputFilter::stringURLUnicodeSlug($data['component_name']);
+ } else {
+ $data['alias'] = OutputFilter::stringURLSafe($data['component_name']);
+ }
+}
+```
+##### Ordering
+The ordering value is calculated by finding the maximum value in the column and then
+incrementing it.
+```php
+/* if it is 0 -> get the max + 1 value */
+if (!$data['ordering']) {
+ $db = Factory::getDbo();
+ $query = $db->getQuery(true)
+ ->select('MAX(ordering)')
+ ->from('#__depot');
+
+ $db->setQuery($query);
+ $max = $db->loadResult();
+
+ $data['ordering'] = $max + 1;
+}
+
+```
+#### 2. bind()
+The `bind()` splits the article text or description into intro text and full text based on read
+more tag in the content. This method also converts fields data from arrays to JSON for
+saving into the database.
+
+```php
+public function bind($array, $ignore = '')
+{
+ if (isset($array['attribs']) && \is_array($array['attribs'])) {
+ $registry = new Registry($array['attribs']);
+ $array['attribs'] = (string) $registry;
+ }
+
+ return parent::bind($array, $ignore);
+}
+
+```
+
+#### 3. check()
+The check() checks whether title of the article is not empty. This method also sets the alias,
+hits, publishing dates.
+```php
+public function check()
+{
+ try {
+ parent::check();
+ }
+ catch (\Exception $e) {
+ $this->setError($e->getMessage());
+
+ return false;
+ }
+
+ if (trim($this->title) == '') {
+ $this->setError('Title (title) is not set.');
+
+ return false;
+ }
+
+ if (trim($this->alias) == '') {
+ $this->alias = $this->title;
+ }
+
+ $this->alias = ApplicationHelper::stringURLSave($this->alias, $this->language);
+
+ // Ensure any new items have compulsory fields set
+ if (!$this->id) {
+ // Hits must be zero on a new item
+ $this-hits = 0;
+ }
+
+ // Set publish_up to null if not set
+ if (!$this->publish_up) {
+ $this->publish_up = null;
+ }
+
+ // Set publish_down to null if not set
+ if (!$this->publish_down) {
+ $this->publish_down = null;
+ }
+
+ // Check the publish down date is not earlier than publish up.
+ if (!is_null($this->publish_up) &&
+ !is_null($this->publish_down) &&
+ $this->publish_down < $this->publish_up) {
+ // swap the dates
+ $temp = $this->publish_up;
+ $this->publish_up = $this->publish_down;
+ $this->publish_down = $temp;
+ }
+ return true;
+}
+```
+
+#### 4. store()
+The `store()` sets created and modified dates, created by and modified by users, and also
+checks for unique alias.
+```php
+public function store($updateNulls = true)
+{
+ $app = Factory::getApplication();
+ $date = Factory::getDate()->toSql();
+ $user = Factory::getUser();
+
+ if (!this->created) {
+ $this->created = $date;
+ }
+
+ if (!this->created_by) {
+ $this->created_by = $user->get('id');
+ }
+
+ if ($this->id) {
+ // Existing item
+ $this->modified_by = $user->get('id');
+ $this->modified = $date;
+ } else {
+
+ // Set modified to created date if not set
+ if (!$this->modified)) {
+ $this->modified = $this->created;
+ }
+
+ // Set modified_by to created_by user if not set
+ if (empty($this->modified_by)) {
+ $this->modified_by = $this->created_by;
+ }
+ }
+
+ // Verify that the alias is unique
+ $table = $app->bootComponent('com_depot')->getMVCFactory()
+ ->createTable('Part','Administrator');
+ if ($table->load(['alias' => $this->alias]) &&
+ ($table->id != $this->id || $this->id == 0)) {
+ $this->setError('Alias is not unique.');
+
+ if ($table->state == -2) {
+ $this->setError('Alias is not unique. The item is in trash.');
+ }
+ return false;
+ }
+
+ return parent::store($updateNulls);
+}
+```
+
+---
diff --git a/admin/forms/part.xml b/admin/forms/part.xml
index 5167343..eca411e 100644
--- a/admin/forms/part.xml
+++ b/admin/forms/part.xml
@@ -1,18 +1,72 @@
diff --git a/admin/language/en-GB/com_depot.ini b/admin/language/en-GB/com_depot.ini
index a706a2b..98b5f8e 100644
--- a/admin/language/en-GB/com_depot.ini
+++ b/admin/language/en-GB/com_depot.ini
@@ -5,6 +5,16 @@
; @license GNU General Public License version 2 or later; see LICENSE.md
; @since 0.0.1
;
+COM_DEPOT_FIELD_ALIAS_PLACEHOLDER="Auto-generate from component name"
COM_DEPOT_FIELD_COMPONENT_NAME_DESC="The name of the component is unique. Please do not enter special characters or umlauts."
COM_DEPOT_FIELD_COMPONENT_NAME_LABEL="Component Name"
+COM_DEPOT_FIELD_QUANTITY_LABEL="Quantity"
+COM_DEPOT_FIELD_QUANTITY_DESC="Enter here the current number of components"
+COM_DEPOT_FIELD_QUANTITY_EXP_LABEL="Quantity Exponent"
+COM_DEPOT_FIELD_QUANTITY_EXP_DESC="Exponent (10^x of the number, usually 0 i.e. 10⁰)"
+COM_DEPOT_FIELD_SELECT_MANUFACTURER="Manufacturer"
+COM_DEPOT_LEGEND_DETAILS="Component Details"
+COM_DEPOT_SELECT_YOUR_OPTION="Select your option"
+COM_DEPOT_TAB_NEW_PART="New Component"
+COM_DEPOT_TAB_EDIT_PART="Component Details"
COM_DEPOT_XML_DESCRIPTION="Depot, the component warehouse"
diff --git a/admin/sql/install.mysql.utf8.sql b/admin/sql/install.mysql.utf8.sql
index 40517fc..235da7c 100644
--- a/admin/sql/install.mysql.utf8.sql
+++ b/admin/sql/install.mysql.utf8.sql
@@ -49,3 +49,33 @@ INSERT INTO `#__depot` (`component_name`,`alias`,`description`,`quantity`,`creat
`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);
+
+DROP TABLE IF EXISTS `#__depot_manufacturer`;
+CREATE TABLE `#__depot_manufacturer` (
+ `id` SERIAL,
+ `name_short` CHAR(25) CHARACTER SET ascii COLLATE ascii_general_ci NULL DEFAULT NULL
+ COMMENT 'unique manufacturer name or abbriviation',
+ `name_long` VARCHAR(1024) NOT NULL DEFAULT '',
+ `url` VARCHAR(1024) NOT NULL DEFAULT '',
+ `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,
+ `description` VARCHAR(4000) NOT NULL DEFAULT '',
+ `state` TINYINT(4) NOT NULL DEFAULT 0,
+ `image` VARCHAR(1024) NOT NULL DEFAULT '',
+ `access` TINYINT(4) NOT NULL DEFAULT 0,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `name_short` (`name_short`)
+) ENGINE=InnoDB
+ AUTO_INCREMENT=0
+ DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
+
+INSERT INTO `#__depot_manufacturer` (`name_short`, `name_long`, `url`,
+ `description`, `image`) VALUES
+('TSC','Taiwan Semiconductor','https://www.taiwansemi.com',
+ 'Diodes, ECAD Models, ICs, MOSFETs, Protection Devices, AEC-Q qualified',''),
+('ST','STMicroelectronics','https://www.st.com',
+ 'Microprocessors, Audio ICs, OPamps, Diodes, Memories, MEMS, NFCs, Transistors, Wireless, Automotive electronics, etc.','');
diff --git a/admin/sql/updates/mysql/0.0.5.sql b/admin/sql/updates/mysql/0.0.5.sql
new file mode 100644
index 0000000..e5c5376
--- /dev/null
+++ b/admin/sql/updates/mysql/0.0.5.sql
@@ -0,0 +1,35 @@
+-- @package Depot.SQL MariaDB -- UPDATE to 0.0.5
+-- @subpackage com_depot
+-- @author Thomas Kuschel
+-- @copyright (C) 2023 KW4NZ,
+-- @license GNU General Public License version 2 or later; see LICENSE.md
+-- @since 0.0.5
+
+CREATE TABLE IF NOT EXISTS `#__depot_manufacturer` (
+ `id` SERIAL,
+ `name_short` CHAR(25) CHARACTER SET ascii COLLATE ascii_general_ci NULL DEFAULT NULL
+ COMMENT 'unique manufacturer name or abbriviation',
+ `name_long` VARCHAR(1024) NOT NULL DEFAULT '',
+ `url` VARCHAR(1024) NOT NULL DEFAULT '',
+ `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,
+ `description` VARCHAR(4000) NOT NULL DEFAULT '',
+ `state` TINYINT(4) NOT NULL DEFAULT 0,
+ `image` VARCHAR(1024) NOT NULL DEFAULT '',
+ `access` TINYINT(4) NOT NULL DEFAULT 0,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `name_short` (`name_short`)
+) ENGINE=InnoDB
+ AUTO_INCREMENT=0
+ DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
+
+INSERT INTO `#__depot_manufacturer` (`name_short`, `name_long`, `url`,
+ `description`, `image`) VALUES
+('TSC','Taiwan Semiconductor','https://www.taiwansemi.com',
+ 'Diodes, ECAD Models, ICs, MOSFETs, Protection Devices, AEC-Q qualified',''),
+('ST','STMicroelectronics','https://www.st.com',
+ 'Microprocessors, Audio ICs, OPamps, Diodes, Memories, MEMS, NFCs, Transistors, Wireless, Automotive electronics, etc.','');
diff --git a/admin/src/Model/PartModel.php b/admin/src/Model/PartModel.php
index 944c6bd..81be2f5 100644
--- a/admin/src/Model/PartModel.php
+++ b/admin/src/Model/PartModel.php
@@ -10,6 +10,7 @@
namespace KW4NZ\Component\Depot\Administrator\Model;
+use Joomla\CMS\Application\ApplicationHelper;
use Joomla\CMS\Factory;
use Joomla\CMS\MVC\Model\AdminModel;
@@ -39,4 +40,25 @@ class PartModel extends AdminModel
return $data;
}
+
+ public function save($data)
+ {
+ /* Add code to modify data before saving */
+
+ // if (Factory::getConfig()->get('unicodeslugs') == 1) {
+ // $data['alias'] = OutputFilter::stringURLUnicodeSlug($data['component_name']);
+ // } else {
+ // $data['alias'] = OutputFilter::stringURLSafe($data['component_name']);
+ // }
+
+ /* replaced by: */
+ if (empty($data['alias'])) {
+ $data['alias'] = ApplicationHelper::stringURLSafe($data['component_name']);
+ }
+ $result = parent::save($data);
+ // if ($result) {
+ // $this->getTable('', 'Administrator')->rebuild(1);
+ // }
+ return $result;
+ }
}
\ No newline at end of file
diff --git a/admin/tmpl/part/edit.php b/admin/tmpl/part/edit.php
index 3fc2f28..96b6072 100644
--- a/admin/tmpl/part/edit.php
+++ b/admin/tmpl/part/edit.php
@@ -8,6 +8,7 @@
* @since 0.0.3
*/
use Joomla\CMS\HTML\HTMLHelper;
+use Joomla\CMS\Language\Text;
use Joomla\CMS\Router\Route;
/** @var Joomla\CMS\WebAsset\WebAssetManager $wa */
@@ -19,9 +20,35 @@ $wa->useScript('form.validate')
\ No newline at end of file
diff --git a/depot.xml b/depot.xml
index 90878b0..a7d8419 100644
--- a/depot.xml
+++ b/depot.xml
@@ -7,7 +7,7 @@
GPL v2 +; see LICENSE.md
thomas@kuschel.at
https://kuschel.at
- 0.0.4
+ 0.0.5
COM_DEPOT_XML_DESCRIPTION
KW4NZ\Component\Depot