Release of v3.2.4-alpha1

Add push option to powers area.
This commit is contained in:
2024-08-20 22:32:57 +02:00
parent ca7138cb4a
commit 4bed7a52da
79 changed files with 1530 additions and 156 deletions

View File

@ -17,6 +17,7 @@ use VDM\Joomla\Interfaces\Data\ItemsInterface as Items;
use VDM\Joomla\Interfaces\Readme\ItemInterface as ItemReadme;
use VDM\Joomla\Interfaces\Readme\MainInterface as MainReadme;
use VDM\Joomla\Interfaces\Git\Repository\ContentsInterface as Git;
use VDM\Joomla\Utilities\ObjectHelper;
use VDM\Joomla\Interfaces\Remote\SetInterface;
@ -147,6 +148,27 @@ abstract class Set implements SetInterface
*/
protected string $index_settings_path = 'index.json';
/**
* Core Placeholders
*
* @var array
* @since 5.0.3
*/
protected array $placeholders = [
'[['.'[NamespacePrefix]]]' => 'VDM',
'[['.'[ComponentNamespace]]]' => 'Componentbuilder',
'[['.'[Component]]]' => 'Componentbuilder',
'[['.'[component]]]' => 'componentbuilder'
];
/**
* Repo Placeholders
*
* @var array
* @since 5.0.3
*/
protected array $repoPlaceholders = [];
/**
* Constructor.
*
@ -499,55 +521,10 @@ abstract class Set implements SetInterface
* @since 3.2.2
*/
protected 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 ids of the items
*
* @return array|null
* @since 3.2.2
*/
protected function fetchLocalItems(array $guids): ?array
{
return $this->items->table($this->getTable())->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
*
@ -562,7 +539,15 @@ abstract class Set implements SetInterface
foreach ($this->map as $key => $map)
{
$power[$key] = $item->{$map} ?? null;
$methodName = "mapItemValue_{$key}";
if (method_exists($this, $methodName))
{
$this->{$methodName}($item, $power);
}
else
{
$power[$key] = $item->{$map} ?? null;
}
}
return (object) $power;
@ -586,11 +571,15 @@ abstract class Set implements SetInterface
$index_item = null;
foreach ($this->repos as $key => $repo)
{
if (empty($repo->write_branch) || $repo->write_branch === 'default')
if (empty($repo->write_branch) || $repo->write_branch === 'default' || !$this->targetRepo($item, $repo))
{
continue;
}
$item = $this->mapItem($item);
$this->setRepoPlaceholders($repo);
$this->git->load_($repo->base ?? null, $repo->token ?? null);
if (($existing = $this->grep->get($item->guid, ['remote'], $repo)) !== null)
@ -622,6 +611,43 @@ abstract class Set implements SetInterface
}
}
/**
* Set the Repo Placeholders
*
* @param object $repo The repo
*
* @return void
* @since 5.0.3
*/
protected function setRepoPlaceholders(object $repo): void
{
$this->repoPlaceholders = $this->placeholders;
if (!empty($repo->placeholders) && is_array($repo->placeholders))
{
foreach ($repo->placeholders as $key => $value)
{
$this->repoPlaceholders[$key] = $value;
}
}
}
/**
* Update Placeholders in String
*
* @param string $string The value to update
*
* @return string
* @since 5.0.3
*/
protected function updatePlaceholders(string $string): string
{
return str_replace(
array_keys($this->repoPlaceholders),
array_values($this->repoPlaceholders),
$string
);
}
/**
* Get index values
*
@ -669,25 +695,36 @@ abstract class Set implements SetInterface
}
/**
* Checks if two objects are equal by comparing their JSON representations.
* check that we have a target repo of this item
*
* 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 $item The item
* @param object $repo The current repo
*
* @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
* @return bool
* @since 5.0.3
*/
protected function areObjectsEqual(object $obj1, object $obj2): bool
protected function targetRepo(object $item, object $repo): bool
{
// Convert both objects to JSON strings
$json1 = json_encode($obj1);
$json2 = json_encode($obj2);
return true; // for more control in children classes
}
// Compare the JSON strings
return $json1 === $json2;
/**
* Checks if two objects are equal by comparing their properties and values.
*
* This method converts both input objects to associative arrays, sorts the arrays by keys,
* and compares these sorted arrays.
*
* If the arrays are identical, the objects are considered equal.
*
* @param object|null $obj1 The first object to compare.
* @param object|null $obj2 The second object to compare.
*
* @return bool True if the objects are equal, false otherwise.
* @since 5.0.2
*/
protected function areObjectsEqual(?object $obj1, ?object $obj2): bool
{
return ObjectHelper::equal($obj1, $obj2); // basic comparison
}
/**

View File

@ -143,6 +143,60 @@ final class Grep extends ExtendingGrep implements GrepInterface
// set the git details in params
$power->main_class_code = $code;
}
// set the git details in params
$path_guid = $path->guid ?? null;
if ($path_guid !== null)
{
// get the Settings meta
if (($meta = $this->contents->metadata($path->organisation, $path->repository, $path->index->{$guid}->settings, $branch)) !== null &&
isset($meta->sha))
{
if (isset($power->params) && is_object($power->params) &&
isset($power->params->source) && is_array($power->params->source))
{
$power->params->source[$path_guid . '-settings'] = $meta->sha;
}
else
{
$power->params = (object) [
'source' => [$path_guid . '-settings' => $meta->sha]
];
}
}
// get the power meta
if (($meta = $this->contents->metadata($path->organisation, $path->repository, $path->index->{$guid}->power, $branch)) !== null &&
isset($meta->sha))
{
if (isset($power->params) && is_object($power->params) &&
isset($power->params->source) && is_array($power->params->source))
{
$power->params->source[$path_guid . '-power'] = $meta->sha;
}
else
{
$power->params = (object) [
'source' => [$path_guid . '-power' => $meta->sha]
];
}
}
// get the README meta
if (($meta = $this->contents->metadata($path->organisation, $path->repository, $path->index->{$guid}->path . '/README.md', $branch)) !== null &&
isset($meta->sha))
{
if (isset($power->params) && is_object($power->params) &&
isset($power->params->source) && is_array($power->params->source))
{
$power->params->source[$path_guid . '-readme'] = $meta->sha;
}
else
{
$power->params = (object) [
'source' => [$path_guid . '-readme' => $meta->sha]
];
}
}
}
}
// reset back to the global base and token

View File

@ -0,0 +1,794 @@
<?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\Componentbuilder\Power\Remote;
use VDM\Joomla\Interfaces\GrepInterface as Grep;
use VDM\Joomla\Interfaces\Data\ItemsInterface as Items;
use VDM\Joomla\Interfaces\Readme\ItemInterface as ItemReadme;
use VDM\Joomla\Interfaces\Readme\MainInterface as MainReadme;
use VDM\Joomla\Interfaces\Git\Repository\ContentsInterface as Git;
use VDM\Joomla\Componentbuilder\Power\Parser;
use VDM\Joomla\Utilities\String\NamespaceHelper;
use VDM\Joomla\Utilities\ArrayHelper;
use VDM\Joomla\Utilities\StringHelper;
use VDM\Joomla\Utilities\String\ClassfunctionHelper;
use VDM\Joomla\Utilities\GuidHelper;
use VDM\Joomla\Interfaces\Remote\SetInterface;
use VDM\Joomla\Abstraction\Remote\Set as ExtendingSet;
/**
* Set Power based on global unique ids to remote repository
*
* @since 5.0.2
*/
final class Set extends ExtendingSet implements SetInterface
{
/**
* Table Name
*
* @var string
* @since 5.0.3
*/
protected string $table = 'power';
/**
* Area Name
*
* @var string
* @since 5.0.3
*/
protected string $area = 'Super Power';
/**
* Prefix Key
*
* @var string
* @since 5.0.3
*/
protected string $prefix_key = 'Super---';
/**
* The item map
*
* @var array
* @since 5.0.3
*/
protected array $map = [
'add_head' => 'add_head',
'description' => 'description',
'extends' => 'extends',
'extendsinterfaces' => 'extendsinterfaces',
'guid' => 'guid',
'head' => 'head',
'use_selection' => 'use_selection',
'implements' => 'implements',
'load_selection' => 'load_selection',
'name' => 'name',
'power_version' => 'power_version',
'system_name' => 'system_name',
'type' => 'type',
'namespace' => 'namespace',
'composer' => 'composer',
'add_licensing_template' => 'add_licensing_template',
'licensing_template' => 'licensing_template',
'main_class_code' => 'main_class_code'
];
/**
* The index map
*
* @var array
* @since 5.0.3
*/
protected array $index_map = [
'name' => 'index_map_IndexName',
'type' => 'index_map_TypeName',
'namespace' => 'index_map_NameSpace',
'code' => 'index_map_CodePath',
'power' => 'index_map_PowerPath',
'settings' => 'index_map_IndexSettingsPath',
'path' => 'index_map_IndexPath',
'spk' => 'index_map_IndexKey',
'guid' => 'index_map_IndexGUID'
];
/**
* The item settings file path
*
* @var string
* @since 5.0.3
*/
protected string $settings_path = 'settings.json';
/**
* The index settings file path
*
* @var string
* @since 5.0.3
*/
protected string $index_settings_path = 'super-powers.json';
/**
* The Parser Class.
*
* @var Parser|null
* @since 5.0.2
*/
protected ?Parser $parser;
/**
* Constructor.
*
* @param array $repos The active repos
* @param Grep $grep The Grep Class.
* @param Items $items The Items Class.
* @param ItemReadme $itemReadme The Item Readme Class.
* @param MainReadme $mainReadme The Main Readme Class.
* @param Git $git The Contents Class.
* @param string|null $table The table name.
* @param string|null $settingsPath The settings path.
* @param string|null $settingsIndexPath The index settings path.
* @param Parser|null $parser The Parser Class.
*
* @since 3.2.2
*/
public function __construct(array $repos, Grep $grep, Items $items,
ItemReadme $itemReadme, MainReadme $mainReadme, Git $git,
?string $table = null, ?string $settingsPath = null,
?string $settingsIndexPath = null, ?Parser $parser = null)
{
parent::__construct($repos, $grep, $items, $itemReadme, $mainReadme,
$git, $table, $settingsPath, $settingsIndexPath);
$this->parser = $parser;
}
/**
* Map a single item value (extends)
*
* @param object $item The item to be mapped
* @param array $item The bucket to to place new values
* @param string $map The item map to be mapped
*
* @return void
* @since 5.0.2
*/
protected function mapItemValue_extends(object &$item, array &$power): void
{
if ($item->type !== 'interface')
{
$value = $item->extends ?? '';
$extends_custom = $item->extends_custom ?? null;
if ($value == -1 && $extends_custom !== null)
{
$power['extends_name'] = ClassfunctionHelper::safe(
$this->updatePlaceholders((string) $extends_custom)
);
$power['extends_custom'] = $extends_custom;
$power['extends'] = -1;
}
elseif (GuidHelper::valid($value))
{
$name = GuidHelper::item($value, 'power', 'a.name', 'componentbuilder');
if ($name !== null)
{
$power['extends_name'] = ClassfunctionHelper::safe(
$this->updatePlaceholders($name)
);
}
}
else
{
$power['extends'] = '';
}
// always rest these for normal classes
$power['extendsinterfaces'] = null;
$power['extendsinterfaces_custom'] = '';
}
}
/**
* Map a single item value (extendsinterfaces)
*
* @param object $item The item to be mapped
* @param array $item The bucket to to place new values
* @param string $map The item map to be mapped
*
* @return void
* @since 5.0.2
*/
protected function mapItemValue_extendsinterfaces(object &$item, array &$power): void
{
if ($item->type === 'interface')
{
$values = $item->extendsinterfaces ?? null;
if (!empty($values))
{
$values = (array) $values;
$extends_names = [];
$extendsinterfaces_custom = $item->extendsinterfaces_custom ?? null;
foreach ($values as $value)
{
if ($value == -1 && StringHelper::check($extendsinterfaces_custom))
{
$extends_names[] = ClassfunctionHelper::safe(
$this->updatePlaceholders($extendsinterfaces_custom)
);
$power['extendsinterfaces_custom'] = $extendsinterfaces_custom;
$extendsinterfaces_custom = null;
}
elseif (GuidHelper::valid($value))
{
$name = GuidHelper::item($value, 'power', 'a.name', 'componentbuilder');
if ($name !== null)
{
$extends_names[] = ClassfunctionHelper::safe(
$this->updatePlaceholders($name)
);
}
}
}
if ($extends_names !== [])
{
$power['extendsinterfaces'] = array_values($values);
$power['extends_name'] = implode(', ', $extends_names);
}
}
else
{
$power['extendsinterfaces'] = null;
$power['extendsinterfaces_custom'] = '';
}
// always rest these for interfaces
$power['extends'] = '';
$power['extends_custom'] = '';
}
}
/**
* Map a single item value (use_selection)
*
* @param object $item The item to be mapped
* @param array $item The bucket to to place new values
* @param string $map The item map to be mapped
*
* @return void
* @since 5.0.2
*/
protected function mapItemValue_use_selection(object &$item, array &$power): void
{
$value = $item->use_selection ?? null;
if (!empty($value))
{
$value = (array) $value;
$power['use_selection'] = $value;
}
else
{
$power['use_selection'] = null;
}
}
/**
* Map a single item value (load_selection)
*
* @param object $item The item to be mapped
* @param array $item The bucket to to place new values
* @param string $map The item map to be mapped
*
* @return void
* @since 5.0.2
*/
protected function mapItemValue_load_selection(object &$item, array &$power): void
{
$value = $item->load_selection ?? null;
if (!empty($value))
{
$value = (array) $value;
$power['load_selection'] = $value;
}
else
{
$power['load_selection'] = null;
}
}
/**
* Map a single item value (composer)
*
* @param object $item The item to be mapped
* @param array $item The bucket to to place new values
* @param string $map The item map to be mapped
*
* @return void
* @since 5.0.2
*/
protected function mapItemValue_composer(object &$item, array &$power): void
{
$value = $item->composer ?? null;
if (!empty($value))
{
$value = (array) $value;
$power['composer'] = array_values($value);
}
else
{
$power['composer'] = '';
}
}
/**
* Map a single item value (implements)
*
* @param object $item The item to be mapped
* @param array $item The bucket to to place new values
* @param string $map The item map to be mapped
*
* @return void
* @since 5.0.2
*/
protected function mapItemValue_implements(object &$item, array &$power): void
{
$values = $item->implements ?? '';
if (!empty($values))
{
$values = (array) $values;
$implement_names = [];
$implements_custom = $item->implements_custom ?? null;
foreach ($values as $value)
{
if ($value == -1 && StringHelper::check($implements_custom))
{
$implement_names[] = ClassfunctionHelper::safe(
$this->updatePlaceholders($implements_custom)
);
$implements_custom = null;
}
elseif (GuidHelper::valid($value))
{
$name = GuidHelper::item($value, 'power', 'a.name', 'componentbuilder');
if ($name !== null)
{
$implement_names[] = ClassfunctionHelper::safe(
$this->updatePlaceholders($name)
);
}
}
}
if ($implement_names !== [])
{
$power['implements'] = array_values($values);
$power['implement_names'] = $implement_names;
}
else
{
$power['implements'] = null;
}
}
}
/**
* update an existing item (if changed)
*
* @param object $item
* @param object $existing
* @param object $repo
*
* @return bool
* @since 5.0.3
*/
protected function updateItem(object $item, object $existing, object $repo): bool
{
// make sure there was a change
$sha = $existing->params->source[$repo->guid . '-settings'] ?? null;
$_existing = $this->mapItem($existing);
if ($sha === null || $this->areObjectsEqual($item, $_existing))
{
return false;
}
else
{
// strip these values form the settings
$code = (string) $item->main_class_code ?? '';
$extends_name = (string) $item->extends_name ?? '';
$implement_names = (string) $item->implement_names ?? '';
unset($item->main_class_code);
unset($item->extends_name);
unset($item->implement_names);
$this->git->update(
$repo->organisation, // The owner name.
$repo->repository, // The repository name.
'src/' . $item->guid . '/' . $this->getSettingsPath(), // The file path.
json_encode($item, JSON_PRETTY_PRINT), // The file content.
'Update ' . $item->system_name . ' settings', // The commit message.
$sha, // The blob SHA of the old file.
$repo->write_branch // The branch name.
);
$item->main_class_code = $code;
$item->extends_name = $extends_name;
$item->implement_names = $implement_names;
}
return $this->updatePower($item, $existing, $repo);
}
/**
* update an existing power code (if changed)
*
* @param object $item
* @param object $existing
* @param object $repo
*
* @return bool
* @since 5.0.3
*/
protected function updatePower(object $item, object $existing, object $repo): bool
{
// make sure there was a change
$sha = $existing->params->source[$repo->guid . '-power'] ?? null;
if ($sha === null)
{
return false;
}
// Calculate the new SHA from the current content
$power = $item->main_class_code ?? '';
$newSha = sha1("blob " . strlen($power) . "\0" . $power);
// Check if the new SHA matches the existing SHA
if ($sha === $newSha)
{
return false;
}
$this->git->update(
$repo->organisation, // The owner name.
$repo->repository, // The repository name.
'src/' . $item->guid . '/code.power', // The file path.
$power, // The file content.
'Update ' . $item->system_name . ' code', // The commit message.
$sha, // The blob SHA of the old file.
$repo->write_branch // The branch name.
);
return true;
}
/**
* create a new item
*
* @param object $item
* @param object $repo
*
* @return void
* @since 5.0.3
*/
protected function createItem(object $item, object $repo): void
{
// strip these values form the settings
$code = (string) $item->main_class_code ?? '';
$extends_name = (string) $item->extends_name ?? '';
$implement_names = (string) $item->implement_names ?? '';
unset($item->main_class_code);
unset($item->extends_name);
unset($item->implement_names);
$this->git->create(
$repo->organisation, // The owner name.
$repo->repository, // The repository name.
'src/' . $item->guid . '/' . $this->getSettingsPath(), // The file path.
json_encode($item, JSON_PRETTY_PRINT), // The file content.
'Create ' . $item->system_name . ' settings', // The commit message.
$repo->write_branch // The branch name.
);
$item->main_class_code = $code;
$item->extends_name = $extends_name;
$item->implement_names = $implement_names;
$this->createPower($item, $repo);
}
/**
* create a new power
*
* @param object $item
* @param object $repo
*
* @return void
* @since 5.0.3
*/
protected function createPower(object $item, object $repo): void
{
$this->git->create(
$repo->organisation, // The owner name.
$repo->repository, // The repository name.
'src/' . $item->guid . '/code.power', // The file path.
$item->main_class_code, // The file content.
'Create ' . $item->system_name . ' code', // The commit message.
$repo->write_branch // The branch name.
);
}
/**
* update an existing item readme
*
* @param object $item
* @param object $existing
* @param object $repo
*
* @return void
* @since 5.0.3
*/
protected function updateItemReadme(object $item, object $existing, object $repo): void
{
// make sure there was a change
$sha = $existing->params->source[$repo->guid . '-readme'] ?? null;
if ($sha === null)
{
return;
}
if ($this->parser !== null)
{
$item->parsed_class_code = $this->parser->code($item->main_class_code);
}
$item->code_name = $this->index_map_IndexName($item);
$item->_namespace = $this->index_map_NameSpace($item);
$readme = $this->itemReadme->get($item);
$newSha = sha1("blob " . strlen($readme) . "\0" . $readme);
// Check if the new SHA matches the existing SHA
if ($sha === $newSha)
{
return;
}
$this->git->update(
$repo->organisation, // The owner name.
$repo->repository, // The repository name.
'src/' . $item->guid . '/README.md', // The file path.
$readme, // The file content.
'Update ' . $item->system_name . ' readme file', // The commit message.
$sha, // The blob SHA of the old file.
$repo->write_branch // The branch name.
);
}
/**
* create a new item readme
*
* @param object $item
* @param object $repo
*
* @return void
* @since 5.0.3
*/
protected function createItemReadme(object $item, object $repo): void
{
if ($this->parser !== null)
{
$item->parsed_class_code = $this->parser->code($item->main_class_code);
}
$item->code_name = $this->index_map_IndexName($item);
$item->_namespace = $this->index_map_NameSpace($item);
$this->git->create(
$repo->organisation, // The owner name.
$repo->repository, // The repository name.
'src/' . $item->guid . '/README.md', // The file path.
$this->itemReadme->get($item), // The file content.
'Create ' . $item->system_name . ' readme file', // The commit message.
$repo->write_branch // The branch name.
);
}
/**
* check that we have a target repo of this item
*
* @param object $item The item
* @param object $repo The current repo
*
* @return bool
* @since 5.0.3
*/
protected function targetRepo(object $item, object $repo): bool
{
if (!isset($item->approved) || $item->approved != 1 ||
!isset($item->approved_paths) || !is_array($item->approved_paths))
{
return false;
}
$repo_path = "{$repo->organisation}/{$repo->repository}";
foreach ($item->approved_paths as $approved_path)
{
if ($repo_path === $approved_path)
{
return true;
}
}
return false;
}
/**
* Get the item name for the index values
*
* @param object $item
*
* @return string|null
* @since 5.0.3
*/
protected function index_map_IndexName(object $item): ?string
{
$name = $item->name ?? null;
if ($name !== null)
{
return ClassfunctionHelper::safe(
$this->updatePlaceholders($name)
);
}
return null;
}
/**
* Get the item type for the index values
*
* @param object $item
*
* @return string|null
* @since 5.0.3
*/
protected function index_map_TypeName(object $item): ?string
{
return $item->type ?? null;
}
/**
* Get the item code path for the index values
*
* @param object $item
*
* @return string|null
* @since 5.0.3
*/
protected function index_map_CodePath(object $item): ?string
{
return $this->index_map_IndexPath($item) . '/code.php';
}
/**
* Get the item power path for the index values
*
* @param object $item
*
* @return string|null
* @since 5.0.3
*/
protected function index_map_PowerPath(object $item): ?string
{
return $this->index_map_IndexPath($item) . '/code.power';
}
/**
* Get the item namespace for the index values
*
* @param object $item
*
* @return string|null
* @since 5.0.3
*/
protected function index_map_NameSpace(object $item): ?string
{
return $this->getNamespace($item->namespace ?? '', $item->name ?? '');
}
/**
* Set the namespace for this power
*
* @param string $namespace The raw namespace
* @param string $className The class name
*
* @return string|null
* @since 5.0.3
*/
protected function getNamespace(string $namespace, string $className): ?string
{
// set namespace
$namespace = $this->updatePlaceholders($namespace);
// validate namespace
if (strpos($namespace, '\\') === false)
{
// we break out here
return null;
}
// setup the path array
$path_array = (array) explode('\\', $namespace);
// make sure it has two or more
if (ArrayHelper::check($path_array) <= 1)
{
// we break out here
return null;
}
// get the file and class name (the last value in array)
$file_name = array_pop($path_array);
// do we have src folders
if (strpos($file_name, '.') !== false)
{
// we have src folders in the namespace
$src_array = (array) explode('.', $file_name);
// get the file and class name (the last value in array)
$file_name = array_pop($src_array);
// namespace array
$namespace_array = [...$path_array, ...$src_array];
}
else
{
// namespace array
$namespace_array = $path_array;
}
// the last value is the same as the class name
if ($file_name !== $className)
{
// we break out here
return null;
}
// make sure the arrays are namespace safe
$namespace_array =
array_map(
fn($val) => $this->getCleanNamespace($val),
$namespace_array
);
// set the actual class namespace
return implode('\\', $namespace_array);
}
/**
* Get Clean Namespace without use or ; as part of the name space
*
* @param string $namespace The actual name space
*
* @return string
* @since 5.0.3
*/
protected function getCleanNamespace(string $namespace): string
{
// trim possible (use) or (;) or (starting or ending \) added to the namespace
return NamespaceHelper::safe(str_replace(['use ', ';'], '', $namespace));
}
}

