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:
Robot 2024-07-17 02:38:33 +02:00
parent 8ef7c8a4b3
commit 582d6535c7
Signed by untrusted user: Robot
GPG Key ID: 14DECD44E7E1BB95
78 changed files with 3356 additions and 1203 deletions

View File

@ -1,9 +1,8 @@
# v4.0.1-alpha7 # v4.0.1-beta1
- Add push options to Joomla Power - Fix subform set methods
- Complete the Joomla Power Init and Reset features - Improved the Joomla Power Push path
- Fix Gitea Contents class functions - Fix the metadata, metadesc, metakey database issue
- Last Alpha release (feature block)
# v4.0.1-alpha # v4.0.1-alpha
@ -19,6 +18,10 @@
- Add new subform classes - Add new subform classes
- Fix registry class methods return type - Fix registry class methods return type
- Update all list and custom fields to use the new layouts - Update all list and custom fields to use the new layouts
- Add push options to Joomla Power
- Complete the Joomla Power Init and Reset features
- Fix Gitea Contents class functions
- Last Alpha release (feature block)
# v4.0.0 # v4.0.0

View File

@ -20,7 +20,7 @@ use Joomla\CMS\Version;
use Joomla\CMS\HTML\HTMLHelper as Html; use Joomla\CMS\HTML\HTMLHelper as Html;
use Joomla\Filesystem\Folder; use Joomla\Filesystem\Folder;
use Joomla\Database\DatabaseInterface; use Joomla\Database\DatabaseInterface;
use VDM\Joomla\Componentbuilder\Table\Schema; use VDM\Joomla\Componentbuilder\Table\SchemaChecker;
// No direct access to this file // No direct access to this file
defined('_JEXEC') or die; defined('_JEXEC') or die;
@ -556,26 +556,23 @@ class Com_ComponentbuilderInstallerScript implements InstallerScriptInterface
if ($type === 'update') if ($type === 'update')
{ {
// Check if the class and method exist before attempting to call it.
if (class_exists('\VDM\Component\Componentbuilder\Administrator\Helper\ComponentbuilderHelper') &&
method_exists('\VDM\Component\Componentbuilder\Administrator\Helper\ComponentbuilderHelper', 'removeFolder'))
{
// path to the compiler folders
$jcb_powers = [];
$jcb_powers[] = JPATH_LIBRARIES . '/vendor_jcb/VDM.Joomla/src/Componentbuilder';
$jcb_powers[] = JPATH_LIBRARIES . '/jcb_powers/VDM.Joomla/src/Componentbuilder';
$jcb_powers[] = JPATH_LIBRARIES . '/jcb_powers/VDM.Joomla.FOF';
$jcb_powers[] = JPATH_LIBRARIES . '/jcb_powers/VDM.Joomla.Gitea';
$jcb_powers[] = JPATH_LIBRARIES . '/jcb_powers/VDM.Joomla.Openai';
$jcb_powers[] = JPATH_LIBRARIES . '/jcb_powers/VDM.Joomla.Wasabi';
$jcb_powers[] = JPATH_LIBRARIES . '/jcb_powers/VDM.Minify';
$jcb_powers[] = JPATH_LIBRARIES . '/jcb_powers/VDM.Psr';
// we always remove all the old files to avoid mismatching // all things to clear out
foreach ($jcb_powers as $jcb_power) $jcb_cleaner = [];
{ $jcb_cleaner[] = JPATH_ADMINISTRATOR . '/components/com_componentbuilder/helpers/compiler';
\VDM\Component\Componentbuilder\Administrator\Helper\ComponentbuilderHelper::removeFolder($jcb_power); $jcb_cleaner[] = JPATH_ADMINISTRATOR . '/components/com_componentbuilder/helpers/extrusion';
} $jcb_cleaner[] = JPATH_LIBRARIES . '/vendor_jcb/VDM.Joomla/src/Componentbuilder';
$jcb_cleaner[] = JPATH_LIBRARIES . '/jcb_powers/VDM.Joomla/src/Componentbuilder';
$jcb_cleaner[] = JPATH_LIBRARIES . '/jcb_powers/VDM.Joomla.FOF';
$jcb_cleaner[] = JPATH_LIBRARIES . '/jcb_powers/VDM.Joomla.Gitea';
$jcb_cleaner[] = JPATH_LIBRARIES . '/jcb_powers/VDM.Joomla.Openai';
$jcb_cleaner[] = JPATH_LIBRARIES . '/jcb_powers/VDM.Joomla.Wasabi';
$jcb_cleaner[] = JPATH_LIBRARIES . '/jcb_powers/VDM.Minify';
$jcb_cleaner[] = JPATH_LIBRARIES . '/jcb_powers/VDM.Psr';
foreach ($jcb_cleaner as $cleaner)
{
$this->removeFolder($cleaner);
} }
// Check that the required configuration are set for PHP // Check that the required configuration are set for PHP
@ -1525,7 +1522,10 @@ class Com_ComponentbuilderInstallerScript implements InstallerScriptInterface
// Check that the database is up-to date // Check that the database is up-to date
$this->databaseSchemaCheck($this->app); if ($this->classExists(SchemaChecker::class))
{
(new SchemaChecker())->run();
}
echo '<div style="background-color: #fff;" class="alert alert-info"><a target="_blank" href="https://dev.vdm.io" title="Component Builder"> echo '<div style="background-color: #fff;" class="alert alert-info"><a target="_blank" href="https://dev.vdm.io" title="Component Builder">
<img src="components/com_componentbuilder/assets/images/vdm-component.jpg"/> <img src="components/com_componentbuilder/assets/images/vdm-component.jpg"/>
@ -3261,12 +3261,15 @@ class Com_ComponentbuilderInstallerScript implements InstallerScriptInterface
// Check that the database is up-to date // Check that the database is up-to date
$this->databaseSchemaCheck($this->app); if ($this->classExists(SchemaChecker::class))
{
(new SchemaChecker())->run();
}
echo '<div style="background-color: #fff;" class="alert alert-info"><a target="_blank" href="https://dev.vdm.io" title="Component Builder"> echo '<div style="background-color: #fff;" class="alert alert-info"><a target="_blank" href="https://dev.vdm.io" title="Component Builder">
<img src="components/com_componentbuilder/assets/images/vdm-component.jpg"/> <img src="components/com_componentbuilder/assets/images/vdm-component.jpg"/>
</a> </a>
<h3>Upgrade to Version 4.0.1-alpha7 Was Successful! Let us know if anything is not working as expected.</h3></div>'; <h3>Upgrade to Version 4.0.1-beta1 Was Successful! Let us know if anything is not working as expected.</h3></div>';
// Add/Update component in the action logs extensions table. // Add/Update component in the action logs extensions table.
$this->setActionLogsExtensions(); $this->setActionLogsExtensions();
@ -4097,6 +4100,80 @@ class Com_ComponentbuilderInstallerScript implements InstallerScriptInterface
return true; return true;
} }
/**
* Remove folders with files (with ignore options)
*
* @param string $dir The path to the folder to remove.
* @param array|null $ignore The folders and files to ignore and not remove.
*
* @return bool True if all specified files/folders are removed, false otherwise.
* @since 3.2.2
*/
protected function removeFolder(string $dir, ?array $ignore = null): bool
{
if (!is_dir($dir))
{
return false;
}
$it = new \RecursiveDirectoryIterator($dir, \FilesystemIterator::SKIP_DOTS);
$it = new \RecursiveIteratorIterator($it, \RecursiveIteratorIterator::CHILD_FIRST);
// Remove trailing slash
$dir = rtrim($dir, '/');
foreach ($it as $file)
{
$filePath = $file->getPathname();
$relativePath = str_replace($dir . '/', '', $filePath);
if ($ignore !== null && in_array($relativePath, $ignore, true))
{
continue;
}
if ($file->isDir())
{
Folder::delete($filePath);
}
else
{
File::delete($filePath);
}
}
// Delete the root folder if there are no ignored files/folders left
if ($ignore === null || $this->isDirEmpty($dir, $ignore))
{
return Folder::delete($dir);
}
return true;
}
/**
* Check if a directory is empty considering ignored files/folders.
*
* @param string $dir The path to the folder to check.
* @param array $ignore The folders and files to ignore.
*
* @return bool True if the directory is empty or contains only ignored items, false otherwise.
* @since 3.2.1
*/
protected function isDirEmpty(string $dir, array $ignore): bool
{
$it = new \RecursiveDirectoryIterator($dir, \FilesystemIterator::SKIP_DOTS);
foreach ($it as $file)
{
$relativePath = str_replace($dir . '/', '', $file->getPathname());
if (!in_array($relativePath, $ignore, true))
{
return false;
}
}
return true;
}
/** /**
* Remove the files and folders in the given array from * Remove the files and folders in the given array from
* *
@ -4915,6 +4992,35 @@ class Com_ComponentbuilderInstallerScript implements InstallerScriptInterface
} }
} }
/**
* Ensures that a class in the namespace is available.
* If the class is not already loaded, it attempts to load it via the specified autoloader.
*
* @param string $className The fully qualified name of the class to check.
*
* @return bool True if the class exists or was successfully loaded, false otherwise.
* @since 4.0.1
*/
protected function classExists(string $className): bool
{
if (!class_exists($className, true))
{
// The power autoloader for this project (JPATH_ADMINISTRATOR) area.
$power_autoloader = JPATH_ADMINISTRATOR . '/components/com_componentbuilder/src/Helper/PowerloaderHelper.php';
if (file_exists($power_autoloader))
{
require_once $power_autoloader;
}
// Check again if the class now exists after requiring the autoloader
if (!class_exists($className, true))
{
return false;
}
}
return true;
}
/** /**
* Define the required limits with specific messages for success and warning scenarios * Define the required limits with specific messages for success and warning scenarios
* *
@ -5023,66 +5129,6 @@ class Com_ComponentbuilderInstallerScript implements InstallerScriptInterface
} }
} }
/**
* Make sure that the componentbuilder database schema is up to date.
*
* @return void
* @since 3.2.1
*/
protected function databaseSchemaCheck($app): void
{
// try to load the schema class
try
{
// make sure the class is loaded
$this->ensureClassExists(
Schema::class
);
// instantiate the schema class and check/update the database
$messages = (new Schema())->update();
}
catch (\Exception $e)
{
$app->enqueueMessage($e->getMessage(), 'warning');
return;
}
foreach ($messages as $message)
{
$app->enqueueMessage($message, 'message');
}
}
/**
* Ensures that a class in the namespace is available.
* If the class is not already loaded, it attempts to load it via the power autoloader.
*
* @param mixed $nameClass The name::class we are looking for.
*
* @return void
* @since 3.2.1
* @throws \Exception If the class could not be loaded.
*/
protected function ensureClassExists($nameClass): void
{
if (!class_exists($nameClass, true))
{
// The power autoloader for this project admin area.
$power_autoloader = JPATH_ADMINISTRATOR . '/components/com_componentbuilder/src/Helper/PowerloaderHelper.php';
if (file_exists($power_autoloader))
{
require_once $power_autoloader;
}
// Check again if the class now exists after requiring it
if (!class_exists($nameClass, true))
{
throw new \Exception("We failed to find/load the $nameClass");
}
}
}
/** /**
* Method to move folders into place. * Method to move folders into place.
* *

View File

@ -9,7 +9,7 @@ The Component Builder for [Joomla](https://extensions.joomla.org/extension/compo
Whether you're a seasoned [Joomla](https://extensions.joomla.org/extension/component-builder/) developer, or have just started, Component Builder will save you lots of time and money. A real must have! Whether you're a seasoned [Joomla](https://extensions.joomla.org/extension/component-builder/) developer, or have just started, Component Builder will save you lots of time and money. A real must have!
You can install it quite easily and with no limitations. On [gitea](https://git.vdm.dev/joomla/Component-Builder/tags) is the latest release (4.0.1-alpha7) with **ALL** its features and **ALL** concepts totally open-source and free! You can install it quite easily and with no limitations. On [gitea](https://git.vdm.dev/joomla/Component-Builder/tags) is the latest release (4.0.1-beta1) with **ALL** its features and **ALL** concepts totally open-source and free!
> Watch Quick Build of a Hello World component in [JCB on Youtube](https://www.youtube.com/watch?v=IQfsLYIeblk&list=PLQRGFI8XZ_wtGvPQZWBfDzzlERLQgpMRE&index=45) > Watch Quick Build of a Hello World component in [JCB on Youtube](https://www.youtube.com/watch?v=IQfsLYIeblk&list=PLQRGFI8XZ_wtGvPQZWBfDzzlERLQgpMRE&index=45)
@ -144,14 +144,14 @@ TODO
+ *Author*: [Llewellyn van der Merwe](mailto:joomla@vdm.io) + *Author*: [Llewellyn van der Merwe](mailto:joomla@vdm.io)
+ *Name*: [Component Builder](https://git.vdm.dev/joomla/Component-Builder) + *Name*: [Component Builder](https://git.vdm.dev/joomla/Component-Builder)
+ *First Build*: 30th April, 2015 + *First Build*: 30th April, 2015
+ *Last Build*: 8th July, 2024 + *Last Build*: 17th July, 2024
+ *Version*: 4.0.1-alpha7 + *Version*: 4.0.1-beta1
+ *Copyright*: Copyright (C) 2015 Vast Development Method. All rights reserved. + *Copyright*: Copyright (C) 2015 Vast Development Method. All rights reserved.
+ *License*: GNU General Public License version 2 or later; see LICENSE.txt + *License*: GNU General Public License version 2 or later; see LICENSE.txt
+ *Line count*: **764152** + *Line count*: **780724**
+ *Field count*: **2104** + *Field count*: **2104**
+ *File count*: **5402** + *File count*: **5463**
+ *Folder count*: **534** + *Folder count*: **540**
> This **component** was build with a [Joomla](https://extensions.joomla.org/extension/component-builder/) [Automated Component Builder](https://www.joomlacomponentbuilder.com). > This **component** was build with a [Joomla](https://extensions.joomla.org/extension/component-builder/) [Automated Component Builder](https://www.joomlacomponentbuilder.com).
> Developed by [Llewellyn van der Merwe](mailto:joomla@vdm.io) > Developed by [Llewellyn van der Merwe](mailto:joomla@vdm.io)

View File

@ -9,7 +9,7 @@ The Component Builder for [Joomla](https://extensions.joomla.org/extension/compo
Whether you're a seasoned [Joomla](https://extensions.joomla.org/extension/component-builder/) developer, or have just started, Component Builder will save you lots of time and money. A real must have! Whether you're a seasoned [Joomla](https://extensions.joomla.org/extension/component-builder/) developer, or have just started, Component Builder will save you lots of time and money. A real must have!
You can install it quite easily and with no limitations. On [gitea](https://git.vdm.dev/joomla/Component-Builder/tags) is the latest release (4.0.1-alpha7) with **ALL** its features and **ALL** concepts totally open-source and free! You can install it quite easily and with no limitations. On [gitea](https://git.vdm.dev/joomla/Component-Builder/tags) is the latest release (4.0.1-beta1) with **ALL** its features and **ALL** concepts totally open-source and free!
> Watch Quick Build of a Hello World component in [JCB on Youtube](https://www.youtube.com/watch?v=IQfsLYIeblk&list=PLQRGFI8XZ_wtGvPQZWBfDzzlERLQgpMRE&index=45) > Watch Quick Build of a Hello World component in [JCB on Youtube](https://www.youtube.com/watch?v=IQfsLYIeblk&list=PLQRGFI8XZ_wtGvPQZWBfDzzlERLQgpMRE&index=45)
@ -144,14 +144,14 @@ TODO
+ *Author*: [Llewellyn van der Merwe](mailto:joomla@vdm.io) + *Author*: [Llewellyn van der Merwe](mailto:joomla@vdm.io)
+ *Name*: [Component Builder](https://git.vdm.dev/joomla/Component-Builder) + *Name*: [Component Builder](https://git.vdm.dev/joomla/Component-Builder)
+ *First Build*: 30th April, 2015 + *First Build*: 30th April, 2015
+ *Last Build*: 8th July, 2024 + *Last Build*: 17th July, 2024
+ *Version*: 4.0.1-alpha7 + *Version*: 4.0.1-beta1
+ *Copyright*: Copyright (C) 2015 Vast Development Method. All rights reserved. + *Copyright*: Copyright (C) 2015 Vast Development Method. All rights reserved.
+ *License*: GNU General Public License version 2 or later; see LICENSE.txt + *License*: GNU General Public License version 2 or later; see LICENSE.txt
+ *Line count*: **764152** + *Line count*: **780724**
+ *Field count*: **2104** + *Field count*: **2104**
+ *File count*: **5402** + *File count*: **5463**
+ *Folder count*: **534** + *Folder count*: **540**
> This **component** was build with a [Joomla](https://extensions.joomla.org/extension/component-builder/) [Automated Component Builder](https://www.joomlacomponentbuilder.com). > This **component** was build with a [Joomla](https://extensions.joomla.org/extension/component-builder/) [Automated Component Builder](https://www.joomlacomponentbuilder.com).
> Developed by [Llewellyn van der Merwe](mailto:joomla@vdm.io) > Developed by [Llewellyn van der Merwe](mailto:joomla@vdm.io)

View File

@ -17,7 +17,7 @@ defined('_JEXEC') or die('Restricted access');
// No direct access to this file // No direct access to this file
defined('_JEXEC') or die('Restricted access'); defined('_JEXEC') or die('Restricted access');
###CUSTOM_POWER_AUTOLOADER### ###POWER_AUTOLOADER###
###ADMIN_HELPER_CLASS_HEADER### ###ADMIN_HELPER_CLASS_HEADER###

View File

@ -17,7 +17,7 @@ defined('_JEXEC') or die('Restricted access');
// No direct access to this file // No direct access to this file
defined('_JEXEC') or die('Restricted access'); defined('_JEXEC') or die('Restricted access');
###SITE_CUSTOM_POWER_AUTOLOADER### ###SITE_POWER_AUTOLOADER###
###SITE_HELPER_CLASS_HEADER### ###SITE_HELPER_CLASS_HEADER###

View File

@ -17,7 +17,7 @@ defined('_JEXEC') or die('Restricted access');
// No direct access to this file // No direct access to this file
defined('_JEXEC') or die('Restricted access'); defined('_JEXEC') or die('Restricted access');
###CUSTOM_POWER_AUTOLOADER### ###POWER_AUTOLOADER###
###ADMIN_COMPONENT_HEADER### ###ADMIN_COMPONENT_HEADER###

View File

@ -17,7 +17,7 @@ defined('_JEXEC') or die('Restricted access');
// No direct access to this file // No direct access to this file
defined('_JEXEC') or die('Restricted access'); defined('_JEXEC') or die('Restricted access');
###SITE_CUSTOM_POWER_AUTOLOADER### ###SITE_POWER_AUTOLOADER###
###SITE_COMPONENT_HEADER### ###SITE_COMPONENT_HEADER###

View File

@ -138,76 +138,77 @@ class Com_###Component###InstallerScript
} }
/** /**
* Remove folders with files * Remove folders with files (with ignore options)
* *
* @param string $dir The path to folder to remove * @param string $dir The path to the folder to remove.
* @param boolean $ignore The folders and files to ignore and not remove * @param array|null $ignore The folders and files to ignore and not remove.
*
* @return boolean True in all is removed
* *
* @return bool True if all specified files/folders are removed, false otherwise.
* @since 3.2.2
*/ */
protected function removeFolder($dir, $ignore = false) protected function removeFolder(string $dir, ?array $ignore = null): bool
{ {
if (Folder::exists($dir)) if (!is_dir($dir))
{ {
$it = new RecursiveDirectoryIterator($dir); return false;
$it = new RecursiveIteratorIterator($it, RecursiveIteratorIterator::CHILD_FIRST);
// remove ending /
$dir = rtrim($dir, '/');
// now loop the files & folders
foreach ($it as $file)
{
if ('.' === $file->getBasename() || '..' === $file->getBasename()) continue;
// set file dir
$file_dir = $file->getPathname();
// check if this is a dir or a file
if ($file->isDir())
{
$keeper = false;
if ($this->checkArray($ignore))
{
foreach ($ignore as $keep)
{
if (strpos($file_dir, $dir.'/'.$keep) !== false)
{
$keeper = true;
}
}
}
if ($keeper)
{
continue;
}
Folder::delete($file_dir);
}
else
{
$keeper = false;
if ($this->checkArray($ignore))
{
foreach ($ignore as $keep)
{
if (strpos($file_dir, $dir.'/'.$keep) !== false)
{
$keeper = true;
}
}
}
if ($keeper)
{
continue;
}
File::delete($file_dir);
}
}
// delete the root folder if not ignore found
if (!$this->checkArray($ignore))
{
return Folder::delete($dir);
}
return true;
} }
return false;
$it = new \RecursiveDirectoryIterator($dir, \FilesystemIterator::SKIP_DOTS);
$it = new \RecursiveIteratorIterator($it, \RecursiveIteratorIterator::CHILD_FIRST);
// Remove trailing slash
$dir = rtrim($dir, '/');
foreach ($it as $file)
{
$filePath = $file->getPathname();
$relativePath = str_replace($dir . '/', '', $filePath);
if ($ignore !== null && in_array($relativePath, $ignore, true))
{
continue;
}
if ($file->isDir())
{
Folder::delete($filePath);
}
else
{
File::delete($filePath);
}
}
// Delete the root folder if there are no ignored files/folders left
if ($ignore === null || $this->isDirEmpty($dir, $ignore))
{
return Folder::delete($dir);
}
return true;
}
/**
* Check if a directory is empty considering ignored files/folders.
*
* @param string $dir The path to the folder to check.
* @param array $ignore The folders and files to ignore.
*
* @return bool True if the directory is empty or contains only ignored items, false otherwise.
* @since 3.2.1
*/
protected function isDirEmpty(string $dir, array $ignore): bool
{
$it = new \RecursiveDirectoryIterator($dir, \FilesystemIterator::SKIP_DOTS);
foreach ($it as $file)
{
$relativePath = str_replace($dir . '/', '', $file->getPathname());
if (!in_array($relativePath, $ignore, true))
{
return false;
}
}
return true;
} }
/** /**
@ -216,6 +217,7 @@ class Com_###Component###InstallerScript
* @input array The array to check * @input array The array to check
* *
* @returns bool/int number of items in array on success * @returns bool/int number of items in array on success
* @since 3.2.2
*/ */
protected function checkArray($array, $removeEmptyString = false) protected function checkArray($array, $removeEmptyString = false)
{ {
@ -236,5 +238,29 @@ class Com_###Component###InstallerScript
return $nr; return $nr;
} }
return false; return false;
}
/**
* Ensures that a class in the namespace is available.
* If the class is not already loaded, it attempts to load it via the specified autoloader.
*
* @param string $className The fully qualified name of the class to check.
*
* @return bool True if the class exists or was successfully loaded, false otherwise.
* @since 3.2.2
*/
protected function classExists(string $className): bool
{
if (!class_exists($className, true))
{
###THREE_POWER_AUTOLOADER###
// Check again if the class now exists after requiring the autoloader
if (!class_exists($className, true))
{
return false;
}
}
return true;
}###INSTALLERMETHODS### }###INSTALLERMETHODS###
} }

