Checkin und Checkout
Mithilfe der Checkout-Funktion werden unerwartete Ergebnisse vermieden, die auftreten, wenn zwei Benutzer denselben Datensatz gleichzeitig editieren. Das Auschecken sperrt ein Item, wenn ein Anwender es zur Bearbeitung öffnet. Beim Speichern und Schließen wird es dann wieder freigegeben. Eine sinnvolle Funktion, die wir in diesem Teil der Artikelserie unsere Beispielerweiterung integrieren.
Manchmal kommt es vor, dass ein Element als aus gecheckt markiert ist, obwohl es niemand zeitgleich zur Bearbeitung geöffnet hat. Dies passiert in der Regel, wenn ein vorheriges Öffnen nicht korrekt beendet wurde. Beispielsweise wurde der Webbrowser geschlossen, obwohl der Beitrag zur Bearbeitung offen war oder man hat im Menü des Browsers die Zurück-Schaltfläche geklickt anstelle den Beitrag ordnungsgemäß zu schließen.
Für Ungeduldige: Sieh dir den geänderten Programmcode in der Diff-Ansicht[^codeberg.org/astrid/j4examplecode/compare/t20…t21] an und übernimm diese Änderungen in deine Entwicklungsversion.
Schritt für Schritt
Neue Dateien
administrator/components/com_foos/sql/updates/mysql/21.0.0.sql
Wie alle Eigenschaften eines Foo-Elementes, wird der Checkout-Zustand in der Datenbank gespeichert. Wir legen zwei Spalten an. Nachfolgend siehst du das Skript, welches bei einer Joomla-Aktualisierung aufgerufen wird.
administrator/components/com_foos/sql/updates/mysql/21.0.0.sql
<!-- https://codeberg.org/astrid/j4examplecode/raw/branch/t21/src/administrator/components/com_foos/sql/updates/mysql/21.0.0.sql -->
ALTER TABLE `#__foos_details` ADD COLUMN `checked_out` int(10) unsigned NOT NULL DEFAULT 0 AFTER `alias`;
ALTER TABLE `#__foos_details` ADD COLUMN `checked_out_time` datetime AFTER `alias`;
ALTER TABLE `#__foos_details` ADD KEY `idx_checkout` (`checked_out`);
Geänderte Dateien
administrator/components/com_foos/forms/foo.xml
Im Formular fügen wir die Felder für das Speichern des Zustands hinzu. Wir verstecken sie mit dem Attribut hidden
, da sie hier nicht vom Benutzer geändert werden. Joomla setzt die Werte automatisch im Hintergrund.
administrator/components/com_foos/forms/foo.xml
size="1"
/>
+ <field
+ name="checked_out"
+ type="hidden"
+ filter="unset"
+ />
+
+ <field
+ name="checked_out_time"
+ type="hidden"
+ filter="unset"
+ />
+
<field
name="ordering"
type="ordering"
administrator/components/com_foos/sql/install.mysql.utf8.sql
Die Datenbankänderungen, die wir oben für die Aktualisierung in der separaten SQL-Datei eingetragen haben, ergänzen wir im SQL-Skript, welches bei einer neuen Installation aufgerufen wird.
administrator/components/com_foos/sql/install.mysql.utf8.sql
ALTER TABLE `#__foos_details` ADD COLUMN `ordering` int(11) NOT NULL DEFAULT 0 AFTER `alias`;
ALTER TABLE `#__foos_details` ADD COLUMN `params` text NOT NULL AFTER `alias`;
+
+ALTER TABLE `#__foos_details` ADD COLUMN `checked_out` int(10) unsigned NOT NULL DEFAULT 0 AFTER `alias`;
+
+ALTER TABLE `#__foos_details` ADD COLUMN `checked_out_time` datetime AFTER `alias`;
+
+ALTER TABLE `#__foos_details` ADD KEY `idx_checkout` (`checked_out`);
administrator/components/com_foos/src/Model/FoosModel.php
Im Model passen wir alles so an, dass die beiden neuen Spalten korrekt geladen werden.
Beachte die Änderung
array(...)
inexplode(', ',$this->getState(...)...)
. Wir nutzen nun die PHP-Funktionexplode
zusammen mitgetState
um das Array für die Datenbankabfrage zu erstellen. Dies ist sicherer und fehlertoleranter.
administrator/components/com_foos/src/Model/FoosModel.php
// Select the required fields from the table.
$query->select(
$db->quoteName(
- array(
- 'a.id', 'a.name', 'a.alias', 'a.access',
- 'a.catid', 'a.published', 'a.publish_up', 'a.publish_down',
- 'a.language', 'a.ordering', 'a.state'
+ explode(
+ ', ',
+ $this->getState(
+ 'list.select',
+ 'a.id, a.name, a.catid' .
+ ', a.access' .
+ ', a.checked_out' .
+ ', a.checked_out_time' .
+ ', a.language' .
+ ', a.ordering' .
+ ', a.state' .
+ ', a.published' .
+ ', a.publish_up, a.publish_down'
+ )
)
)
);
$query->select('(' . $subQuery . ') AS ' . $db->quoteName('association'));
}
+ // Join over the users for the checked out user.
+ $query->select($db->quoteName('uc.name', 'editor'))
+ ->join(
+ 'LEFT',
+ $db->quoteName('#__users', 'uc') . ' ON ' . $db->quoteName('uc.id') . ' = ' . $db->quoteName('a.checked_out')
+ );
+
// Filter on the language.
if ($language = $this->getState('filter.language'))
{
administrator/components/com_foos/tmpl/foos/default.php
In die Listenansicht fügen wir keine separate Spalte ein. Beim Namen wird ein Symbol angezeigt, wenn das Element gesperrt ist. Für die Anzeige von diesem wähle ich die Funktion, die Joomla in eigenen Erweiterungen einsetzt: echo HTMLHelper::_('jgrid.checkedout', $i, $item->editor, $item->checked_out_time, 'foos.', true)
. Die übernimmt gleichzeitig die Prüfung, ob der Beitrag freigegeben ist oder nicht.
administrator/components/com_foos/tmpl/foos/default.php
<?php echo HTMLHelper::_('grid.id', $i, $item->id); ?>
</td>
<th scope="row" class="has-context">
+ <?php if ($item->checked_out) : ?>
+ <?php echo HTMLHelper::_('jgrid.checkedout', $i, $item->editor, $item->checked_out_time, 'foos.', true); ?>
+ <?php endif; ?>
<div>
<?php echo $this->escape($item->name); ?>
</div>
Ich habe es hier unkompliziert gehalten. Ich prüfe nicht, ob jemand berechtigt ist, einen ausgecheckten Beitrag wieder freizugeben. Die Komponenten in Joomla gestalten dies restriktiver. In
com_contact
sieht die betreffende Zeile beispielsweise so aus:<?php echo HTMLHelper::*('jgrid.checkedout', $i, $item->editor, $item->checked_out_time, 'contacts.', $canCheckin); ?>
. Wenn du ebenfalls nicht jedem das Freigeben erlaubst und dies implementieren möchtest, sieh dir die Implementierung incom_contact
an. Hier findest du den Code, der$canCheckin
berechnet.
Teste deine Joomla-Komponente
- Installiere deine Komponente in Joomla Version 4, um sie zu testen:
Kopiere die Dateien im administrator
Ordner in den administrator
Ordner deiner Joomla 4 Installation.
-
Die Datenbank ist geändert worden, so dass es erforderlich ist, sie zu aktualisieren. Öffne den Bereich
System | Information | Database
, wie im TeilVeröffentlichen und Verstecken
beschrieben. Wähle deine Komponente aus und klicke aufUpdate Structure
. -
Öffne ein Item in der Bearbeitungsansicht.
-
Wechsele in ein anderes Browser-Fenster und versuche, das Item erneut zu bearbeiten.
-
Vergewissere dich, dass du ein Symbol siehst, dass dich darauf hinweist, dass dieses Item gesperrt ist und dass ein berechtigter Benutzer die Sperrung aufheben kann.