View File

@ -18,7 +18,11 @@ use VDM\Joomla\Componentbuilder\Power\Config;
use VDM\Joomla\Componentbuilder\Table;
use VDM\Joomla\Componentbuilder\Power\Grep;
use VDM\Joomla\Componentbuilder\Power\Remote\Get;
use VDM\Joomla\Componentbuilder\Power\Remote\Set;
use VDM\Joomla\Componentbuilder\Power\Parser;
use VDM\Joomla\Componentbuilder\Power\Plantuml;
use VDM\Joomla\Componentbuilder\Power\Readme\Item as ItemReadme;
use VDM\Joomla\Componentbuilder\Power\Readme\Main as MainReadme;
/**
@ -50,8 +54,20 @@ class Power implements ServiceProviderInterface
$container->alias(Get::class, 'Power.Remote.Get')
->share('Power.Remote.Get', [$this, 'getRemoteGet'], true);
$container->alias(Set::class, 'Power.Remote.Set')
->share('Power.Remote.Set', [$this, 'getRemoteSet'], true);
$container->alias(Parser::class, 'Power.Parser')
->share('Power.Parser', [$this, 'getParser'], true);
$container->alias(Plantuml::class, 'Power.Plantuml')
->share('Power.Plantuml', [$this, 'getPlantuml'], true);
$container->alias(ItemReadme::class, 'Power.Readme.Item')
->share('Power.Readme.Item', [$this, 'getItemReadme'], true);
$container->alias(MainReadme::class, 'Power.Readme.Main')
->share('Power.Readme.Main', [$this, 'getMainReadme'], true);
}
/**
@ -113,6 +129,55 @@ class Power implements ServiceProviderInterface
);
}
/**
* Get The Remote Set Class.
*
* @param Container $container The DI container.
*
* @return Set
* @since 5.0.3
*/
public function getRemoteSet(Container $container): Set
{
return new Set(
$container->get('Config')->approved_paths,
$container->get('Power.Grep'),
$container->get('Data.Items'),
$container->get('Power.Readme.Item'),
$container->get('Power.Readme.Main'),
$container->get('Gitea.Repository.Contents'), null, null, null,
$container->get('Power.Parser')
);
}
/**
* Get The Readme Class.
*
* @param Container $container The DI container.
*
* @return ItemReadme
* @since 5.0.3
*/
public function getItemReadme(Container $container): ItemReadme
{
return new ItemReadme(
$container->get('Power.Plantuml')
);
}
/**
* Get The Readme Class.
*
* @param Container $container The DI container.
*
* @return MainReadme
* @since 5.0.3
*/
public function getMainReadme(Container $container): MainReadme
{
return new MainReadme();
}
/**
* Get The Parser Class.
*
@ -124,6 +189,19 @@ class Power implements ServiceProviderInterface
public function getParser(Container $container): Parser
{
return new Parser();
}
/**
* Get The Plantuml Class.
*
* @param Container $container The DI container.
*
* @return Plantuml
* @since 5.0.3
*/
public function getPlantuml(Container $container): Plantuml
{
return new Plantuml();
}
}