View File

@ -15,7 +15,7 @@ defined('_JCB_TEMPLATE') or die;
###BOM### ###BOM###
namespace ###NAMESPACEPREFIX###\Component\###ComponentNamespace###\Administrator\Helper; namespace ###NAMESPACEPREFIX###\Component\###ComponentNamespace###\Administrator\Helper;
###CUSTOM_POWER_AUTOLOADER### ###POWER_AUTOLOADER###
###ADMIN_HELPER_CLASS_HEADER### ###ADMIN_HELPER_CLASS_HEADER###

View File

@ -14,7 +14,7 @@ defined('_JCB_TEMPLATE') or die;
?> ?>
###BOM### ###BOM###
###CUSTOM_POWER_AUTOLOADER### ###POWER_AUTOLOADER###
// (soon) use Joomla\CMS\Association\AssociationExtensionInterface; // (soon) use Joomla\CMS\Association\AssociationExtensionInterface;
use Joomla\CMS\Categories\CategoryFactoryInterface; use Joomla\CMS\Categories\CategoryFactoryInterface;
@ -55,10 +55,10 @@ return new class () implements ServiceProviderInterface
{ {
// (soon) $container->set(AssociationExtensionInterface::class, new AssociationsHelper()); // (soon) $container->set(AssociationExtensionInterface::class, new AssociationsHelper());
$container->registerServiceProvider(new CategoryFactory('\\###NAMESPACEPREFIX###\\Component\\###Component###')); $container->registerServiceProvider(new CategoryFactory('\\###NAMESPACEPREFIX###\\Component\\###ComponentNamespace###'));
$container->registerServiceProvider(new MVCFactory('\\###NAMESPACEPREFIX###\\Component\\###Component###')); $container->registerServiceProvider(new MVCFactory('\\###NAMESPACEPREFIX###\\Component\\###ComponentNamespace###'));
$container->registerServiceProvider(new ComponentDispatcherFactory('\\###NAMESPACEPREFIX###\\Component\\###Component###')); $container->registerServiceProvider(new ComponentDispatcherFactory('\\###NAMESPACEPREFIX###\\Component\\###ComponentNamespace###'));
$container->registerServiceProvider(new RouterFactory('\\###NAMESPACEPREFIX###\\Component\\###Component###')); $container->registerServiceProvider(new RouterFactory('\\###NAMESPACEPREFIX###\\Component\\###ComponentNamespace###'));
$container->set( $container->set(
ComponentInterface::class, ComponentInterface::class,

View File

@ -279,6 +279,80 @@ class Com_###Component###InstallerScript implements InstallerScriptInterface
return true; return true;
} }
/**
* Remove folders with files (with ignore options)
*
* @param string $dir The path to the folder to remove.
* @param array|null $ignore The folders and files to ignore and not remove.
*
* @return bool True if all specified files/folders are removed, false otherwise.
* @since 3.2.2
*/
protected function removeFolder(string $dir, ?array $ignore = null): bool
{
if (!is_dir($dir))
{
return false;
}
$it = new \RecursiveDirectoryIterator($dir, \FilesystemIterator::SKIP_DOTS);
$it = new \RecursiveIteratorIterator($it, \RecursiveIteratorIterator::CHILD_FIRST);
// Remove trailing slash
$dir = rtrim($dir, '/');
foreach ($it as $file)
{
$filePath = $file->getPathname();
$relativePath = str_replace($dir . '/', '', $filePath);
if ($ignore !== null && in_array($relativePath, $ignore, true))
{
continue;
}
if ($file->isDir())
{
Folder::delete($filePath);
}
else
{
File::delete($filePath);
}
}
// Delete the root folder if there are no ignored files/folders left
if ($ignore === null || $this->isDirEmpty($dir, $ignore))
{
return Folder::delete($dir);
}
return true;
}
/**
* Check if a directory is empty considering ignored files/folders.
*
* @param string $dir The path to the folder to check.
* @param array $ignore The folders and files to ignore.
*
* @return bool True if the directory is empty or contains only ignored items, false otherwise.
* @since 3.2.1
*/
protected function isDirEmpty(string $dir, array $ignore): bool
{
$it = new \RecursiveDirectoryIterator($dir, \FilesystemIterator::SKIP_DOTS);
foreach ($it as $file)
{
$relativePath = str_replace($dir . '/', '', $file->getPathname());
if (!in_array($relativePath, $ignore, true))
{
return false;
}
}
return true;
}
/** /**
* Remove the files and folders in the given array from * Remove the files and folders in the given array from
* *
@ -1095,5 +1169,29 @@ class Com_###Component###InstallerScript implements InstallerScriptInterface
); );
} }
} }
}
/**
* Ensures that a class in the namespace is available.
* If the class is not already loaded, it attempts to load it via the specified autoloader.
*
* @param string $className The fully qualified name of the class to check.
*
* @return bool True if the class exists or was successfully loaded, false otherwise.
* @since 4.0.1
*/
protected function classExists(string $className): bool
{
if (!class_exists($className, true))
{
###THREE_POWER_AUTOLOADER###
// Check again if the class now exists after requiring the autoloader
if (!class_exists($className, true))
{
return false;
}
}
return true;
}###INSTALLERMETHODS### }###INSTALLERMETHODS###
} }

View File

@ -15,7 +15,7 @@ defined('_JCB_TEMPLATE') or die;
###BOM### ###BOM###
namespace ###NAMESPACEPREFIX###\Component\###ComponentNamespace###\Site\Helper; namespace ###NAMESPACEPREFIX###\Component\###ComponentNamespace###\Site\Helper;
###SITE_CUSTOM_POWER_AUTOLOADER### ###SITE_POWER_AUTOLOADER###
###SITE_HELPER_CLASS_HEADER### ###SITE_HELPER_CLASS_HEADER###

View File

@ -7943,8 +7943,6 @@ COM_COMPONENTBUILDER_PROPERTY="Property"
COM_COMPONENTBUILDER_PROPERTY_ALREADY_SELECTED_TRY_ANOTHER="Property already selected, try another." COM_COMPONENTBUILDER_PROPERTY_ALREADY_SELECTED_TRY_ANOTHER="Property already selected, try another."
COM_COMPONENTBUILDER_PROPERTY_NAME="Property Name" COM_COMPONENTBUILDER_PROPERTY_NAME="Property Name"
COM_COMPONENTBUILDER_PROPERTY_VALUE="Property Value" COM_COMPONENTBUILDER_PROPERTY_VALUE="Property Value"
COM_COMPONENTBUILDER_PSUPER_POWERB_REPOSITORY_AT_BHTTPSGITVDMDEVSB_CAN_BE_USED_TO_OVERRIDE_ANY_POWERBR_BUT_HAS_NOT_YET_BEEN_SET_IN_YOUR_ACCOUNT_AT_HTTPSGITVDMDEVSBR_SMALLTHIS_IS_AND_OPTIONAL_FEATURESMALL="<p>Super Power</b> repository at <b>https://git.vdm.dev/%s</b> can be used to override any power!<br />But has not yet been set in your account at https://git.vdm.dev/%s<br /><small>This is and optional feature.</small>"
COM_COMPONENTBUILDER_PSUPER_POWERB_REPOSITORY_AT_BSSB_GAVE_THE_FOLLOWING_ERRORBR_SP="<p>Super Power</b> repository at <b>%s/%s</b> gave the following error!<br />%s</p>"
COM_COMPONENTBUILDER_PS_NAMING_MISMATCH_ERROR_SPPTHE_S_NAME_IS_BSB_AND_THE_ENDING_FILE_NAME_IN_THE_NAMESPACE_IS_BSB_THIS_IS_BAD_CONVENTION_PLEASE_SEE_A_HREFS_PSRFOURA_FOR_MORE_INFOPPA_HREFSCLICK_HEREA_TO_FIX_THIS_ISSUEP="<p>%s naming mismatch error (%s)</p><p>The %s name is <b>%s</b> and the ending file name in the namespace is <b>%s</b>. This is bad convention, please see <a href=%s >psr-4</a> for more info.</p><p><a href=%s>Click here</a> to fix this issue.</p>" COM_COMPONENTBUILDER_PS_NAMING_MISMATCH_ERROR_SPPTHE_S_NAME_IS_BSB_AND_THE_ENDING_FILE_NAME_IN_THE_NAMESPACE_IS_BSB_THIS_IS_BAD_CONVENTION_PLEASE_SEE_A_HREFS_PSRFOURA_FOR_MORE_INFOPPA_HREFSCLICK_HEREA_TO_FIX_THIS_ISSUEP="<p>%s naming mismatch error (%s)</p><p>The %s name is <b>%s</b> and the ending file name in the namespace is <b>%s</b>. This is bad convention, please see <a href=%s >psr-4</a> for more info.</p><p><a href=%s>Click here</a> to fix this issue.</p>"
COM_COMPONENTBUILDER_PUBLIC_ACCESS="Public Access" COM_COMPONENTBUILDER_PUBLIC_ACCESS="Public Access"
COM_COMPONENTBUILDER_PUBLISHED="Published" COM_COMPONENTBUILDER_PUBLISHED="Published"

View File

