Release of v4.0.1-beta1

Fix subform set methods. Improved the Joomla Power Push path. Fix the metadata, metadesc, metakey database issue.
This commit is contained in:
2024-07-17 02:38:33 +02:00
parent 8ef7c8a4b3
commit 582d6535c7
78 changed files with 3356 additions and 1203 deletions

View File

@@ -46,7 +46,7 @@ final class MultiSubform implements MultiSubformInterface
/**
* Get a subform items
*
* @param array $getMap The the map to get the subfrom data
* @param array $getMap The map to get the subfrom data
*
* Example:
* $getMap = [
@@ -94,8 +94,8 @@ final class MultiSubform implements MultiSubformInterface
/**
* Set a subform items
*
* @param array $items The list of items from the subform to set
* @param array $setMap The the map to set the subfrom data
* @param mixed $items The list of items from the subform to set
* @param array $setMap The map to set the subfrom data
*
* Example:
* $items,
@@ -117,7 +117,7 @@ final class MultiSubform implements MultiSubformInterface
* @return bool
* @since 3.2.2
*/
public function set(array $items, array $setMap): bool
public function set(mixed $items, array $setMap): bool
{
// Validate the core map presence and structure
if (!isset($setMap['_core']) || !is_array($setMap['_core']) || !$this->validSetMap($setMap['_core']))
@@ -125,6 +125,12 @@ final class MultiSubform implements MultiSubformInterface
return false;
}
// catch an empty set
if (!is_array($items))
{
$items = []; // will delete all existing linked items :( not ideal, but real
}
// Save the core data
if (!$this->setSubformData($items, $setMap['_core']))
{
@@ -167,7 +173,7 @@ final class MultiSubform implements MultiSubformInterface
* Set data based on provided map configuration.
*
* @param array $items The list of items from the subform to set
* @param array $map The the map to set the subfrom data
* @param array $map The map to set the subfrom data
* @param array|null $coreData The core data to be appended with subform data
*
* @return bool

View File

@@ -1,169 +0,0 @@
<?php
/**
* @package Joomla.Component.Builder
*
* @created 4th September, 2022
* @author Llewellyn van der Merwe <https://dev.vdm.io>
* @git Joomla Component Builder <https://git.vdm.dev/joomla/Component-Builder>
* @copyright Copyright (C) 2015 Vast Development Method. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace VDM\Joomla\Data;
use VDM\Joomla\Interfaces\GrepInterface as Grep;
use VDM\Joomla\Interfaces\Data\ItemInterface as Item;
use VDM\Joomla\Interfaces\Data\RemoteInterface;
/**
* Load data based on global unique ids from remote system
*
* @since 3.2.0
*/
class Remote implements RemoteInterface
{
/**
* The Grep Class.
*
* @var Grep
* @since 3.2.0
*/
protected Grep $grep;
/**
* The Item Class.
*
* @var Item
* @since 3.2.0
*/
protected Item $item;
/**
* Table Name
*
* @var string
* @since 3.2.1
*/
protected string $table;
/**
* Constructor.
*
* @param Grep $grep The GrepInterface Class.
* @param Item $item The ItemInterface Class.
* @param string|null $table The table name.
*
* @since 3.2.0
*/
public function __construct(Grep $grep, Item $item, ?string $table = null)
{
$this->grep = $grep;
$this->item = $item;
if ($table !== null)
{
$this->table = $table;
}
}
/**
* Set the current active table
*
* @param string $table The table that should be active
*
* @return self
* @since 3.2.2
*/
public function table(string $table): self
{
$this->table = $table;
return $this;
}
/**
* Init all items not found in database
*
* @return bool
* @since 3.2.0
*/
public function init(): bool
{
if (($items = $this->grep->getRemotePowersGuid()) !== null)
{
foreach($items as $guid)
{
if ($this->item->table($this->getTable())->value($guid) !== null &&
($item = $this->grep->get($guid, ['remote'])) !== null)
{
$this->item->set($item);
}
}
return true;
}
return false;
}
/**
* Reset the items
*
* @param array $items The global unique ids of the items
*
* @return bool
* @since 3.2.0
*/
public function reset(array $items): bool
{
if ($items === [])
{
return false;
}
$success = true;
foreach($items as $guid)
{
if (!$this->load($guid, ['remote']))
{
$success = false;
}
}
return $success;
}
/**
* Load a item
*
* @param string $guid The global unique id of the item
* @param array $order The search order
* @param string|null $action The action to load power
*
* @return bool
* @since 3.2.0
*/
public function load(string $guid, array $order = ['remote', 'local'], ?string $action = null): bool
{
if (($item = $this->grep->get($guid, $order)) !== null)
{
return $this->item->table($this->getTable())->set($item);
}
return false;
}
/**
* Get the current active table
*
* @return string
* @since 3.2.2
*/
public function getTable(): string
{
return $this->table;
}
}

View File

@@ -1,386 +0,0 @@
<?php
/**
* @package Joomla.Component.Builder
*
* @created 4th September, 2022
* @author Llewellyn van der Merwe <https://dev.vdm.io>
* @git Joomla Component Builder <https://git.vdm.dev/joomla/Component-Builder>
* @copyright Copyright (C) 2015 Vast Development Method. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace VDM\Joomla\Data;
use VDM\Joomla\Interfaces\GrepInterface as Grep;
use VDM\Joomla\Interfaces\Data\ItemsInterface as Items;
use VDM\Joomla\Gitea\Repository\Contents as Git;
/**
* Set data based on global unique ids to remote repository
*
* @since 3.2.2
*/
class Repository
{
/**
* The GrepInterface Class.
*
* @var Grep
* @since 3.2.2
*/
protected Grep $grep;
/**
* The ItemsInterface Class.
*
* @var Items
* @since 3.2.2
*/
protected Items $items;
/**
* The Contents Class.
*
* @var Git
* @since 3.2.2
*/
protected Git $git;
/**
* All active repos
*
* @var array
* @since 3.2.0
**/
public array $repos;
/**
* Table Name
*
* @var string
* @since 3.2.1
*/
protected string $table;
/**
* The item map
*
* @var array
* @since 3.2.2
*/
protected array $map;
/**
* Constructor.
*
* @param array $repos The active repos
* @param Grep $grep The GrepInterface Class.
* @param Items $items The ItemsInterface Class.
* @param Git $git The Contents Class.
* @param string|null $table The table name.
*
* @since 3.2.2
*/
public function __construct(array $repos, Grep $grep, Items $items, Git $git, ?string $table = null)
{
$this->repos = $repos;
$this->grep = $grep;
$this->items = $items;
$this->git = $git;
if ($table !== null)
{
$this->table = $table;
}
// set the branch to writing
$this->grep->setBranchField('write_branch');
}
/**
* Set the current active table
*
* @param string $table The table that should be active
*
* @return self
* @since 3.2.2
*/
public function table(string $table): self
{
$this->table = $table;
return $this;
}
/**
* Set items
*
* @param array $guids The global unique id of the item
*
* @return bool
* @throws \Exception
* @since 3.2.0
*/
public function set(array $guids): bool
{
if (($items = $this->getLocalItems($guids)) === null)
{
throw new \Exception("At least one valid local [Joomla Power] must exist for the push function to operate correctly.");
}
if (!$this->canWrite())
{
throw new \Exception("At least one [Joomla Power] content repository must be configured with a [Write Branch] value in the repositories area for the push function to operate correctly.");
}
// update the existing found
if (($existing_items = $this->getRepoItems($guids)) !== [])
{
foreach ($existing_items as $e_guid => $item)
{
if (isset($items[$e_guid]))
{
$this->updateItem($items[$e_guid], $item);
unset($items[$e_guid]);
}
}
}
// create the new items
foreach ($items as $item)
{
$this->createItem($item);
}
return true;
}
/**
* Get the current active table
*
* @return string
* @since 3.2.2
*/
public function getTable(): string
{
return $this->table;
}
/**
* Get items
*
* @param array $guids The global unique id of the item
*
* @return array|null
* @since 3.2.2
*/
public function getLocalItems(array $guids): ?array
{
$items = $this->fetchLocalItems($guids);
if ($items === null)
{
return null;
}
return $this->mapItems($items);
}
/**
* Fetch items from the database
*
* @param array $guids The global unique id of the item
*
* @return array|null
* @since 3.2.2
*/
protected function fetchLocalItems(array $guids): ?array
{
return $this->items->table($this->table)->get($guids);
}
/**
* Map items to their properties
*
* @param array $items The items fetched from the database
*
* @return array
* @since 3.2.2
*/
protected function mapItems(array $items): array
{
$bucket = [];
foreach ($items as $item)
{
if (!isset($item->guid))
{
continue;
}
$bucket[$item->guid] = $this->mapItem($item);
}
return $bucket;
}
/**
* Map a single item to its properties
*
* @param object $item The item to be mapped
*
* @return object
* @since 3.2.2
*/
protected function mapItem(object $item): object
{
$power = [];
foreach ($this->map as $key => $map)
{
$power[$key] = $item->{$map} ?? null;
}
return (object) $power;
}
/**
* get existing items
*
* @param array $guids The global unique id of the item
*
* @return array|null
* @since 3.2.2
*/
protected function getRepoItems(array $guids): ?array
{
$bucket = [];
foreach ($guids as $guid)
{
if (($item = $this->grep->get($guid)) !== null)
{
$bucket[$guid] = (object) $item;
}
}
return $bucket ?? null;
}
/**
* check that we have an active repo towards which we can write data
*
* @return bool
* @since 3.2.2
*/
protected function canWrite(): bool
{
foreach ($this->repos as $repo)
{
if (!empty($repo->write_branch) && $repo->write_branch !== 'default')
{
return true;
}
}
return false;
}
/**
* Checks if two objects are equal by comparing their JSON representations.
*
* This method converts both input objects to JSON strings and compares these strings.
* If the JSON strings are identical, the objects are considered equal.
*
* @param object $obj1 The first object to compare.
* @param object $obj2 The second object to compare.
*
* @return bool True if the objects are equal, false otherwise.
* @since 3.2.2
*/
protected function areObjectsEqual(object $obj1, object $obj2): bool
{
// Convert both objects to JSON strings
$json1 = json_encode($obj1);
$json2 = json_encode($obj2);
// Compare the JSON strings
return $json1 === $json2;
}
/**
* update an existing item (if changed)
*
* @param object $item
* @param object $existing
*
* @return void
* @since 3.2.2
*/
protected function updateItem(object $item, object $existing): void
{
if (isset($existing->params->source) && is_array($existing->params->source))
{
// get the source values
$source = $existing->params->source;
// make sure there was a change
$existing = $this->mapItem($existing);
if ($this->areObjectsEqual($item, $existing))
{
return;
}
foreach ($this->repos as $repo)
{
if (isset($source[$repo->guid]))
{
$this->git->load_($repo->base ?? null, $repo->token ?? null);
$this->git->update(
$repo->organisation, // The owner name.
$repo->repository, // The repository name.
'src/' . $item->guid . '/item.json', // The file path.
json_encode($item, JSON_PRETTY_PRINT), // The file content.
'Update ' . $item->system_name, // The commit message.
$source[$repo->guid], // The blob SHA of the old file.
$repo->write_branch // The branch name.
);
$this->git->reset_();
// only update in the first found repo
return;
}
}
}
}
/**
* create a new item
*
* @param object $item
*
* @return void
* @since 3.2.2
*/
protected function createItem(object $item): void
{
foreach ($this->repos as $repo)
{
if (!empty($repo->write_branch) && $repo->write_branch !== 'default')
{
$this->git->load_($repo->base ?? null, $repo->token ?? null);
$this->git->create(
$repo->organisation, // The owner name.
$repo->repository, // The repository name.
'src/' . $item->guid . '/item.json', // The file path.
json_encode($item, JSON_PRETTY_PRINT), // The file content.
'Create ' . $item->system_name, // The commit message.
$repo->write_branch // The branch name.
);
$this->git->reset_();
// only create in the first found repo
return;
}
}
}
}

View File

@@ -94,7 +94,7 @@ final class Subform implements SubformInterface
/**
* Set a subform items
*
* @param array $items The list of items from the subform to set
* @param mixed $items The list of items from the subform to set
* @param string $indexKey The index key on which the items should be observed as it relates to insert/update/delete.
* @param string $linkKey The link key on which the items where linked in the child table.
* @param string $linkValue The value of the link key in child table.
@@ -102,12 +102,17 @@ final class Subform implements SubformInterface
* @return bool
* @since 3.2.2
*/
public function set(array $items, string $indexKey, string $linkKey, string $linkValue): bool
public function set(mixed $items, string $indexKey, string $linkKey, string $linkValue): bool
{
$items = $this->process($items, $indexKey, $linkKey, $linkValue);
$this->purge($items, $indexKey, $linkKey, $linkValue);
if (empty($items))
{
return true; // nothing to set (already purged)
}
return $this->items->table($this->getTable())->set(
$items, $indexKey
);
@@ -142,10 +147,19 @@ final class Subform implements SubformInterface
if ($currentIndexValues !== null)
{
// Extract the index values from the items array
$activeIndexValues = array_values(array_map(function($item) use ($indexKey) {
return $item[$indexKey] ?? null;
}, $items));
// Check if the items array is empty
if (empty($items))
{
// Set activeIndexValues to an empty array if items is empty
$activeIndexValues = [];
}
else
{
// Extract the index values from the items array
$activeIndexValues = array_values(array_map(function($item) use ($indexKey) {
return $item[$indexKey] ?? null;
}, $items));
}
// Find the index values that are no longer in the items array
$inactiveIndexValues = array_diff($currentIndexValues, $activeIndexValues);
@@ -205,7 +219,7 @@ final class Subform implements SubformInterface
/**
* Processes an array of arrays based on the specified key.
*
* @param array $items Array of arrays to be processed.
* @param mixed $items Array of arrays to be processed.
* @param string $indexKey The index key on which the items should be observed as it relates to insert/update/delete
* @param string $linkKey The link key on which the items where linked in the child table.
* @param string $linkValue The value of the link key in child table.
@@ -213,8 +227,9 @@ final class Subform implements SubformInterface
* @return array The processed array of arrays.
* @since 3.2.2
*/
private function process(array $items, string $indexKey, string $linkKey, string $linkValue): array
private function process($items, string $indexKey, string $linkKey, string $linkValue): array
{
$items = is_array($items) ? $items : [];
foreach ($items as &$item)
{
$value = $item[$indexKey] ?? '';