View File

@ -9104,6 +9104,22 @@ final class Table extends BaseTable implements Tableinterface
'key' => true,
],
],
'addplaceholders' => [
'name' => 'addplaceholders',
'label' => 'COM_COMPONENTBUILDER_REPOSITORY_ADDPLACEHOLDERS_LABEL',
'type' => 'subform',
'title' => false,
'list' => 'repositories',
'store' => 'json',
'tab_name' => 'Placeholders',
'db' => [
'type' => 'TEXT',
'default' => 'EMPTY',
'null_switch' => 'NOT NULL',
'unique_key' => false,
'key' => false,
],
],
'access_repo' => [
'name' => 'access_repo',
'label' => 'COM_COMPONENTBUILDER_REPOSITORY_ACCESS_REPO_LABEL',

View File

@ -13,6 +13,8 @@ namespace VDM\Joomla\Componentbuilder\Utilities;
use Joomla\CMS\Factory;
use VDM\Joomla\Utilities\JsonHelper;
use VDM\Joomla\Utilities\ArrayHelper;
/**
@ -45,6 +47,7 @@ abstract class RepoHelper
'username',
'target',
'access_repo',
'addplaceholders',
'guid'
)))
->from($db->quoteName('#__componentbuilder_repository'))
@ -66,13 +69,43 @@ abstract class RepoHelper
unset($item->token);
}
unset($item->access_repo);
$item->placeholders = self::setPlaceholders($item->addplaceholders ?? '');
unset($item->addplaceholders);
$path = $item->organisation . '/' . $item->repository;
$options[$path] = $item;
}
return $options;
}
return null;
}
/**
* set the placeholders for this repo
*
* @param string $placeholders The repo placeholders
*
* @return array The result set
* @since 5.0.3
**/
protected static function setPlaceholders(string $placeholders): array
{
$bucket = [];
if (JsonHelper::check($placeholders))
{
$placeholders = json_decode((string) $placeholders, true);
if (ArrayHelper::check($placeholders))
{
foreach ($placeholders as $row)
{
$bucket[$row['target']] = $row['value'];
}
}
}
return $bucket;
}
}

