Release of v3.2.4-alpha1
Add push option to powers area.
This commit is contained in:
@ -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
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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',
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user