@ -109,8 +109,8 @@ CREATE TABLE IF NOT EXISTS `#__componentbuilder_joomla_component` (
`access` INT(10) unsigned NOT NULL DEFAULT 0, `access` INT(10) unsigned NOT NULL DEFAULT 0,
`ordering` INT(11) NOT NULL DEFAULT 0, `ordering` INT(11) NOT NULL DEFAULT 0,
`metakey` TEXT, `metakey` TEXT,
`metadesc` TEXT NOT NULL, `metadesc` TEXT,
`metadata` TEXT NOT NULL, `metadata` TEXT,
PRIMARY KEY (`id`), PRIMARY KEY (`id`),
KEY `idx_system_name` (`system_name`), KEY `idx_system_name` (`system_name`),
KEY `idx_name_code` (`name_code`), KEY `idx_name_code` (`name_code`),
@ -2469,7 +2469,7 @@ INSERT INTO `#__componentbuilder_repository` (`id`, `system_name`, `organisation
(8, 'Minify', 'joomla', 'minify', 1, 1, 'https://git.vdm.dev', '6c741f48-a192-4e17-a932-df552164cffb', 'master', 1, 8, 1, '2024-06-15 17:43:09', '2024-06-10 11:03:30', ''), (8, 'Minify', 'joomla', 'minify', 1, 1, 'https://git.vdm.dev', '6c741f48-a192-4e17-a932-df552164cffb', 'master', 1, 8, 1, '2024-06-15 17:43:09', '2024-06-10 11:03:30', ''),
(9, 'psr', 'joomla', 'psr', 1, 1, 'https://git.vdm.dev', 'bfaa857a-df24-4d8c-97c3-1da4167a2bc8', 'master', 1, 9, 1, '2024-06-15 17:43:09', '2024-06-10 11:03:41', ''), (9, 'psr', 'joomla', 'psr', 1, 1, 'https://git.vdm.dev', 'bfaa857a-df24-4d8c-97c3-1da4167a2bc8', 'master', 1, 9, 1, '2024-06-15 17:43:09', '2024-06-10 11:03:41', ''),
(10, 'fof', 'joomla', 'fof', 1, 1, 'https://git.vdm.dev', 'dd591247-1215-4faf-8a00-1f294768ba13', 'master', 1, 10, 1, '2024-06-15 17:43:09', '2024-06-10 11:03:47', ''), (10, 'fof', 'joomla', 'fof', 1, 1, 'https://git.vdm.dev', 'dd591247-1215-4faf-8a00-1f294768ba13', 'master', 1, 10, 1, '2024-06-15 17:43:09', '2024-06-10 11:03:47', ''),
(12, 'Joomla Powers', 'joomla', 'joomla-powers', 2, 1, 'https://git.vdm.dev', 'dfba58ef-f823-43d4-ab73-865fdaf09294', 'master', 1, 12, 1, '2024-07-08 20:29:15', '2024-07-08 14:07:31', ''); (12, 'Joomla Powers', 'joomla', 'joomla-powers', 2, 1, 'https://git.vdm.dev', 'dfba58ef-f823-43d4-ab73-865fdaf09294', 'master', 1, 12, '', '2024-07-16 22:05:16', '2024-07-08 14:07:31', '');
-- --
-- Dumping data for table `#__componentbuilder_help_document` -- Dumping data for table `#__componentbuilder_help_document`

View File

@ -108,7 +108,7 @@ class Joomla_powerController extends FormController
elseif($user->authorise('power.reset', 'com_componentbuilder')) elseif($user->authorise('power.reset', 'com_componentbuilder'))
{ {
try { try {
if (JoomlaPowerFactory::_('Joomlapower')->reset([$guid])) if (JoomlaPowerFactory::_('Joomla.Power.Remote.Get')->reset([$guid]))
{ {
// set success message // set success message
$message = '<h1>'.Text::_('COM_COMPONENTBUILDER_SUCCESS').'</h1>'; $message = '<h1>'.Text::_('COM_COMPONENTBUILDER_SUCCESS').'</h1>';
@ -183,7 +183,7 @@ class Joomla_powerController extends FormController
elseif($user->authorise('power.push', 'com_componentbuilder')) elseif($user->authorise('power.push', 'com_componentbuilder'))
{ {
try { try {
if (JoomlaPowerFactory::_('Joomla.Power.Repository')->set([$guid])) if (JoomlaPowerFactory::_('Joomla.Power.Remote.Set')->items([$guid]))
{ {
// set success message // set success message
$message = '<h1>'.Text::_('COM_COMPONENTBUILDER_SUCCESS').'</h1>'; $message = '<h1>'.Text::_('COM_COMPONENTBUILDER_SUCCESS').'</h1>';

View File

@ -83,7 +83,7 @@ class Joomla_powersController extends AdminController
if($user->authorise('power.init', 'com_componentbuilder')) if($user->authorise('power.init', 'com_componentbuilder'))
{ {
try { try {
if (JoomlaPowerFactory::_('Joomlapower')->init()) if (JoomlaPowerFactory::_('Joomla.Power.Remote.Get')->init())
{ {
// set success message // set success message
$message = '<h1>' . Text::_('COM_COMPONENTBUILDER_SUCCESSFULLY_INITIALIZED_ALL_REMOTE_JOOMLA_POWERS') . '</h1>'; $message = '<h1>' . Text::_('COM_COMPONENTBUILDER_SUCCESSFULLY_INITIALIZED_ALL_REMOTE_JOOMLA_POWERS') . '</h1>';
@ -158,7 +158,7 @@ class Joomla_powersController extends AdminController
$guids = GetHelper::vars('joomla_power', $pks, 'id', 'guid'); $guids = GetHelper::vars('joomla_power', $pks, 'id', 'guid');
try { try {
if (JoomlaPowerFactory::_('Joomlapower')->reset($guids)) if (JoomlaPowerFactory::_('Joomla.Power.Remote.Get')->reset($guids))
{ {
// set success message // set success message
$message = '<h1>'.Text::_('COM_COMPONENTBUILDER_SUCCESS').'</h1>'; $message = '<h1>'.Text::_('COM_COMPONENTBUILDER_SUCCESS').'</h1>';
@ -237,7 +237,7 @@ class Joomla_powersController extends AdminController
$guids = GetHelper::vars('joomla_power', $pks, 'id', 'guid'); $guids = GetHelper::vars('joomla_power', $pks, 'id', 'guid');
try { try {
if (JoomlaPowerFactory::_('Joomla.Power.Repository')->set($guids)) if (JoomlaPowerFactory::_('Joomla.Power.Remote.Set')->items($guids))
{ {
// set success message // set success message
$message = '<h1>'.Text::_('COM_COMPONENTBUILDER_SUCCESS').'</h1>'; $message = '<h1>'.Text::_('COM_COMPONENTBUILDER_SUCCESS').'</h1>';

View File

@ -107,7 +107,7 @@ class PowerController extends FormController
} }
elseif($user->authorise('power.reset', 'com_componentbuilder')) elseif($user->authorise('power.reset', 'com_componentbuilder'))
{ {
if (PowerFactory::_('Superpower')->reset([$guid])) if (PowerFactory::_('Power.Remote.Get')->reset([$guid]))
{ {
// set success message // set success message
$message = '<h1>'.Text::_('COM_COMPONENTBUILDER_SUCCESS').'</h1>'; $message = '<h1>'.Text::_('COM_COMPONENTBUILDER_SUCCESS').'</h1>';

View File

@ -138,7 +138,7 @@ class PowersController extends AdminController
if($user->authorise('power.init', 'com_componentbuilder')) if($user->authorise('power.init', 'com_componentbuilder'))
{ {
if (PowerFactory::_('Superpower')->init()) if (PowerFactory::_('Power.Remote.Get')->init())
{ {
// set success message // set success message
$message = '<h1>' . Text::_('COM_COMPONENTBUILDER_SUCCESSFULLY_INITIALIZED_ALL_REMOTE_POWERS') . '</h1>'; $message = '<h1>' . Text::_('COM_COMPONENTBUILDER_SUCCESSFULLY_INITIALIZED_ALL_REMOTE_POWERS') . '</h1>';
@ -208,7 +208,7 @@ class PowersController extends AdminController
{ {
$guids = GetHelper::vars('power', $pks, 'id', 'guid'); $guids = GetHelper::vars('power', $pks, 'id', 'guid');
if (PowerFactory::_('Superpower')->reset($guids)) if (PowerFactory::_('Power.Remote.Get')->reset($guids))
{ {
// set success message // set success message
$message = '<h1>'.Text::_('COM_COMPONENTBUILDER_SUCCESS').'</h1>'; $message = '<h1>'.Text::_('COM_COMPONENTBUILDER_SUCCESS').'</h1>';

View File

@ -1,15 +1,15 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<extension type="component" version="4.0" method="upgrade"> <extension type="component" version="4.0" method="upgrade">
<name>COM_COMPONENTBUILDER</name> <name>COM_COMPONENTBUILDER</name>
<creationDate>8th July, 2024</creationDate> <creationDate>17th July, 2024</creationDate>
<author>Llewellyn van der Merwe</author> <author>Llewellyn van der Merwe</author>
<authorEmail>joomla@vdm.io</authorEmail> <authorEmail>joomla@vdm.io</authorEmail>
<authorUrl>https://dev.vdm.io</authorUrl> <authorUrl>https://dev.vdm.io</authorUrl>
<copyright>Copyright (C) 2015 Vast Development Method. All rights reserved.</copyright> <copyright>Copyright (C) 2015 Vast Development Method. All rights reserved.</copyright>
<license>GNU General Public License version 2 or later; see LICENSE.txt</license> <license>GNU General Public License version 2 or later; see LICENSE.txt</license>
<version>4.0.1-alpha7</version> <version>4.0.1-beta1</version>
<description><![CDATA[ <description><![CDATA[
<h1>Component Builder (v.4.0.1-alpha7)</h1> <h1>Component Builder (v.4.0.1-beta1)</h1>
<div style="clear: both;"></div> <div style="clear: both;"></div>
<p>The Component Builder for [Joomla](https://extensions.joomla.org/extension/component-builder/) is highly advanced tool that is truly able to build extremely complex components in a fraction of the time. <p>The Component Builder for [Joomla](https://extensions.joomla.org/extension/component-builder/) is highly advanced tool that is truly able to build extremely complex components in a fraction of the time.

View File

@ -59,13 +59,13 @@
<element>pkg_component_builder</element> <element>pkg_component_builder</element>
<type>package</type> <type>package</type>
<client>site</client> <client>site</client>
<version>4.0.1-alpha7</version> <version>4.0.1-beta1</version>
<infourl title="Component Builder!">https://dev.vdm.io</infourl> <infourl title="Component Builder!">https://dev.vdm.io</infourl>
<downloads> <downloads>
<downloadurl type="full" format="zip">https://git.vdm.dev/api/v1/repos/joomla/pkg-component-builder/archive/v4.0.1-alpha7.zip</downloadurl> <downloadurl type="full" format="zip">https://git.vdm.dev/api/v1/repos/joomla/pkg-component-builder/archive/v4.0.1-beta1.zip</downloadurl>
</downloads> </downloads>
<tags> <tags>
<tag>alpha</tag> <tag>beta</tag>
</tags> </tags>
<maintainer>Llewellyn van der Merwe</maintainer> <maintainer>Llewellyn van der Merwe</maintainer>
<maintainerurl>https://dev.vdm.io</maintainerurl> <maintainerurl>https://dev.vdm.io</maintainerurl>

View File

@ -15,6 +15,7 @@ namespace VDM\Joomla\Gitea\Abstraction;
use VDM\Joomla\Gitea\Utilities\Http; use VDM\Joomla\Gitea\Utilities\Http;
use VDM\Joomla\Gitea\Utilities\Uri; use VDM\Joomla\Gitea\Utilities\Uri;
use VDM\Joomla\Gitea\Utilities\Response; use VDM\Joomla\Gitea\Utilities\Response;
use VDM\Joomla\Interfaces\Git\ApiInterface;
/** /**
@ -22,7 +23,7 @@ use VDM\Joomla\Gitea\Utilities\Response;
* *
* @since 3.2.0 * @since 3.2.0
*/ */
abstract class Api abstract class Api implements ApiInterface
{ {
/** /**
* The Http class * The Http class

View File

@ -12,6 +12,7 @@
namespace VDM\Joomla\Gitea\Repository; namespace VDM\Joomla\Gitea\Repository;
use VDM\Joomla\Interfaces\Git\Repository\ContentsInterface;
use VDM\Joomla\Gitea\Abstraction\Api; use VDM\Joomla\Gitea\Abstraction\Api;
@ -20,7 +21,7 @@ use VDM\Joomla\Gitea\Abstraction\Api;
* *
* @since 3.2.0 * @since 3.2.0
*/ */
class Contents extends Api class Contents extends Api implements ContentsInterface
{ {
/** /**
* Get a file from a repository. * Get a file from a repository.
@ -345,20 +346,20 @@ class Contents extends Api
/** /**
* Delete a file in a repository. * Delete a file in a repository.
* *
* @param string $owner The owner name. * @param string $owner The owner name.
* @param string $repo The repository name. * @param string $repo The repository name.
* @param string $filepath The file path. * @param string $filepath The file path.
* @param string $message The commit message. * @param string $message The commit message.
* @param string $branch The branch name (optional). * @param string $sha The blob SHA of the file.
* @param string $sha The blob SHA of the file. * @param string|null $branch The branch name (optional).
* @param string $authorName The author name (optional). * @param string|null $authorName The author name (optional).
* @param string $authorEmail The author email (optional). * @param string|null $authorEmail The author email (optional).
* @param string $committerName The committer name (optional). * @param string|null $committerName The committer name (optional).
* @param string $committerEmail The committer email (optional). * @param string|null $committerEmail The committer email (optional).
* @param string $authorDate The author date (optional). * @param string|null $authorDate The author date (optional).
* @param string $committerDate The committer date (optional). * @param string|null $committerDate The committer date (optional).
* @param string $newBranch The new branch name (optional). * @param string|null $newBranch The new branch name (optional).
* @param bool $signoff Add a Signed-off-by trailer (optional). * @param bool|null $signoff Add a Signed-off-by trailer (optional).
* *
* @return object|null * @return object|null
* @since 3.2.0 * @since 3.2.0
@ -449,7 +450,7 @@ class Contents extends Api
// Send the delete request. // Send the delete request.
return $this->response->get( return $this->response->get(
$this->http->delete( $this->http->delete(
$this->uri->get($path), $this->uri->get($path), [], null,
json_encode($data) json_encode($data)
) )
); );
@ -458,10 +459,10 @@ class Contents extends Api
/** /**
* Get the EditorConfig definitions of a file in a repository. * Get the EditorConfig definitions of a file in a repository.
* *
* @param string $owner The owner name. * @param string $owner The owner name.
* @param string $repo The repository name. * @param string $repo The repository name.
* @param string $filepath The file path. * @param string $filepath The file path.
* @param string $ref The name of the commit/branch/tag. * @param string|null $ref The name of the commit/branch/tag.
* *
* @return string|null * @return string|null
* @since 3.2.0 * @since 3.2.0

View File

@ -13,9 +13,11 @@ namespace VDM\Joomla\Gitea\Utilities;
use Joomla\CMS\Http\Http as JoomlaHttp; use Joomla\CMS\Http\Http as JoomlaHttp;
use Joomla\CMS\Uri\Uri;
use Joomla\Registry\Registry; use Joomla\Registry\Registry;
/** /**
* The Gitea Http * The Gitea Http
* *

View File

@ -13,9 +13,12 @@ namespace VDM\Joomla\Abstraction;
use Joomla\CMS\Factory; use Joomla\CMS\Factory;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Filesystem\Folder; use Joomla\CMS\Filesystem\Folder;
use Joomla\CMS\Application\CMSApplication; use Joomla\CMS\Application\CMSApplication;
use VDM\Joomla\Gitea\Repository\Contents; use VDM\Joomla\Gitea\Repository\Contents;
use VDM\Joomla\Utilities\FileHelper;
use VDM\Joomla\Utilities\JsonHelper;
use VDM\Joomla\Interfaces\GrepInterface; use VDM\Joomla\Interfaces\GrepInterface;
@ -24,7 +27,7 @@ use VDM\Joomla\Interfaces\GrepInterface;
* *
* The Grep feature will try to find your power in the repositories listed in the global * The Grep feature will try to find your power in the repositories listed in the global
* Options of JCB in the super powers tab, and if it can't be found there will try the global core * Options of JCB in the super powers tab, and if it can't be found there will try the global core
* Super powers of JCB. All searches are performed according the the [algorithm:cascading] * Super powers of JCB. All searches are performed according the [algorithm:cascading]
* See documentation for more details: https://git.vdm.dev/joomla/super-powers/wiki * See documentation for more details: https://git.vdm.dev/joomla/super-powers/wiki
* *
* @since 3.2.1 * @since 3.2.1
@ -34,7 +37,7 @@ abstract class Grep implements GrepInterface
/** /**
* The local path * The local path
* *
* @var string * @var string|null
* @since 3.2.0 * @since 3.2.0
**/ **/
public ?string $path; public ?string $path;
@ -42,7 +45,7 @@ abstract class Grep implements GrepInterface
/** /**
* All approved paths * All approved paths
* *
* @var array * @var array|null
* @since 3.2.0 * @since 3.2.0
**/ **/
public ?array $paths; public ?array $paths;
@ -63,6 +66,22 @@ abstract class Grep implements GrepInterface
**/ **/
protected string $branch_field = 'read_branch'; protected string $branch_field = 'read_branch';
/**
* The target default branch name
*
* @var string|null
* @since 3.2.2
**/
protected ?string $branch_name = null;
/**
* The index file path
*
* @var string
* @since 3.2.2
*/
protected string $index_path = 'index.json';
/** /**
* Gitea Repository Contents * Gitea Repository Contents
* *
@ -92,21 +111,65 @@ abstract class Grep implements GrepInterface
*/ */
public function __construct(Contents $contents, array $paths, ?string $path = null, ?CMSApplication $app = null) public function __construct(Contents $contents, array $paths, ?string $path = null, ?CMSApplication $app = null)
{ {
$this->paths = $paths;
$this->contents = $contents; $this->contents = $contents;
$this->paths = $paths;
$this->path = $path; $this->path = $path;
$this->app = $app ?: Factory::getApplication(); $this->app = $app ?: Factory::getApplication();
$this->init(); $this->initializeInstances();
} }
/** /**
* Get all remote powers GUID's * Get an item
*
* @param string $guid The global unique id of the item
* @param array|null $order The search order
* @param object|null $repo The repository object to search. If null, all repos will be searched.
*
* @return object|null
* @since 3.2.2
*/
public function get(string $guid, ?array $order = null, ?object $repo = null): ?object
{
$order = $order ?? $this->order;
if ($repo !== null)
{
return $this->searchSingleRepo($guid, $order, $repo);
}
return $this->searchAllRepos($guid, $order);
}
/**
* Check if an item exists in any repo or in a specific repo.
*
* @param string $guid The unique identifier for the item.
* @param object|null $repo The repository object to check against. If null, all repos will be checked.
* @param array|null $order The order of the targets to check. If null, the default order will be used.
*
* @return bool True if the item exists, false otherwise.
* @since 3.2.2
*/
public function exists(string $guid, ?object $repo = null, ?array $order = null): bool
{
$order = $order ?? $this->order;
if ($repo !== null)
{
return $this->itemExistsInRepo($guid, $repo, $order);
}
return $this->itemExistsInAllRepos($guid, $order);
}
/**
* Get all remote GUID's
* *
* @return array|null * @return array|null
* @since 3.2.0 * @since 3.2.0
*/ */
public function getRemotePowersGuid(): ?array public function getRemoteGuid(): ?array
{ {
if (!is_array($this->paths) || $this->paths === []) if (!is_array($this->paths) || $this->paths === [])
{ {
@ -117,7 +180,7 @@ abstract class Grep implements GrepInterface
foreach ($this->paths as $path) foreach ($this->paths as $path)
{ {
// Get remote index // Get remote index
$this->remoteIndex($path); $this->indexRemote($path);
if (isset($path->index) && is_object($path->index)) if (isset($path->index) && is_object($path->index))
{ {
@ -131,7 +194,7 @@ abstract class Grep implements GrepInterface
/** /**
* Set the branch field * Set the branch field
* *
* @param string $field The global unique id of the power * @param string $field The field to use to get the branch name from the data set
* *
* @return void * @return void
* @since 3.2.2 * @since 3.2.2
@ -142,28 +205,113 @@ abstract class Grep implements GrepInterface
} }
/** /**
* Get a power * Set the DEFAULT branch name (only used if branch field is not found)
* *
* @param string $guid The global unique id of the power * @param string|null $name The default branch to use if no name could be found
* @param array|null $order The search order *
* @return void
* @since 3.2.2
*/
public function setBranchDefaultName(?string $name): void
{
$this->branch_name = $name;
}
/**
* Set the index path
*
* @param string $indexPath The repository index path
*
* @return void
* @since 3.2.2
*/
public function setIndexPath(string $indexPath): void
{
$this->index_path = $indexPath;
}
/**
* Get the index of a repo
*
* @param string $guid The unique identifier for the repo.
* *
* @return object|null * @return object|null
* @since 3.2.0 * @since 3.2.2
*/ */
public function get(string $guid, ?array $order = null): ?object public function getRemoteIndex(string $guid): ?object
{ {
if ($order === null) if (!is_array($this->paths) || $this->paths === [] || empty($guid))
{ {
$order = $this->order; return null;
} }
// we can only search if we have paths foreach ($this->paths as $path)
if (is_array($this->paths) && $this->paths !== [])
{ {
foreach ($order as $target) if (!isset($path->guid) || $guid !== $path->guid)
{ {
if (($function_name = $this->getFunctionName($target)) !== null && continue;
($power = $this->{$function_name}($guid)) !== null) }
// Get remote index
$this->indexRemote($path);
if (isset($path->index) && is_object($path->index))
{
return $path->index;
}
}
return null;
}
/**
* Set repository messages and errors based on given conditions.
*
* @param string $message The message to set (if error)
* @param string $path Path value
* @param string $repository Repository name
* @param string $organisation Organisation name
* @param string|null $base Base URL
*
* @return void
* @since 3.2.0
*/
abstract protected function setRemoteIndexMessage(string $message, string $path, string $repository, string $organisation, ?string $base): void;
/**
* Get function name
*
* @param string $name The targeted area name
* @param string $type The type of function name
*
* @return string|null
* @since 3.2.0
*/
protected function getFunctionName(string $name, string $type = 'search'): ?string
{
$function_name = $type . ucfirst(strtolower($name));
return method_exists($this, $function_name) ? $function_name : null;
}
/**
* Search a single repository for an item
*
* @param string $guid The unique identifier for the item.
* @param array $order The order of the targets to check.
* @param object $repo The repository object to check against.
*
* @return object|null
* @since 3.2.2
*/
protected function searchSingleRepo(string $guid, array $order, object $repo): ?object
{
foreach ($order as $target)
{
if ($this->itemExists($guid, $repo, $target))
{
$functionName = $this->getFunctionName($target, 'get');
if ($functionName !== null && ($power = $this->{$functionName}($repo, $guid)) !== null)
{ {
return $power; return $power;
} }
@ -173,6 +321,251 @@ abstract class Grep implements GrepInterface
return null; return null;
} }
/**
* Search all repositories for an item
*
* @param string $guid The unique identifier for the item.
* @param object $repo The repository object to check against.
*
* @return object|null
* @since 3.2.2
*/
protected function searchAllRepos(string $guid, array $order): ?object
{
if (is_array($this->paths) && $this->paths !== [])
{
foreach ($order as $target)
{
$functionName = $this->getFunctionName($target);
if ($functionName !== null && ($power = $this->{$functionName}($guid)) !== null)
{
return $power;
}
}
}
return null;
}
/**
* Check if an item exists in a specific repository.
*
* @param string $guid The unique identifier for the item.
* @param object $repo The repository object to check against.
* @param array $order The order of the targets to check.
*
* @return bool True if the item exists, false otherwise.
* @since 3.2.2
*/
protected function itemExistsInRepo(string $guid, object $repo, array $order): bool
{
foreach ($order as $target)
{
if ($this->itemExists($guid, $repo, $target))
{
return true;
}
}
return false;
}
/**
* Check if an item exists in any of the repositories.
*
* @param string $guid The unique identifier for the item.
* @param array $order The order of the targets to check.
*
* @return bool True if the item exists, false otherwise.
* @since 3.2.2
*/
protected function itemExistsInAllRepos(string $guid, array $order): bool
{
// We can only search if we have paths
if (is_array($this->paths) && $this->paths !== [])
{
foreach ($order as $target)
{
foreach ($this->paths as $path)
{
if ($this->itemExists($guid, $path, $target))
{
return true;
}
}
}
}
return false;
}
/**
* Get the branch field
*
* @return string
* @since 3.2.2
*/
protected function getBranchField(): string
{
return $this->branch_field;
}
/**
* Get the branch default name
*
* @return string|null
* @since 3.2.2
*/
protected function getBranchDefaultName(): ?string
{
return $this->branch_name;
}
/**
* Get the branch name
*
* @param object $item The item path
*
* @return string|null
* @since 3.2.2
*/
protected function getBranchName(object $item): ?string
{
// get the branch field name
$branch_field = $this->getBranchField();
return $item->{$branch_field} ?? $this->getBranchDefaultName();
}
/**
* Get the index path
*
* @return string
* @since 3.2.2
*/
protected function getIndexPath(): string
{
return $this->index_path;
}
/**
* Check if an item exists in a specific repo and target.
*
* @param string $guid The unique identifier for the item.
* @param object $repo The repository object to check against.
* @param string $target The target to check within the repo.
*
* @return bool True if the item exists, false otherwise.
* @since 3.2.2
*/
protected function itemExists(string $guid, object &$repo, string $target): bool
{
if (($function_name = $this->getFunctionName($target, 'index')) !== null)
{
$this->{$function_name}($repo);
if (($function_name = $this->getFunctionName($target, 'exists')) !== null &&
$this->{$function_name}($guid, $repo))
{
return true;
}
}
return false;
}
/**
* Check if item exists locally
*
* @param string $guid The global unique id of the item
*
* @return object|null return path object
* @since 3.2.2
*/
protected function existsLocally(string $guid): ?object
{
// we can only search if we have paths
if ($this->path && $this->paths)
{
foreach ($this->paths as $path)
{
// get local index
$this->indexLocal($path);
if ($this->existsLocal($guid, $path))
{
return $path;
}
}
}
return null;
}
/**
* Check if item exists remotely
*
* @param string $guid The global unique id of the item
*
* @return object|null return path object
* @since 3.2.2
*/
protected function existsRemotely(string $guid): ?object
{
// we can only search if we have paths
if ($this->paths)
{
foreach ($this->paths as $path)
{
// get local index
$this->indexRemote($path);
if ($this->existsRemote($guid, $path))
{
return $path;
}
}
}
return null;
}
/**
* Check if item exists locally
*
* @param string $guid The global unique id of the item
* @param object $path The path object
*
* @return bool true if it exists
* @since 3.2.2
*/
protected function existsLocal(string $guid, object $path): bool
{
if (!empty($path->local) && isset($path->local->{$guid}))
{
return true;
}
return false;
}
/**
* Check if item exists remotely
*
* @param string $guid The global unique id of the item
* @param object $path The path object
*
* @return bool true if it exists
* @since 3.2.2
*/
protected function existsRemote(string $guid, object $path): bool
{
if (!empty($path->index) && isset($path->index->{$guid}))
{
return true;
}
return false;
}
/** /**
* Load the remote repository index of powers * Load the remote repository index of powers
* *
@ -181,21 +574,55 @@ abstract class Grep implements GrepInterface
* @return void * @return void
* @since 3.2.0 * @since 3.2.0
*/ */
abstract protected function remoteIndex(object &$path): void; protected function indexRemote(object &$path): void
{
if (isset($path->index))
{
return; // already set
}
try
{
// load the base and token if set
$this->contents->load_($path->base ?? null, $path->token ?? null);
$path->index = $this->contents->get($path->organisation, $path->repository, $this->getIndexPath(), $this->getBranchName($path));
}
catch (\Exception $e)
{
$path->index = null;
$this->setRemoteIndexMessage($e->getMessage(), $path->path, $path->repository, $path->organisation, $path->base ?? null);
}
finally
{
// reset back to the global base and token
$this->contents->reset_();
}
}
/** /**
* Get function name * Load the local repository index of powers
* *
* @param string $name The targeted function name * @param object $path The repository path details
* *
* @return string|null * @return void
* @since 3.2.0 * @since 3.2.0
*/ */
protected function getFunctionName(string $name): ?string protected function indexLocal(object &$path): void
{ {
$function_name = 'search' . ucfirst(strtolower($name)); if (isset($path->local) || !isset($path->full_path))
{
return;
}
return method_exists($this, $function_name) ? $function_name : null; if (($content = FileHelper::getContent($path->full_path . '/' . $this->getIndexPath(), null)) !== null &&
JsonHelper::check($content))
{
$path->local = json_decode($content);
return;
}
$path->local = null;
} }
/** /**
@ -204,7 +631,7 @@ abstract class Grep implements GrepInterface
* @return void * @return void
* @since 3.2.0 * @since 3.2.0
*/ */
protected function init(): void protected function initializeInstances(): void
{ {
if (is_array($this->paths) && $this->paths !== []) if (is_array($this->paths) && $this->paths !== [])
{ {
@ -216,12 +643,14 @@ abstract class Grep implements GrepInterface
// build the path // build the path
$path->path = trim($path->organisation) . '/' . trim($path->repository); $path->path = trim($path->organisation) . '/' . trim($path->repository);
// update the branch // get the branch field name
$branch_field = $this->getBranchField(); $branch_field = $this->getBranchField();
$branch = $path->{$branch_field} ?? null; // get the branch name
$branch = $this->getBranchName($path);
if ($branch === 'default' || empty($branch)) if ($branch === 'default' || empty($branch))
{ {
// will allow us to target the default branch as set by the git system
$path->{$branch_field} = null; $path->{$branch_field} = null;
} }
@ -240,14 +669,33 @@ abstract class Grep implements GrepInterface
} }
/** /**
* Get the branch field * Load the remote file
* *
* @return string * @param string $organisation The repository organisation
* @since 3.2.2 * @param string $repository The repository name
* @param string $path The repository path to file
* @param string|null $branch The repository branch name
*
* @return mixed
* @since 3.2.0
*/ */
public function getBranchField(): string protected function loadRemoteFile(string $organisation, string $repository, string $path, ?string $branch)
{ {
return $this->branch_field; try
{
$data = $this->contents->get($organisation, $repository, $path, $branch);
}
catch (\Exception $e)
{
$this->app->enqueueMessage(
Text::sprintf('COM_COMPONENTBUILDER_PFILE_AT_BSSB_GAVE_THE_FOLLOWING_ERRORBR_SP', $this->contents->api(), $path, $e->getMessage()),
'Error'
);
return null;
}
return $data;
} }
} }

View File

@ -9,20 +9,20 @@
* @license GNU General Public License version 2 or later; see LICENSE.txt * @license GNU General Public License version 2 or later; see LICENSE.txt
*/ */
namespace VDM\Joomla\Data; namespace VDM\Joomla\Abstraction\Remote;
use VDM\Joomla\Interfaces\GrepInterface as Grep; use VDM\Joomla\Interfaces\GrepInterface as Grep;
use VDM\Joomla\Interfaces\Data\ItemInterface as Item; use VDM\Joomla\Interfaces\Data\ItemInterface as Item;
use VDM\Joomla\Interfaces\Data\RemoteInterface; use VDM\Joomla\Interfaces\Remote\GetInterface;
/** /**
* Load data based on global unique ids from remote system * Get data based on global unique ids from remote system
* *
* @since 3.2.0 * @since 3.2.0
*/ */
class Remote implements RemoteInterface abstract class Get implements GetInterface
{ {
/** /**
* The Grep Class. * The Grep Class.
@ -90,7 +90,7 @@ class Remote implements RemoteInterface
*/ */
public function init(): bool public function init(): bool
{ {
if (($items = $this->grep->getRemotePowersGuid()) !== null) if (($items = $this->grep->getRemoteGuid()) !== null)
{ {
foreach($items as $guid) foreach($items as $guid)
{ {
@ -126,7 +126,7 @@ class Remote implements RemoteInterface
foreach($items as $guid) foreach($items as $guid)
{ {
if (!$this->load($guid, ['remote'])) if (!$this->item($guid, ['remote']))
{ {
$success = false; $success = false;
} }
@ -136,7 +136,7 @@ class Remote implements RemoteInterface
} }
/** /**
* Load a item * Load an item
* *
* @param string $guid The global unique id of the item * @param string $guid The global unique id of the item
* @param array $order The search order * @param array $order The search order
@ -145,7 +145,7 @@ class Remote implements RemoteInterface
* @return bool * @return bool
* @since 3.2.0 * @since 3.2.0
*/ */
public function load(string $guid, array $order = ['remote', 'local'], ?string $action = null): bool public function item(string $guid, array $order = ['remote', 'local'], ?string $action = null): bool
{ {
if (($item = $this->grep->get($guid, $order)) !== null) if (($item = $this->grep->get($guid, $order)) !== null)
{ {

View File

@ -0,0 +1,782 @@
<?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\Abstraction\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\Interfaces\Remote\SetInterface;
/**
* Set data based on global unique ids to remote repository
*
* @since 3.2.2
*/
abstract class Set implements SetInterface
{
/**
* The Grep Class.
*
* @var Grep
* @since 3.2.2
*/
protected Grep $grep;
/**
* The Items Class.
*
* @var Items
* @since 3.2.2
*/
protected Items $items;
/**
* The Item Readme Class.
*
* @var ItemReadme
* @since 3.2.2
*/
protected ItemReadme $itemReadme;
/**
* The Main Readme Class.
*
* @var MainReadme
* @since 3.2.2
*/
protected MainReadme $mainReadme;
/**
* 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;
/**
* Area Name
*
* @var string
* @since 3.2.1
*/
protected string $area;
/**
* The item map
*
* @var array
* @since 3.2.2
*/
protected array $map;
/**
* The index map
*
* @var array
* @since 3.2.2
*/
protected array $index_map;
/**
* The repo main settings
*
* @var array
* @since 3.2.2
*/
protected array $settings;
/**
* Prefix Key
*
* @var string
* @since 3.2.2
*/
protected string $prefix_key = 'Super---';
/**
* Suffix Key
*
* @var string
* @since 3.2.2
*/
protected string $suffix_key = '---Power';
/**
* The item settings file path
*
* @var string
* @since 3.2.2
*/
protected string $settings_path = 'item.json';
/**
* The index settings file path
*
* @var string
* @since 3.2.2
*/
protected string $index_settings_path = 'index.json';
/**
* 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.
*
* @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)
{
$this->repos = $repos;
$this->grep = $grep;
$this->items = $items;
$this->itemReadme = $itemReadme;
$this->mainReadme = $mainReadme;
$this->git = $git;
if ($table !== null)
{
$this->table = $table;
}
if ($settingsPath !== null)
{
$this->settings_path = $settingsPath;
}
if ($settingsIndexPath !== null)
{
$this->setIndexSettingsPath($settingsIndexPath);
}
if (empty($this->area))
{
$this->area = ucfirst(str_replace('_', ' ', $this->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 the current active area
*
* @param string $area The area that should be active
*
* @return self
* @since 3.2.2
*/
public function area(string $area): self
{
$this->area = ucfirst(str_replace('_', ' ', $area));
return $this;
}
/**
* Set the settings path
*
* @param string $settingsPath The repository settings path
*
* @return self
* @since 3.2.2
*/
public function setSettingsPath(string $settingsPath): self
{
$this->settings_path = $settingsPath;
return $this;
}
/**
* Set the index settings path
*
* @param string $settingsIndexPath The repository index settings path
*
* @return self
* @since 3.2.2
*/
public function setIndexSettingsPath(string $settingsIndexPath): self
{
$this->index_settings_path = $settingsIndexPath;
$this->grep->setIndexPath($settingsIndexPath);
return $this;
}
/**
* Save items remotely
*
* @param array $guids The global unique id of the item
*
* @return bool
* @throws \Exception
* @since 3.2.2
*/
public function items(array $guids): bool
{
if (!$this->canWrite())
{
throw new \Exception("At least one [{$this->getArea()}] content repository must be configured with a [Write Branch] value in the repositories area for the push function to operate correctly.");
}
// we reset the index settings
$this->settings = [];
if (($items = $this->getLocalItems($guids)) === null)
{
throw new \Exception("At least one valid local [{$this->getArea()}] must exist for the push function to operate correctly.");
}
foreach ($items as $item)
{
$this->save($item);
}
// update the repos main readme and index settings
if ($this->settings !== [])
{
foreach ($this->settings as $repo)
{
$this->saveRepoMainSettings($repo);
}
}
return true;
}
/**
* update an existing item (if changed)
*
* @param object $item
* @param object $existing
* @param object $repo
*
* @return bool
* @since 3.2.2
*/
abstract protected function updateItem(object $item, object $existing, object $repo): bool;
/**
* create a new item
*
* @param object $item
* @param object $repo
*
* @return void
* @since 3.2.2
*/
abstract protected function createItem(object $item, object $repo): void;
/**
* update an existing item readme
*
* @param object $item
* @param object $existing
* @param object $repo
*
* @return void
* @since 3.2.2
*/
abstract protected function updateItemReadme(object $item, object $existing, object $repo): void;
/**
* create a new item readme
*
* @param object $item
* @param object $repo
*
* @return void
* @since 3.2.2
*/
abstract protected function createItemReadme(object $item, object $repo): void;
/**
* Get the current active table
*
* @return string
* @since 3.2.2
*/
protected function getTable(): string
{
return $this->table;
}
/**
* Get the current active area
*
* @return string
* @since 3.2.2
*/
protected function getArea(): string
{
return $this->area;
}
/**
* Update/Create the repo main readme and index
*
* @param array $repoBucket
*
* @return void
* @since 3.2.2
*/
protected function saveRepoMainSettings(array $repoBucket): void
{
$repo = $repoBucket['repo'] ?? null;
$settings = $repoBucket['items'] ?? null;
if ($this->isInvalidIndexRepo($repo, $settings))
{
return;
}
$repoGuid = $repo->guid ?? null;
if (empty($repoGuid))
{
return;
}
$settings = $this->mergeIndexSettings($repoGuid, $settings);
$this->updateIndexMainFile(
$repo,
$this->getIndexSettingsPath(),
json_encode($settings, JSON_PRETTY_PRINT),
'Update main index file'
);
$this->updateIndexMainFile(
$repo,
'README.md',
$this->mainReadme->get($settings),
'Update main readme file'
);
}
/**
* Validate repository and settings
*
* @param mixed $repo
* @param mixed $settings
*
* @return bool
* @since 3.2.2
*/
protected function isInvalidIndexRepo($repo, $settings): bool
{
return empty($repo) || empty($settings);
}
/**
* Merge current settings with new settings
*
* @param string $repoGuid
* @param array $settings
*
* @return array
* @since 3.2.2
*/
protected function mergeIndexSettings(string $repoGuid, array $settings): array
{
$current_settings = $this->grep->getRemoteIndex($repoGuid);
if ($current_settings === null || (array) $current_settings === [])
{
return $settings;
}
$mergedSettings = [];
foreach ($current_settings as $guid => $setting)
{
$mergedSettings[$guid] = (array) $setting;
}
foreach ($settings as $guid => $setting)
{
$mergedSettings[$guid] = (array) $setting;
}
return $mergedSettings;
}
/**
* Update a file in the repository
*
* @param object $repo
* @param string $path
* @param string $content
* @param string $message
*
* @return void
* @since 3.2.2
*/
protected function updateIndexMainFile(object $repo, string $path,
string $content, string $message): void
{
$meta = $this->git->metadata(
$repo->organisation,
$repo->repository,
$path,
$repo->write_branch
);
if ($meta !== null && isset($meta->sha))
{
$this->git->update(
$repo->organisation,
$repo->repository,
$path,
$content,
$message,
$meta->sha,
$repo->write_branch
);
}
}
/**
* Get items
*
* @param array $guids The global unique id of the item
*
* @return array|null
* @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
*
* @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;
}
/**
* Save an item remotely
*
* @param object $item The item to save
*
* @return void
* @since 3.2.2
*/
protected function save(object $item): void
{
if (empty($item->guid))
{
return;
}
$index_item = null;
foreach ($this->repos as $key => $repo)
{
if (empty($repo->write_branch) || $repo->write_branch === 'default')
{
continue;
}
$this->git->load_($repo->base ?? null, $repo->token ?? null);
if (($existing = $this->grep->get($item->guid, ['remote'], $repo)) !== null)
{
if ($this->updateItem($item, $existing, $repo))
{
$this->updateItemReadme($item, $existing, $repo);
}
}
else
{
$this->createItem($item, $repo);
$this->createItemReadme($item, $repo);
$index_item ??= $this->getIndexItem($item);
if (!isset($this->settings[$key]))
{
$this->settings[$key] = ['repo' => $repo, 'items' => [$item->guid => $index_item]];
}
else
{
$this->settings[$key]['items'][$item->guid] = $index_item;
}
}
$this->git->reset_();
}
}
/**
* Get index values
*
* @param object $item The item
*
* @return array|null
* @since 3.2.0
*/
protected function getIndexItem(object $item): ?array
{
if (empty($this->index_map))
{
return null;
}
$index_item = [];
foreach ($this->index_map as $key => $function_name)
{
if (method_exists($this, $function_name))
{
$index_item[$key] = $this->{$function_name}($item);
}
}
return $index_item ?? 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;
}
/**
* Get the settings path
*
* @return string
* @since 3.2.2
*/
protected function getSettingsPath(): string
{
return $this->settings_path;
}
/**
* Get the index settings path
*
* @return string
* @since 3.2.2
*/
protected function getIndexSettingsPath(): string
{
return $this->index_settings_path;
}
//// index_map_ (area) /////////////////////////////////////////////
/**
* Get the item name for the index values
*
* @param object $item
*
* @return string|null
* @since 3.2.2
*/
protected function index_map_IndexName(object $item): ?string
{
return $item->system_name ?? null;
}
/**
* Get the item settings path for the index values
*
* @param object $item
*
* @return string
* @since 3.2.2
*/
protected function index_map_IndexSettingsPath(object $item): string
{
return "src/{$item->guid}/" . $this->getSettingsPath();
}
/**
* Get the item path for the index values
*
* @param object $item
*
* @return string
* @since 3.2.2
*/
protected function index_map_IndexPath(object $item): string
{
return "src/{$item->guid}";
}
/**
* Get the item JPK for the index values
*
* @param object $item
*
* @return string
* @since 3.2.2
*/
protected function index_map_IndexKey(object $item): string
{
return $this->prefix_key . str_replace('-', '_', $item->guid) . $this->suffix_key;
}
/**
* Get the item GUID for the index values
*
* @param object $item
*
* @return string
* @since 3.2.2
*/
protected function index_map_IndexGUID(object $item): string
{
return $item->guid;
}
}

View File

@ -0,0 +1,196 @@
<?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\Abstraction;
use Joomla\CMS\Factory;
use Joomla\CMS\Application\CMSApplication;
use VDM\Joomla\Interfaces\SchemaInterface as Schema;
use VDM\Joomla\Interfaces\Tableinterface as Table;
use VDM\Joomla\Utilities\ClassHelper;
use VDM\Joomla\Interfaces\SchemaCheckerInterface;
/**
* Schema Checker
*
* @since 3.2.2
*/
abstract class SchemaChecker implements SchemaCheckerInterface
{
/**
* The Table Class.
*
* @var Table|null
* @since 3.2.2
*/
protected ?Table $table;
/**
* The Schema Class.
*
* @var Schema|null
* @since 3.2.2
*/
protected ?Schema $schema;
/**
* Application object.
*
* @var CMSApplication
* @since 3.2.2
**/
protected CMSApplication $app;
/**
* Constructor.
*
* @param Schema|null $schema The Schema Class.
* @param Table|null $table The Table Class.
* @param CMSApplication|null $app The app object.
*
* @throws \Exception
* @since 3.2.2
*/
public function __construct(?Schema $schema = null, ?Table $table = null, ?CMSApplication $app = null)
{
$this->schema = $schema;
$this->table = $table;
$this->app = $app ?: Factory::getApplication();
// Validate classes are set
// Since this class is often called from outside a container
$this->initializeInstances();
// I don't care! I have more important thing to do, maybe later... (last updated in 1983 ;)
}
/**
* Make sure that the database schema is up-to-date.
*
* @return void
* @since 3.2.2
*/
public function run(): void
{
if ($this->schema === null)
{
$this->app->enqueueMessage('We failed to find/load the Schema class', 'warning');
return;
}
// try to load the update the tables with the schema class
try
{
$messages = $this->schema->update();
}
catch (\Exception $e)
{
$this->app->enqueueMessage($e->getMessage(), 'warning');
return;
}
foreach ($messages as $message)
{
$this->app->enqueueMessage($message, 'message');
}
}
/**
* Initialize the needed class instances if needed
*
* @return void
* @since 3.2.2
*/
protected function initializeInstances(): void
{
if ($this->schema !== null)
{
return;
}
if ($this->table === null)
{
$this->setTableInstance();
}
$this->setSchemaInstance();
}
/**
* set the schema class instance
*
* @return void
* @since 3.2.2
*/
protected function setSchemaInstance(): void
{
// make sure the class is loaded
if (ClassHelper::exists(
$this->getSchemaClass(), $this->getCode(), $this->getPowerPath()
))
{
// instantiate the schema class
$this->schema = new ($this->getSchemaClass())($this->table);
}
}
/**
* set the table class instance
*
* @return void
* @since 3.2.2
*/
protected function setTableInstance(): void
{
// make sure the class is loaded
if (ClassHelper::exists(
$this->getTableClass(), $this->getCode(), $this->getPowerPath()
))
{
// instantiate the table class
$this->table = new ($this->getTableClass())();
}
}
/**
* Get the targeted component code
*
* @return string
* @since 3.2.2
*/
abstract protected function getCode(): string;
/**
* Get the targeted component power path
*
* @return string
* @since 3.2.2
*/
abstract protected function getPowerPath(): string;
/**
* Get the fully qualified name of the schema class.
*
* @return string
* @since 3.2.2
*/
abstract protected function getSchemaClass(): string;
/**
* Get the fully qualified name of the table class.
*
* @return string
* @since 3.2.2
*/
abstract protected function getTableClass(): string;
}

View File

@ -23,7 +23,7 @@ use VDM\Joomla\Utilities\String\FieldHelper;
use VDM\Joomla\Componentbuilder\Compiler\Factory as Compiler; use VDM\Joomla\Componentbuilder\Compiler\Factory as Compiler;
use VDM\Joomla\Componentbuilder\Compiler\Config; use VDM\Joomla\Componentbuilder\Compiler\Config;
use VDM\Joomla\Componentbuilder\Compiler\Placeholder\Reverse; use VDM\Joomla\Componentbuilder\Compiler\Placeholder\Reverse;
use VDM\Joomla\Componentbuilder\Compiler\Power\Parser; use VDM\Joomla\Componentbuilder\Power\Parser;
use VDM\Joomla\Componentbuilder\Compiler\Interfaces\Customcode\GuiInterface; use VDM\Joomla\Componentbuilder\Compiler\Interfaces\Customcode\GuiInterface;

View File

@ -10476,14 +10476,30 @@ class Interpretation extends Fields
// check if default field was overwritten // check if default field was overwritten
if (!CFactory::_('Compiler.Builder.Field.Names')->isString($view . '.metadesc')) if (!CFactory::_('Compiler.Builder.Field.Names')->isString($view . '.metadesc'))
{ {
$db_ .= PHP_EOL . Indent::_(1) if (CFactory::_('Config')->get('joomla_version', 3) == 3)
. "`metadesc` TEXT NOT NULL,"; {
$db_ .= PHP_EOL . Indent::_(1)
. "`metadesc` TEXT NOT NULL,";
}
else
{
$db_ .= PHP_EOL . Indent::_(1)
. "`metadesc` TEXT,";
}
} }
// check if default field was overwritten // check if default field was overwritten
if (!CFactory::_('Compiler.Builder.Field.Names')->isString($view . '.metadata')) if (!CFactory::_('Compiler.Builder.Field.Names')->isString($view . '.metadata'))
{ {
$db_ .= PHP_EOL . Indent::_(1) if (CFactory::_('Config')->get('joomla_version', 3) == 3)
. "`metadata` TEXT NOT NULL,"; {
$db_ .= PHP_EOL . Indent::_(1)
. "`metadata` TEXT NOT NULL,";
}
else
{
$db_ .= PHP_EOL . Indent::_(1)
. "`metadata` TEXT,";
}
} }
// add to component dynamic fields // add to component dynamic fields
CFactory::_('Compiler.Builder.Component.Fields')->set($view . '.metakey', CFactory::_('Compiler.Builder.Component.Fields')->set($view . '.metakey',
@ -10495,8 +10511,7 @@ class Interpretation extends Fields
'store' => NULL, 'store' => NULL,
'tab_name' => 'publishing', 'tab_name' => 'publishing',
'db' => [ 'db' => [
'type' => 'TEXT', 'type' => 'TEXT'
'default' => ''
] ]
] ]
); );
@ -10509,8 +10524,7 @@ class Interpretation extends Fields
'store' => NULL, 'store' => NULL,
'tab_name' => 'publishing', 'tab_name' => 'publishing',
'db' => [ 'db' => [
'type' => 'TEXT', 'type' => 'TEXT'
'default' => ''
] ]
] ]
); );
@ -10523,8 +10537,7 @@ class Interpretation extends Fields
'store' => 'json', 'store' => 'json',
'tab_name' => 'publishing', 'tab_name' => 'publishing',
'db' => [ 'db' => [
'type' => 'TEXT', 'type' => 'TEXT'
'default' => ''
] ]
] ]
); );

View File

@ -19,7 +19,7 @@ use VDM\Joomla\Componentbuilder\Compiler\Config;
use VDM\Joomla\Componentbuilder\Compiler\Placeholder; use VDM\Joomla\Componentbuilder\Compiler\Placeholder;
use VDM\Joomla\Componentbuilder\Compiler\Customcode; use VDM\Joomla\Componentbuilder\Compiler\Customcode;
use VDM\Joomla\Componentbuilder\Compiler\Customcode\Gui; use VDM\Joomla\Componentbuilder\Compiler\Customcode\Gui;
use VDM\Joomla\Componentbuilder\JoomlaPower\Super as SuperPower; use VDM\Joomla\Componentbuilder\JoomlaPower\Remote\Get as SuperPower;
use VDM\Joomla\Utilities\ArrayHelper; use VDM\Joomla\Utilities\ArrayHelper;
use VDM\Joomla\Utilities\JsonHelper; use VDM\Joomla\Utilities\JsonHelper;
use VDM\Joomla\Utilities\GuidHelper; use VDM\Joomla\Utilities\GuidHelper;
@ -377,7 +377,7 @@ final class JoomlaPower implements PowerInterface
*/ */
private function handlePowerNotFound(string $guid): bool private function handlePowerNotFound(string $guid): bool
{ {
if (empty($this->retry[$guid]) && $this->superpower->load($guid, ['remote', 'local'])) if (empty($this->retry[$guid]) && $this->superpower->item($guid, ['remote', 'local']))
{ {
// Retry loading the power // Retry loading the power
unset($this->state[$guid]); unset($this->state[$guid]);

View File

@ -25,7 +25,7 @@ use VDM\Joomla\Componentbuilder\Compiler\Config;
use VDM\Joomla\Componentbuilder\Compiler\Placeholder; use VDM\Joomla\Componentbuilder\Compiler\Placeholder;
use VDM\Joomla\Componentbuilder\Compiler\Customcode; use VDM\Joomla\Componentbuilder\Compiler\Customcode;
use VDM\Joomla\Componentbuilder\Compiler\Customcode\Gui; use VDM\Joomla\Componentbuilder\Compiler\Customcode\Gui;
use VDM\Joomla\Componentbuilder\Power\Super as Superpower; use VDM\Joomla\Componentbuilder\Power\Remote\Get as Superpower;
use VDM\Joomla\Componentbuilder\Compiler\Interfaces\PowerInterface; use VDM\Joomla\Componentbuilder\Compiler\Interfaces\PowerInterface;
@ -1148,7 +1148,7 @@ class Power implements PowerInterface
$repo = $global_path . '/' . $path; $repo = $global_path . '/' . $path;
// set SuperPowerKey (spk) // set SuperPowerKey (spk)
$spk = 'Super_'.'_' . str_replace('-', '_', $guid) . '_'.'_Power'; $spk = 'Super---' . str_replace('-', '_', $guid) . '---Power';
// set the global super power // set the global super power
$this->superpowers[$repo][$guid] = [ $this->superpowers[$repo][$guid] = [

View File

@ -78,9 +78,17 @@ class Autoloader
$this->content->set('ADMIN_POWER_HELPER', ''); $this->content->set('ADMIN_POWER_HELPER', '');
$this->content->set('SITE_POWER_HELPER', ''); $this->content->set('SITE_POWER_HELPER', '');
$this->content->set('PLUGIN_POWER_AUTOLOADER', ''); $this->content->set('PLUGIN_POWER_AUTOLOADER', '');
$this->content->set('CUSTOM_POWER_AUTOLOADER', '');
$this->content->set('SITE_PLUGIN_POWER_AUTOLOADER', ''); $this->content->set('SITE_PLUGIN_POWER_AUTOLOADER', '');
$this->content->set('SITE_CUSTOM_POWER_AUTOLOADER', ''); $this->content->set('POWER_AUTOLOADER', '');
$this->content->set('ONE_POWER_AUTOLOADER', '');
$this->content->set('TWO_POWER_AUTOLOADER', '');
$this->content->set('THREE_POWER_AUTOLOADER', '');
$this->content->set('FOUR_POWER_AUTOLOADER', '');
$this->content->set('SITE_POWER_AUTOLOADER', '');
$this->content->set('SITE_ONE_POWER_AUTOLOADER', '');
$this->content->set('SITE_TWO_POWER_AUTOLOADER', '');
$this->content->set('SITE_THREE_POWER_AUTOLOADER', '');
$this->content->set('SITE_FOUR_POWER_AUTOLOADER', '');
} }
/** /**
@ -91,13 +99,25 @@ class Autoloader
*/ */
public function setFiles() public function setFiles()
{ {
// check if we are using a plugin // for plugins
$this->content->set('PLUGIN_POWER_AUTOLOADER', PHP_EOL . PHP_EOL . $this->getAutoloaderFile(2)); $this->content->set('PLUGIN_POWER_AUTOLOADER', PHP_EOL . PHP_EOL . $this->getAutoloaderFile(2));
$this->content->set('SITE_PLUGIN_POWER_AUTOLOADER', PHP_EOL . PHP_EOL . $this->getAutoloaderFile(2, 'JPATH_SITE')); $this->content->set('SITE_PLUGIN_POWER_AUTOLOADER', PHP_EOL . PHP_EOL . $this->getAutoloaderFile(2, 'JPATH_SITE'));
// for site spaced special cases
$this->content->set('SITE_ONE_POWER_AUTOLOADER', $this->getAutoloaderFile(1, 'JPATH_SITE'));
$this->content->set('SITE_TWO_POWER_AUTOLOADER', $this->getAutoloaderFile(2, 'JPATH_SITE'));
$this->content->set('SITE_THREE_POWER_AUTOLOADER', $this->getAutoloaderFile(3, 'JPATH_SITE'));
$this->content->set('SITE_FOUR_POWER_AUTOLOADER', $this->getAutoloaderFile(4, 'JPATH_SITE'));
// for admin spaced special cases
$this->content->set('ONE_POWER_AUTOLOADER', $this->getAutoloaderFile(1));
$this->content->set('TWO_POWER_AUTOLOADER', $this->getAutoloaderFile(2));
$this->content->set('THREE_POWER_AUTOLOADER', $this->getAutoloaderFile(3));
$this->content->set('FOUR_POWER_AUTOLOADER', $this->getAutoloaderFile(4));
// to add to custom files // to add to custom files
$this->content->add('CUSTOM_POWER_AUTOLOADER', $this->getAutoloaderFile(0)); $this->content->add('POWER_AUTOLOADER', $this->getAutoloaderFile(0));
$this->content->add('SITE_CUSTOM_POWER_AUTOLOADER', $this->getAutoloaderFile(0, 'JPATH_SITE')); $this->content->add('SITE_POWER_AUTOLOADER', $this->getAutoloaderFile(0, 'JPATH_SITE'));
} }
/** /**

View File

@ -16,9 +16,9 @@ use VDM\Joomla\Componentbuilder\Compiler\Config;
use VDM\Joomla\Componentbuilder\Compiler\Power; use VDM\Joomla\Componentbuilder\Compiler\Power;
use VDM\Joomla\Componentbuilder\Compiler\Builder\ContentOne as Content; use VDM\Joomla\Componentbuilder\Compiler\Builder\ContentOne as Content;
use VDM\Joomla\Componentbuilder\Compiler\Builder\ContentMulti as Contents; use VDM\Joomla\Componentbuilder\Compiler\Builder\ContentMulti as Contents;
use VDM\Joomla\Componentbuilder\Compiler\Power\Parser; use VDM\Joomla\Componentbuilder\Power\Parser;
use VDM\Joomla\Componentbuilder\Compiler\Power\Repo\Readme as RepoReadme; use VDM\Joomla\Interfaces\Readme\ItemInterface as ItemReadme;
use VDM\Joomla\Componentbuilder\Compiler\Power\Repos\Readme as ReposReadme; use VDM\Joomla\Interfaces\Readme\MainInterface as MainReadme;
use VDM\Joomla\Componentbuilder\Compiler\Placeholder; use VDM\Joomla\Componentbuilder\Compiler\Placeholder;
use VDM\Joomla\Componentbuilder\Compiler\Interfaces\EventInterface as Event; use VDM\Joomla\Componentbuilder\Compiler\Interfaces\EventInterface as Event;
use VDM\Joomla\Utilities\StringHelper; use VDM\Joomla\Utilities\StringHelper;
@ -75,18 +75,18 @@ class Infusion
/** /**
* The Readme Class. * The Readme Class.
* *
* @var RepoReadme * @var ItemReadme
* @since 3.2.0 * @since 3.2.0
*/ */
protected RepoReadme $reporeadme; protected ItemReadme $itemreadme;
/** /**
* The Readme Class. * The Readme Class.
* *
* @var ReposReadme * @var MainReadme
* @since 3.2.0 * @since 3.2.0
*/ */
protected ReposReadme $reposreadme; protected MainReadme $mainreadme;
/** /**
* The Placeholder Class. * The Placeholder Class.
@ -165,16 +165,16 @@ class Infusion
* @param Content $content The ContentOne Class. * @param Content $content The ContentOne Class.
* @param Contents $contents The ContentMulti Class. * @param Contents $contents The ContentMulti Class.
* @param Parser $parser The Parser Class. * @param Parser $parser The Parser Class.
* @param RepoReadme $reporeadme The Readme Class. * @param ItemReadme $itemreadme The Readme Class.
* @param ReposReadme $reposreadme The Readme Class. * @param MainReadme $mainreadme The Readme Class.
* @param Placeholder $placeholder The Placeholder Class. * @param Placeholder $placeholder The Placeholder Class.
* @param Event $event The EventInterface Class. * @param Event $event The EventInterface Class.
* *
* @since 3.2.0 * @since 3.2.0
*/ */
public function __construct(Config $config, Power $power, Content $content, public function __construct(Config $config, Power $power, Content $content,
Contents $contents, Parser $parser, RepoReadme $reporeadme, Contents $contents, Parser $parser, ItemReadme $itemreadme,
ReposReadme $reposreadme, Placeholder $placeholder, MainReadme $mainreadme, Placeholder $placeholder,
Event $event) Event $event)
{ {
$this->config = $config; $this->config = $config;
@ -182,8 +182,8 @@ class Infusion
$this->content = $content; $this->content = $content;
$this->contents = $contents; $this->contents = $contents;
$this->parser = $parser; $this->parser = $parser;
$this->reporeadme = $reporeadme; $this->itemreadme = $itemreadme;
$this->reposreadme = $reposreadme; $this->mainreadme = $mainreadme;
$this->placeholder = $placeholder; $this->placeholder = $placeholder;
$this->event = $event; $this->event = $event;
} }
@ -273,7 +273,7 @@ class Infusion
} }
// POWERREADME // POWERREADME
$this->contents->set("{$key}|POWERREADME", $this->reposreadme->get($powers)); $this->contents->set("{$key}|POWERREADME", $this->mainreadme->get($powers));
// sort all powers // sort all powers
$this->sortPowers($powers); $this->sortPowers($powers);
@ -355,7 +355,7 @@ class Infusion
$this->contents->set("{$power->key}|POWERLINKER", $this->linker($power)); $this->contents->set("{$power->key}|POWERLINKER", $this->linker($power));
// POWERLINKER // POWERLINKER
$this->contents->set("{$power->key}|POWERREADME", $this->reporeadme->get($power)); $this->contents->set("{$power->key}|POWERREADME", $this->itemreadme->get($power));
// Trigger Event: jcb_ce_onAfterInfusePowerData // Trigger Event: jcb_ce_onAfterInfusePowerData
$this->event->trigger( $this->event->trigger(

View File

@ -14,7 +14,7 @@ namespace VDM\Joomla\Componentbuilder\Compiler\Power;
use VDM\Joomla\Componentbuilder\Compiler\Interfaces\PowerInterface as Power; use VDM\Joomla\Componentbuilder\Compiler\Interfaces\PowerInterface as Power;
use VDM\Joomla\Componentbuilder\Compiler\Interfaces\Power\ExtractorInterface as Extractor; use VDM\Joomla\Componentbuilder\Compiler\Interfaces\Power\ExtractorInterface as Extractor;
use VDM\Joomla\Componentbuilder\Compiler\Power\Parser; use VDM\Joomla\Componentbuilder\Power\Parser;
use VDM\Joomla\Componentbuilder\Compiler\Placeholder; use VDM\Joomla\Componentbuilder\Compiler\Placeholder;
use VDM\Joomla\Componentbuilder\Compiler\Interfaces\Power\InjectorInterface; use VDM\Joomla\Componentbuilder\Compiler\Interfaces\Power\InjectorInterface;

View File

@ -1,107 +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\Componentbuilder\Compiler\Power\Repo;
use VDM\Joomla\Componentbuilder\Compiler\Factory as Compiler;
use VDM\Joomla\Componentbuilder\Compiler\Power;
use VDM\Joomla\Componentbuilder\Compiler\Power\Plantuml;
/**
* Compiler Power Repo Readme
* @since 3.2.0
*/
class Readme
{
/**
* Power Objects
*
* @var Power
* @since 3.2.0
**/
protected Power $power;
/**
* Compiler Powers Plantuml Builder
*
* @var Plantuml
* @since 3.2.0
**/
protected Plantuml $plantuml;
/**
* Constructor.
*
* @param Power|null $power The power object.
* @param Plantuml|null $plantuml The powers plantuml builder object.
*
* @since 3.2.0
*/
public function __construct(?Power $power = null, ?Plantuml $plantuml = null)
{
$this->power = $power ?: Compiler::_('Power');
$this->plantuml = $plantuml ?: Compiler::_('Power.Plantuml');
}
/**
* Get a Power Readme
*
* @param object $power A power details.
*
* @return string
* @since 3.2.0
*/
public function get(object $power): string
{
// build readme
$readme = ["```
██████╗ ██████╗ ██╗ ██╗███████╗██████╗
██╔══██╗██╔═══██╗██║ ██║██╔════╝██╔══██╗
██████╔╝██║ ██║██║ █╗ ██║█████╗ ██████╔╝
██╔═══╝ ██║ ██║██║███╗██║██╔══╝ ██╔══██╗
██║ ╚██████╔╝╚███╔███╔╝███████╗██║ ██║
╚═╝ ╚═════╝ ╚══╝╚══╝ ╚══════╝╚═╝ ╚═╝
```"];
// add the class diagram
$parsed_class_code = [];
if (isset($power->parsed_class_code) && is_array($power->parsed_class_code))
{
$parsed_class_code = $power->parsed_class_code;
}
$readme[] = "# " . $power->type . " " . $power->code_name . " (Details)";
$readme[] = "> namespace: **" . $power->_namespace . "**";
if ($power->extends != 0)
{
$readme[] = "> extends: **" . $power->extends_name . "**";
}
$readme[] = "```uml\n@startuml" . $this->plantuml->classDetailedDiagram(
['name' => $power->code_name, 'type' => $power->type],
$parsed_class_code
) . " \n@enduml\n```";
// yes you can remove this, but why?
$readme[] = "\n---\n```
██╗ ██████╗██████╗
██║██╔════╝██╔══██╗
██║██║ ██████╔╝
██ ██║██║ ██╔══██╗
╚█████╔╝╚██████╗██████╔╝
╚════╝ ╚═════╝╚═════╝
```\n> Build with [Joomla Component Builder](https://git.vdm.dev/joomla/Component-Builder)\n\n";
return implode("\n", $readme);
}
}

View File

@ -16,7 +16,7 @@ use Joomla\DI\Container;
use Joomla\DI\ServiceProviderInterface; use Joomla\DI\ServiceProviderInterface;
use VDM\Joomla\Componentbuilder\Compiler\JoomlaPower as Powers; use VDM\Joomla\Componentbuilder\Compiler\JoomlaPower as Powers;
use VDM\Joomla\Componentbuilder\JoomlaPower\Grep; use VDM\Joomla\Componentbuilder\JoomlaPower\Grep;
use VDM\Joomla\Componentbuilder\JoomlaPower\Super as Superpower; use VDM\Joomla\Componentbuilder\JoomlaPower\Remote\Get;
use VDM\Joomla\Componentbuilder\Compiler\JoomlaPower\Extractor; use VDM\Joomla\Componentbuilder\Compiler\JoomlaPower\Extractor;
use VDM\Joomla\Componentbuilder\Compiler\JoomlaPower\Injector; use VDM\Joomla\Componentbuilder\Compiler\JoomlaPower\Injector;
@ -41,8 +41,8 @@ class JoomlaPower implements ServiceProviderInterface
$container->alias(Powers::class, 'Joomla.Power') $container->alias(Powers::class, 'Joomla.Power')
->share('Joomla.Power', [$this, 'getPowers'], true); ->share('Joomla.Power', [$this, 'getPowers'], true);
$container->alias(Superpower::class, 'Joomlapower') $container->alias(Get::class, 'Joomla.Power.Remote.Get')
->share('Joomlapower', [$this, 'getSuperpower'], true); ->share('Joomla.Power.Remote.Get', [$this, 'getRemoteGet'], true);
$container->alias(Grep::class, 'Joomla.Power.Grep') $container->alias(Grep::class, 'Joomla.Power.Grep')
->share('Joomla.Power.Grep', [$this, 'getGrep'], true); ->share('Joomla.Power.Grep', [$this, 'getGrep'], true);
@ -69,21 +69,21 @@ class JoomlaPower implements ServiceProviderInterface
$container->get('Placeholder'), $container->get('Placeholder'),
$container->get('Customcode'), $container->get('Customcode'),
$container->get('Customcode.Gui'), $container->get('Customcode.Gui'),
$container->get('Joomlapower') $container->get('Joomla.Power.Remote.Get')
); );
} }
/** /**
* Get the Superpower * Get the Remote Get
* *
* @param Container $container The DI container. * @param Container $container The DI container.
* *
* @return Superpower * @return Get
* @since 3.2.0 * @since 3.2.0
*/ */
public function getSuperpower(Container $container): Superpower public function getRemoteGet(Container $container): Get
{ {
return new Superpower( return new Get(
$container->get('Joomla.Power.Grep'), $container->get('Joomla.Power.Grep'),
$container->get('Data.Item') $container->get('Data.Item')
); );

View File

@ -15,15 +15,15 @@ namespace VDM\Joomla\Componentbuilder\Compiler\Service;
use Joomla\DI\Container; use Joomla\DI\Container;
use Joomla\DI\ServiceProviderInterface; use Joomla\DI\ServiceProviderInterface;
use VDM\Joomla\Componentbuilder\Compiler\Power as Powers; use VDM\Joomla\Componentbuilder\Compiler\Power as Powers;
use VDM\Joomla\Componentbuilder\Power\Super as Superpower; use VDM\Joomla\Componentbuilder\Power\Remote\Get;
use VDM\Joomla\Componentbuilder\Power\Grep; use VDM\Joomla\Componentbuilder\Power\Grep;
use VDM\Joomla\Componentbuilder\Compiler\Power\Autoloader; use VDM\Joomla\Componentbuilder\Compiler\Power\Autoloader;
use VDM\Joomla\Componentbuilder\Compiler\Power\Infusion; use VDM\Joomla\Componentbuilder\Compiler\Power\Infusion;
use VDM\Joomla\Componentbuilder\Compiler\Power\Structure; use VDM\Joomla\Componentbuilder\Compiler\Power\Structure;
use VDM\Joomla\Componentbuilder\Compiler\Power\Parser; use VDM\Joomla\Componentbuilder\Power\Parser;
use VDM\Joomla\Componentbuilder\Compiler\Power\Plantuml; use VDM\Joomla\Componentbuilder\Power\Plantuml;
use VDM\Joomla\Componentbuilder\Compiler\Power\Repo\Readme as RepoReadme; use VDM\Joomla\Componentbuilder\Power\Readme\Item as ItemReadme;
use VDM\Joomla\Componentbuilder\Compiler\Power\Repos\Readme as ReposReadme; use VDM\Joomla\Componentbuilder\Power\Readme\Main as MainReadme;
use VDM\Joomla\Componentbuilder\Compiler\Power\Extractor; use VDM\Joomla\Componentbuilder\Compiler\Power\Extractor;
use VDM\Joomla\Componentbuilder\Compiler\Power\Injector; use VDM\Joomla\Componentbuilder\Compiler\Power\Injector;
@ -48,8 +48,8 @@ class Power implements ServiceProviderInterface
$container->alias(Powers::class, 'Power') $container->alias(Powers::class, 'Power')
->share('Power', [$this, 'getPowers'], true); ->share('Power', [$this, 'getPowers'], true);
$container->alias(Superpower::class, 'Superpower') $container->alias(Get::class, 'Power.Remote.Get')
->share('Superpower', [$this, 'getSuperpower'], true); ->share('Power.Remote.Get', [$this, 'getRemoteGet'], true);
$container->alias(Grep::class, 'Power.Grep') $container->alias(Grep::class, 'Power.Grep')
->share('Power.Grep', [$this, 'getGrep'], true); ->share('Power.Grep', [$this, 'getGrep'], true);
@ -69,11 +69,11 @@ class Power implements ServiceProviderInterface
$container->alias(Plantuml::class, 'Power.Plantuml') $container->alias(Plantuml::class, 'Power.Plantuml')
->share('Power.Plantuml', [$this, 'getPlantuml'], true); ->share('Power.Plantuml', [$this, 'getPlantuml'], true);
$container->alias(RepoReadme::class, 'Power.Repo.Readme') $container->alias(ItemReadme::class, 'Power.Readme.Item')
->share('Power.Repo.Readme', [$this, 'getRepoReadme'], true); ->share('Power.Readme.Item', [$this, 'getItemReadme'], true);
$container->alias(ReposReadme::class, 'Power.Repos.Readme') $container->alias(MainReadme::class, 'Power.Readme.Main')
->share('Power.Repos.Readme', [$this, 'getReposReadme'], true); ->share('Power.Readme.Main', [$this, 'getMainReadme'], true);
$container->alias(Extractor::class, 'Power.Extractor') $container->alias(Extractor::class, 'Power.Extractor')
->share('Power.Extractor', [$this, 'getExtractor'], true); ->share('Power.Extractor', [$this, 'getExtractor'], true);
@ -97,21 +97,21 @@ class Power implements ServiceProviderInterface
$container->get('Placeholder'), $container->get('Placeholder'),
$container->get('Customcode'), $container->get('Customcode'),
$container->get('Customcode.Gui'), $container->get('Customcode.Gui'),
$container->get('Superpower') $container->get('Power.Remote.Get')
); );
} }
/** /**
* Get The Super Class. * Get The Remote Get Class.
* *
* @param Container $container The DI container. * @param Container $container The DI container.
* *
* @return Superpower * @return Get
* @since 3.2.0 * @since 3.2.0
*/ */
public function getSuperpower(Container $container): Superpower public function getRemoteGet(Container $container): Get
{ {
return new Superpower( return new Get(
$container->get('Power.Grep'), $container->get('Power.Grep'),
$container->get('Data.Item') $container->get('Data.Item')
); );
@ -167,8 +167,8 @@ class Power implements ServiceProviderInterface
$container->get('Compiler.Builder.Content.One'), $container->get('Compiler.Builder.Content.One'),
$container->get('Compiler.Builder.Content.Multi'), $container->get('Compiler.Builder.Content.Multi'),
$container->get('Power.Parser'), $container->get('Power.Parser'),
$container->get('Power.Repo.Readme'), $container->get('Power.Readme.Item'),
$container->get('Power.Repos.Readme'), $container->get('Power.Readme.Main'),
$container->get('Placeholder'), $container->get('Placeholder'),
$container->get('Event') $container->get('Event')
); );
@ -228,13 +228,12 @@ class Power implements ServiceProviderInterface
* *
* @param Container $container The DI container. * @param Container $container The DI container.
* *
* @return RepoReadme * @return ItemReadme
* @since 3.2.0 * @since 3.2.0
*/ */
public function getRepoReadme(Container $container): RepoReadme public function getItemReadme(Container $container): ItemReadme
{ {
return new RepoReadme( return new ItemReadme(
$container->get('Power'),
$container->get('Power.Plantuml') $container->get('Power.Plantuml')
); );
} }
@ -244,15 +243,12 @@ class Power implements ServiceProviderInterface
* *
* @param Container $container The DI container. * @param Container $container The DI container.
* *
* @return ReposReadme * @return MainReadme
* @since 3.2.0 * @since 3.2.0
*/ */
public function getReposReadme(Container $container): ReposReadme public function getMainReadme(Container $container): MainReadme
{ {
return new ReposReadme( return new MainReadme();
$container->get('Power'),
$container->get('Power.Plantuml')
);
} }
/** /**

View File

@ -13,8 +13,6 @@ namespace VDM\Joomla\Componentbuilder\JoomlaPower;
use Joomla\CMS\Language\Text; use Joomla\CMS\Language\Text;
use VDM\Joomla\Utilities\FileHelper;
use VDM\Joomla\Utilities\JsonHelper;
use VDM\Joomla\Interfaces\GrepInterface; use VDM\Joomla\Interfaces\GrepInterface;
use VDM\Joomla\Abstraction\Grep as ExtendingGrep; use VDM\Joomla\Abstraction\Grep as ExtendingGrep;
@ -24,7 +22,7 @@ use VDM\Joomla\Abstraction\Grep as ExtendingGrep;
* *
* The Grep feature will try to find your joomla power in the repositories listed in the global * The Grep feature will try to find your joomla power in the repositories listed in the global
* Options of JCB in the super powers tab, and if it can't be found there will try the global core * Options of JCB in the super powers tab, and if it can't be found there will try the global core
* Super powers of JCB. All searches are performed according the the [algorithm:cascading] * Super powers of JCB. All searches are performed according the [algorithm:cascading]
* See documentation for more details: https://git.vdm.dev/joomla/super-powers/wiki * See documentation for more details: https://git.vdm.dev/joomla/super-powers/wiki
* *
* @since 3.2.1 * @since 3.2.1
@ -40,76 +38,19 @@ final class Grep extends ExtendingGrep implements GrepInterface
protected array $order = ['remote']; protected array $order = ['remote'];
/** /**
* Load the remote repository index of powers * Search for a remote item
* *
* @param object $path The repository path details * @param string $guid The global unique id of the item
*
* @return void
* @since 3.2.0
*/
protected function remoteIndex(object &$path): void
{
if (isset($path->index))
{
return;
}
$path->index = null;
// update the branch
$branch_field = $this->getBranchField();
$branch = $path->{$branch_field} ?? $path->read_branch ?? 'master';
try
{
$this->contents->load_($path->base ?? null, $path->token ?? null);
$source = $this->contents->metadata($path->organisation, $path->repository, 'src', $branch);
if ($source && is_array($source))
{
$path->index = new \stdClass();
foreach ($source as $index)
{
if (is_object($index) && isset($index->name))
{
$path->index->{$index->name} = $index;
}
}
}
$this->contents->reset_();
}
catch (\Exception $e)
{
$this->app->enqueueMessage(
Text::sprintf('COM_COMPONENTBUILDER_PJOOMLA_POWERB_REPOSITORY_AT_BSSB_GAVE_THE_FOLLOWING_ERRORBR_SP', $this->contents->api(), $path->path, $e->getMessage()),
'Error'
);
}
}
/**
* Search for a remote power
*
* @param string $guid The global unique id of the power
* *
* @return object|null * @return object|null
* @since 3.2.0 * @since 3.2.0
*/ */
protected function searchRemote(string $guid): ?object protected function searchRemote(string $guid): ?object
{ {
// we can only search if we have paths // check if it exists remotely
if (is_array($this->paths)) if (($path = $this->existsRemotely($guid)) !== null)
{ {
foreach ($this->paths as $path) return $this->getRemote($path, $guid);
{
// get local index
$this->remoteIndex($path);
if (!empty($path->index) && isset($path->index->{$guid}))
{
return $this->getRemote($path, $guid);
}
}
} }
return null; return null;
@ -133,11 +74,12 @@ final class Grep extends ExtendingGrep implements GrepInterface
} }
// get the branch name // get the branch name
$branch_field = $this->getBranchField(); $branch = $this->getBranchName($path);
$branch = $path->{$branch_field} ?? $path->read_branch ?? 'master';
// load the base and token if set
$this->contents->load_($path->base ?? null, $path->token ?? null);
// get the settings // get the settings
$this->contents->load_($path->base ?? null, $path->token ?? null);
if (($power = $this->loadRemoteFile($path->organisation, $path->repository, $path->index->{$guid}->path . '/item.json', $branch)) !== null && if (($power = $this->loadRemoteFile($path->organisation, $path->repository, $path->index->{$guid}->path . '/item.json', $branch)) !== null &&
isset($power->guid)) isset($power->guid))
{ {
@ -145,56 +87,65 @@ final class Grep extends ExtendingGrep implements GrepInterface
$path_guid = $path->guid ?? null; $path_guid = $path->guid ?? null;
if ($path_guid !== null) if ($path_guid !== null)
{ {
// get the Settings meta
if (($meta = $this->contents->metadata($path->organisation, $path->repository, $path->index->{$guid}->path . '/item.json', $branch)) !== null && if (($meta = $this->contents->metadata($path->organisation, $path->repository, $path->index->{$guid}->path . '/item.json', $branch)) !== null &&
isset($meta->sha)) isset($meta->sha))
{ {
if (isset($power->params) && is_object($power->params) && if (isset($power->params) && is_object($power->params) &&
isset($power->params->source) && is_array($power->params->source)) isset($power->params->source) && is_array($power->params->source))
{ {
$power->params->source[$path_guid] = $meta->sha; $power->params->source[$path_guid . '-settings'] = $meta->sha;
} }
else else
{ {
$power->params = (object)[ $power->params = (object) [
'source' => [$path_guid => $meta->sha] 'source' => [$path_guid . '-settings' => $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
$this->contents->reset_(); $this->contents->reset_();
return $power; return $power;
} }
/** /**
* Load the remote file * Set repository messages and errors based on given conditions.
* *
* @param string $organisation The repository organisation * @param string $message The message to set (if error)
* @param string $repository The repository name * @param string $path Path value
* @param string $path The repository path to file * @param string $repository Repository name
* @param string|null $branch The repository branch name * @param string $organisation Organisation name
* @param string|null $base Base URL
* *
* @return mixed * @return void
* @since 3.2.0 * @since 3.2.0
*/ */
protected function loadRemoteFile(string $organisation, string $repository, string $path, ?string $branch) protected function setRemoteIndexMessage(string $message, string $path, string $repository, string $organisation, ?string $base): void
{ {
try $this->app->enqueueMessage(
{ Text::sprintf('COM_COMPONENTBUILDER_PJOOMLA_POWERB_REPOSITORY_AT_BSSB_GAVE_THE_FOLLOWING_ERRORBR_SP', $this->contents->api(), $path, $message),
$data = $this->contents->get($organisation, $repository, $path, $branch); 'Error'
} );
catch (\Exception $e)
{
$this->app->enqueueMessage(
Text::sprintf('COM_COMPONENTBUILDER_PFILE_AT_BSSB_GAVE_THE_FOLLOWING_ERRORBR_SP', $this->contents->api(), $path, $e->getMessage()),
'Error'
);
return null;
}
return $data;
} }
} }

View File

@ -0,0 +1,66 @@
<?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\JoomlaPower\Readme;
use VDM\Joomla\Interfaces\Readme\ItemInterface;
/**
* Compiler Joomla Power Item Readme
* @since 3.2.0
*/
final class Item implements ItemInterface
{
/**
* Get an item readme
*
* @param object $item An item details.
*
* @return string
* @since 3.2.2
*/
public function get(object $item): string
{
// build readme
$readme = ["```
██╗ ██████╗ ██████╗ ███╗ ███╗██╗ █████╗ ██████╗ ██████╗ ██╗ ██╗███████╗██████╗
██║██╔═══██╗██╔═══██╗████╗ ████║██║ ██╔══██╗ ██╔══██╗██╔═══██╗██║ ██║██╔════╝██╔══██╗
██║██║ ██║██║ ██║██╔████╔██║██║ ███████║ ██████╔╝██║ ██║██║ █╗ ██║█████╗ ██████╔╝
██ ██║██║ ██║██║ ██║██║╚██╔╝██║██║ ██╔══██║ ██╔═══╝ ██║ ██║██║███╗██║██╔══╝ ██╔══██╗
╚█████╔╝╚██████╔╝╚██████╔╝██║ ╚═╝ ██║███████╗██║ ██║ ██║ ╚██████╔╝╚███╔███╔╝███████╗██║ ██║
╚════╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚══╝╚══╝ ╚══════╝╚═╝ ╚═╝
```"];
// system name
$readme[] = "# " . $item->system_name;
if (!empty($item->description))
{
$readme[] = "\n" . $item->description;
}
$readme[] = "\nThe Joomla! Power feature allows you to use Joomla classes in your project without manually managing their namespaces. JCB will automatically add the correct namespaces to your files. If Joomla classes change in future versions, such as from Joomla 3 to 5, JCB will update them for you.\n\nHowever, if there are breaking changes in function names, you may need to make some manual adjustments. The Joomla Power Key (JPK) helps you easily search for these classes.\n\nBy using the JPK (Joomla Power Key) in your custom code (replacing the class name in your code with the JPK), JCB will automatically pull the Joomla! Power from the repository into your project.\n\nTo add this specific power to your project in JCB:\n\n> simply use this JPK\n```\n" . 'Joomla---' . str_replace('-', '_', $item->guid) . '---Power' . "\n```\n> remember to replace the `---` with `___` to activate this Joomla! Power in your code";
// yes you can remove this, but why?
$readme[] = "\n---\n```
██╗ ██████╗██████╗
██║██╔════╝██╔══██╗
██║██║ ██████╔╝
██ ██║██║ ██╔══██╗
╚█████╔╝╚██████╗██████╔╝
╚════╝ ╚═════╝╚═════╝
```\n> Build with [Joomla Component Builder](https://git.vdm.dev/joomla/Component-Builder)\n\n";
return implode("\n", $readme);
}
}

View File

@ -0,0 +1,234 @@
<?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\JoomlaPower\Readme;
use VDM\Joomla\Interfaces\Readme\MainInterface;
/**
* Compiler Power Main Readme
* @since 3.2.0
*/
final class Main implements MainInterface
{
/**
* Get Main Readme
*
* @param array $items All items of this repository.
*
* @return string
* @since 3.2.0
*/
public function get(array $items): string
{
// build readme
$readme = ["```
██╗ ██████╗ ██████╗ ███╗ ███╗██╗ █████╗
██║██╔═══██╗██╔═══██╗████╗ ████║██║ ██╔══██╗
██║██║ ██║██║ ██║██╔████╔██║██║ ███████║
██ ██║██║ ██║██║ ██║██║╚██╔╝██║██║ ██╔══██║
╚█████╔╝╚██████╔╝╚██████╔╝██║ ╚═╝ ██║███████╗██║ ██║
╚════╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝
██████╗ ██████╗ ██╗ ██╗███████╗██████╗ ███████╗
██╔══██╗██╔═══██╗██║ ██║██╔════╝██╔══██╗██╔════╝
██████╔╝██║ ██║██║ █╗ ██║█████╗ ██████╔╝███████╗
██╔═══╝ ██║ ██║██║███╗██║██╔══╝ ██╔══██╗╚════██║
██║ ╚██████╔╝╚███╔███╔╝███████╗██║ ██║███████║
╚═╝ ╚═════╝ ╚══╝╚══╝ ╚══════╝╚═╝ ╚═╝╚══════╝
```"];
// default description of super powers
$readme[] = "\n### What is JCB Joomla Powers?\nThe Joomla Component Builder (JCB) Joomla Power features are designed to enhance JCB's functionality and streamline the development process. The Joomla powers enable developers to effectively leverage Joomla classes in their custom code without needing to manually add the `use` statements for those classes to the file headers. JCB automatically updates these `use` statements in the necessary headers when it detects a Joomla power key in the custom code.\n
\n
By doing this, we can control the `use` statements dynamically from a central point. This is particularly beneficial when transitioning from Joomla 3 to Joomla 4, as it allows us to seamlessly switch from certain classes to their respective Joomla framework classes and vice versa. Maintaining these `use` statements in the Joomla Power area ensures that JCB handles the inclusion and updating of class names to prevent conflicts with other classes.\n
\n
This approach is convenient and allows developers to focus on the bespoke parts of their application logic without worrying about class declarations.\n
\nThis repository contains an index (see below) of all the Joomla! Powers within the JCB core GUI. These Joomla! Powers are automatically added to the repository by our maintainers, ensuring a well-organized and accessible collection of Joomla Classes are maintained.\n";
// get the readme body
$readme[] = $this->readmeBuilder($items);
// yes you can remove this, but why?
$readme[] = "\n---\n```
██╗ ██████╗ ██████╗ ███╗ ███╗██╗ █████╗
██║██╔═══██╗██╔═══██╗████╗ ████║██║ ██╔══██╗
██║██║ ██║██║ ██║██╔████╔██║██║ ███████║
██ ██║██║ ██║██║ ██║██║╚██╔╝██║██║ ██╔══██║
╚█████╔╝╚██████╔╝╚██████╔╝██║ ╚═╝ ██║███████╗██║ ██║
╚════╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝
██████╗ ██████╗ ███╗ ███╗██████╗ ██████╗ ███╗ ██╗███████╗███╗ ██╗████████╗
██╔════╝██╔═══██╗████╗ ████║██╔══██╗██╔═══██╗████╗ ██║██╔════╝████╗ ██║╚══██╔══╝
██║ ██║ ██║██╔████╔██║██████╔╝██║ ██║██╔██╗ ██║█████╗ ██╔██╗ ██║ ██║
██║ ██║ ██║██║╚██╔╝██║██╔═══╝ ██║ ██║██║╚██╗██║██╔══╝ ██║╚██╗██║ ██║
╚██████╗╚██████╔╝██║ ╚═╝ ██║██║ ╚██████╔╝██║ ╚████║███████╗██║ ╚████║ ██║
╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═════╝ ╚═╝ ╚═══╝╚══════╝╚═╝ ╚═══╝ ╚═╝
██████╗ ██╗ ██╗██╗██╗ ██████╗ ███████╗██████╗
██╔══██╗██║ ██║██║██║ ██╔══██╗██╔════╝██╔══██╗
██████╔╝██║ ██║██║██║ ██║ ██║█████╗ ██████╔╝
██╔══██╗██║ ██║██║██║ ██║ ██║██╔══╝ ██╔══██╗
██████╔╝╚██████╔╝██║███████╗██████╔╝███████╗██║ ██║
╚═════╝ ╚═════╝ ╚═╝╚══════╝╚═════╝ ╚══════╝╚═╝ ╚═╝
```\n> Build with [Joomla Component Builder](https://git.vdm.dev/joomla/Component-Builder)\n\n";
return implode("\n", $readme);
}
/**
* The readme builder
*
* @param array $classes The powers.
*
* @return string
* @since 3.2.0
*/
private function readmeBuilder(array &$items): string
{
$classes = [];
foreach ($items as $guid => $power)
{
// add to the sort bucket
$classes[] = [
'name' => $power['name'],
'link' => $this->indexLinkPower($power)
];
}
return $this->readmeModel($classes);
}
/**
* Sort and model the readme classes
*
* @param array $classes The powers.
*
* @return string
* @since 3.2.0
*/
private function readmeModel(array &$classes): string
{
$this->sortClasses($classes);
return $this->generateIndex($classes);
}
/**
* Generate the index string for classes
*
* @param array $classes The sorted classes
*
* @return string The index string
*/
private function generateIndex(array &$classes): string
{
$result = "# Index of Joomla! Powers\n";
foreach ($classes as $class)
{
// Add the class details
$result .= "\n - " . $class['link'];
}
$result .= "\n> remember to replace the `---` with `___` in the JPK to activate that Joomla! Power in your code";
return $result;
}
/**
* Sort the flattened array using a single sorting function
*
* @param array $classes The classes to sort
*
* @since 3.2.0
*/
private function sortClasses(array &$classes): void
{
usort($classes, function ($a, $b) {
return $this->compareName($a, $b);
});
}
/**
* Compare the name of two classes
*
* @param array $a First class
* @param array $b Second class
*
* @return int Comparison result
* @since 3.2.0
*/
private function compareName(array $a, array $b): int
{
return strcmp($a['name'], $b['name']);
}
/**
* Build the Link to the power in this repository
*
* @param array $power The power details.
*
* @return string
* @since 3.2.0
*/
private function indexLinkPower(array &$power): string
{
$name = $power['name'] ?? 'error';
return '**' . $name . "** | "
. $this->linkPowerRepo($power) . ' | '
. $this->linkPowerSettings($power) . ' | JPK: `'
. $this->linkPowerJPK($power) .'`';
}
/**
* Build the Link to the power in this repository
*
* @param array $power The power details.
*
* @return string
* @since 3.2.0
*/
private function linkPowerRepo(array &$power): string
{
$path = $power['path'] ?? 'error';
return '[Details](' . $path . ')';
}
/**
* Build the Link to the power settings in this repository
*
* @param array $power The power details.
*
* @return string
* @since 3.2.0
*/
private function linkPowerSettings(array &$power): string
{
$settings = $power['settings'] ?? 'error';
return '[Settings](' . $settings . ')';
}
/**
* Get the JoomlaPowerKey (JPK)
*
* @param array $power The power details.
*
* @return string
* @since 3.2.0
*/
private function linkPowerJPK(array &$power): string
{
$jpk = $power['jpk'] ?? 'error';
return $jpk;
}
}

View File

@ -9,19 +9,19 @@
* @license GNU General Public License version 2 or later; see LICENSE.txt * @license GNU General Public License version 2 or later; see LICENSE.txt
*/ */
namespace VDM\Joomla\Componentbuilder\JoomlaPower; namespace VDM\Joomla\Componentbuilder\JoomlaPower\Remote;
use VDM\Joomla\Interfaces\Data\RemoteInterface; use VDM\Joomla\Interfaces\Remote\GetInterface;
use VDM\Joomla\Data\Remote; use VDM\Joomla\Abstraction\Remote\Get as ExtendingGet;
/** /**
* Super Joomla Power of JCB * Remote Get Joomla Power of JCB
* *
* @since 3.2.0 * @since 3.2.0
*/ */
final class Super extends Remote implements RemoteInterface final class Get extends ExtendingGet implements GetInterface
{ {
/** /**
* Table Name * Table Name

View File

@ -0,0 +1,182 @@
<?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\JoomlaPower\Remote;
use VDM\Joomla\Interfaces\Remote\SetInterface;
use VDM\Joomla\Abstraction\Remote\Set as ExtendingSet;
/**
* Set JoomlaPower based on global unique ids to remote repository
*
* @since 3.2.2
*/
final class Set extends ExtendingSet implements SetInterface
{
/**
* Table Name
*
* @var string
* @since 3.2.1
*/
protected string $table = 'joomla_power';
/**
* Area Name
*
* @var string
* @since 3.2.1
*/
protected string $area = 'Joomla Power';
/**
* Prefix Key
*
* @var string
* @since 3.2.2
*/
protected string $prefix_key = 'Joomla---';
/**
* The item map
*
* @var array
* @since 3.2.2
*/
protected array $map = [
'system_name' => 'system_name',
'settings' => 'settings',
'guid' => 'guid',
'description' => 'description'
];
/**
* The index map
*
* @var array
* @since 3.2.2
*/
protected array $index_map = [
'name' => 'index_map_IndexName',
'settings' => 'index_map_IndexSettingsPath',
'path' => 'index_map_IndexPath',
'jpk' => 'index_map_IndexKey',
'guid' => 'index_map_IndexGUID'
];
/**
* update an existing item (if changed)
*
* @param object $item
* @param object $existing
* @param object $repo
*
* @return bool
* @since 3.2.2
*/
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;
}
$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, // 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 3.2.2
*/
protected function createItem(object $item, object $repo): void
{
$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, // 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 3.2.2
*/
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;
}
$this->git->update(
$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.
'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 3.2.2
*/
protected function createItemReadme(object $item, object $repo): void
{
$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.
);
}
}

View File

@ -1,46 +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\Componentbuilder\JoomlaPower;
use VDM\Joomla\Data\Repository as ExtendingRepository;
/**
* Set JoomlaPower based on global unique ids to remote repository
*
* @since 3.2.2
*/
final class Repository extends ExtendingRepository
{
/**
* Table Name
*
* @var string
* @since 3.2.1
*/
protected string $table = 'joomla_power';
/**
* The item map
*
* @var array
* @since 3.2.2
*/
protected array $map = [
'system_name' => 'system_name',
'settings' => 'settings',
'guid' => 'guid',
'description' => 'description'
];
}

View File

@ -17,9 +17,10 @@ use Joomla\DI\ServiceProviderInterface;
use VDM\Joomla\Componentbuilder\JoomlaPower\Config; use VDM\Joomla\Componentbuilder\JoomlaPower\Config;
use VDM\Joomla\Componentbuilder\Table; use VDM\Joomla\Componentbuilder\Table;
use VDM\Joomla\Componentbuilder\JoomlaPower\Grep; use VDM\Joomla\Componentbuilder\JoomlaPower\Grep;
use VDM\Joomla\Componentbuilder\JoomlaPower\Super as Superpower; use VDM\Joomla\Componentbuilder\JoomlaPower\Remote\Get;
use VDM\Joomla\Componentbuilder\JoomlaPower\Repository; use VDM\Joomla\Componentbuilder\JoomlaPower\Remote\Set;
use VDM\Joomla\Componentbuilder\Compiler\Power\Parser; use VDM\Joomla\Componentbuilder\JoomlaPower\Readme\Item as ItemReadme;
use VDM\Joomla\Componentbuilder\JoomlaPower\Readme\Main as MainReadme;
/** /**
@ -48,14 +49,17 @@ class JoomlaPower implements ServiceProviderInterface
$container->alias(Grep::class, 'Joomla.Power.Grep') $container->alias(Grep::class, 'Joomla.Power.Grep')
->share('Joomla.Power.Grep', [$this, 'getGrep'], true); ->share('Joomla.Power.Grep', [$this, 'getGrep'], true);
$container->alias(Superpower::class, 'Joomlapower') $container->alias(Get::class, 'Joomla.Power.Remote.Get')
->share('Joomlapower', [$this, 'getSuperpower'], true); ->share('Joomla.Power.Remote.Get', [$this, 'getRemoteGet'], true);
$container->alias(Repository::class, 'Joomla.Power.Repository') $container->alias(Set::class, 'Joomla.Power.Remote.Set')
->share('Joomla.Power.Repository', [$this, 'getRepository'], true); ->share('Joomla.Power.Remote.Set', [$this, 'getRemoteSet'], true);
$container->alias(Parser::class, 'Power.Parser') $container->alias(ItemReadme::class, 'Joomla.Power.Readme.Item')
->share('Power.Parser', [$this, 'getParser'], true); ->share('Joomla.Power.Readme.Item', [$this, 'getItemReadme'], true);
$container->alias(MainReadme::class, 'Joomla.Power.Readme.Main')
->share('Joomla.Power.Readme.Main', [$this, 'getMainReadme'], true);
} }
/** /**
@ -101,50 +105,65 @@ class JoomlaPower implements ServiceProviderInterface
} }
/** /**
* Get The Super Class. * Get The Remote Get Class.
* *
* @param Container $container The DI container. * @param Container $container The DI container.
* *
* @return Superpower * @return Get
* @since 3.2.1 * @since 3.2.1
*/ */
public function getSuperpower(Container $container): Superpower public function getRemoteGet(Container $container): Get
{ {
return new Superpower( return new Get(
$container->get('Joomla.Power.Grep'), $container->get('Joomla.Power.Grep'),
$container->get('Data.Item') $container->get('Data.Item')
); );
} }
/** /**
* Get The Repository Class. * Get The Remote Set Class.
* *
* @param Container $container The DI container. * @param Container $container The DI container.
* *
* @return Repository * @return Set
* @since 3.2.2 * @since 3.2.2
*/ */
public function getRepository(Container $container): Repository public function getRemoteSet(Container $container): Set
{ {
return new Repository( return new Set(
$container->get('Config')->approved_joomla_paths, $container->get('Config')->approved_joomla_paths,
$container->get('Joomla.Power.Grep'), $container->get('Joomla.Power.Grep'),
$container->get('Data.Items'), $container->get('Data.Items'),
$container->get('Joomla.Power.Readme.Item'),
$container->get('Joomla.Power.Readme.Main'),
$container->get('Gitea.Repository.Contents') $container->get('Gitea.Repository.Contents')
); );
} }
/** /**
* Get The Parser Class. * Get The Item Class.
* *
* @param Container $container The DI container. * @param Container $container The DI container.
* *
* @return Parser * @return ItemReadme
* @since 3.2.1 * @since 3.2.1
*/ */
public function getParser(Container $container): Parser public function getItemReadme(Container $container): ItemReadme
{ {
return new Parser(); return new ItemReadme();
}
/**
* Get The Main Class.
*
* @param Container $container The DI container.
*
* @return MainReadme
* @since 3.2.1
*/
public function getMainReadme(Container $container): MainReadme
{
return new MainReadme();
} }
} }

View File

@ -13,7 +13,7 @@ namespace VDM\Joomla\Componentbuilder\Power\Generator;
use VDM\Joomla\Data\Action\Load as Database; use VDM\Joomla\Data\Action\Load as Database;
use VDM\Joomla\Componentbuilder\Compiler\Power\Parser; use VDM\Joomla\Componentbuilder\Power\Parser;
use VDM\Joomla\Componentbuilder\Power\Generator\Bucket; use VDM\Joomla\Componentbuilder\Power\Generator\Bucket;
use VDM\Joomla\Utilities\String\ClassfunctionHelper; use VDM\Joomla\Utilities\String\ClassfunctionHelper;

View File

@ -32,100 +32,46 @@ use VDM\Joomla\Abstraction\Grep as ExtendingGrep;
final class Grep extends ExtendingGrep implements GrepInterface final class Grep extends ExtendingGrep implements GrepInterface
{ {
/** /**
* Load the remote repository index of powers * The index file path
* *
* @param object $path The repository path details * @var string
* * @since 3.2.2
* @return void
* @since 3.2.0
*/ */
protected function remoteIndex(object &$path): void protected string $index_path = 'super-powers.json';
{
if (isset($path->index))
{
return;
}
try
{
$this->contents->load_($path->base ?? null, $path->token ?? null);
$path->index = $this->contents->get($path->organisation, $path->repository, 'super-powers.json', $path->read_branch);
$this->contents->reset_();
}
catch (\Exception $e)
{
if ('super-powers' === $path->repository && 'joomla' !== $path->organisation && (empty($path->base) || $path->base === 'https://git.vdm.dev'))
{
// give heads-up about the overriding feature
$this->app->enqueueMessage(
Text::sprintf('COM_COMPONENTBUILDER_PSUPER_POWERB_REPOSITORY_AT_BHTTPSGITVDMDEVSB_CAN_BE_USED_TO_OVERRIDE_ANY_POWERBR_BUT_HAS_NOT_YET_BEEN_SET_IN_YOUR_ACCOUNT_AT_HTTPSGITVDMDEVSBR_SMALLTHIS_IS_AND_OPTIONAL_FEATURESMALL', $path->path, $path->organisation),
'Message'
);
}
else
{
// give error
$this->app->enqueueMessage(
Text::sprintf('COM_COMPONENTBUILDER_PSUPER_POWERB_REPOSITORY_AT_BSSB_GAVE_THE_FOLLOWING_ERRORBR_SP', $this->contents->api(), $path->path, $e->getMessage()),
'Error'
);
}
$path->index = null;
}
}
/** /**
* Search for a local power * Search for a local item
* *
* @param string $guid The global unique id of the power * @param string $guid The global unique id of the item
* *
* @return object|null * @return object|null
* @since 3.2.0 * @since 3.2.0
*/ */
protected function searchLocal(string $guid): ?object protected function searchLocal(string $guid): ?object
{ {
// we can only search if we have paths // check if it exists locally
if ($this->path && $this->paths) if (($path = $this->existsLocally($guid)) !== null)
{ {
foreach ($this->paths as $path) return $this->getLocal($path, $guid);
{
// get local index
$this->localIndex($path);
if (!empty($path->local) && isset($path->local->{$guid}))
{
return $this->getLocal($path, $guid);
}
}
} }
return null; return null;
} }
/** /**
* Search for a remote power * Search for a remote item
* *
* @param string $guid The global unique id of the power * @param string $guid The global unique id of the item
* *
* @return object|null * @return object|null
* @since 3.2.0 * @since 3.2.0
*/ */
protected function searchRemote(string $guid): ?object protected function searchRemote(string $guid): ?object
{ {
// we can only search if we have paths // check if it exists remotely
if ($this->path && $this->paths) if (($path = $this->existsRemotely($guid)) !== null)
{ {
foreach ($this->paths as $path) return $this->getRemote($path, $guid);
{
// get local index
$this->remoteIndex($path);
if (!empty($path->index) && isset($path->index->{$guid}))
{
return $this->getRemote($path, $guid);
}
}
} }
return null; return null;
@ -181,80 +127,69 @@ final class Grep extends ExtendingGrep implements GrepInterface
return $power; return $power;
} }
// get the settings // get the branch name
$branch = $this->getBranchName($path);
// load the base and token if set
$this->contents->load_($path->base ?? null, $path->token ?? null); $this->contents->load_($path->base ?? null, $path->token ?? null);
if (($power = $this->loadRemoteFile($path->organisation, $path->repository, $path->index->{$guid}->settings, $path->read_branch)) !== null &&
// get the settings
if (($power = $this->loadRemoteFile($path->organisation, $path->repository, $path->index->{$guid}->settings, $branch)) !== null &&
isset($power->guid)) isset($power->guid))
{ {
// get the code // get the code
if (($code = $this->loadRemoteFile($path->organisation, $path->repository, $path->index->{$guid}->power, $path->read_branch)) !== null) if (($code = $this->loadRemoteFile($path->organisation, $path->repository, $path->index->{$guid}->power, $branch)) !== null)
{ {
// set the git details in params // set the git details in params
$power->params = (object) [
'source' => ['guid' => $path->guid ?? null]
];
$power->main_class_code = $code; $power->main_class_code = $code;
} }
} }
// reset back to the global base and token
$this->contents->reset_(); $this->contents->reset_();
return $power; return $power;
} }
/** /**
* Load the remote file * Set repository messages and errors based on given conditions.
* *
* @param string $organisation The repository organisation * @param string $message The message to set (if error)
* @param string $repository The repository name * @param string $path Path value
* @param string $path The repository path to file * @param string $repository Repository name
* @param string|null $branch The repository branch name * @param string $organisation Organisation name
* * @param string|null $base Base URL
* @return mixed
* @since 3.2.0
*/
protected function loadRemoteFile(string $organisation, string $repository, string $path, ?string $branch)
{
try
{
$data = $this->contents->get($organisation, $repository, $path, $branch);
}
catch (\Exception $e)
{
$this->app->enqueueMessage(
Text::sprintf('COM_COMPONENTBUILDER_PFILE_AT_BSSB_GAVE_THE_FOLLOWING_ERRORBR_SP', $this->contents->api(), $path, $e->getMessage()),
'Error'
);
return null;
}
return $data;
}
/**
* Load the local repository index of powers
*
* @param object $path The repository path details
* *
* @return void * @return void
* @since 3.2.0 * @since 3.2.0
*/ */
protected function localIndex(object &$path) protected function setRemoteIndexMessage(string $message, string $path, string $repository, string $organisation, ?string $base): void
{ {
if (isset($path->local) || !isset($path->full_path)) if ($repository === 'super-powers' && $organisation !== 'joomla' && (empty($base) || $base === 'https://git.vdm.dev'))
{ {
return; // Give heads-up about the overriding feature
$this->app->enqueueMessage(
Text::sprintf(
'<p>Super Power</b> repository at <b>https://git.vdm.dev/%s</b> can be used to override any power!<br />But has not yet been set in your account at https://git.vdm.dev/%s<br /><small>This is an optional feature.</small>',
$path,
$organisation
),
'Message'
);
} }
else
if (($content = FileHelper::getContent($path->full_path . '/super-powers.json', null)) !== null &&
JsonHelper::check($content))
{ {
$path->local = json_decode($content); // Give error
$this->app->enqueueMessage(
return; Text::sprintf(
'<p>Super Power</b> repository at <b>%s/%s</b> gave the following error!<br />%s</p>',
$this->contents->api(),
$path,
$message
),
'Error'
);
} }
$path->local = null;
} }
} }

View File

@ -9,7 +9,7 @@
* @license GNU General Public License version 2 or later; see LICENSE.txt * @license GNU General Public License version 2 or later; see LICENSE.txt
*/ */
namespace VDM\Joomla\Componentbuilder\Compiler\Power; namespace VDM\Joomla\Componentbuilder\Power;
/** /**

View File

@ -9,11 +9,11 @@
* @license GNU General Public License version 2 or later; see LICENSE.txt * @license GNU General Public License version 2 or later; see LICENSE.txt
*/ */
namespace VDM\Joomla\Componentbuilder\Compiler\Power; namespace VDM\Joomla\Componentbuilder\Power;
/** /**
* Compiler Power Plantuml Builder * Power Plantuml Builder
* @since 3.2.0 * @since 3.2.0
*/ */
class Plantuml class Plantuml

View File

@ -0,0 +1,97 @@
<?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\Readme;
use VDM\Joomla\Componentbuilder\Power\Plantuml;
use VDM\Joomla\Interfaces\Readme\ItemInterface;
/**
* Compiler Power Item Readme
* @since 3.2.0
*/
final class Item implements ItemInterface
{
/**
* Compiler Powers Plantuml Builder
*
* @var Plantuml
* @since 3.2.0
**/
protected Plantuml $plantuml;
/**
* Constructor.
*
* @param Plantuml $plantuml The powers plantuml builder object.
*
* @since 3.2.0
*/
public function __construct(Plantuml $plantuml)
{
$this->plantuml = $plantuml;
}
/**
* Get an item readme
*
* @param object $item An item details.
*
* @return string
* @since 3.2.2
*/
public function get(object $item): string
{
// build readme
$readme = ["```
██████╗ ██████╗ ██╗ ██╗███████╗██████╗
██╔══██╗██╔═══██╗██║ ██║██╔════╝██╔══██╗
██████╔╝██║ ██║██║ █╗ ██║█████╗ ██████╔╝
██╔═══╝ ██║ ██║██║███╗██║██╔══╝ ██╔══██╗
██║ ╚██████╔╝╚███╔███╔╝███████╗██║ ██║
╚═╝ ╚═════╝ ╚══╝╚══╝ ╚══════╝╚═╝ ╚═╝
```"];
// add the class diagram
$parsed_class_code = [];
if (isset($item->parsed_class_code) && is_array($item->parsed_class_code))
{
$parsed_class_code = $item->parsed_class_code;
}
$readme[] = "# " . $item->type . " " . $item->code_name . " (Details)";
$readme[] = "> namespace: **" . $item->_namespace . "**";
if (!empty($item->extends_name))
{
$readme[] = "> extends: **" . $item->extends_name . "**";
}
$readme[] = "\n```uml\n@startuml" . $this->plantuml->classDetailedDiagram(
['name' => $item->code_name, 'type' => $item->type],
$parsed_class_code
) . " \n@enduml\n```";
$readme[] = "\nThe Power feature in JCB allows you to write PHP classes and their implementations, making it easy to include them in your Joomla project. JCB handles linking, autoloading, namespacing, and folder structure creation for you.\n\nBy using the SPK (Super Power Key) in your custom code (replacing the class name in your code with the SPK), JCB will automatically pull the power from the repository into your project. This makes it available in your JCB instance, allowing you to edit it and include the class in your generated Joomla component.\n\nJCB uses placeholders like [[[`NamespacePrefix`]]] and [[[`ComponentNamespace`]]] in namespacing to prevent collisions and improve reusability across different JCB systems. You can also set the **JCB powers path** globally or per component under the **Dynamic Integration** tab, providing flexibility and easy maintainability.\n\nTo add this specific Power to your project in JCB:\n\n> simply use this SPK\n```\n" . 'Super---' . str_replace('-', '_', $item->guid) . '---Power' . "\n```\n> remember to replace the `---` with `___` to activate this Power in your code";
// yes you can remove this, but why?
$readme[] = "\n---\n```
██╗ ██████╗██████╗
██║██╔════╝██╔══██╗
██║██║ ██████╔╝
██ ██║██║ ██╔══██╗
╚█████╔╝╚██████╗██████╔╝
╚════╝ ╚═════╝╚═════╝
```\n> Build with [Joomla Component Builder](https://git.vdm.dev/joomla/Component-Builder)\n\n";
return implode("\n", $readme);
}
}

View File

@ -9,59 +9,27 @@
* @license GNU General Public License version 2 or later; see LICENSE.txt * @license GNU General Public License version 2 or later; see LICENSE.txt
*/ */
namespace VDM\Joomla\Componentbuilder\Compiler\Power\Repos; namespace VDM\Joomla\Componentbuilder\Power\Readme;
use VDM\Joomla\Componentbuilder\Compiler\Factory as Compiler; use VDM\Joomla\Interfaces\Readme\MainInterface;
use VDM\Joomla\Componentbuilder\Compiler\Power;
use VDM\Joomla\Componentbuilder\Compiler\Power\Plantuml;
/** /**
* Compiler Power Repos Readme * Compiler Power Main Readme
* @since 3.2.0 * @since 3.2.0
*/ */
class Readme final class Main implements MainInterface
{ {
/** /**
* Power Objects * Get Main Readme
* *
* @var Power * @param array $items All items of this repository.
* @since 3.2.0
**/
protected Power $power;
/**
* Compiler Powers Plantuml Builder
*
* @var Plantuml
* @since 3.2.0
**/
protected Plantuml $plantuml;
/**
* Constructor.
*
* @param Power|null $power The power object.
* @param Plantuml|null $plantuml The powers plantuml builder object.
*
* @since 3.2.0
*/
public function __construct(?Power $power = null, ?Plantuml $plantuml = null)
{
$this->power = $power ?: Compiler::_('Power');
$this->plantuml = $plantuml ?: Compiler::_('Power.Plantuml');
}
/**
* Get Super Power Readme
*
* @param array $powers All powers of this super power.
* *
* @return string * @return string
* @since 3.2.0 * @since 3.2.0
*/ */
public function get(array $powers): string public function get(array $items): string
{ {
// build readme // build readme
$readme = ["``` $readme = ["```
@ -83,7 +51,7 @@ class Readme
$readme[] = "\n### What is JCB Super Powers?\nThe Joomla Component Builder (JCB) Super Power features are designed to enhance JCB's functionality and streamline the development process. These Super Powers enable developers to efficiently manage and share their custom powers across multiple JCB instances through repositories hosted on [https://git.vdm.dev/[username]/[repository-name]](https://git.vdm.dev). JCB Super Powers are managed using a combination of layers, events, tasks, methods, switches, and algorithms, which work together to provide powerful customization and extensibility options. More details on JCB Super Powers can be found in the [Super Powers Documentation](https://git.vdm.dev/joomla/super-powers/wiki).\n\nIn summary, JCB Super Powers offer a flexible and efficient way to manage and share functionalities between JCB instances. By utilizing a sophisticated system of layers, events, tasks, methods, switches, and algorithms, developers can seamlessly integrate JCB core powers and their custom powers. For more information on how to work with JCB Super Powers, refer to the [Super Powers User Guide](https://git.vdm.dev/joomla/super-powers/wiki).\n\n### What can I find here?\nThis repository contains an index (see below) of all the approved powers within the JCB GUI. During the compilation of a component, these powers are automatically added to the repository, ensuring a well-organized and accessible collection of functionalities.\n"; $readme[] = "\n### What is JCB Super Powers?\nThe Joomla Component Builder (JCB) Super Power features are designed to enhance JCB's functionality and streamline the development process. These Super Powers enable developers to efficiently manage and share their custom powers across multiple JCB instances through repositories hosted on [https://git.vdm.dev/[username]/[repository-name]](https://git.vdm.dev). JCB Super Powers are managed using a combination of layers, events, tasks, methods, switches, and algorithms, which work together to provide powerful customization and extensibility options. More details on JCB Super Powers can be found in the [Super Powers Documentation](https://git.vdm.dev/joomla/super-powers/wiki).\n\nIn summary, JCB Super Powers offer a flexible and efficient way to manage and share functionalities between JCB instances. By utilizing a sophisticated system of layers, events, tasks, methods, switches, and algorithms, developers can seamlessly integrate JCB core powers and their custom powers. For more information on how to work with JCB Super Powers, refer to the [Super Powers User Guide](https://git.vdm.dev/joomla/super-powers/wiki).\n\n### What can I find here?\nThis repository contains an index (see below) of all the approved powers within the JCB GUI. During the compilation of a component, these powers are automatically added to the repository, ensuring a well-organized and accessible collection of functionalities.\n";
// get the readme body // get the readme body
$readme[] = $this->readmeBuilder($powers); $readme[] = $this->readmeBuilder($items);
// yes you can remove this, but why? // yes you can remove this, but why?
$readme[] = "\n---\n``` $readme[] = "\n---\n```
@ -118,10 +86,10 @@ class Readme
* @return string * @return string
* @since 3.2.0 * @since 3.2.0
*/ */
private function readmeBuilder(array &$powers): string private function readmeBuilder(array &$items): string
{ {
$classes = []; $classes = [];
foreach ($powers as $guid => $power) foreach ($items as $guid => $power)
{ {
// add to the sort bucket // add to the sort bucket
$classes[] = [ $classes[] = [
@ -175,6 +143,8 @@ class Readme
$result .= "\n - " . $class['link']; $result .= "\n - " . $class['link'];
} }
$result .= "\n> remember to replace the `---` with `___` in the SPK to activate that Power in your code";
return $result; return $result;
} }
@ -290,8 +260,8 @@ class Readme
return '**' . $type . ' ' . $name . "** | " return '**' . $type . ' ' . $name . "** | "
. $this->linkPowerRepo($power) . ' | ' . $this->linkPowerRepo($power) . ' | '
. $this->linkPowerCode($power) . ' | ' . $this->linkPowerCode($power) . ' | '
. $this->linkPowerSettings($power) . ' | ' . $this->linkPowerSettings($power) . ' | SPK: `'
. $this->linkPowerSPK($power); . $this->linkPowerSPK($power) .'`';
} }
/** /**

View File

@ -0,0 +1 @@
<html><body bgcolor="#FFFFFF"></body></html>

View File

@ -9,19 +9,19 @@
* @license GNU General Public License version 2 or later; see LICENSE.txt * @license GNU General Public License version 2 or later; see LICENSE.txt
*/ */
namespace VDM\Joomla\Componentbuilder\Power; namespace VDM\Joomla\Componentbuilder\Power\Remote;
use VDM\Joomla\Interfaces\Data\RemoteInterface; use VDM\Joomla\Interfaces\Remote\GetInterface;
use VDM\Joomla\Data\Remote; use VDM\Joomla\Abstraction\Remote\Get as ExtendingGet;
/** /**
* Superpower of JCB * Remote Get Power of JCB
* *
* @since 3.2.0 * @since 3.2.0
*/ */
final class Super extends Remote implements RemoteInterface final class Get extends ExtendingGet implements GetInterface
{ {
/** /**
* Table Name * Table Name

View File

@ -0,0 +1 @@
<html><body bgcolor="#FFFFFF"></body></html>

View File

@ -17,8 +17,8 @@ use Joomla\DI\ServiceProviderInterface;
use VDM\Joomla\Componentbuilder\Power\Config; use VDM\Joomla\Componentbuilder\Power\Config;
use VDM\Joomla\Componentbuilder\Table; use VDM\Joomla\Componentbuilder\Table;
use VDM\Joomla\Componentbuilder\Power\Grep; use VDM\Joomla\Componentbuilder\Power\Grep;
use VDM\Joomla\Componentbuilder\Power\Super as Superpower; use VDM\Joomla\Componentbuilder\Power\Remote\Get;
use VDM\Joomla\Componentbuilder\Compiler\Power\Parser; use VDM\Joomla\Componentbuilder\Power\Parser;
/** /**
@ -47,8 +47,8 @@ class Power implements ServiceProviderInterface
$container->alias(Grep::class, 'Power.Grep') $container->alias(Grep::class, 'Power.Grep')
->share('Power.Grep', [$this, 'getGrep'], true); ->share('Power.Grep', [$this, 'getGrep'], true);
$container->alias(Superpower::class, 'Superpower') $container->alias(Get::class, 'Power.Remote.Get')
->share('Superpower', [$this, 'getSuperpower'], true); ->share('Power.Remote.Get', [$this, 'getRemoteGet'], true);
$container->alias(Parser::class, 'Power.Parser') $container->alias(Parser::class, 'Power.Parser')
->share('Power.Parser', [$this, 'getParser'], true); ->share('Power.Parser', [$this, 'getParser'], true);
@ -98,16 +98,16 @@ class Power implements ServiceProviderInterface
} }
/** /**
* Get The Super Class. * Get The Remote Get Class.
* *
* @param Container $container The DI container. * @param Container $container The DI container.
* *
* @return Superpower * @return Get
* @since 3.2.0 * @since 3.2.0
*/ */
public function getSuperpower(Container $container): Superpower public function getRemoteGet(Container $container): Get
{ {
return new Superpower( return new Get(
$container->get('Power.Grep'), $container->get('Power.Grep'),
$container->get('Data.Item') $container->get('Data.Item')
); );

View File

@ -1558,7 +1558,6 @@ final class Table extends BaseTable implements Tableinterface
'tab_name' => 'publishing', 'tab_name' => 'publishing',
'db' => [ 'db' => [
'type' => 'TEXT', 'type' => 'TEXT',
'default' => '',
], ],
], ],
'metadesc' => [ 'metadesc' => [
@ -1570,7 +1569,6 @@ final class Table extends BaseTable implements Tableinterface
'tab_name' => 'publishing', 'tab_name' => 'publishing',
'db' => [ 'db' => [
'type' => 'TEXT', 'type' => 'TEXT',
'default' => '',
], ],
], ],
'metadata' => [ 'metadata' => [
@ -1582,7 +1580,6 @@ final class Table extends BaseTable implements Tableinterface
'tab_name' => 'publishing', 'tab_name' => 'publishing',
'db' => [ 'db' => [
'type' => 'TEXT', 'type' => 'TEXT',
'default' => '',
], ],
], ],
], ],

View File

@ -0,0 +1,72 @@
<?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\Table;
use VDM\Joomla\Componentbuilder\Table;
use VDM\Joomla\Componentbuilder\Table\Schema;
use VDM\Joomla\Interfaces\SchemaCheckerInterface;
use VDM\Joomla\Abstraction\SchemaChecker as ExtendingSchemaChecker;
/**
* Componentbuilder Tables Schema Checker
*
* @since 3.2.2
*/
final class SchemaChecker extends ExtendingSchemaChecker implements SchemaCheckerInterface
{
/**
* Get the targeted component code
*
* @return string
* @since 3.2.2
*/
protected function getCode(): string
{
return 'componentbuilder';
}
/**
* Get the targeted component power path
*
* @return string
* @since 3.2.2
*/
protected function getPowerPath(): string
{
return 'src/Helper/PowerloaderHelper.php';
}
/**
* Get the fully qualified name of the schema class.
*
* @return string
* @since 3.2.2
*/
protected function getSchemaClass(): string
{
return Schema::class;
}
/**
* Get the fully qualified name of the table class.
*
* @return string
* @since 3.2.2
*/
protected function getTableClass(): string
{
return Table::class;
}
}

View File

@ -46,7 +46,7 @@ final class MultiSubform implements MultiSubformInterface
/** /**
* Get a subform items * 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: * Example:
* $getMap = [ * $getMap = [
@ -94,8 +94,8 @@ final class MultiSubform implements MultiSubformInterface
/** /**
* Set a subform items * 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 array $setMap The the map to set the subfrom data * @param array $setMap The map to set the subfrom data
* *
* Example: * Example:
* $items, * $items,
@ -117,7 +117,7 @@ final class MultiSubform implements MultiSubformInterface
* @return bool * @return bool
* @since 3.2.2 * @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 // Validate the core map presence and structure
if (!isset($setMap['_core']) || !is_array($setMap['_core']) || !$this->validSetMap($setMap['_core'])) if (!isset($setMap['_core']) || !is_array($setMap['_core']) || !$this->validSetMap($setMap['_core']))
@ -125,6 +125,12 @@ final class MultiSubform implements MultiSubformInterface
return false; 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 // Save the core data
if (!$this->setSubformData($items, $setMap['_core'])) if (!$this->setSubformData($items, $setMap['_core']))
{ {
@ -167,7 +173,7 @@ final class MultiSubform implements MultiSubformInterface
* Set data based on provided map configuration. * Set data based on provided map configuration.
* *
* @param array $items The list of items from the subform to set * @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 * @param array|null $coreData The core data to be appended with subform data
* *
* @return bool * @return bool

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 * 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 $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 $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. * @param string $linkValue The value of the link key in child table.
@ -102,12 +102,17 @@ final class Subform implements SubformInterface
* @return bool * @return bool
* @since 3.2.2 * @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); $items = $this->process($items, $indexKey, $linkKey, $linkValue);
$this->purge($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( return $this->items->table($this->getTable())->set(
$items, $indexKey $items, $indexKey
); );
@ -142,10 +147,19 @@ final class Subform implements SubformInterface
if ($currentIndexValues !== null) if ($currentIndexValues !== null)
{ {
// Extract the index values from the items array // Check if the items array is empty
$activeIndexValues = array_values(array_map(function($item) use ($indexKey) { if (empty($items))
return $item[$indexKey] ?? null; {
}, $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 // Find the index values that are no longer in the items array
$inactiveIndexValues = array_diff($currentIndexValues, $activeIndexValues); $inactiveIndexValues = array_diff($currentIndexValues, $activeIndexValues);
@ -205,7 +219,7 @@ final class Subform implements SubformInterface
/** /**
* Processes an array of arrays based on the specified key. * 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 $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 $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. * @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. * @return array The processed array of arrays.
* @since 3.2.2 * @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) foreach ($items as &$item)
{ {
$value = $item[$indexKey] ?? ''; $value = $item[$indexKey] ?? '';

View File

@ -49,7 +49,7 @@ interface MultiSubformInterface
/** /**
* Set a subform items * 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 array $setMap The the map to set the subfrom data * @param array $setMap The the map to set the subfrom data
* *
* Example: * Example:
@ -72,6 +72,6 @@ interface MultiSubformInterface
* @return bool * @return bool
* @since 3.2.2 * @since 3.2.2
*/ */
public function set(array $items, array $setMap): bool; public function set(mixed $items, array $setMap): bool;
} }

View File

@ -35,17 +35,17 @@ interface SubformInterface
* @param string $linkValue The value of the link key in child table. * @param string $linkValue The value of the link key in child table.
* @param string $linkKey The link key on which the items where linked in the child table. * @param string $linkKey The link key on which the items where linked in the child table.
* @param string $field The parent field name of the subform in the parent view. * @param string $field The parent field name of the subform in the parent view.
* @param array $set The array SET of the keys of each row in the subform. * @param array $get The array SET of the keys of each row in the subform.
* *
* @return array|null The subform * @return array|null The subform
* @since 3.2.2 * @since 3.2.2
*/ */
public function get(string $linkValue, string $linkKey, string $field, array $set): ?array; public function get(string $linkValue, string $linkKey, string $field, array $get): ?array;
/** /**
* Set a subform items * 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 $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 $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. * @param string $linkValue The value of the link key in child table.
@ -53,7 +53,7 @@ interface SubformInterface
* @return bool * @return bool
* @since 3.2.2 * @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;
/** /**
* Get the current active table * Get the current active table

View File

@ -0,0 +1,50 @@
<?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\Interfaces\Git;
/**
* The Git Api Interface
*
* @since 3.2.0
*/
interface ApiInterface
{
/**
* Load/Reload API.
*
* @param string|null $url The url.
* @param token|null $token The token.
* @param bool $backup The backup swapping switch.
*
* @return void
* @since 3.2.0
**/
public function load_(?string $url = null, ?string $token = null, bool $backup = true): void;
/**
* Reset to previous toke, url it set
*
* @return void
* @since 3.2.0
**/
public function reset_(): void;
/**
* Get the API url
*
* @return string
* @since 3.2.0
**/
public function api();
}

View File

@ -0,0 +1,209 @@
<?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\Interfaces\Git\Repository;
use VDM\Joomla\Interfaces\Git\ApiInterface;
/**
* The Git Repository Contents Interface
*
* @since 3.2.2
*/
interface ContentsInterface extends ApiInterface
{
/**
* Get a file from a repository.
*
* @param string $owner The owner name.
* @param string $repo The repository name.
* @param string $filepath The file path.
* @param string|null $ref Optional. The name of the commit/branch/tag.
* Default the repository's default branch (usually master).
*
* @return mixed
* @since 3.2.0
**/
public function get(string $owner, string $repo, string $filepath, ?string $ref = null);
/**
* Get the metadata and contents (if a file) of an entry in a repository,
* or a list of entries if a directory.
*
* @param string $owner The owner name.
* @param string $repo The repository name.
* @param string $filepath The file or directory path.
* @param string|null $ref Optional. The name of the commit/branch/tag.
* Default the repository's default branch (usually master).
*
* @return null|array|object
* @since 3.2.0
**/
public function metadata(string $owner, string $repo, string $filepath, ?string $ref = null): null|array|object;
/**
* Create a file in a repository.
*
* @param string $owner The owner name.
* @param string $repo The repository name.
* @param string $filepath The file path.
* @param string $content The file content.
* @param string $message The commit message.
* @param string $branch The branch name. Defaults to the repository's default branch.
* @param string|null $authorName The author's name.
* @param string|null $authorEmail The author's email.
* @param string|null $committerName The committer's name.
* @param string|null $committerEmail The committer's email.
* @param string|null $newBranch Whether to create a new branch. Defaults to null.
* @param string|null $authorDate The author's date.
* @param string|null $committerDate The committer's date.
* @param bool|null $signoff Add a Signed-off-by trailer. Defaults to null.
*
* @return object|null
* @since 3.2.0
**/
public function create(
string $owner,
string $repo,
string $filepath,
string $content,
string $message,
string $branch = 'master',
?string $authorName = null,
?string $authorEmail = null,
?string $committerName = null,
?string $committerEmail = null,
?string $newBranch = null,
?string $authorDate = null,
?string $committerDate = null,
?bool $signoff = null
): ?object;
/**
* Get the metadata of all the entries of the root directory.
*
* @param string $owner The owner name.
* @param string $repo The repository name.
* @param string|null $ref The name of the commit/branch/tag. Default the repository's default branch (usually master).
*
* @return array|null
* @since 3.2.0
**/
public function root(string $owner, string $repo, ?string $ref = null): ?array;
/**
* Update a file in a repository.
*
* @param string $owner The owner name.
* @param string $repo The repository name.
* @param string $filepath The file path.
* @param string $content The file content.
* @param string $message The commit message.
* @param string $sha The blob SHA of the file.
* @param string $branch The branch name. Defaults to the repository's default branch.
* @param string|null $authorName The author name. Defaults to the authenticated user.
* @param string|null $authorEmail The author email. Defaults to the authenticated user.
* @param string|null $committerName The committer name. Defaults to the authenticated user.
* @param string|null $committerEmail The committer email. Defaults to the authenticated user.
* @param string|null $authorDate The author date.
* @param string|null $committerDate The committer date.
* @param string|null $fromPath The original file path to move/rename.
* @param string|null $newBranch The new branch to create from the specified branch.
* @param bool|null $signoff Add a Signed-off-by trailer.
*
* @return object|null
* @since 3.2.0
**/
public function update(
string $owner,
string $repo,
string $filepath,
string $content,
string $message,
string $sha,
string $branch = 'master',
?string $authorName = null,
?string $authorEmail = null,
?string $committerName = null,
?string $committerEmail = null,
?string $authorDate = null,
?string $committerDate = null,
?string $fromPath = null,
?string $newBranch = null,
?bool $signoff = null
): ?object;
/**
* Delete a file in a repository.
*
* @param string $owner The owner name.
* @param string $repo The repository name.
* @param string $filepath The file path.
* @param string $message The commit message.
* @param string $sha The blob SHA of the file.
* @param string|null $branch The branch name (optional).
* @param string|null $authorName The author name (optional).
* @param string|null $authorEmail The author email (optional).
* @param string|null $committerName The committer name (optional).
* @param string|null $committerEmail The committer email (optional).
* @param string|null $authorDate The author date (optional).
* @param string|null $committerDate The committer date (optional).
* @param string|null $newBranch The new branch name (optional).
* @param bool|null $signoff Add a Signed-off-by trailer (optional).
*
* @return object|null
* @since 3.2.0
**/
public function delete(
string $owner,
string $repo,
string $filepath,
string $message,
string $sha,
?string $branch = null,
?string $authorName = null,
?string $authorEmail = null,
?string $committerName = null,
?string $committerEmail = null,
?string $authorDate = null,
?string $committerDate = null,
?string $newBranch = null,
?bool $signoff = null
): ?object;
/**
* Get the EditorConfig definitions of a file in a repository.
*
* @param string $owner The owner name.
* @param string $repo The repository name.
* @param string $filepath The file path.
* @param string|null $ref The name of the commit/branch/tag.
*
* @return string|null
* @since 3.2.0
**/
public function editor(string $owner, string $repo, string $filepath, string $ref = null): ?string;
/**
* Get the blob of a repository.
*
* @param string $owner The owner name.
* @param string $repo The repository name.
* @param string $sha The SHA hash of the blob.
*
* @return object|null
* @since 3.2.0
**/
public function blob(string $owner, string $repo, string $sha): ?object;
}

View File

@ -0,0 +1 @@
<html><body bgcolor="#FFFFFF"></body></html>

View File

@ -0,0 +1 @@
<html><body bgcolor="#FFFFFF"></body></html>

View File

@ -20,17 +20,29 @@ namespace VDM\Joomla\Interfaces;
interface GrepInterface interface GrepInterface
{ {
/** /**
* Get all remote powers GUID's * Get an item
*
* @param string $guid The global unique id of the item
* @param array|null $order The search order
* @param object|null $repo The repository object to search. If null, all repos will be searched.
*
* @return object|null
* @since 3.2.2
*/
public function get(string $guid, ?array $order = null, ?object $repo = null): ?object;
/**
* Get all remote GUID's
* *
* @return array|null * @return array|null
* @since 3.2.0 * @since 3.2.0
*/ */
public function getRemotePowersGuid(): ?array; public function getRemoteGuid(): ?array;
/** /**
* Set the branch field * Set the branch field
* *
* @param string $field The global unique id of the power * @param string $field The field to use to get the branch name from the data set
* *
* @return void * @return void
* @since 3.2.2 * @since 3.2.2
@ -38,14 +50,33 @@ interface GrepInterface
public function setBranchField(string $field): void; public function setBranchField(string $field): void;
/** /**
* Get a power * Set the DEFAULT branch name (only used if branch field is not found)
* *
* @param string $guid The global unique id of the power * @param string|null $name The default branch to use if no name could be found
* @param array $order The search order *
* @return void
* @since 3.2.2
*/
public function setBranchDefaultName(?string $name): void;
/**
* Set the index path
*
* @param string $indexPath The repository index path
*
* @return void
* @since 3.2.2
*/
public function setIndexPath(string $indexPath): void;
/**
* Get the index of a repo
*
* @param string $guid The unique identifier for the repo.
* *
* @return object|null * @return object|null
* @since 3.2.0 * @since 3.2.2
*/ */
public function get(string $guid, array $order = ['local', 'remote']): ?object; public function getRemoteIndex(string $guid): ?object;
} }

View File

@ -0,0 +1,32 @@
<?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\Interfaces\Readme;
/**
* Item Readme Interface
*
* @since 3.2.2
*/
interface ItemInterface
{
/**
* Get an item readme
*
* @param object $item An item details.
*
* @return string
* @since 3.2.2
*/
public function get(object $item): string;
}

View File

@ -0,0 +1,32 @@
<?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\Interfaces\Readme;
/**
* Main Readme Interface
*
* @since 3.2.2
*/
interface MainInterface
{
/**
* Get Main Readme
*
* @param array $items All items of this repository.
*
* @return string
* @since 3.2.0
*/
public function get(array $items): string;
}

View File

@ -0,0 +1 @@
<html><body bgcolor="#FFFFFF"></body></html>

View File

@ -9,7 +9,7 @@
* @license GNU General Public License version 2 or later; see LICENSE.txt * @license GNU General Public License version 2 or later; see LICENSE.txt
*/ */
namespace VDM\Joomla\Interfaces\Data; namespace VDM\Joomla\Interfaces\Remote;
/** /**
@ -17,7 +17,7 @@ namespace VDM\Joomla\Interfaces\Data;
* *
* @since 3.2.2 * @since 3.2.2
*/ */
interface RemoteInterface interface GetInterface
{ {
/** /**
* Set the current active table * Set the current active table
@ -48,7 +48,7 @@ interface RemoteInterface
public function reset(array $items): bool; public function reset(array $items): bool;
/** /**
* Load a item * Load an item
* *
* @param string $guid The global unique id of the item * @param string $guid The global unique id of the item
* @param array $order The search order * @param array $order The search order
@ -56,7 +56,7 @@ interface RemoteInterface
* @return bool * @return bool
* @since 3.2.2 * @since 3.2.2
*/ */
public function load(string $guid, array $order = ['remote', 'local']): bool; public function item(string $guid, array $order = ['remote', 'local']): bool;
/** /**
* Get the current active table * Get the current active table

View File

@ -0,0 +1,73 @@
<?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\Interfaces\Remote;
/**
* Set data based on global unique ids to remote system
*
* @since 3.2.2
*/
interface SetInterface
{
/**
* 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;
/**
* Set the current active area
*
* @param string $area The area that should be active
*
* @return self
* @since 3.2.2
*/
public function area(string $area): self;
/**
* Set the settings path
*
* @param string $settingsPath The repository settings path
*
* @return self
* @since 3.2.2
*/
public function setSettingsPath(string $settingsPath): self;
/**
* Set the index settings path
*
* @param string $settingsIndexPath The repository index settings path
*
* @return self
* @since 3.2.2
*/
public function setIndexSettingsPath(string $settingsIndexPath): self;
/**
* Save items remotely
*
* @param array $guids The global unique id of the item
*
* @return bool
* @throws \Exception
* @since 3.2.2
*/
public function items(array $guids): bool;
}

View File

@ -0,0 +1 @@
<html><body bgcolor="#FFFFFF"></body></html>

View File

@ -0,0 +1,30 @@
<?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\Interfaces;
/**
* Schema Checker Interface
*
* @since 3.2.2
*/
interface SchemaCheckerInterface
{
/**
* Make sure that the database schema is up-to-date.
*
* @return void
* @since 3.2.2
*/
public function run(): void;
}

View File

@ -0,0 +1,55 @@
<?php
/**
* @package Joomla.Component.Builder
*
* @created 3rd September, 2020
* @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\Utilities;
/**
* Class Helper for JCB Powers
*
* @since 3.2.2
*/
abstract class ClassHelper
{
/**
* Ensures that a class in the namespace is available.
* If the class is not already loaded, it attempts to load it via the specified autoloader.
*
* @param string $className The fully qualified name of the class to check.
* @param string $component The component name where the autoloader resides.
* @param string $autoloaderPath The path to the autoloader file within the component.
*
* @return bool True if the class exists or was successfully loaded, false otherwise.
* @since 3.2.2
*/
public static function exists(string $className, string $component, string $autoloaderPath): bool
{
if (!class_exists($className, true))
{
// Construct the path to the autoloader file
$autoloaderFile = JPATH_ADMINISTRATOR . '/components/com_' . $component . '/' . $autoloaderPath;
if (file_exists($autoloaderFile))
{
require_once $autoloaderFile;
}
// Check again if the class now exists after requiring the autoloader
if (!class_exists($className, true))
{
return false;
}
}
return true;
}
}