View File

@ -39,17 +39,19 @@ abstract class ObjectHelper
}
/**
* Compare two objects for equality based on their property values.
* Checks if two objects are equal by comparing their properties and values.
*
* Note that this method works only for simple objects that don't
* contain any nested objects or resource references. If you need
* to compare more complex objects, you may need to use a
* more advanced method such as serialization or reflection.
* This method converts both input objects to
* associative arrays, sorts the arrays by keys,
* and compares these sorted arrays.
*
* @param object|null $obj1 The first object to compare.
* @param object|null $obj2 The second object to compare.
* If the arrays are identical, the objects are considered equal.
*
* @return bool True if the objects have the same key-value pairs and false otherwise.
* @param object|null $obj1 The first object to compare.
* @param object|null $obj2 The second object to compare.
*
* @return bool True if the objects are equal, false otherwise.
* @since 5.0.2
*/
public static function equal(?object $obj1, ?object $obj2): bool
{
@ -62,17 +64,41 @@ abstract class ObjectHelper
return false;
}
// Convert the objects to arrays of their property values using get_object_vars.
$array1 = get_object_vars($obj1);
$array2 = get_object_vars($obj2);
// Convert both objects to associative arrays
$array1 = json_decode(json_encode($obj1), true);
$array2 = json_decode(json_encode($obj2), true);
// Compare the arrays using array_diff_assoc to detect any differences.
$diff1 = array_diff_assoc($array1, $array2);
$diff2 = array_diff_assoc($array2, $array1);
// Sort the arrays by keys
self::recursiveKsort($array1);
self::recursiveKsort($array2);
// If the arrays have the same key-value pairs, they will have no differences, so return true.
return empty($diff1) && empty($diff2);
// Compare the sorted arrays
return $array1 === $array2;
}
/**
* Recursively sorts an associative array by keys.
*
* This method will sort an associative array by its keys at all levels.
*
* @param array &$array The array to sort.
*
* @return void
* @since 5.0.2
*/
protected static function recursiveKsort(array &$array): void
{
// Sort the array by its keys
ksort($array);
// Recursively sort nested arrays
foreach ($array as &$value)
{
if (is_array($value))
{
self::recursiveKsort($value);
}
}
}
}