Fix the update server #978 issue. Fixed the change log to load all entries, not just the last one. Fixed #983 so that database updates are created when adding a new adminview. Moved a few builder arrays to the Compiler Registry. Adds super powers to JCB. Adds Gitea API library. Improves Power filters. Fix #991 to add the Utilities service class. Adds Superpower Key (SPK) replacement feature. Adds Superpower search (GREP) feature. Adds Power Insert/Update Classe. Fix #995 that all update sites are using the correct URL.
This commit is contained in:
@@ -65,6 +65,11 @@ abstract class Database
|
||||
**/
|
||||
protected function quote($value)
|
||||
{
|
||||
if ($value === null) // hmm the null does pose an issue (will keep an eye on this)
|
||||
{
|
||||
return 'NULL';
|
||||
}
|
||||
|
||||
if (is_numeric($value))
|
||||
{
|
||||
if (filter_var($value, FILTER_VALIDATE_INT))
|
||||
@@ -76,12 +81,18 @@ abstract class Database
|
||||
return (float) $value;
|
||||
}
|
||||
}
|
||||
elseif (is_bool($value))
|
||||
elseif (is_bool($value)) // not sure if this will work well (but its correct)
|
||||
{
|
||||
return (int) $value;
|
||||
return $value ? 'TRUE' : 'FALSE';
|
||||
}
|
||||
|
||||
// default just escape it
|
||||
// For date and datetime values
|
||||
if ($value instanceof \DateTime)
|
||||
{
|
||||
return $this->db->quote($value->format('Y-m-d H:i:s'));
|
||||
}
|
||||
|
||||
// For other data types, just escape it
|
||||
return $this->db->quote($value);
|
||||
}
|
||||
|
||||
|
@@ -32,6 +32,17 @@ abstract class Mapper implements Mapperdoubleinterface, Mappersingleinterface
|
||||
**/
|
||||
public array $active = [];
|
||||
|
||||
/**
|
||||
* Check if any values are set in the active array
|
||||
*
|
||||
* @return bool Returns true if the active array is not empty, false otherwise
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function isActive(): bool
|
||||
{
|
||||
return !empty($this->active);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set content
|
||||
*
|
||||
@@ -128,6 +139,32 @@ abstract class Mapper implements Mapperdoubleinterface, Mappersingleinterface
|
||||
**/
|
||||
public array $_active = [];
|
||||
|
||||
/**
|
||||
* Check if any values are set in the active array.
|
||||
*
|
||||
* @param string|null $firstKey Optional. The first key to check for values.
|
||||
*
|
||||
* @return bool True if the active array or the specified subarray is not empty, false otherwise.
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function isActive_(string $firstKey = null): bool
|
||||
{
|
||||
// If a firstKey is provided, check if it has any values.
|
||||
if (is_string($firstKey))
|
||||
{
|
||||
// Get the first key from the input parameter and check if it exists in the active array.
|
||||
$firstKey = $this->firstKey($firstKey);
|
||||
if (isset($this->_active[$firstKey]))
|
||||
{
|
||||
return !empty($this->_active[$firstKey]);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// If no firstKey is provided, check if the entire active array has any values.
|
||||
return !empty($this->_active);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set dynamic content
|
||||
*
|
||||
|
@@ -31,6 +31,17 @@ abstract class MapperSingle implements Mappersingleinterface
|
||||
**/
|
||||
public array $active = [];
|
||||
|
||||
/**
|
||||
* Check if any values are set in the active array
|
||||
*
|
||||
* @return bool Returns true if the active array is not empty, false otherwise
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function isActive(): bool
|
||||
{
|
||||
return !empty($this->active);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set content
|
||||
*
|
||||
|
@@ -67,7 +67,7 @@ abstract class Model
|
||||
|
||||
/**
|
||||
* Model the values of an item
|
||||
* Example: $this->item('table_name', Object);
|
||||
* Example: $this->item(Object, 'table_name');
|
||||
*
|
||||
* @param object $item The item object
|
||||
* @param string|null $table The table
|
||||
@@ -83,35 +83,42 @@ abstract class Model
|
||||
$table = $this->getTable();
|
||||
}
|
||||
|
||||
// field counter
|
||||
$field_number = 0;
|
||||
|
||||
// check if this is a valid table
|
||||
if (($fields = $this->getTableFields($table)) !== null)
|
||||
if (($fields = $this->getTableFields($table, true)) !== null)
|
||||
{
|
||||
// field counter
|
||||
$field_number = 0;
|
||||
|
||||
// check if this is a valid table
|
||||
$item_bucket = new \stdClass();
|
||||
|
||||
foreach ($fields as $field)
|
||||
{
|
||||
// model a value if it exists
|
||||
if(isset($item->{$field}))
|
||||
{
|
||||
if (!$this->validateBefore($item->{$field}, $field, $table))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$item->{$field} = $this->value($item->{$field}, $field, $table);
|
||||
|
||||
if ($this->validate($item->{$field}))
|
||||
if (!$this->validateAfter($item->{$field}, $field, $table))
|
||||
{
|
||||
$field_number++;
|
||||
}
|
||||
else
|
||||
{
|
||||
unset($item->{$field});
|
||||
continue;
|
||||
}
|
||||
|
||||
$item_bucket->{$field} = $item->{$field};
|
||||
|
||||
$field_number++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// all items must have more than one field or its empty (1 = id)
|
||||
if ($field_number > 1)
|
||||
{
|
||||
return $item;
|
||||
// all items must have more than one field or its empty (1 = id or guid)
|
||||
if ($field_number > 1)
|
||||
{
|
||||
return $item_bucket;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
@@ -144,7 +151,110 @@ abstract class Model
|
||||
if (($item = $this->item($item, $table)) !== null)
|
||||
{
|
||||
// add the last ID
|
||||
$this->last[$table] = $item->id;
|
||||
$this->last[$table] = $item->id ?? $this->last[$table] ?? null;
|
||||
}
|
||||
else
|
||||
{
|
||||
unset($items[$id]);
|
||||
}
|
||||
}
|
||||
|
||||
if (ArrayHelper::check($items))
|
||||
{
|
||||
return $items;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Model the values of an row
|
||||
* Example: $this->item(Array, 'table_name');
|
||||
*
|
||||
* @param array $item The item array
|
||||
* @param string|null $table The table
|
||||
*
|
||||
* @return array|null
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function row(array $item, ?string $table = null): ?array
|
||||
{
|
||||
// set the table name
|
||||
if (empty($table))
|
||||
{
|
||||
$table = $this->getTable();
|
||||
}
|
||||
|
||||
if (($fields = $this->getTableFields($table, true)) !== null)
|
||||
{
|
||||
// field counter
|
||||
$field_number = 0;
|
||||
|
||||
// check if this is a valid table
|
||||
$item_bucket = [];
|
||||
|
||||
foreach ($fields as $field)
|
||||
{
|
||||
// model a value if it exists
|
||||
if(isset($item[$field]))
|
||||
{
|
||||
if (!$this->validateBefore($item[$field], $field, $table))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$item[$field] = $this->value($item[$field], $field, $table);
|
||||
|
||||
if (!$this->validateAfter($item[$field], $field, $table))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$item_bucket[$field] = $item[$field];
|
||||
|
||||
$field_number++;
|
||||
}
|
||||
}
|
||||
|
||||
// all items must have more than one field or its empty (1 = id or guid)
|
||||
if ($field_number > 1)
|
||||
{
|
||||
return $item_bucket;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Model the values of multiple rows
|
||||
* Example: $this->items(Array, 'table_name');
|
||||
*
|
||||
* @param array|null $items The array of item array
|
||||
* @param string|null $table The table
|
||||
*
|
||||
* @return array|null
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function rows(?array $items = null, ?string $table = null): ?array
|
||||
{
|
||||
// check if this is a valid table
|
||||
if (ArrayHelper::check($items))
|
||||
{
|
||||
// set the table name
|
||||
if (empty($table))
|
||||
{
|
||||
$table = $this->getTable();
|
||||
}
|
||||
|
||||
foreach ($items as $id => &$item)
|
||||
{
|
||||
// model the item
|
||||
if (($item = $this->row($item, $table)) !== null)
|
||||
{
|
||||
// add the last ID
|
||||
$this->last[$table] = $item['id'] ?? $this->last[$table] ?? null;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -188,7 +298,21 @@ abstract class Model
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the values (basic, override in child class)
|
||||
* Get the current active table's fields (including defaults)
|
||||
*
|
||||
* @param string $table The area
|
||||
* @param bool $default Add the default fields
|
||||
*
|
||||
* @return array
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected function getTableFields(string $table, bool $default = false): ?array
|
||||
{
|
||||
return $this->table->fields($table, $default);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate before the value is modelled (basic, override in child class)
|
||||
*
|
||||
* @param mixed $value The field value
|
||||
* @param string|null $field The field key
|
||||
@@ -197,29 +321,19 @@ abstract class Model
|
||||
* @return bool
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected function validate(&$value, ?string $field = null, ?string $table = null): bool
|
||||
{
|
||||
// check values
|
||||
if (StringHelper::check($value) || ArrayHelper::check($value, true))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
// remove empty values
|
||||
return false;
|
||||
}
|
||||
abstract protected function validateBefore(&$value, ?string $field = null, ?string $table = null): bool;
|
||||
|
||||
/**
|
||||
* Get the current active table's fields
|
||||
* Validate after the value is modelled (basic, override in child class)
|
||||
*
|
||||
* @param string $table The table
|
||||
* @param mixed $value The field value
|
||||
* @param string|null $field The field key
|
||||
* @param string|null $table The table
|
||||
*
|
||||
* @return array
|
||||
* @return bool
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected function getTableFields(string $table): ?array
|
||||
{
|
||||
return $this->table->fields($table);
|
||||
}
|
||||
abstract protected function validateAfter(&$value, ?string $field = null, ?string $table = null): bool;
|
||||
|
||||
/**
|
||||
* Get the current active table
|
||||
|
@@ -0,0 +1,40 @@
|
||||
<?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\Builder\Update;
|
||||
|
||||
|
||||
use VDM\Joomla\Componentbuilder\Interfaces\Mappersingleinterface;
|
||||
use VDM\Joomla\Componentbuilder\Abstraction\MapperSingle;
|
||||
|
||||
|
||||
/**
|
||||
* Compiler Builder Update Mysql
|
||||
*
|
||||
* @since 3.2.0
|
||||
*/
|
||||
class Mysql extends MapperSingle implements Mappersingleinterface
|
||||
{
|
||||
/**
|
||||
* Model the key
|
||||
*
|
||||
* @param string $key The key to model
|
||||
*
|
||||
* @return string
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected function key(string $key): string
|
||||
{
|
||||
return preg_replace('/\s+/', '', $key);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -0,0 +1 @@
|
||||
<html><body bgcolor="#FFFFFF"></body></html>
|
@@ -796,15 +796,16 @@ class Data
|
||||
$this->config->lang_target = $nowLang;
|
||||
|
||||
// catch empty URL to update server TODO: we need to fix this in better way later
|
||||
if ($component->add_update_server == 1 && $component->update_server_target !== 3
|
||||
if (empty($component->add_update_server) || ($component->add_update_server == 1 && $component->update_server_target != 3
|
||||
&& (
|
||||
!StringHelper::check($component->update_server_url)
|
||||
|| strpos($component->update_server_url, 'http') === false
|
||||
))
|
||||
)))
|
||||
{
|
||||
// we fall back to other, since we can't work with an empty update server URL
|
||||
$component->add_update_server = 0;
|
||||
$component->update_server_target = 3;
|
||||
$component->update_server_url = '';
|
||||
}
|
||||
|
||||
// add the update/sales server FTP details if that is the expected protocol
|
||||
|
@@ -57,6 +57,17 @@ class Config extends BaseConfig
|
||||
$this->config = $config ?: JoomlaFactory::getConfig();
|
||||
}
|
||||
|
||||
/**
|
||||
* get Gitea Access Token
|
||||
*
|
||||
* @return string the access token
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected function getGiteatoken(): ?string
|
||||
{
|
||||
return $this->params->get('access.token');
|
||||
}
|
||||
|
||||
/**
|
||||
* get add contributors switch
|
||||
*
|
||||
@@ -538,6 +549,68 @@ class Config extends BaseConfig
|
||||
return $this->params->get('jcb_powers_path', 'libraries/jcb_powers');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get local super powers repository path
|
||||
*
|
||||
* @return string The path to the local repository
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected function getLocalpowersrepositorypath(): string
|
||||
{
|
||||
$default = $this->tmp_path . '/super_powers';
|
||||
|
||||
if (!$this->add_super_powers)
|
||||
{
|
||||
return $default;
|
||||
}
|
||||
|
||||
$global = $this->params->get('local_powers_repository_path', $default);
|
||||
|
||||
if (!$this->show_advanced_options)
|
||||
{
|
||||
return $global;
|
||||
}
|
||||
|
||||
$value = $this->input->post->get('powers_repository', 2, 'INT');
|
||||
|
||||
return $value == 1
|
||||
? $this->input->post->get('local_powers_repository_path', $global, 'PATH')
|
||||
: $global;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get super power approved paths
|
||||
*
|
||||
* @return array The approved paths to the repositories on Gitea
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected function getApprovedpaths(): array
|
||||
{
|
||||
$default = (object) ['owner' => 'joomla', 'repo' => 'super-powers', 'branch' => 'master'];
|
||||
|
||||
if (!$this->add_own_powers)
|
||||
{
|
||||
return [$default];
|
||||
}
|
||||
|
||||
$paths = $this->params->get('approved_paths');
|
||||
|
||||
$approved = [];
|
||||
if (!empty($paths))
|
||||
{
|
||||
foreach ($paths as $path)
|
||||
{
|
||||
// we make sure to get only the objects
|
||||
$approved[] = $path;
|
||||
}
|
||||
}
|
||||
|
||||
// finally we add the default
|
||||
$approved[] = $default;
|
||||
|
||||
return $approved;
|
||||
}
|
||||
|
||||
/**
|
||||
* get bom path
|
||||
*
|
||||
@@ -661,6 +734,42 @@ class Config extends BaseConfig
|
||||
return (bool) $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get switch to add super powers
|
||||
*
|
||||
* @return bool Switch to add super powers
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected function getAddsuperpowers(): bool
|
||||
{
|
||||
$default = (bool) $this->params->get('powers_repository', 0);
|
||||
|
||||
if (!$this->show_advanced_options)
|
||||
{
|
||||
return $default;
|
||||
}
|
||||
|
||||
$value = $this->input->post->get('powers_repository', 2, 'INT');
|
||||
|
||||
return $value == 2 ? $default : (bool) $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get switch to add own super powers
|
||||
*
|
||||
* @return bool Switch to add own super powers
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected function getAddownpowers(): bool
|
||||
{
|
||||
if ($this->add_super_powers)
|
||||
{
|
||||
return (bool) $this->params->get('super_powers_repositories', 0);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* get switch build target switch
|
||||
*
|
||||
|
@@ -20,6 +20,7 @@ use VDM\Joomla\Componentbuilder\Compiler\Factory as Compiler;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Config;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Placeholder;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Language\Extractor;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Power\Extractor as Power;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Customcode\External;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Utilities\Placefix;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Interfaces\CustomcodeInterface;
|
||||
@@ -102,6 +103,14 @@ class Customcode implements CustomcodeInterface
|
||||
**/
|
||||
protected Extractor $extractor;
|
||||
|
||||
/**
|
||||
* Super Power Extractor
|
||||
*
|
||||
* @var Power
|
||||
* @since 3.2.0
|
||||
**/
|
||||
protected Power $power;
|
||||
|
||||
/**
|
||||
* Compiler Custom Code External
|
||||
*
|
||||
@@ -124,17 +133,19 @@ class Customcode implements CustomcodeInterface
|
||||
* @param Config|null $config The compiler config object.
|
||||
* @param Placeholder|null $placeholder The compiler placeholder object.
|
||||
* @param Extractor|null $extractor The compiler language extractor object.
|
||||
* @param External|null $external The compiler external custom code object.
|
||||
* @param Power|null $power The compiler power extractor object.
|
||||
* @param External|null $external The compiler external custom code object.
|
||||
* @param \JDatabaseDriver $db The Database Driver object.
|
||||
*
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function __construct(?Config $config = null, ?Placeholder $placeholder = null,
|
||||
?Extractor $extractor = null, ?External $external = null, ?\JDatabaseDriver $db = null)
|
||||
?Extractor $extractor = null, ?Power $power = null, ?External $external = null, ?\JDatabaseDriver $db = null)
|
||||
{
|
||||
$this->config = $config ?: Compiler::_('Config');
|
||||
$this->placeholder = $placeholder ?: Compiler::_('Placeholder');
|
||||
$this->extractor = $extractor ?: Compiler::_('Language.Extractor');
|
||||
$this->power = $power ?: Compiler::_('Power.Extractor');
|
||||
$this->external = $external ?: Compiler::_('Customcode.External');
|
||||
$this->db = $db ?: Factory::getDbo();
|
||||
}
|
||||
@@ -159,6 +170,9 @@ class Customcode implements CustomcodeInterface
|
||||
$this->external->set($string, $debug), $debug
|
||||
)
|
||||
);
|
||||
|
||||
// extract any found super powers
|
||||
$this->power->search($string);
|
||||
}
|
||||
// if debug
|
||||
if ($debug)
|
||||
@@ -276,8 +290,7 @@ class Customcode implements CustomcodeInterface
|
||||
if (strpos($array[1], ',') !== false)
|
||||
{
|
||||
// update the function values with the custom code key placeholders (this allow the use of [] + and , in the values)
|
||||
$this->data[$id]['args'][$key]
|
||||
= array_map(
|
||||
$this->data[$id]['args'][$key] = array_map(
|
||||
fn($_key) => $this->placeholder->update(
|
||||
$_key,
|
||||
$this->keys
|
||||
@@ -288,8 +301,7 @@ class Customcode implements CustomcodeInterface
|
||||
$array[1]
|
||||
))
|
||||
{
|
||||
$this->data[$id]['args'][$key]
|
||||
= [];
|
||||
$this->data[$id]['args'][$key] = [];
|
||||
// update the function values with the custom code key placeholders (this allow the use of [] + and , in the values)
|
||||
$this->data[$id]['args'][$key][]
|
||||
= $this->placeholder->update(
|
||||
|
@@ -124,39 +124,10 @@ class Dispenser implements DispenserInterface
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// this needs refactoring (TODO)
|
||||
if (!isset($this->hub[$first])
|
||||
|| ($second
|
||||
&& !isset($this->hub[$first][$second])))
|
||||
{
|
||||
// check if the script first key is set
|
||||
if ($second && !isset($this->hub[$first]))
|
||||
{
|
||||
$this->hub[$first] = [];
|
||||
}
|
||||
elseif ($add && !$second
|
||||
&& !isset($this->hub[$first]))
|
||||
{
|
||||
$this->hub[$first] = '';
|
||||
}
|
||||
// check if the script second key is set
|
||||
if ($second && $third
|
||||
&& !isset($this->hub[$first][$second]))
|
||||
{
|
||||
$this->hub[$first][$second] = [];
|
||||
}
|
||||
elseif ($add && $second && !$third
|
||||
&& !isset($this->hub[$first][$second]))
|
||||
{
|
||||
$this->hub[$first][$second] = '';
|
||||
}
|
||||
// check if the script third key is set
|
||||
if ($add && $second && $third
|
||||
&& !isset($this->hub[$first][$second][$third]))
|
||||
{
|
||||
$this->hub[$first][$second][$third] = '';
|
||||
}
|
||||
}
|
||||
|
||||
// init all needed arrays
|
||||
$this->initHub($first, $second, $third, $add);
|
||||
|
||||
// prep the script string
|
||||
if ($base64 && $dynamic)
|
||||
{
|
||||
@@ -166,7 +137,7 @@ class Dispenser implements DispenserInterface
|
||||
{
|
||||
$script = base64_decode($script);
|
||||
}
|
||||
elseif ($dynamic) // this does not happen (just incase)
|
||||
elseif ($dynamic) // this does not happen (just in-case)
|
||||
{
|
||||
$script = $this->customcode->update($script);
|
||||
}
|
||||
@@ -178,49 +149,15 @@ class Dispenser implements DispenserInterface
|
||||
{
|
||||
$script = $this->gui->set($script, $config);
|
||||
}
|
||||
|
||||
// add Dynamic HASHING option of a file/string
|
||||
$script = $this->hash->set($script);
|
||||
|
||||
// add base64 locking option of a string
|
||||
$script = $this->base64->set($script);
|
||||
|
||||
// load the script
|
||||
if ($first && $second && $third)
|
||||
{
|
||||
// now act on loading option
|
||||
if ($add)
|
||||
{
|
||||
$this->hub[$first][$second][$third]
|
||||
.= $script;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->hub[$first][$second][$third]
|
||||
= $script;
|
||||
}
|
||||
}
|
||||
elseif ($first && $second)
|
||||
{
|
||||
// now act on loading option
|
||||
if ($add)
|
||||
{
|
||||
$this->hub[$first][$second] .= $script;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->hub[$first][$second] = $script;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// now act on loading option
|
||||
if ($add)
|
||||
{
|
||||
$this->hub[$first] .= $script;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->hub[$first] = $script;
|
||||
}
|
||||
}
|
||||
$this->setHub($script, $first, $second, $third, $add);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -240,7 +177,6 @@ class Dispenser implements DispenserInterface
|
||||
* @param string $suffix The suffix to add after the script if found
|
||||
*
|
||||
* @return mixed The string/script if found or the default value if not found
|
||||
*
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function get(string $first, string $second, string $prefix = '', ?string $note = null,
|
||||
@@ -279,6 +215,71 @@ class Dispenser implements DispenserInterface
|
||||
|
||||
return $script;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Make sure the hub arrays are all set
|
||||
*
|
||||
* @param string $first The first key
|
||||
* @param string|null $second The second key (if not set we use only first key)
|
||||
* @param string|null $third The third key (if not set we use only first and second key)
|
||||
* @param bool $add The switch to add to exiting instead of replace
|
||||
* default: false
|
||||
*
|
||||
* @return void
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected function initHub(string $first, ?string $second = null, ?string $third = null, bool $add = false)
|
||||
{
|
||||
if (!isset($this->hub[$first]))
|
||||
{
|
||||
$this->hub[$first] = ($second !== null || $add) ? ($second !== null ? [] : '') : [];
|
||||
}
|
||||
|
||||
if ($second !== null && !isset($this->hub[$first][$second]))
|
||||
{
|
||||
$this->hub[$first][$second] = ($third !== null || $add) ? ($third !== null ? [] : '') : [];
|
||||
}
|
||||
|
||||
if ($third !== null && !isset($this->hub[$first][$second][$third]))
|
||||
{
|
||||
$this->hub[$first][$second][$third] = $add ? '' : [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a script in the hub
|
||||
*
|
||||
* @param string $script The script
|
||||
* @param string $first The first key
|
||||
* @param string|null $second The second key (if not set we use only first key)
|
||||
* @param string|null $third The third key (if not set we use only first and second key)
|
||||
* @param bool $add The switch to add to exiting instead of replace
|
||||
* default: false
|
||||
*
|
||||
* @return void
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected function setHub(string $script, string $first, ?string $second = null, ?string $third = null, bool $add = false)
|
||||
{
|
||||
// Load the script
|
||||
if ($second !== null)
|
||||
{
|
||||
if ($third !== null)
|
||||
{
|
||||
$this->hub[$first][$second][$third] =
|
||||
$add ? $this->hub[$first][$second][$third] . $script : $script;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->hub[$first][$second] =
|
||||
$add ? $this->hub[$first][$second] . $script : $script;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->hub[$first] =
|
||||
$add ? $this->hub[$first] . $script : $script;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -23,6 +23,7 @@ use VDM\Joomla\Utilities\String\FieldHelper;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Factory as Compiler;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Config;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Placeholder\Reverse;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Power\Parser;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Interfaces\Customcode\GuiInterface;
|
||||
|
||||
|
||||
@@ -49,6 +50,14 @@ class Gui implements GuiInterface
|
||||
**/
|
||||
protected Reverse $reverse;
|
||||
|
||||
/**
|
||||
* Compiler Powers Parser
|
||||
*
|
||||
* @var Parser
|
||||
* @since 3.2.0
|
||||
**/
|
||||
protected Parser $parser;
|
||||
|
||||
/**
|
||||
* Database object to query local DB
|
||||
*
|
||||
@@ -70,17 +79,19 @@ class Gui implements GuiInterface
|
||||
*
|
||||
* @param Config|null $config The compiler config object.
|
||||
* @param Reverse|null $reverse The compiler placeholder reverse object.
|
||||
* @param Parser|null $parser The powers parser object.
|
||||
* @param \JDatabaseDriver|null $db The Database Driver object.
|
||||
* @param CMSApplication|null $app The CMS Application object.
|
||||
*
|
||||
* @throws \Exception
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function __construct(?Config $config = null, ?Reverse $reverse = null,
|
||||
public function __construct(?Config $config = null, ?Reverse $reverse = null, ?Parser $parser = null,
|
||||
?\JDatabaseDriver $db = null, ?CMSApplication $app = null)
|
||||
{
|
||||
$this->config = $config ?: Compiler::_('Config');
|
||||
$this->reverse = $reverse ?: Compiler::_('Placeholder.Reverse');
|
||||
$this->parser = $parser ?: Compiler::_('Power.Parser');
|
||||
$this->db = $db ?: Factory::getDbo();
|
||||
$this->app = $app ?: Factory::getApplication();
|
||||
}
|
||||
@@ -181,15 +192,18 @@ class Gui implements GuiInterface
|
||||
public function search(string &$file, array &$placeholders, string &$today, string &$target)
|
||||
{
|
||||
// get file content
|
||||
$file_conent = FileHelper::getContent($file);
|
||||
$file_content = FileHelper::getContent($file);
|
||||
|
||||
// get the USE statements (to reverse engineer super power keys)
|
||||
$use_statements = $this->parser->getUseStatements($file_content);
|
||||
|
||||
$guiCode = [];
|
||||
// we add a new search for the GUI CODE Blocks
|
||||
$guiCode[] = GetHelper::allBetween(
|
||||
$file_conent, '/***[JCB' . 'GUI<>', '/***[/JCBGUI' . '$$$$]***/'
|
||||
$file_content, '/***[JCB' . 'GUI<>', '/***[/JCBGUI' . '$$$$]***/'
|
||||
);
|
||||
$guiCode[] = GetHelper::allBetween(
|
||||
$file_conent, '<!--[JCB' . 'GUI<>', '<!--[/JCBGUI' . '$$$$]-->'
|
||||
$file_content, '<!--[JCB' . 'GUI<>', '<!--[/JCBGUI' . '$$$$]-->'
|
||||
);
|
||||
|
||||
if (($guiCode = ArrayHelper::merge($guiCode)) !== false
|
||||
@@ -214,7 +228,7 @@ class Gui implements GuiInterface
|
||||
$table = StringHelper::safe($query[0]);
|
||||
// reverse placeholder as much as we can
|
||||
$code = $this->reverse->engine(
|
||||
$code, $placeholders, $target, $id, $field, $table
|
||||
$code, $placeholders, $target, $id, $field, $table, $use_statements
|
||||
);
|
||||
// update the GUI/Tables/Database
|
||||
$object = new \stdClass();
|
||||
|
@@ -35,6 +35,18 @@ use VDM\Joomla\Componentbuilder\Compiler\Service\Field;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Service\Joomlamodule;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Service\Joomlaplugin;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Service\Utilities;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Service\Builder;
|
||||
use VDM\Joomla\Componentbuilder\Service\Gitea;
|
||||
use VDM\Joomla\Gitea\Service\Utilities as GiteaUtilities;
|
||||
use VDM\Joomla\Gitea\Service\Settings as GiteaSettings;
|
||||
use VDM\Joomla\Gitea\Service\Organization as GiteaOrg;
|
||||
use VDM\Joomla\Gitea\Service\User as GiteaUser;
|
||||
use VDM\Joomla\Gitea\Service\Repository as GiteaRepo;
|
||||
use VDM\Joomla\Gitea\Service\Package as GiteaPackage;
|
||||
use VDM\Joomla\Gitea\Service\Issue as GiteaIssue;
|
||||
use VDM\Joomla\Gitea\Service\Notifications as GiteNotifi;
|
||||
use VDM\Joomla\Gitea\Service\Miscellaneous as GiteaMisc;
|
||||
use VDM\Joomla\Gitea\Service\Admin as GiteaAdmin;
|
||||
use VDM\Joomla\Componentbuilder\Interfaces\FactoryInterface;
|
||||
|
||||
|
||||
@@ -138,7 +150,19 @@ abstract class Factory implements FactoryInterface
|
||||
->registerServiceProvider(new Field())
|
||||
->registerServiceProvider(new Joomlamodule())
|
||||
->registerServiceProvider(new Joomlaplugin())
|
||||
->registerServiceProvider(new Utilities());
|
||||
->registerServiceProvider(new Utilities())
|
||||
->registerServiceProvider(new Builder())
|
||||
->registerServiceProvider(new Gitea())
|
||||
->registerServiceProvider(new GiteaUtilities())
|
||||
->registerServiceProvider(new GiteaSettings())
|
||||
->registerServiceProvider(new GiteaOrg())
|
||||
->registerServiceProvider(new GiteaUser())
|
||||
->registerServiceProvider(new GiteaRepo())
|
||||
->registerServiceProvider(new GiteaPackage())
|
||||
->registerServiceProvider(new GiteaIssue())
|
||||
->registerServiceProvider(new GiteNotifi())
|
||||
->registerServiceProvider(new GiteaMisc())
|
||||
->registerServiceProvider(new GiteaAdmin());
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -77,7 +77,7 @@ class Historyadminview
|
||||
*/
|
||||
public function set(object &$item)
|
||||
{
|
||||
if ($old = $this->history->get('admin_view', $item->id))
|
||||
if (($old = $this->history->get('admin_view', $item->id)) !== null)
|
||||
{
|
||||
// check if the view name changed
|
||||
if (StringHelper::check($old->name_single))
|
||||
|
@@ -78,54 +78,72 @@ class Historycomponent
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function set(object &$item)
|
||||
{
|
||||
// update SQL for admin views
|
||||
$this->setAdminView($item);
|
||||
|
||||
// update SQL for component
|
||||
$this->setComponent($item);
|
||||
}
|
||||
|
||||
/**
|
||||
* check if an update SQL is needed
|
||||
*
|
||||
* @param object $item The item data
|
||||
*
|
||||
* @return void
|
||||
* @since 3.2.0
|
||||
*/
|
||||
private function setAdminView(object $item)
|
||||
{
|
||||
$old_admin_views = $this->history->get(
|
||||
'component_admin_views', $item->addadmin_views_id
|
||||
);
|
||||
|
||||
// add new views if found
|
||||
if ($old_admin_views && ObjectHelper::check($old_admin_views))
|
||||
{
|
||||
if (isset($old_admin_views->addadmin_views)
|
||||
&& JsonHelper::check(
|
||||
$old_admin_views->addadmin_views
|
||||
))
|
||||
{
|
||||
$this->updatesql->set(
|
||||
json_decode((string) $old_admin_views->addadmin_views, true),
|
||||
$item->addadmin_views, 'adminview'
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the component history
|
||||
*
|
||||
* @param object $item The item data
|
||||
*
|
||||
* @return void
|
||||
* @since 3.2.0
|
||||
*/
|
||||
private function setComponent(object &$item)
|
||||
{
|
||||
$old_component = $this->history->get(
|
||||
'joomla_component', $this->config->component_id
|
||||
);
|
||||
|
||||
if ($old_component || $old_admin_views)
|
||||
// check if a new version was manually set
|
||||
if ($old_component && ObjectHelper::check($old_component))
|
||||
{
|
||||
if (ObjectHelper::check($old_admin_views))
|
||||
$old_component_version = preg_replace(
|
||||
'/[^0-9.]+/', '', (string) $old_component->component_version
|
||||
);
|
||||
if ($old_component_version != $this->config->component_version)
|
||||
{
|
||||
// add new views if found
|
||||
if (isset($old_admin_views->addadmin_views)
|
||||
&& JsonHelper::check(
|
||||
$old_admin_views->addadmin_views
|
||||
))
|
||||
{
|
||||
$this->updatesql->set(
|
||||
json_decode((string) $old_admin_views->addadmin_views, true),
|
||||
$item->addadmin_views, 'adminview'
|
||||
);
|
||||
}
|
||||
|
||||
// check if a new version was manually set
|
||||
if (ObjectHelper::check($old_component))
|
||||
{
|
||||
$old_component_version = preg_replace(
|
||||
'/[^0-9.]+/', '', (string) $old_component->component_version
|
||||
);
|
||||
if ($old_component_version != $this->config->component_version)
|
||||
{
|
||||
// yes, this is a new version, this mean there may
|
||||
// be manual sql and must be checked and updated
|
||||
$item->old_component_version
|
||||
= $old_component_version;
|
||||
}
|
||||
// clear this data
|
||||
unset($old_component);
|
||||
}
|
||||
|
||||
// clear this data
|
||||
unset($old_admin_views);
|
||||
// yes, this is a new version, this mean there may
|
||||
// be manual sql and must be checked and updated
|
||||
$item->old_component_version
|
||||
= $old_component_version;
|
||||
}
|
||||
}
|
||||
|
||||
// unset original value
|
||||
unset($item->addadmin_views);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -12,8 +12,6 @@
|
||||
namespace VDM\Joomla\Componentbuilder\Compiler\Model;
|
||||
|
||||
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Factory as Compiler;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Registry;
|
||||
use VDM\Joomla\Utilities\ArrayHelper;
|
||||
use VDM\Joomla\Utilities\JsonHelper;
|
||||
use VDM\Joomla\Utilities\StringHelper;
|
||||
@@ -26,26 +24,6 @@ use VDM\Joomla\Utilities\StringHelper;
|
||||
*/
|
||||
class Updateserver
|
||||
{
|
||||
/**
|
||||
* Compiler Registry Class
|
||||
*
|
||||
* @var Registry
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected Registry $registry;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param Registry|null $registry The compiler registry object.
|
||||
*
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function __construct(?Registry $registry = null)
|
||||
{
|
||||
$this->registry = $registry ?: Compiler::_('Registry');
|
||||
}
|
||||
|
||||
/**
|
||||
* Set version updates
|
||||
*
|
||||
@@ -72,9 +50,9 @@ class Updateserver
|
||||
}
|
||||
|
||||
/**
|
||||
* Set changelog values to registry
|
||||
* Set changelog values to component changelog
|
||||
*
|
||||
* @param array $updates The update data
|
||||
* @param object $item The item data
|
||||
*
|
||||
* @return void
|
||||
* @since 3.2.0
|
||||
@@ -82,9 +60,9 @@ class Updateserver
|
||||
protected function changelog(object &$item)
|
||||
{
|
||||
// set the version updates
|
||||
$bucket = [];
|
||||
foreach ($item->version_update as $update)
|
||||
{
|
||||
$bucket = [];
|
||||
if (isset($update['change_log']) && StringHelper::check($update['change_log'])
|
||||
&& isset($update['version']) && StringHelper::check($update['version']))
|
||||
{
|
||||
|
@@ -223,8 +223,8 @@ class Updatesql
|
||||
// convert admin view id to name
|
||||
if ('adminview' === $type)
|
||||
{
|
||||
$this->registry->set('builder.add_sql.' . $type,
|
||||
$this->name($item)
|
||||
$this->registry->set('builder.add_sql.' . $type . '.' . $this->name($item),
|
||||
$item
|
||||
);
|
||||
}
|
||||
else
|
||||
|
@@ -20,6 +20,7 @@ use VDM\Joomla\Componentbuilder\Compiler\Config;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Placeholder;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Language;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Language\Extractor;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Power\Extractor as Power;
|
||||
|
||||
|
||||
/**
|
||||
@@ -61,41 +62,54 @@ class Reverse
|
||||
**/
|
||||
protected Extractor $extractor;
|
||||
|
||||
/**
|
||||
* Super Power Extractor
|
||||
*
|
||||
* @var Power
|
||||
* @since 3.2.0
|
||||
**/
|
||||
protected Power $power;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param Config|null $config The compiler config object.
|
||||
* @param Placeholder|null $placeholder The compiler placeholder object.
|
||||
* @param Language|null $language The compiler language object.
|
||||
* @param Extract|null $extractor The compiler language extractor object.
|
||||
* @param Extractor|null $extractor The compiler language extractor object.
|
||||
* @param Power|null $power The compiler power extractor object.
|
||||
*
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function __construct(
|
||||
?Config $config = null, ?Placeholder $placeholder = null,
|
||||
?Language $language = null, ?Extractor $extractor = null)
|
||||
?Language $language = null, ?Extractor $extractor = null,
|
||||
?Power $power = null)
|
||||
{
|
||||
$this->config = $config ?: Compiler::_('Config');
|
||||
$this->placeholder = $placeholder ?: Compiler::_('Placeholder');
|
||||
$this->language = $language ?: Compiler::_('Language');
|
||||
$this->extractor = $extractor ?: Compiler::_('Language.Extractor');
|
||||
$this->power = $power ?: Compiler::_('Power.Extractor');
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse Engineer the dynamic placeholders (TODO hmmmm this is not ideal)
|
||||
*
|
||||
* @param string $string The string to revers
|
||||
* @param array $placeholders The values to search for
|
||||
* @param string $target The target path type
|
||||
* @param int|null $id The custom code id
|
||||
* @param string $field The field name
|
||||
* @param string $table The table name
|
||||
* @param string $string The string to reverse
|
||||
* @param array $placeholders The values to search for
|
||||
* @param string $target The target path type
|
||||
* @param int|null $id The custom code id
|
||||
* @param string $field The field name
|
||||
* @param string $table The table name
|
||||
* @param array|null $useStatements The file use statements (needed for super powers)
|
||||
*
|
||||
* @return string
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function engine(string $string, array &$placeholders,
|
||||
string $target, ?int $id = null, string $field = 'code', string $table = 'custom_code'): string
|
||||
string $target, ?int $id = null, string $field = 'code',
|
||||
string $table = 'custom_code', ?array $useStatements = null): string
|
||||
{
|
||||
// get local code if set
|
||||
if ($id > 0 && $code = base64_decode(
|
||||
@@ -103,13 +117,112 @@ class Reverse
|
||||
))
|
||||
{
|
||||
$string = $this->setReverse(
|
||||
$string, $code, $target
|
||||
$string, $code, $target, $useStatements
|
||||
);
|
||||
}
|
||||
|
||||
return $this->placeholder->update($string, $placeholders, 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse engineer the dynamic language, and super powers
|
||||
*
|
||||
* @param string $updateString The string to update
|
||||
* @param string $string The string to use language update
|
||||
* @param string $target The target path type
|
||||
* @param array|null $useStatements The file use statements (needed for super powers)
|
||||
*
|
||||
* @return string
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected function setReverse(string $updateString, string $string,
|
||||
string $target, ?array $useStatements): string
|
||||
{
|
||||
// we have to reverse engineer to super powers
|
||||
$updateString = $this->reverseSuperPowers($updateString, $string, $useStatements);
|
||||
|
||||
// reverse engineer the language strings
|
||||
$updateString = $this->reverseLanguage($updateString, $string, $target);
|
||||
|
||||
// reverse engineer the custom code (if possible)
|
||||
// $updateString = $this->reverseCustomCode($updateString, $string); // TODO - we would like to also reverse basic customcode
|
||||
|
||||
return $updateString;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the super powers keys for the reveres process
|
||||
*
|
||||
* @param string $updateString The string to update
|
||||
* @param string $string The string to use for super power update
|
||||
* @param array|null $useStatements The file use statements (needed for super powers)
|
||||
*
|
||||
* @return string
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected function reverseSuperPowers(string $updateString, string $string,
|
||||
?array $useStatements): string
|
||||
{
|
||||
// only if we have use statements can we reverse engineer this
|
||||
if ($useStatements !== null && ($powers = $this->power->reverse($string)) !== null &&
|
||||
($reverse = $this->getReversePower($powers, $useStatements)) !== null)
|
||||
{
|
||||
return $this->placeholder->update($updateString, $reverse);
|
||||
}
|
||||
|
||||
return $updateString;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the super powers keys for the reveres process
|
||||
*
|
||||
* @param array $powers The powers found in the database text
|
||||
* @param array $useStatements The file use statements
|
||||
*
|
||||
* @return array|null
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected function getReversePower(array $powers, array $useStatements): ?array
|
||||
{
|
||||
$matching_statements = [];
|
||||
foreach ($useStatements as $use_statement)
|
||||
{
|
||||
$namespace = substr($use_statement, 4, -1); // remove 'use ' and ';'
|
||||
$class_name = '';
|
||||
|
||||
// Check for 'as' alias
|
||||
if (strpos($namespace, ' as ') !== false)
|
||||
{
|
||||
list($namespace, $class_name) = explode(' as ', $namespace);
|
||||
}
|
||||
|
||||
// If there is no 'as' alias, get the class name from the last '\'
|
||||
if (empty($class_name))
|
||||
{
|
||||
$last_slash = strrpos($namespace, '\\');
|
||||
if ($last_slash !== false)
|
||||
{
|
||||
$class_name = substr($namespace, $last_slash + 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the namespace is in the powers array
|
||||
if (in_array($namespace, $powers))
|
||||
{
|
||||
$guid = array_search($namespace, $powers);
|
||||
$matching_statements[$class_name] =
|
||||
'Super_'.'_'.'_' . str_replace('-', '_', $guid) . '_'.'_'.'_Power';
|
||||
}
|
||||
}
|
||||
|
||||
if ($matching_statements !== [])
|
||||
{
|
||||
return $matching_statements;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the language strings for the reveres process
|
||||
*
|
||||
@@ -120,7 +233,7 @@ class Reverse
|
||||
* @return string
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected function setReverse(string $updateString, string $string, string $target): string
|
||||
protected function reverseLanguage(string $updateString, string $string, string $target): string
|
||||
{
|
||||
// get targets to search for
|
||||
$lang_string_targets = array_filter(
|
||||
@@ -184,7 +297,7 @@ class Reverse
|
||||
$string, $lang_string_target . "'", "'"
|
||||
);
|
||||
$lang_check[] = GetHelper::allBetween(
|
||||
$string, $lang_string_target . "'", "'"
|
||||
$string, $lang_string_target . '"', '"'
|
||||
);
|
||||
}
|
||||
// merge arrays
|
||||
@@ -232,6 +345,56 @@ class Reverse
|
||||
|
||||
return $updateString;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the custom code placeholder for the reveres process
|
||||
*
|
||||
* @param string $updateString The string to update
|
||||
* @param string $string The string to use for super power update
|
||||
*
|
||||
* @return string
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected function reverseCustomCode(string $updateString, string $string): string
|
||||
{
|
||||
// check if content has custom code place holder
|
||||
if (strpos($string, '[CUSTO' . 'MCODE=') !== false)
|
||||
{
|
||||
$found = GetHelper::allBetween(
|
||||
$string, '[CUSTO' . 'MCODE=', ']'
|
||||
);
|
||||
$bucket = [];
|
||||
if (ArrayHelper::check($found))
|
||||
{
|
||||
foreach ($found as $key)
|
||||
{
|
||||
// we only update those without args
|
||||
if (is_numeric($key) && $get_func_name = GetHelper::var(
|
||||
'custom_code', $key, 'id', 'function_name'
|
||||
))
|
||||
{
|
||||
$bucket[$get_func_name] = (int) $key;
|
||||
}
|
||||
elseif (StringHelper::check($key)
|
||||
&& strpos((string) $key, '+') === false)
|
||||
{
|
||||
$get_func_name = trim((string) $key);
|
||||
if (isset($bucket[$get_func_name]) || !$found_local = GetHelper::var(
|
||||
'custom_code', $get_func_name, 'function_name',
|
||||
'id'
|
||||
))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
$bucket[$get_func_name] = (int) $found_local;
|
||||
}
|
||||
}
|
||||
// TODO - we need to now get the customcode
|
||||
// search and replace the customcode with the placeholder
|
||||
}
|
||||
}
|
||||
|
||||
return $updateString;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -26,6 +26,7 @@ use VDM\Joomla\Componentbuilder\Compiler\Config;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Placeholder;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Customcode;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Customcode\Gui;
|
||||
use VDM\Joomla\Componentbuilder\Power\Super as Superpower;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Interfaces\PowerInterface;
|
||||
|
||||
|
||||
@@ -60,6 +61,14 @@ class Power implements PowerInterface
|
||||
**/
|
||||
public array $composer = [];
|
||||
|
||||
/**
|
||||
* All super powers of this build
|
||||
*
|
||||
* @var array
|
||||
* @since 3.2.0
|
||||
**/
|
||||
public array $superpowers = [];
|
||||
|
||||
/**
|
||||
* The url to the power, if there is an error.
|
||||
*
|
||||
@@ -76,6 +85,14 @@ class Power implements PowerInterface
|
||||
**/
|
||||
protected array $state = [];
|
||||
|
||||
/**
|
||||
* The state of retry to loaded powers
|
||||
*
|
||||
* @var array
|
||||
* @since 3.2.0
|
||||
**/
|
||||
protected array $retry = [];
|
||||
|
||||
/**
|
||||
* Compiler Config
|
||||
*
|
||||
@@ -108,6 +125,14 @@ class Power implements PowerInterface
|
||||
**/
|
||||
protected Gui $gui;
|
||||
|
||||
/**
|
||||
* The JCB Superpower class
|
||||
*
|
||||
* @var Superpower
|
||||
* @since 3.2.0
|
||||
**/
|
||||
protected Superpower $superpower;
|
||||
|
||||
/**
|
||||
* Database object to query local DB
|
||||
*
|
||||
@@ -131,6 +156,7 @@ class Power implements PowerInterface
|
||||
* @param Placeholder|null $placeholder The compiler placeholder object.
|
||||
* @param Customcode|null $customcode The compiler customcode object.
|
||||
* @param Gui|null $gui The compiler customcode gui object.
|
||||
* @param Superpower|null $superpower The JCB superpower object.
|
||||
* @param \JDatabaseDriver|null $db The Database Driver object.
|
||||
* @param CMSApplication|null $app The CMS Application object.
|
||||
*
|
||||
@@ -138,13 +164,14 @@ class Power implements PowerInterface
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function __construct(?Config $config = null, ?Placeholder $placeholder = null,
|
||||
?Customcode $customcode = null, ?Gui $gui = null,
|
||||
?Customcode $customcode = null, ?Gui $gui = null, ?Superpower $superpower = null,
|
||||
?\JDatabaseDriver $db = null, ?CMSApplication $app = null)
|
||||
{
|
||||
$this->config = $config ?: Compiler::_('Config');
|
||||
$this->placeholder = $placeholder ?: Compiler::_('Placeholder');
|
||||
$this->customcode = $customcode ?: Compiler::_('Customcode');
|
||||
$this->gui = $gui ?: Compiler::_('Customcode.Gui');
|
||||
$this->superpower = $superpower ?: Compiler::_('Superpower');
|
||||
$this->db = $db ?: Factory::getDbo();
|
||||
$this->app = $app ?: Factory::getApplication();
|
||||
}
|
||||
@@ -229,6 +256,10 @@ class Power implements PowerInterface
|
||||
$this->active[$guid]->target_type = 'P0m3R!';
|
||||
$this->active[$guid]->key = $this->active[$guid]->id . '_' . $this->active[$guid]->target_type;
|
||||
|
||||
// reserve some values for the linker
|
||||
$this->active[$guid]->unchanged_namespace = $this->active[$guid]->namespace;
|
||||
$this->active[$guid]->unchanged_description = $this->active[$guid]->description;
|
||||
|
||||
// now set the name
|
||||
$this->active[$guid]->name = $this->placeholder->update_(
|
||||
$this->customcode->update($this->active[$guid]->name)
|
||||
@@ -301,6 +332,9 @@ class Power implements PowerInterface
|
||||
// reset back to starting value
|
||||
$this->config->lang_target = $tmp_lang_target;
|
||||
|
||||
// set the approved super power values
|
||||
$this->setSuperPowers($guid);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -310,6 +344,20 @@ class Power implements PowerInterface
|
||||
// only if guid is valid
|
||||
if ($this->isGuidValid($guid))
|
||||
{
|
||||
// now we search for it via the super power paths
|
||||
if (empty($this->retry[$guid]) && $this->superpower->load($guid, ['remote', 'local']))
|
||||
{
|
||||
// we found it and it was loaded into the database
|
||||
unset($this->state[$guid]);
|
||||
unset($this->active[$guid]);
|
||||
|
||||
// we make sure that this retry only happen once! (just in-case...)
|
||||
$this->retry[$guid] = true;
|
||||
|
||||
// so we try to load it again
|
||||
return $this->set($guid);
|
||||
}
|
||||
|
||||
$this->app->enqueueMessage(
|
||||
Text::sprintf('COM_COMPONENTBUILDER_PPOWER_BGUIDSB_NOT_FOUNDP', $guid),
|
||||
'Error'
|
||||
@@ -513,7 +561,7 @@ class Power implements PowerInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Use Classess
|
||||
* Set Use Classes
|
||||
*
|
||||
* @param string $guid The global unique id of the power
|
||||
* @param array $use The use array
|
||||
@@ -596,6 +644,9 @@ class Power implements PowerInterface
|
||||
|
||||
if (ArrayHelper::check($_composer))
|
||||
{
|
||||
// reserve composer values for the linker
|
||||
$this->active[$guid]->unchanged_composer = $_composer;
|
||||
|
||||
foreach ($_composer as $composer)
|
||||
{
|
||||
if (isset($composer['access_point']) && StringHelper::check($composer['access_point']) &&
|
||||
@@ -641,6 +692,11 @@ class Power implements PowerInterface
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// reserve composer values for the linker
|
||||
$this->active[$guid]->unchanged_composer = '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -670,9 +726,13 @@ class Power implements PowerInterface
|
||||
if ($implement == -1
|
||||
&& StringHelper::check($this->active[$guid]->implements_custom))
|
||||
{
|
||||
// reserve implements custom for the linker
|
||||
$this->active[$guid]->unchanged_implements_custom = $this->active[$guid]->implements_custom;
|
||||
|
||||
$this->active[$guid]->implement_names[] = $this->placeholder->update_(
|
||||
$this->customcode->update($this->active[$guid]->implements_custom)
|
||||
);
|
||||
|
||||
// just add this once
|
||||
unset($this->active[$guid]->implements_custom);
|
||||
}
|
||||
@@ -710,9 +770,13 @@ class Power implements PowerInterface
|
||||
if ($this->active[$guid]->extends == -1
|
||||
&& StringHelper::check($this->active[$guid]->extends_custom))
|
||||
{
|
||||
// reserve extends custom for the linker
|
||||
$this->active[$guid]->unchanged_extends_custom = $this->active[$guid]->extends_custom;
|
||||
|
||||
$this->active[$guid]->extends_name = $this->placeholder->update_(
|
||||
$this->customcode->update($this->active[$guid]->extends_custom)
|
||||
);
|
||||
|
||||
// just add once
|
||||
unset($this->active[$guid]->extends_custom);
|
||||
}
|
||||
@@ -838,13 +902,16 @@ class Power implements PowerInterface
|
||||
// set GUI mapper field
|
||||
$guiMapper['field'] = 'licensing_template';
|
||||
|
||||
// reserve licensing template for the linker
|
||||
$this->active[$guid]->unchanged_licensing_template = base64_decode(
|
||||
(string) $this->active[$guid]->licensing_template
|
||||
);
|
||||
|
||||
// base64 Decode code
|
||||
$this->active[$guid]->licensing_template = $this->gui->set(
|
||||
$this->placeholder->update_(
|
||||
$this->customcode->update(
|
||||
base64_decode(
|
||||
(string) $this->active[$guid]->licensing_template
|
||||
)
|
||||
$this->active[$guid]->unchanged_licensing_template
|
||||
)
|
||||
),
|
||||
$guiMapper
|
||||
@@ -854,6 +921,7 @@ class Power implements PowerInterface
|
||||
{
|
||||
$this->active[$guid]->add_licensing_template = 1;
|
||||
$this->active[$guid]->licensing_template = '';
|
||||
$this->active[$guid]->unchanged_licensing_template = '';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -873,13 +941,16 @@ class Power implements PowerInterface
|
||||
// set GUI mapper field
|
||||
$guiMapper['field'] = 'head';
|
||||
|
||||
// reserve header for the linker
|
||||
$this->active[$guid]->unchanged_head = base64_decode(
|
||||
(string) $this->active[$guid]->head
|
||||
);
|
||||
|
||||
// base64 Decode code
|
||||
$this->active[$guid]->head = $this->gui->set(
|
||||
$this->placeholder->update_(
|
||||
$this->customcode->update(
|
||||
base64_decode(
|
||||
(string) $this->active[$guid]->head
|
||||
)
|
||||
$this->active[$guid]->unchanged_head
|
||||
)
|
||||
),
|
||||
$guiMapper
|
||||
@@ -888,6 +959,7 @@ class Power implements PowerInterface
|
||||
else
|
||||
{
|
||||
$this->active[$guid]->head = '';
|
||||
$this->active[$guid]->unchanged_head = '';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -904,6 +976,11 @@ class Power implements PowerInterface
|
||||
{
|
||||
if (StringHelper::check($this->active[$guid]->main_class_code))
|
||||
{
|
||||
// reserve main class code for the linker
|
||||
$this->active[$guid]->unchanged_main_class_code = base64_decode(
|
||||
(string) $this->active[$guid]->main_class_code
|
||||
);
|
||||
|
||||
// set GUI mapper field
|
||||
$guiMapper['field'] = 'main_class_code';
|
||||
|
||||
@@ -911,15 +988,75 @@ class Power implements PowerInterface
|
||||
$this->active[$guid]->main_class_code = $this->gui->set(
|
||||
$this->placeholder->update_(
|
||||
$this->customcode->update(
|
||||
base64_decode(
|
||||
(string) $this->active[$guid]->main_class_code
|
||||
)
|
||||
$this->active[$guid]->unchanged_main_class_code
|
||||
)
|
||||
),
|
||||
$guiMapper
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the super powers of this power
|
||||
*
|
||||
* @param string $guid The global unique id of the power
|
||||
*
|
||||
* @return void
|
||||
* @since 3.2.0
|
||||
*/
|
||||
private function setSuperPowers(string $guid): void
|
||||
{
|
||||
// set the approved super power values
|
||||
if ($this->config->add_super_powers && $this->active[$guid]->approved == 1)
|
||||
{
|
||||
$this->active[$guid]->approved_paths = (isset($this->active[$guid]->approved_paths)
|
||||
&& JsonHelper::check(
|
||||
$this->active[$guid]->approved_paths
|
||||
)) ? json_decode((string) $this->active[$guid]->approved_paths, true) : null;
|
||||
|
||||
if (ArrayHelper::check($this->active[$guid]->approved_paths))
|
||||
{
|
||||
$global_path = $this->config->local_powers_repository_path;
|
||||
|
||||
// update all paths
|
||||
$this->active[$guid]->super_power_paths = array_map(function($path) use($global_path, $guid) {
|
||||
|
||||
// remove branch
|
||||
if (($pos = strpos($path, ':')) !== false)
|
||||
{
|
||||
$path = substr($path, 0, $pos);
|
||||
}
|
||||
|
||||
// set the repo path
|
||||
$repo = $global_path . '/' . $path;
|
||||
|
||||
// set SuperPowerKey (spk)
|
||||
$spk = 'Super_'.'_' . str_replace('-', '_', $guid) . '_'.'_Power';
|
||||
|
||||
// set the global super power
|
||||
$this->superpowers[$repo][$guid] = [
|
||||
'name' => $this->active[$guid]->code_name,
|
||||
'type' => $this->active[$guid]->type,
|
||||
'namespace' => $this->active[$guid]->_namespace,
|
||||
'code' => 'src/' . $guid . '/code.php',
|
||||
'power' => 'src/' . $guid . '/code.power',
|
||||
'settings' => 'src/' . $guid . '/settings.json',
|
||||
'path' => 'src/' . $guid,
|
||||
'spk' => $spk,
|
||||
'guid' => $guid
|
||||
];
|
||||
|
||||
return $repo . '/src/' . $guid;
|
||||
}, array_values($this->active[$guid]->approved_paths));
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// reset all to avoid any misunderstanding down steam
|
||||
$this->active[$guid]->super_power_paths = null;
|
||||
$this->active[$guid]->approved_paths = null;
|
||||
$this->active[$guid]->approved = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -0,0 +1,244 @@
|
||||
<?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;
|
||||
|
||||
|
||||
use Joomla\CMS\Factory;
|
||||
use VDM\Joomla\Utilities\GuidHelper;
|
||||
|
||||
|
||||
/**
|
||||
* Compiler Power Extractor
|
||||
* @since 3.2.0
|
||||
*/
|
||||
final class Extractor
|
||||
{
|
||||
/**
|
||||
* The pattern to get the powers
|
||||
*
|
||||
* @var string
|
||||
* @since 3.2.0
|
||||
**/
|
||||
protected string $pattern = '/Super_'.'_'.'_[a-zA-Z0-9_]+_'.'_'.'_Power/';
|
||||
|
||||
/**
|
||||
* Powers GUID's
|
||||
*
|
||||
* @var array
|
||||
* @since 3.2.0
|
||||
**/
|
||||
protected array $powers = [];
|
||||
|
||||
/**
|
||||
* Database object to query local DB
|
||||
*
|
||||
* @var \JDatabaseDriver
|
||||
* @since 3.2.0
|
||||
**/
|
||||
protected \JDatabaseDriver $db;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param \JDatabaseDriver|null $db The database object.
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function __construct(?\JDatabaseDriver $db = null)
|
||||
{
|
||||
$this->db = $db ?: Factory::getDbo();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Super Powers from the code string
|
||||
*
|
||||
* @param string $code The code
|
||||
*
|
||||
* @return array|null
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function get_(): ?array
|
||||
{
|
||||
return $this->powers !== [] ? $this->powers : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Super Powers from the code string
|
||||
*
|
||||
* @param string $code The code
|
||||
*
|
||||
* @return array|null
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function get(string $code): ?array
|
||||
{
|
||||
$matches = [];
|
||||
preg_match_all($this->pattern, $code, $matches);
|
||||
|
||||
$found = $matches[0];
|
||||
|
||||
if (!empty($found))
|
||||
{
|
||||
return $this->map($found);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Super Powers from the code string
|
||||
*
|
||||
* @param string $code The code
|
||||
*
|
||||
* @return array|null
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function reverse(string $code): ?array
|
||||
{
|
||||
$matches = [];
|
||||
preg_match_all($this->pattern, $code, $matches);
|
||||
|
||||
$found = $matches[0];
|
||||
|
||||
if (!empty($found) && ($guids = $this->filter($found)) !== null)
|
||||
{
|
||||
return $this->namespaces($guids);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Super Powers from the code string and load it
|
||||
*
|
||||
* @param string $code The code
|
||||
*
|
||||
* @return void
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function search(string $code)
|
||||
{
|
||||
$matches = [];
|
||||
preg_match_all($this->pattern, $code, $matches);
|
||||
|
||||
$found = $matches[0];
|
||||
|
||||
if (!empty($found))
|
||||
{
|
||||
$this->load($found);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the Super Powers found
|
||||
*
|
||||
* @param array $found The found Super Powers
|
||||
*
|
||||
* @return void
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected function load(array $found)
|
||||
{
|
||||
foreach ($found as $super_power)
|
||||
{
|
||||
$guid = str_replace(['Super_'.'_'.'_', '_'.'_'.'_Power'], '', $super_power);
|
||||
$guid = str_replace('_', '-', $guid);
|
||||
|
||||
if (GuidHelper::valid($guid))
|
||||
{
|
||||
$this->powers[$guid] = 1; // 1 force the power to be added
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Map the Super Powers to GUIDs
|
||||
*
|
||||
* @param array $found The found Super Powers
|
||||
*
|
||||
* @return array
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected function map(array $found): ?array
|
||||
{
|
||||
$guids = [];
|
||||
|
||||
foreach ($found as $super_power)
|
||||
{
|
||||
$guid = str_replace(['Super_'.'_'.'_', '_'.'_'.'_Power'], '', $super_power);
|
||||
$guid = str_replace('_', '-', $guid);
|
||||
|
||||
if (GuidHelper::valid($guid))
|
||||
{
|
||||
$guids[$super_power] = $guid;
|
||||
}
|
||||
}
|
||||
|
||||
return $guids !== [] ? $guids : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter the Super Powers to GUIDs
|
||||
*
|
||||
* @param array $found The found Super Powers
|
||||
*
|
||||
* @return array
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected function filter(array $found): ?array
|
||||
{
|
||||
$guids = [];
|
||||
|
||||
foreach ($found as $super_power)
|
||||
{
|
||||
$guid = str_replace(['Super_'.'_'.'_', '_'.'_'.'_Power'], '', $super_power);
|
||||
$guid = str_replace('_', '-', $guid);
|
||||
|
||||
if (GuidHelper::valid($guid))
|
||||
{
|
||||
$guids[$guid] = $guid;
|
||||
}
|
||||
}
|
||||
|
||||
return $guids !== [] ? array_values($guids) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the complete namespace strings of the guids passed as an array.
|
||||
*
|
||||
* @param array $guids The guids to filter the results
|
||||
*
|
||||
* @return array|null The result namespaces with their guids
|
||||
* @since 3.2.0
|
||||
**/
|
||||
protected function namespaces(array $guids): ?array
|
||||
{
|
||||
$query = $this->db->getQuery(true);
|
||||
$query->select(
|
||||
'DISTINCT REPLACE('
|
||||
. $this->db->quoteName('namespace')
|
||||
. ', ".", "\\\") AS full_namespace, '
|
||||
. $this->db->quoteName('guid')
|
||||
)
|
||||
->from($this->db->quoteName('#__componentbuilder_power'))
|
||||
->where($this->db->quoteName('guid') . ' IN (' . implode(',', array_map([$this->db, 'quote'], $guids)) . ')');
|
||||
$this->db->setQuery($query);
|
||||
$this->db->execute();
|
||||
|
||||
if ($this->db->getNumRows())
|
||||
{
|
||||
return $this->db->loadAssocList('guid', 'full_namespace');
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@@ -17,6 +17,9 @@ use VDM\Joomla\Componentbuilder\Compiler\Config;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Power;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Content;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Power\Autoloader;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Power\Parser;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Power\Repo\Readme as RepoReadme;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Power\Repos\Readme as ReposReadme;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Placeholder;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Interfaces\EventInterface as Event;
|
||||
use VDM\Joomla\Utilities\StringHelper;
|
||||
@@ -62,6 +65,30 @@ class Infusion
|
||||
**/
|
||||
protected Autoloader $autoloader;
|
||||
|
||||
/**
|
||||
* Compiler Powers Parser
|
||||
*
|
||||
* @var Parser
|
||||
* @since 3.2.0
|
||||
**/
|
||||
protected Parser $parser;
|
||||
|
||||
/**
|
||||
* Compiler Powers Repo Readme Builder
|
||||
*
|
||||
* @var RepoReadme
|
||||
* @since 3.2.0
|
||||
**/
|
||||
protected RepoReadme $reporeadme;
|
||||
|
||||
/**
|
||||
* Compiler Powers Repos Readme Builder
|
||||
*
|
||||
* @var ReposReadme
|
||||
* @since 3.2.0
|
||||
**/
|
||||
protected ReposReadme $reposreadme;
|
||||
|
||||
/**
|
||||
* Compiler Placeholder
|
||||
*
|
||||
@@ -78,6 +105,34 @@ class Infusion
|
||||
**/
|
||||
protected Event $event;
|
||||
|
||||
/**
|
||||
* Power linker values
|
||||
*
|
||||
* @var array
|
||||
* @since 3.2.0
|
||||
**/
|
||||
protected array $linker = [
|
||||
'add_head' => 'add_head',
|
||||
'unchanged_composer' => 'composer',
|
||||
'unchanged_description' => 'description',
|
||||
'extends' => 'extends',
|
||||
'unchanged_extends_custom' => 'extends_custom',
|
||||
'guid' => 'guid',
|
||||
'unchanged_head' => 'head',
|
||||
'use_selection' => 'use_selection',
|
||||
'implements' => 'implements',
|
||||
'unchanged_implements_custom' => 'implements_custom',
|
||||
'load_selection' => 'load_selection',
|
||||
'name' => 'name',
|
||||
'power_version' => 'power_version',
|
||||
'system_name' => 'system_name',
|
||||
'type' => 'type',
|
||||
'unchanged_namespace' => 'namespace',
|
||||
'unchanged_composer' => 'composer',
|
||||
'add_licensing_template' => 'add_licensing_template',
|
||||
'unchanged_licensing_template' => 'licensing_template'
|
||||
];
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
@@ -85,18 +140,25 @@ class Infusion
|
||||
* @param Power|null $power The power object.
|
||||
* @param Content|null $content The compiler content object.
|
||||
* @param Autoloader|null $autoloader The powers autoloader object.
|
||||
* @param Parser|null $parser The powers parser object.
|
||||
* @param RepoReadme|null $reporeadme The powers repo readme builder object.
|
||||
* @param ReposReadme|null $reposreadme The powers repos readme builder object.
|
||||
* @param Placeholder|null $placeholder The placeholder object.
|
||||
* @param Event|null $event The events object.
|
||||
*
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function __construct(?Config $config = null, ?Power $power = null, ?Content $content = null,
|
||||
?Autoloader $autoloader = null, ?Placeholder $placeholder = null, ?Event $event = null)
|
||||
?Autoloader $autoloader = null, ?Parser $parser = null, ?RepoReadme $reporeadme = null,
|
||||
?ReposReadme $reposreadme = null, ?Placeholder $placeholder = null, ?Event $event = null)
|
||||
{
|
||||
$this->config = $config ?: Compiler::_('Config');
|
||||
$this->power = $power ?: Compiler::_('Power');
|
||||
$this->content = $content ?: Compiler::_('Content');
|
||||
$this->autoloader = $autoloader ?: Compiler::_('Power.Autoloader');
|
||||
$this->parser = $parser ?: Compiler::_('Power.Parser');
|
||||
$this->reporeadme = $reporeadme ?: Compiler::_('Power.Repo.Readme');
|
||||
$this->reposreadme = $reposreadme ?: Compiler::_('Power.Repos.Readme');
|
||||
$this->placeholder = $placeholder ?: Compiler::_('Placeholder');
|
||||
$this->event = $event ?: Compiler::_('Event');
|
||||
}
|
||||
@@ -108,6 +170,90 @@ class Infusion
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function set()
|
||||
{
|
||||
// parse all powers main code
|
||||
$this->parsePowers();
|
||||
|
||||
// set the powers
|
||||
$this->setSuperPowers();
|
||||
|
||||
// set the powers
|
||||
$this->setPowers();
|
||||
}
|
||||
|
||||
/**
|
||||
* We parse the powers to get the class map of all methods
|
||||
*
|
||||
* @return void
|
||||
* @since 3.2.0
|
||||
*/
|
||||
private function parsePowers()
|
||||
{
|
||||
// we only do this if super powers are active
|
||||
if ($this->config->add_super_powers && ArrayHelper::check($this->power->superpowers))
|
||||
{
|
||||
foreach ($this->power->active as $n => &$power)
|
||||
{
|
||||
if (ObjectHelper::check($power) && isset($power->main_class_code) &&
|
||||
StringHelper::check($power->main_class_code))
|
||||
{
|
||||
// only parse those approved
|
||||
if ($power->approved == 1)
|
||||
{
|
||||
$power->main_class_code = $this->placeholder->update($power->main_class_code, $this->content->active);
|
||||
$power->parsed_class_code = $this->parser->code($power->main_class_code);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Super Powers details
|
||||
*
|
||||
* @return void
|
||||
* @since 3.2.0
|
||||
*/
|
||||
private function setSuperPowers()
|
||||
{
|
||||
// infuse super powers details if set
|
||||
if ($this->config->add_super_powers && ArrayHelper::check($this->power->superpowers))
|
||||
{
|
||||
// TODO we need to update the event signatures
|
||||
$context = $this->config->component_context;
|
||||
|
||||
foreach ($this->power->superpowers as $path => $powers)
|
||||
{
|
||||
$key = StringHelper::safe($path);
|
||||
|
||||
// Trigger Event: jcb_ce_onBeforeInfuseSuperPowerDetails
|
||||
$this->event->trigger(
|
||||
'jcb_ce_onBeforeInfuseSuperPowerDetails',
|
||||
array(&$context, &$path, &$key, &$powers)
|
||||
);
|
||||
|
||||
// POWERREADME
|
||||
$this->content->set_($key, 'POWERREADME', $this->reposreadme->get($powers));
|
||||
|
||||
// POWERINDEX
|
||||
$this->content->set_($key, 'POWERINDEX', $this->index($powers));
|
||||
|
||||
// Trigger Event: jcb_ce_onAfterInfuseSuperPowerDetails
|
||||
$this->event->trigger(
|
||||
'jcb_ce_onAfterInfuseSuperPowerDetails',
|
||||
array(&$context, &$path, &$key, &$powers)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Powers code
|
||||
*
|
||||
* @return void
|
||||
* @since 3.2.0
|
||||
*/
|
||||
private function setPowers()
|
||||
{
|
||||
// infuse powers data if set
|
||||
if (ArrayHelper::check($this->power->active))
|
||||
@@ -126,12 +272,16 @@ class Infusion
|
||||
);
|
||||
|
||||
// POWERCODE
|
||||
$this->content->set_($power->key, 'POWERCODE', $this->get($power));
|
||||
$this->content->set_($power->key, 'POWERCODE', $this->code($power));
|
||||
|
||||
// CODEPOWER
|
||||
$this->content->set_($power->key, 'CODEPOWER', $this->raw($power));
|
||||
|
||||
// POWERLINKER
|
||||
// SOON WE STILL NEED TO THINK THIS OVER
|
||||
// $this->content->set_($power->key, 'POWERLINKER', $this->linker($power));
|
||||
$this->content->set_($power->key, 'POWERLINKER', '');
|
||||
$this->content->set_($power->key, 'POWERLINKER', $this->linker($power));
|
||||
|
||||
// POWERLINKER
|
||||
$this->content->set_($power->key, 'POWERREADME', $this->reporeadme->get($power));
|
||||
|
||||
// Trigger Event: jcb_ce_onAfterInfusePowerData
|
||||
$this->event->trigger(
|
||||
@@ -146,6 +296,19 @@ class Infusion
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the Super Power Index
|
||||
*
|
||||
* @param array $powers All powers of this super power.
|
||||
*
|
||||
* @return string
|
||||
* @since 3.2.0
|
||||
*/
|
||||
private function index(array &$powers): string
|
||||
{
|
||||
return json_encode($powers, JSON_PRETTY_PRINT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Power code
|
||||
*
|
||||
@@ -154,7 +317,7 @@ class Infusion
|
||||
* @return string
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected function get(object &$power): string
|
||||
private function code(object &$power): string
|
||||
{
|
||||
$code = [];
|
||||
|
||||
@@ -208,6 +371,24 @@ class Infusion
|
||||
return $this->placeholder->update(implode(PHP_EOL, $code), $this->content->active);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Raw (unchanged) Power code
|
||||
*
|
||||
* @param object $power A power object.
|
||||
*
|
||||
* @return string
|
||||
* @since 3.2.0
|
||||
*/
|
||||
private function raw(object &$power): string
|
||||
{
|
||||
// add the raw main code if set
|
||||
if (isset($power->unchanged_main_class_code) && StringHelper::check($power->unchanged_main_class_code))
|
||||
{
|
||||
return $power->unchanged_main_class_code;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Power Linker
|
||||
*
|
||||
@@ -216,70 +397,20 @@ class Infusion
|
||||
* @return string
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected function linker(object &$power): string
|
||||
private function linker(object &$power): string
|
||||
{
|
||||
$map = [];
|
||||
$body = [];
|
||||
$linker = [];
|
||||
|
||||
// set the LINKER
|
||||
$map[] = '/******************| POWER LINKER |*******************|';
|
||||
$map[] = '';
|
||||
$map[] = '{';
|
||||
|
||||
// we build the JSON body
|
||||
$body[] = ' "guid": "' . $power->guid . '"';
|
||||
|
||||
// load extends
|
||||
if (GuidHelper::valid($power->extends))
|
||||
// set the linking values
|
||||
foreach ($power as $key => $value)
|
||||
{
|
||||
$body[] = ' "extends": "' . $power->extends . '"';
|
||||
}
|
||||
|
||||
// load implements
|
||||
if (ArrayHelper::check($power->implements))
|
||||
{
|
||||
$sud = [];
|
||||
foreach ($power->implements as $implement)
|
||||
if (isset($this->linker[$key]))
|
||||
{
|
||||
$sud[] = ' "' . $implement . '"';
|
||||
$linker[$this->linker[$key]] = $value;
|
||||
}
|
||||
$sud = implode(','. PHP_EOL, $sud);
|
||||
|
||||
$body[] = ' "implements": [' . PHP_EOL . $sud . PHP_EOL . ' ]';
|
||||
}
|
||||
|
||||
// load (Use Selection)
|
||||
if (ArrayHelper::check($power->use_selection))
|
||||
{
|
||||
$sud = [];
|
||||
foreach ($power->use_selection as $use)
|
||||
{
|
||||
$sud[] = ' "' . $use['use'] . '"';
|
||||
}
|
||||
$sud = implode(','. PHP_EOL, $sud);
|
||||
|
||||
$body[] = ' "use": [' . PHP_EOL . $sud . PHP_EOL . ' ]';
|
||||
}
|
||||
|
||||
// load (Load Selection)
|
||||
if (ArrayHelper::check($power->load_selection))
|
||||
{
|
||||
$sud = [];
|
||||
foreach ($power->load_selection as $load)
|
||||
{
|
||||
$sud[] = ' "' . $load['load'] . '"';
|
||||
}
|
||||
$sud = implode(','. PHP_EOL, $sud);
|
||||
|
||||
$body[] = ' "load": [' . PHP_EOL . $sud . PHP_EOL . ' ]';
|
||||
}
|
||||
$map[] = implode(','. PHP_EOL, $body);
|
||||
|
||||
$map[] = '}';
|
||||
$map[] = '';
|
||||
$map[] = '|******************| POWER LINKER |*******************/' . PHP_EOL . PHP_EOL;
|
||||
|
||||
return implode(PHP_EOL, $map);
|
||||
return json_encode($linker, JSON_PRETTY_PRINT);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -0,0 +1,481 @@
|
||||
<?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;
|
||||
|
||||
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Factory as Compiler;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Power;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Power\Extractor;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Power\Parser;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Placeholder;
|
||||
|
||||
|
||||
/**
|
||||
* Compiler Power Injector
|
||||
* @since 3.2.0
|
||||
*/
|
||||
final class Injector
|
||||
{
|
||||
/**
|
||||
* Power Objects
|
||||
*
|
||||
* @var Power
|
||||
* @since 3.2.0
|
||||
**/
|
||||
protected Power $power;
|
||||
|
||||
/**
|
||||
* Compiler Powers Extractor
|
||||
*
|
||||
* @var Extractor
|
||||
* @since 3.2.0
|
||||
**/
|
||||
protected Extractor $extractor;
|
||||
|
||||
/**
|
||||
* Compiler Powers Parser
|
||||
*
|
||||
* @var Parser
|
||||
* @since 3.2.0
|
||||
**/
|
||||
protected Parser $parser;
|
||||
|
||||
/**
|
||||
* Compiler Placeholder
|
||||
*
|
||||
* @var Placeholder
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected Placeholder $placeholder;
|
||||
|
||||
/**
|
||||
* Super Power Update Map
|
||||
*
|
||||
* @var array
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected array $map = [];
|
||||
|
||||
/**
|
||||
* Insert Use Statements
|
||||
*
|
||||
* @var array
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected array $useStatements = [];
|
||||
|
||||
/**
|
||||
* Insert Trait Statements
|
||||
*
|
||||
* @var array
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected array $traits = [];
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param Power|null $power The power object.
|
||||
* @param Extractor|null $extractor The powers extractor object.
|
||||
* @param Parser|null $parser The powers parser object.
|
||||
* @param Placeholder|null $placeholder The compiler placeholder object.
|
||||
*
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function __construct(?Power $power = null, ?Extractor $extractor = null,
|
||||
?Parser $parser = null, ?Placeholder $placeholder = null)
|
||||
{
|
||||
$this->power = $power ?: Compiler::_('Power');
|
||||
$this->extractor = $extractor ?: Compiler::_('Power.Extractor');
|
||||
$this->parser = $parser ?: Compiler::_('Power.Parser');
|
||||
$this->placeholder = $placeholder ?: Compiler::_('Placeholder');
|
||||
}
|
||||
|
||||
/**
|
||||
* Inject the powers found in the code
|
||||
*
|
||||
* @param string $code The class code
|
||||
*
|
||||
* @return string The updated code
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function power(string $code): string
|
||||
{
|
||||
if (($guids = $this->extractor->get($code)) !== null)
|
||||
{
|
||||
return $this->update($guids, $code);
|
||||
}
|
||||
|
||||
return $code;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the code
|
||||
*
|
||||
* @param array $guids The Power guids found
|
||||
* @param string $code The class code
|
||||
*
|
||||
* @return string The updated code
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected function update(array $guids, string $code): string
|
||||
{
|
||||
$use_statements = $this->parser->getUseStatements($code);
|
||||
$traits = $this->parser->getTraits(
|
||||
$this->parser->getClassCode($code) ?? ''
|
||||
);
|
||||
|
||||
// reset with each file
|
||||
$this->map = [];
|
||||
$this->useStatements = [];
|
||||
$this->traits = [];
|
||||
|
||||
foreach ($guids as $key => $guid)
|
||||
{
|
||||
if (($power = $this->power->get($guid)) !== null)
|
||||
{
|
||||
if (($name = $this->inspect($power, $use_statements, $traits)) !== null)
|
||||
{
|
||||
$this->map[$key] = $name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// update
|
||||
if ($this->map !== [])
|
||||
{
|
||||
if ($this->useStatements !== [])
|
||||
{
|
||||
$code = $this->addUseStatements($code, $use_statements);
|
||||
}
|
||||
|
||||
return $this->placeholder->update($code, $this->map);
|
||||
}
|
||||
|
||||
return $code;
|
||||
}
|
||||
|
||||
/**
|
||||
* inspect the super power
|
||||
*
|
||||
* @param object|null $power The power object.
|
||||
* @param array|null $useStatements The code use statments
|
||||
* @param array|null $traits The code traits use statments
|
||||
*
|
||||
* @return string|null The class name (or as name)
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected function inspect(object $power, ?array $useStatements, ?array $traits): ?string
|
||||
{
|
||||
if (isset($power->type) && in_array($power->type, ['class', 'abstract class', 'final class', 'trait']))
|
||||
{
|
||||
$statement = 'use ' . $power->_namespace . '\\' . $power->class_name;
|
||||
// other class names
|
||||
$use_other = [];
|
||||
$trait_other = [];
|
||||
// some tracker globals
|
||||
$has_use_statement = false; // add if not found
|
||||
$has_trait_statement = !('trait' === $power->type); // don't add if not trait
|
||||
$name = null;
|
||||
$trait_name = null;
|
||||
|
||||
// check if the name space is loaded
|
||||
if ($useStatements !== null)
|
||||
{
|
||||
foreach ($useStatements as $use_statement)
|
||||
{
|
||||
if ($use_statement === $statement . ';' || strpos($use_statement, $statement . ' as ') !== false)
|
||||
{
|
||||
$name = $this->getName($use_statement);
|
||||
$has_use_statement = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
$tmp = $this->getName($use_statement);
|
||||
if ($power->class_name === $tmp)
|
||||
{
|
||||
$use_other[$tmp] = $tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check if the trait is loaded
|
||||
if (!$has_trait_statement && $traits !== null)
|
||||
{
|
||||
$trait_statement = $name ?? $power->class_name;
|
||||
|
||||
foreach ($traits as $trait)
|
||||
{
|
||||
if ($trait === $trait_statement)
|
||||
{
|
||||
$trait_name = $trait;
|
||||
$has_trait_statement = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// build the name
|
||||
$name = $trait_name ?? $name ?? $power->class_name;
|
||||
|
||||
// if we have a trait we may need to add use and trait
|
||||
if ('trait' === $power->type)
|
||||
{
|
||||
if (!$has_trait_statement)
|
||||
{
|
||||
$this->traits[$name] = 'use ' . $name . ';';
|
||||
}
|
||||
}
|
||||
|
||||
// check if we need to update the name
|
||||
if ($use_other !== [])
|
||||
{
|
||||
// set search namespace
|
||||
$namespace = ($name !== $power->class_name) ? $power->_namespace . '\\' . $power->class_name : $power->_namespace;
|
||||
|
||||
// get the unique name
|
||||
$name = $this->getUniqueName($name, $namespace, $use_other);
|
||||
}
|
||||
|
||||
if (!$has_use_statement)
|
||||
{
|
||||
// if the name is not the same as class name
|
||||
if ($name !== $power->class_name)
|
||||
{
|
||||
$statement .= ' as ' . $name . ';';
|
||||
}
|
||||
else
|
||||
{
|
||||
$statement .= ';';
|
||||
}
|
||||
|
||||
$this->useStatements[$name] = $statement;
|
||||
}
|
||||
|
||||
return $name;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the class name from a use statement.
|
||||
*
|
||||
* @param string $useStatement The use statement from which to extract the class name
|
||||
*
|
||||
* @return string|null The class name or null if not found
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected function getName(string $useStatement): ?string
|
||||
{
|
||||
// If the input doesn't start with 'use ', assume it's a class name without a use statement
|
||||
if (strpos($useStatement, 'use ') !== 0)
|
||||
{
|
||||
$parts = explode('\\', $useStatement);
|
||||
$result = end($parts);
|
||||
|
||||
// Remove '\\' from the beginning and end of the resulting string
|
||||
$result = trim($result, '\\');
|
||||
|
||||
// If the resulting string is empty, return null
|
||||
return empty($result) ? null : $result;
|
||||
}
|
||||
|
||||
$pattern = '/use\s+([\w\\\\]+)(?:\s+as\s+)?([\w]+)?;/';
|
||||
|
||||
if (preg_match($pattern, $useStatement, $matches))
|
||||
{
|
||||
// If there's an alias, return it
|
||||
if (!empty($matches[2]))
|
||||
{
|
||||
return $matches[2];
|
||||
}
|
||||
|
||||
// If there's no alias, extract the class name from the namespace
|
||||
$parts = explode('\\', $matches[1]);
|
||||
return end($parts);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the last space from the namespace.
|
||||
*
|
||||
* @param string $name The current name
|
||||
* @param string $namespace The namespace
|
||||
* @param array $useOther The other use names
|
||||
*
|
||||
* @return string The namespace shortened
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected function getUniqueName(string $name, string $namespace, array $useOther): string
|
||||
{
|
||||
// if the name is already used
|
||||
while (isset($useOther[$name]))
|
||||
{
|
||||
if (($tmp = $this->getName($namespace)) !== null)
|
||||
{
|
||||
$name = ucfirst($tmp) . $name;
|
||||
$namespace = $this->removeLastSpace($namespace);
|
||||
}
|
||||
}
|
||||
|
||||
return $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the last space from the namespace.
|
||||
*
|
||||
* @param string $namespace The namespace
|
||||
*
|
||||
* @return string The namespace shortened
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected function removeLastSpace(string $namespace): string
|
||||
{
|
||||
// Remove '\\' from the beginning and end of the resulting string
|
||||
$namespace = trim($namespace, '\\');
|
||||
|
||||
$parts = explode('\\', $namespace);
|
||||
|
||||
// Remove the last part (the class name)
|
||||
array_pop($parts);
|
||||
|
||||
// Reassemble the namespace without the class name
|
||||
return implode('\\', $parts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert a line before the class declaration in the given class code.
|
||||
*
|
||||
* @param string $code The class code
|
||||
* @param array|null $useStatements The existing use statements
|
||||
*
|
||||
* @return string The modified file content
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected function addUseStatements(string $code, ?array $useStatements): string
|
||||
{
|
||||
if ($useStatements !== null)
|
||||
{
|
||||
// we add the use statements using existing use statements
|
||||
$key = end($useStatements);
|
||||
|
||||
array_unshift($this->useStatements, $key);
|
||||
|
||||
return $this->placeholder->update($code, [$key => implode(PHP_EOL, array_values($this->useStatements))]);
|
||||
}
|
||||
|
||||
return $this->addLines($code, implode(PHP_EOL, array_values($this->useStatements)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert a line before the class declaration in the given class code.
|
||||
*
|
||||
* @param string $code The class code
|
||||
* @param string $lines The new lines to insert
|
||||
*
|
||||
* @return string The modified file content
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected function addLines(string $code, string $lines): string
|
||||
{
|
||||
// Pattern to match class, final class, abstract class, interface, and trait
|
||||
$pattern = '/(?:class|final class|abstract class|interface|trait)\s+[a-zA-Z0-9_]+\s*(?:extends\s+[a-zA-Z0-9_]+\s*)?(?:implements\s+[a-zA-Z0-9_]+(?:\s*,\s*[a-zA-Z0-9_]+)*)?\s*\{/s';
|
||||
|
||||
// Find the position of the class declaration
|
||||
preg_match($pattern, $code, $matches, PREG_OFFSET_CAPTURE);
|
||||
$class_declaration_pos = $matches[0][1] ?? null;
|
||||
|
||||
if (null !== $class_declaration_pos)
|
||||
{
|
||||
// Find the position of the last newline character before the class declaration
|
||||
$last_newline_pos = strrpos($code, PHP_EOL, -(strlen($code) - $class_declaration_pos));
|
||||
|
||||
// Find the position of the comment block right before the class declaration
|
||||
$comment_pattern = '/\s*\*\/\s*$/m';
|
||||
$insert_pos = null;
|
||||
if (preg_match($comment_pattern, $code, $comment_matches, PREG_OFFSET_CAPTURE, 0, $last_newline_pos))
|
||||
{
|
||||
$insert_pos = (int) $comment_matches[0][1] + strlen($comment_matches[0][0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Find the last empty line before the class declaration
|
||||
$empty_line_pattern = '/(^|\r\n|\r|\n)[\s]*($|\r\n|\r|\n)/';
|
||||
if (preg_match($empty_line_pattern, $code, $empty_line_matches, PREG_OFFSET_CAPTURE, 0, $last_newline_pos))
|
||||
{
|
||||
$insert_pos = (int) $empty_line_matches[0][1] + strlen($empty_line_matches[0][0]);
|
||||
}
|
||||
}
|
||||
|
||||
// Insert the new line at the found position
|
||||
if (null !== $insert_pos)
|
||||
{
|
||||
return substr_replace($code, $lines . PHP_EOL, $insert_pos, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// last try targeting the defined line
|
||||
return $this->addLinesAfterDefinedLine($code, $lines);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts a new line after the defined('_JEXEC') line.
|
||||
*
|
||||
* @param string $code The class code
|
||||
* @param string $lines The new lines to insert
|
||||
*
|
||||
* @return string The modified file content
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected function addLinesAfterDefinedLine(string $code, string $lines): string
|
||||
{
|
||||
// Patterns to match the defined('_JEXEC') and defined('JPATH_BASE') lines
|
||||
$patterns = [
|
||||
"/defined\('_JEXEC'\)(.*?)\s*;/",
|
||||
"/defined\('JPATH_BASE'\)(.*?)\s*;/",
|
||||
];
|
||||
|
||||
$insert_pos = null;
|
||||
|
||||
// Iterate through the patterns and try to find a match
|
||||
foreach ($patterns as $pattern)
|
||||
{
|
||||
preg_match($pattern, $code, $matches, PREG_OFFSET_CAPTURE);
|
||||
$defined_line_pos = $matches[0][1] ?? null;
|
||||
|
||||
if ($defined_line_pos !== null)
|
||||
{
|
||||
// Find the position of the newline character after the defined() line
|
||||
$next_lines_pos = strpos($code, PHP_EOL, (int) $defined_line_pos + strlen($matches[0][0]));
|
||||
|
||||
// Insert the new line at the found position
|
||||
if ($next_lines_pos !== false)
|
||||
{
|
||||
$insert_pos = $next_lines_pos;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Insert the new line at the found position
|
||||
if ($insert_pos !== null)
|
||||
{
|
||||
$code = substr_replace($code, PHP_EOL . $lines, $insert_pos, 0);
|
||||
}
|
||||
|
||||
return $code;
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,592 @@
|
||||
<?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;
|
||||
|
||||
|
||||
/**
|
||||
* Compiler Power Parser
|
||||
* Very basic php class methods parser, does not catch all edge-cases!
|
||||
* Use this only on code that are following standard good practices
|
||||
* Suggested improvements are welcome
|
||||
* @since 3.2.0
|
||||
*/
|
||||
final class Parser
|
||||
{
|
||||
/**
|
||||
* Get properties and method declarations and other details from the given code.
|
||||
*
|
||||
* @param string $code The code containing class properties & methods
|
||||
*
|
||||
* @return array An array of properties & method declarations of the given code
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function code(string $code): array
|
||||
{
|
||||
return [
|
||||
'properties' => $this->properties($code),
|
||||
'methods' => $this->methods($code)
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the class body
|
||||
*
|
||||
* @param string $code The class as a string
|
||||
*
|
||||
* @return string|null The class body, or null if not found
|
||||
* @since 3.2.0
|
||||
**/
|
||||
public function getClassCode(string $code): ?string
|
||||
{
|
||||
// Match class, final class, abstract class, interface, and trait
|
||||
$pattern = '/(?:class|final class|abstract class|interface|trait)\s+[a-zA-Z0-9_]+\s*(?:extends\s+[a-zA-Z0-9_]+\s*)?(?:implements\s+[a-zA-Z0-9_]+(?:\s*,\s*[a-zA-Z0-9_]+)*)?\s*\{/s';
|
||||
|
||||
// Split the input code based on the class declaration pattern
|
||||
$parts = preg_split($pattern, $code, 2, PREG_SPLIT_DELIM_CAPTURE);
|
||||
$body = $parts[1] ?? '';
|
||||
|
||||
if ($body !== '')
|
||||
{
|
||||
// Remove leading and trailing white space
|
||||
$body = trim($body);
|
||||
|
||||
// Remove the first opening curly brace if it exists
|
||||
if (mb_substr($body, 0, 1) === '{')
|
||||
{
|
||||
$body = mb_substr($body, 1);
|
||||
}
|
||||
|
||||
// Remove the last closing curly brace if it exists
|
||||
if (mb_substr($body, -1) === '}')
|
||||
{
|
||||
$body = mb_substr($body, 0, -1);
|
||||
}
|
||||
|
||||
return $body;
|
||||
}
|
||||
|
||||
// No class body found, return null
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the class license
|
||||
*
|
||||
* @param string $code The class as a string
|
||||
*
|
||||
* @return string|null The class license, or null if not found
|
||||
* @since 3.2.0
|
||||
**/
|
||||
public function getClassLicense(string $code): ?string
|
||||
{
|
||||
// Check if the file starts with '<?php'
|
||||
if (substr($code, 0, 5) !== '<?php')
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// Trim the '<?php' part
|
||||
$code = ltrim(substr($code, 5));
|
||||
|
||||
// Check if the next part starts with '/*'
|
||||
if (substr($code, 0, 2) !== '/*')
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// Find the position of the closing comment '*/'
|
||||
$endCommentPos = strpos($code, '*/');
|
||||
|
||||
// If the closing comment '*/' is found, extract and return the license
|
||||
if ($endCommentPos !== false)
|
||||
{
|
||||
$license = substr($code, 2, $endCommentPos - 2);
|
||||
return trim($license);
|
||||
}
|
||||
|
||||
// No license found, return null
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the first consecutive `use` statements from the given PHP class.
|
||||
*
|
||||
* @param string $code The PHP class as a string
|
||||
*
|
||||
* @return array|null An array of consecutive `use` statements
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function getUseStatements(string $code): ?array
|
||||
{
|
||||
// Match class, final class, abstract class, interface, and trait
|
||||
$pattern = '/(?:class|final class|abstract class|interface|trait)\s+[a-zA-Z0-9_]+\s*(?:extends\s+[a-zA-Z0-9_]+\s*)?(?:implements\s+[a-zA-Z0-9_]+(?:\s*,\s*[a-zA-Z0-9_]+)*)?\s*\{/s';
|
||||
|
||||
// Split the input code based on the class declaration pattern
|
||||
$parts = preg_split($pattern, $code, 2, PREG_SPLIT_DELIM_CAPTURE);
|
||||
$header = $parts[0] ?? '';
|
||||
|
||||
$use_statements = [];
|
||||
$found_first_use = false;
|
||||
|
||||
if ($header !== '')
|
||||
{
|
||||
$lines = explode(PHP_EOL, $header);
|
||||
|
||||
foreach ($lines as $line)
|
||||
{
|
||||
if (strpos($line, 'use ') === 0)
|
||||
{
|
||||
$use_statements[] = trim($line);
|
||||
$found_first_use = true;
|
||||
}
|
||||
elseif ($found_first_use && trim($line) === '')
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $found_first_use ? $use_statements : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts trait use statements from the given code.
|
||||
*
|
||||
* @param string $code The code containing class traits
|
||||
*
|
||||
* @return array|null An array of trait names
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function getTraits(string $code): ?array
|
||||
{
|
||||
// regex to target trait use statements
|
||||
$traitPattern = '/^\s*use\s+[\p{L}0-9\\\\_]+(?:\s*,\s*[\p{L}0-9\\\\_]+)*\s*;/mu';
|
||||
|
||||
preg_match_all($traitPattern, $code, $matches, PREG_SET_ORDER);
|
||||
|
||||
if ($matches != [])
|
||||
{
|
||||
$traitNames = [];
|
||||
|
||||
foreach ($matches as $n => $match)
|
||||
{
|
||||
$declaration = $match[0] ?? null;
|
||||
|
||||
if ($declaration !== null)
|
||||
{
|
||||
$names = preg_replace('/\s*use\s+/', '', $declaration);
|
||||
$names = preg_replace('/\s*;/', '', $names);
|
||||
$names = preg_split('/\s*,\s*/', $names);
|
||||
|
||||
$traitNames = array_merge($traitNames, $names);
|
||||
}
|
||||
}
|
||||
|
||||
return $traitNames;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts properties declarations and other details from the given code.
|
||||
*
|
||||
* @param string $code The code containing class properties
|
||||
*
|
||||
* @return array|null An array of properties declarations and details
|
||||
* @since 3.2.0
|
||||
*/
|
||||
private function properties(string $code): ?array
|
||||
{
|
||||
// regex to target all properties
|
||||
$access = '(?<access>var|public|protected|private)';
|
||||
$type = '(?<type>(?:\?|)[\p{L}0-9\\\\]*\s+)?';
|
||||
$static = '(?<static>static)?';
|
||||
$name = '\$(?<name>\p{L}[\p{L}0-9]*)';
|
||||
$default = '(?:\s*=\s*(?<default>\[[^\]]*\]|\d+|\'[^\']*?\'|"[^"]*?"|false|true|null))?';
|
||||
$property_pattern = "/\b{$access}\s*{$type}{$static}\s*{$name}{$default};/u";
|
||||
|
||||
preg_match_all($property_pattern, $code, $matches, PREG_SET_ORDER);
|
||||
|
||||
if ($matches != [])
|
||||
{
|
||||
$properties = [];
|
||||
foreach ($matches as $n => $match)
|
||||
{
|
||||
$declaration = $match[0] ?? null;
|
||||
|
||||
if (is_string($declaration))
|
||||
{
|
||||
$comment = $this->extractDocBlock($code, $declaration);
|
||||
$declaration = trim(preg_replace('/\s{2,}/', ' ',
|
||||
preg_replace('/[\r\n]+/', ' ', $declaration)));
|
||||
|
||||
$properties[] = [
|
||||
'name' => isset($match['name']) ? '$' . $match['name'] : 'error',
|
||||
'access' => $match['access'] ?? 'public',
|
||||
'type' => isset($match['type']) ? trim($match['type']) : null,
|
||||
'static' => (bool) $match['static'] ?? false,
|
||||
'default' => $match['default'] ?? null,
|
||||
'comment' => $comment,
|
||||
'declaration' => $declaration
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return $properties;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts method declarations and other details from the given code.
|
||||
*
|
||||
* @param string $code The code containing class methods
|
||||
*
|
||||
* @return array|null An array of method declarations and details
|
||||
* @since 3.2.0
|
||||
*/
|
||||
private function methods(string $code): ?array
|
||||
{
|
||||
// regex to target all methods/functions
|
||||
$final_modifier = '(?P<final_modifier>final)?\s*';
|
||||
$abstract_modifier = '(?P<abstract_modifier>abstract)?\s*';
|
||||
$access_modifier = '(?P<access_modifier>public|protected|private)?\s*';
|
||||
$static_modifier = '(?P<static_modifier>static)?\s*';
|
||||
$modifier = "{$final_modifier}{$abstract_modifier}{$access_modifier}{$static_modifier}";
|
||||
$name = '(?P<name>\w+)';
|
||||
$arguments = '(?P<arguments>\(.*?\))?';
|
||||
$return_type = '(?P<return_type>\s*:\s*(?:\?[\w\\\\]+|\\\\?[\w\\\\]+(?:\|\s*(?:\?[\w\\\\]+|\\\\?[\w\\\\]+))*)?)?';
|
||||
$method_pattern = "/(^\s*?\b{$modifier}function\s+{$name}{$arguments}{$return_type})/sm";
|
||||
|
||||
preg_match_all($method_pattern, $code, $matches, PREG_SET_ORDER);
|
||||
|
||||
if ($matches != [])
|
||||
{
|
||||
$methods = [];
|
||||
foreach ($matches as $n => $match)
|
||||
{
|
||||
$full_declaration = $match[0] ?? null;
|
||||
|
||||
if (is_string($full_declaration))
|
||||
{
|
||||
$comment = $this->extractDocBlock($code, $full_declaration);
|
||||
|
||||
$full_declaration = trim(preg_replace('/\s{2,}/', ' ',
|
||||
preg_replace('/[\r\n]+/', ' ', $full_declaration)));
|
||||
|
||||
// now load what we found
|
||||
$methods[] = [
|
||||
'name' => $match['name'] ?? 'error',
|
||||
'access' => $match['access_modifier'] ?? 'public',
|
||||
'static' => (bool) $match['static_modifier'] ?? false,
|
||||
'final' => (bool) $match['final_modifier'] ?? false,
|
||||
'abstract' => (bool) $match['abstract_modifier'] ?? false,
|
||||
'return_type' => $this->extractReturnType($match['return_type'] ?? null, $comment),
|
||||
'since' => $this->extractSinceVersion($comment),
|
||||
'deprecated' => $this->extractDeprecatedVersion($comment),
|
||||
'arguments' => $this->extractFunctionArgumentDetails($comment, $match['arguments'] ?? null),
|
||||
'comment' => $comment,
|
||||
'declaration' => str_replace(["\r\n", "\r", "\n"], '', $full_declaration)
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return $methods;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the PHPDoc block for a given function declaration.
|
||||
*
|
||||
* @param string $code The source code containing the function
|
||||
* @param string $declaration The part of the function declaration
|
||||
*
|
||||
* @return string|null The PHPDoc block, or null if not found
|
||||
* @since 3.2.0
|
||||
*/
|
||||
private function extractDocBlock(string $code, string $declaration): ?string
|
||||
{
|
||||
// Split the code string with the function declaration
|
||||
$parts = explode($declaration, $code);
|
||||
if (count($parts) < 2)
|
||||
{
|
||||
// Function declaration not found in the code
|
||||
return null;
|
||||
}
|
||||
|
||||
// Get the part with the comment (if any)
|
||||
$comment = $parts[0];
|
||||
|
||||
// Split the last part using the comment block start marker
|
||||
$commentParts = preg_split('/(})?\s+(?=\s*\/\*)(\*)?/', $comment);
|
||||
|
||||
// Get the last comment block
|
||||
$lastCommentPart = end($commentParts);
|
||||
|
||||
// Search for the comment block in the last comment part
|
||||
if (preg_match('/(\/\*\*[\s\S]*?\*\/)\s*$/u', $lastCommentPart, $matches))
|
||||
{
|
||||
$comment = $matches[1] ?? null;
|
||||
// check if we actually have a comment
|
||||
if ($comment)
|
||||
{
|
||||
return $this->removeWhiteSpaceFromComment($comment);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the function argument details.
|
||||
*
|
||||
* @param string|null $comment The function comment if found
|
||||
* @param string|null $arguments The arguments found on function declaration
|
||||
*
|
||||
* @return array|null The function argument details
|
||||
* @since 3.2.0
|
||||
*/
|
||||
private function extractFunctionArgumentDetails(?string $comment, ?string $arguments): ?array
|
||||
{
|
||||
$arg_types_from_declaration = $this->extractArgTypesArguments($arguments);
|
||||
$arg_types_from_comments = null;
|
||||
|
||||
if ($comment)
|
||||
{
|
||||
$arg_types_from_comments = $this->extractArgTypesFromComment($comment);
|
||||
}
|
||||
|
||||
// merge the types
|
||||
if ($arg_types_from_declaration)
|
||||
{
|
||||
return $this->mergeArgumentTypes($arg_types_from_declaration, $arg_types_from_comments);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the function return type.
|
||||
*
|
||||
* @param string|null $returnType The return type found in declaration
|
||||
* @param string|null $comment The function comment if found
|
||||
*
|
||||
* @return string|null The function return type
|
||||
* @since 3.2.0
|
||||
*/
|
||||
private function extractReturnType(?string $returnType, ?string $comment): ?string
|
||||
{
|
||||
if ($returnType === null && $comment)
|
||||
{
|
||||
return $this->extractReturnTypeFromComment($comment);
|
||||
}
|
||||
|
||||
return trim(trim($returnType, ':'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts argument types from a given comment.
|
||||
*
|
||||
* @param string $comment The comment containing the argument types
|
||||
*
|
||||
* @return array|null An array of argument types
|
||||
* @since 3.2.0
|
||||
*/
|
||||
private function extractArgTypesFromComment(string $comment): ?array
|
||||
{
|
||||
preg_match_all('/@param\s+((?:[^\s|]+(?:\|)?)+)?\s+\$([^\s]+)/', $comment, $matches, PREG_SET_ORDER);
|
||||
|
||||
if ($matches !== [])
|
||||
{
|
||||
$arg_types = [];
|
||||
|
||||
foreach ($matches as $match)
|
||||
{
|
||||
$arg = $match[2] ?? null;
|
||||
$type = $match[1] ?: null;
|
||||
if (is_string($arg))
|
||||
{
|
||||
$arg_types['$' .$arg] = $type;
|
||||
}
|
||||
}
|
||||
|
||||
return $arg_types;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts argument types from a given declaration.
|
||||
*
|
||||
* @param string|null $arguments The arguments found on function declaration
|
||||
*
|
||||
* @return array|null An array of argument types
|
||||
* @since 3.2.0
|
||||
*/
|
||||
private function extractArgTypesArguments(?string $arguments): ?array
|
||||
{
|
||||
if ($arguments)
|
||||
{
|
||||
$args = preg_split('/,(?![^()\[\]]*(\)|\]))/', trim($arguments, '()'));
|
||||
if ($args !== [])
|
||||
{
|
||||
$argument_types = [];
|
||||
foreach ($args as $arg)
|
||||
{
|
||||
$eqPos = strpos($arg, '=');
|
||||
|
||||
if ($eqPos !== false)
|
||||
{
|
||||
$arg_parts = [
|
||||
substr($arg, 0, $eqPos),
|
||||
substr($arg, $eqPos + 1)
|
||||
];
|
||||
}
|
||||
else
|
||||
{
|
||||
$arg_parts = [$arg];
|
||||
}
|
||||
|
||||
if (preg_match('/(?:(\??(?:\w+|\\\\[\w\\\\]+)(?:\|\s*\??(?:\w+|\\\\[\w\\\\]+))*)\s+)?\$(\w+)/', $arg_parts[0], $arg_matches))
|
||||
{
|
||||
$type = $arg_matches[1] ?: null;
|
||||
$name = $arg_matches[2] ?: null;
|
||||
$default = isset($arg_parts[1]) ? preg_replace('/\s{2,}/', ' ',
|
||||
preg_replace('/[\r\n]+/', ' ', trim($arg_parts[1]))) : null;
|
||||
|
||||
if (is_string($name))
|
||||
{
|
||||
$argument_types['$' . $name] = [
|
||||
'type' => $type,
|
||||
'default' => $default,
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $argument_types;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts return type from a given declaration.
|
||||
*
|
||||
* @param string $comment The comment containing the return type
|
||||
*
|
||||
* @return string|null The return type
|
||||
* @since 3.2.0
|
||||
*/
|
||||
private function extractReturnTypeFromComment(string $comment): ?string
|
||||
{
|
||||
if (preg_match('/@return\s+((?:[^\s|]+(?:\|)?)+)/', $comment, $matches))
|
||||
{
|
||||
return $matches[1] ?: null;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the version number from the @since tag in the given comment.
|
||||
*
|
||||
* @param string|null $comment The comment containing the @since tag and version number
|
||||
*
|
||||
* @return string|null The extracted version number or null if not found
|
||||
* @since 3.2.0
|
||||
*/
|
||||
private function extractSinceVersion(?string $comment): ?string
|
||||
{
|
||||
if (is_string($comment) && preg_match('/@since\s+(v?\d+(?:\.\d+)*(?:-(?:alpha|beta|rc)\d*)?)/', $comment, $matches))
|
||||
{
|
||||
return $matches[1] ?: null;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the version number from the deprecated tag in the given comment.
|
||||
*
|
||||
* @param string|null $comment The comment containing the deprecated tag and version number
|
||||
*
|
||||
* @return string|null The extracted version number or null if not found
|
||||
* @since 3.2.0
|
||||
*/
|
||||
private function extractDeprecatedVersion(?string $comment): ?string
|
||||
{
|
||||
if (is_string($comment) && preg_match('/@deprecated\s+(v?\d+(?:\.\d+)*(?:-(?:alpha|beta|rc)\d*)?)/', $comment, $matches))
|
||||
{
|
||||
return $matches[1] ?: null;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all white space from each line of the comment
|
||||
*
|
||||
* @param string $comment The function declaration containing the return type
|
||||
*
|
||||
* @return string The return comment
|
||||
* @since 3.2.0
|
||||
*/
|
||||
private function removeWhiteSpaceFromComment(string $comment): string
|
||||
{
|
||||
// Remove comment markers and leading/trailing whitespace
|
||||
$comment = preg_replace('/^\/\*\*[\r\n\s]*|[\r\n\s]*\*\/$/m', '', $comment);
|
||||
$comment = preg_replace('/^[\s]*\*[\s]?/m', '', $comment);
|
||||
|
||||
// Split the comment into lines
|
||||
$lines = preg_split('/\r\n|\r|\n/', $comment);
|
||||
|
||||
// Remove white spaces from each line
|
||||
$trimmedLines = array_map('trim', $lines);
|
||||
|
||||
// Join the lines back together
|
||||
return implode("\n", array_filter($trimmedLines));
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges the types from the comments and the arguments.
|
||||
*
|
||||
* @param array $argTypesFromDeclaration An array of argument types and default values from the declaration
|
||||
* @param array|null $argTypesFromComments An array of argument types from the comments
|
||||
*
|
||||
* @return array A merged array of argument information
|
||||
* @since 3.2.0
|
||||
*/
|
||||
private function mergeArgumentTypes(array $argTypesFromDeclaration, ?array $argTypesFromComments): array
|
||||
{
|
||||
$mergedArguments = [];
|
||||
|
||||
foreach ($argTypesFromDeclaration as $name => $declarationInfo)
|
||||
{
|
||||
$mergedArguments[$name] = [
|
||||
'name' => $name,
|
||||
'type' => $declarationInfo['type'] ?: $argTypesFromComments[$name] ?? null,
|
||||
'default' => $declarationInfo['default'] ?: null,
|
||||
];
|
||||
}
|
||||
|
||||
return $mergedArguments;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -0,0 +1,459 @@
|
||||
<?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;
|
||||
|
||||
|
||||
/**
|
||||
* Compiler Power Plantuml Builder
|
||||
* @since 3.2.0
|
||||
*/
|
||||
class Plantuml
|
||||
{
|
||||
/**
|
||||
* Get a namespace diagram of a group of class
|
||||
*
|
||||
* @param string $namespace the namespace name
|
||||
* @param string $classes the ready build class uml
|
||||
*
|
||||
* @return string
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function namespaceDiagram(string $namespace, string $classes): string
|
||||
{
|
||||
$namespace_depth = substr_count($namespace, '\\');
|
||||
$namespace_color = $this->getNamespaceColor($namespace_depth);
|
||||
|
||||
// Set the scale of the diagram
|
||||
// $plant_uml = "scale 0.8\n\n";
|
||||
|
||||
// Add namespace
|
||||
$plant_uml = "namespace $namespace #$namespace_color {\n\n";
|
||||
|
||||
// Add class
|
||||
$plant_uml .= $classes;
|
||||
|
||||
$plant_uml .= "}\n";
|
||||
|
||||
return $plant_uml;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a class basic diagram of a class
|
||||
*
|
||||
* @param array $power the class being built
|
||||
* @param array $code the class code being built
|
||||
*
|
||||
* @return string
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function classBasicDiagram(array $power, array $code): string
|
||||
{
|
||||
// Set some global values
|
||||
$class_name = $power['name'];
|
||||
$class_type = $power['type'];
|
||||
|
||||
// set the class color
|
||||
$class_color = $this->getClassColor($class_type);
|
||||
|
||||
// set the class type label
|
||||
$type_label = $this->getClassTypeLable($class_type);
|
||||
|
||||
// set the class type tag
|
||||
$type_tag = $this->getClassTypeTag($class_type);
|
||||
|
||||
// Add class
|
||||
$plant_uml = "\n $type_label $class_name $type_tag #$class_color {\n";
|
||||
|
||||
// Add properties
|
||||
if ($code['properties'])
|
||||
{
|
||||
$plant_uml .= $this->generatePropertiesPlantUML($code['properties'], ' ');
|
||||
}
|
||||
|
||||
// Add methods
|
||||
if ($code['methods'])
|
||||
{
|
||||
$plant_uml .= $this->generateBasicMethodsPlantUML($code['methods']);
|
||||
}
|
||||
|
||||
$plant_uml .= " }\n";
|
||||
|
||||
return $plant_uml;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a class detailed diagram of a class
|
||||
*
|
||||
* @param array $power the class being built
|
||||
* @param array $code the class code being built
|
||||
*
|
||||
* @return string
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function classDetailedDiagram(array $power, array $code): string
|
||||
{
|
||||
// Set some global values
|
||||
$class_name = $power['name'];
|
||||
$class_type = $power['type'];
|
||||
|
||||
// set the class color
|
||||
$class_color = $this->getClassColor($class_type);
|
||||
|
||||
// set the class type label
|
||||
$type_label = $this->getClassTypeLable($class_type);
|
||||
|
||||
// set the class type tag
|
||||
$type_tag = $this->getClassTypeTag($class_type);
|
||||
|
||||
// Add class
|
||||
$plant_uml = "\n$type_label $class_name $type_tag #$class_color {\n";
|
||||
|
||||
// Add properties
|
||||
if ($code['properties'])
|
||||
{
|
||||
$plant_uml .= $this->generatePropertiesPlantUML($code['properties'], ' ');
|
||||
}
|
||||
|
||||
// Add methods
|
||||
if ($code['methods'])
|
||||
{
|
||||
list($methods_plant_uml, $notes) = $this->generateDetailedMethodsPlantUML($code['methods'], $class_name);
|
||||
$plant_uml .= $methods_plant_uml;
|
||||
}
|
||||
|
||||
$plant_uml .= "}\n";
|
||||
|
||||
if (!empty($notes))
|
||||
{
|
||||
$plant_uml .= $this->generateNotesPlantUML($notes);
|
||||
}
|
||||
|
||||
return $plant_uml;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate properties PlantUML
|
||||
*
|
||||
* @param array $properties
|
||||
* @param string $space
|
||||
*
|
||||
* @return string
|
||||
* @since 3.2.0
|
||||
*/
|
||||
private function generatePropertiesPlantUML(array $properties, string $space): string
|
||||
{
|
||||
$plant_uml = "";
|
||||
|
||||
foreach ($properties as $property)
|
||||
{
|
||||
$access_sign = $this->getAccessSign($property['access']);
|
||||
$static = $property['static'] ? '{static} ' : '';
|
||||
$type = $property['type'] ? $property['type'] . ' ' : '';
|
||||
$plant_uml .= "{$space}$access_sign $static{$type}{$property['name']}\n";
|
||||
}
|
||||
|
||||
return $plant_uml;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate detailed methods PlantUML
|
||||
*
|
||||
* @param array $methods
|
||||
* @param string $class_name
|
||||
*
|
||||
* @return array
|
||||
* @since 3.2.0
|
||||
*/
|
||||
private function generateDetailedMethodsPlantUML(array $methods, string $class_name): array
|
||||
{
|
||||
$plant_uml = "";
|
||||
$notes = [];
|
||||
|
||||
foreach ($methods as $method)
|
||||
{
|
||||
$notes = $this->generateMethodNotes($method, $class_name, $notes);
|
||||
|
||||
$access_sign = $this->getAccessSign($method['access']);
|
||||
|
||||
$arguments = '';
|
||||
if ($method['arguments'])
|
||||
{
|
||||
$arguments = $this->generateMethodArgumentsAndNotes(
|
||||
$method['arguments'], $class_name, $method['name'], $notes);
|
||||
|
||||
$arguments = implode(', ', $arguments);
|
||||
}
|
||||
|
||||
$static = $method['static'] ? '{static} ' : '';
|
||||
$abstract = $method['abstract'] ? '{abstract} ' : '';
|
||||
$return_type = $method['return_type'] ? " : {$method['return_type']}" : '';
|
||||
|
||||
$plant_uml .= " $access_sign {$abstract}$static{$method['name']}({$arguments})$return_type\n";
|
||||
}
|
||||
|
||||
return [$plant_uml, $notes];
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate basic methods PlantUML
|
||||
*
|
||||
* @param array $properties
|
||||
*
|
||||
* @return string
|
||||
* @since 3.2.0
|
||||
*/
|
||||
private function generateBasicMethodsPlantUML(array $methods): string
|
||||
{
|
||||
$plant_uml = "";
|
||||
|
||||
foreach ($methods as $method)
|
||||
{
|
||||
$access_sign = $this->getAccessSign($method['access']);
|
||||
$static = $method['static'] ? '{static} ' : '';
|
||||
$abstract = $method['abstract'] ? '{abstract} ' : '';
|
||||
$return_type = $method['return_type'] ? " : {$method['return_type']}" : '';
|
||||
$plant_uml .= " $access_sign {$abstract}$static{$method['name']}()$return_type\n";
|
||||
}
|
||||
|
||||
return $plant_uml;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate method arguments and notes
|
||||
*
|
||||
* @param array $arguments
|
||||
* @param string $class_name
|
||||
* @param string $method_name
|
||||
* @param array $notes
|
||||
*
|
||||
* @return array
|
||||
* @since 3.2.0
|
||||
*/
|
||||
private function generateMethodArgumentsAndNotes(array $arguments, string $class_name,
|
||||
string $method_name, array &$notes): array
|
||||
{
|
||||
$formatted_arguments = [];
|
||||
$notes_bucket = [];
|
||||
$limit = 2;
|
||||
|
||||
foreach ($arguments as $name => $arg)
|
||||
{
|
||||
$arg_type = $arg['type'] ? "{$arg['type']} " : '';
|
||||
$arg_default = $arg['default'] ? " = {$arg['default']}" : '';
|
||||
$arg_statment = "{$arg_type}$name{$arg_default}";
|
||||
|
||||
if ($limit == 0)
|
||||
{
|
||||
$formatted_arguments[] = "...";
|
||||
$limit = -1;
|
||||
}
|
||||
elseif ($limit > 0)
|
||||
{
|
||||
$formatted_arguments[] = $arg_statment;
|
||||
$limit--;
|
||||
}
|
||||
|
||||
$notes_bucket[] = $arg_statment;
|
||||
}
|
||||
|
||||
if ($limit == -1)
|
||||
{
|
||||
$notes["{$class_name}::{$method_name}"][] = "\n arguments:\n " . implode("\n ", $notes_bucket);
|
||||
}
|
||||
|
||||
return $formatted_arguments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate method notes
|
||||
*
|
||||
* @param array $method
|
||||
* @param string $class_name
|
||||
* @param array $notes
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function generateMethodNotes(array $method, string $class_name, array &$notes): array
|
||||
{
|
||||
$notes_key = "{$class_name}::{$method['name']}";
|
||||
|
||||
if (is_string($method['comment']) && strlen($method['comment']) > 4)
|
||||
{
|
||||
$notes[$notes_key][] = trim(preg_replace("/^@.*[\r\n]*/m", '', $method['comment'])) . "\n";
|
||||
}
|
||||
|
||||
if (is_string($method['since']) && strlen($method['since']) > 3)
|
||||
{
|
||||
$notes[$notes_key][] = "since: {$method['since']}";
|
||||
}
|
||||
|
||||
if (is_string($method['return_type']) && strlen($method['return_type']) > 1)
|
||||
{
|
||||
$notes[$notes_key][] = "return: {$method['return_type']}";
|
||||
}
|
||||
|
||||
if (is_string($method['deprecated']) && strlen($method['deprecated']) > 3)
|
||||
{
|
||||
$notes[$notes_key][] = "deprecated: {$method['deprecated']}";
|
||||
}
|
||||
|
||||
return $notes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate notes PlantUML
|
||||
*
|
||||
* @param array $notes
|
||||
*
|
||||
* @return string
|
||||
* @since 3.2.0
|
||||
*/
|
||||
private function generateNotesPlantUML(array $notes): string
|
||||
{
|
||||
$plant_uml = "";
|
||||
$note_count = count($notes);
|
||||
|
||||
$positions = ['right', 'left'];
|
||||
$position_index = 0;
|
||||
|
||||
foreach ($notes as $area => $note)
|
||||
{
|
||||
if ($note_count <= 7)
|
||||
{
|
||||
$position = 'right';
|
||||
}
|
||||
else
|
||||
{
|
||||
$position = $positions[$position_index % 2];
|
||||
$position_index++;
|
||||
}
|
||||
|
||||
$plant_uml .= "\nnote $position of {$area}\n";
|
||||
$plant_uml .= " " . implode("\n ", $note) . "\n";
|
||||
$plant_uml .= "end note\n";
|
||||
}
|
||||
|
||||
return $plant_uml;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the access sign based on the access level.
|
||||
*
|
||||
* @param string $access The access level.
|
||||
*
|
||||
* @return string The corresponding access sign.
|
||||
* @since 3.2.0
|
||||
*/
|
||||
private function getAccessSign(string $access): string
|
||||
{
|
||||
switch ($access)
|
||||
{
|
||||
case 'private':
|
||||
return '-';
|
||||
case 'protected':
|
||||
return '#';
|
||||
case 'public':
|
||||
return '+';
|
||||
case 'var':
|
||||
return '+';
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the correct class type.
|
||||
*
|
||||
* @param string $type The class type.
|
||||
*
|
||||
* @return string The correct class type label.
|
||||
* @since 3.2.0
|
||||
*/
|
||||
private function getClassTypeLable(string $type): string
|
||||
{
|
||||
$class_type_updater = [
|
||||
'final class' => 'class',
|
||||
'abstract class' => 'abstract',
|
||||
'trait' => 'class'
|
||||
];
|
||||
|
||||
return $class_type_updater[$type] ?? $type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the extra class type tag.
|
||||
*
|
||||
* @param string $type The class type.
|
||||
*
|
||||
* @return string The correct class type label.
|
||||
* @since 3.2.0
|
||||
*/
|
||||
private function getClassTypeTag(string $type): string
|
||||
{
|
||||
$class_type_updater = [
|
||||
'final class' => '<< (F,LightGreen) >>',
|
||||
'trait' => '<< (T,Orange) >>'
|
||||
];
|
||||
|
||||
return $class_type_updater[$type] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get class color based on class type.
|
||||
*
|
||||
* @param string $classType The class type.
|
||||
*
|
||||
* @return string The corresponding color.
|
||||
* @since 3.2.0
|
||||
*/
|
||||
private function getClassColor(string $classType): string
|
||||
{
|
||||
$class_colors = [
|
||||
'class' => 'Gold',
|
||||
'final' => 'RoyalBlue',
|
||||
'abstract class' => 'Orange',
|
||||
'interface' => 'Lavender',
|
||||
'trait' => 'Turquoise'
|
||||
];
|
||||
|
||||
return $class_colors[$classType] ?? 'Green';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get namespace color based on namespace depth.
|
||||
*
|
||||
* @param int $namespaceDepth The depth of the namespace.
|
||||
*
|
||||
* @return string The corresponding color.
|
||||
* @since 3.2.0
|
||||
*/
|
||||
private function getNamespaceColor(int $namespaceDepth): string
|
||||
{
|
||||
$namespace_colors = [
|
||||
'lightgrey',
|
||||
'Azure',
|
||||
'DarkCyan',
|
||||
'Olive',
|
||||
'LightGreen',
|
||||
'DeepSkyBlue',
|
||||
'Wheat',
|
||||
'Coral',
|
||||
'Beige',
|
||||
'DeepPink',
|
||||
'DeepSkyBlue'
|
||||
];
|
||||
|
||||
return $namespace_colors[$namespaceDepth % count($namespace_colors)] ?? 'lightgrey';
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -0,0 +1,104 @@
|
||||
<?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
|
||||
if (isset($power->parsed_class_code) && is_array($power->parsed_class_code))
|
||||
{
|
||||
$readme[] = "# " . $power->type . " " . $power->code_name . " (Details)";
|
||||
$readme[] = "> namespace: **" . $power->_namespace . "**";
|
||||
$readme[] = "```uml\n@startuml" . $this->plantuml->classDetailedDiagram(
|
||||
['name' => $power->code_name, 'type' => $power->type],
|
||||
$power->parsed_class_code
|
||||
) . " \n@enduml\n```";
|
||||
}
|
||||
else
|
||||
{
|
||||
$readme[] = "> Error adding class diagram";
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -0,0 +1 @@
|
||||
<html><body bgcolor="#FFFFFF"></body></html>
|
@@ -0,0 +1,409 @@
|
||||
<?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\Repos;
|
||||
|
||||
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Factory as Compiler;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Power;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Power\Plantuml;
|
||||
|
||||
|
||||
/**
|
||||
* Compiler Power Repos 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 Super Power Readme
|
||||
*
|
||||
* @param array $powers All powers of this super power.
|
||||
*
|
||||
* @return string
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function get(array $powers): string
|
||||
{
|
||||
// build readme
|
||||
$readme = ["```
|
||||
███████╗██╗ ██╗██████╗ ███████╗██████╗
|
||||
██╔════╝██║ ██║██╔══██╗██╔════╝██╔══██╗
|
||||
███████╗██║ ██║██████╔╝█████╗ ██████╔╝
|
||||
╚════██║██║ ██║██╔═══╝ ██╔══╝ ██╔══██╗
|
||||
███████║╚██████╔╝██║ ███████╗██║ ██║
|
||||
╚══════╝ ╚═════╝ ╚═╝ ╚══════╝╚═╝ ╚═╝
|
||||
██████╗ ██████╗ ██╗ ██╗███████╗██████╗ ███████╗
|
||||
██╔══██╗██╔═══██╗██║ ██║██╔════╝██╔══██╗██╔════╝
|
||||
██████╔╝██║ ██║██║ █╗ ██║█████╗ ██████╔╝███████╗
|
||||
██╔═══╝ ██║ ██║██║███╗██║██╔══╝ ██╔══██╗╚════██║
|
||||
██║ ╚██████╔╝╚███╔███╔╝███████╗██║ ██║███████║
|
||||
╚═╝ ╚═════╝ ╚══╝╚══╝ ╚══════╝╚═╝ ╚═╝╚══════╝
|
||||
```"];
|
||||
|
||||
// default description of super powers
|
||||
$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
|
||||
$readme[] = $this->readmeBuilder($powers);
|
||||
|
||||
// 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 &$powers): string
|
||||
{
|
||||
$classes = [];
|
||||
foreach ($powers as $guid => $power)
|
||||
{
|
||||
$power_object = $this->power->get($guid);
|
||||
if (isset($power_object->parsed_class_code) && is_array($power_object->parsed_class_code))
|
||||
{
|
||||
// add to the sort bucket
|
||||
$classes[] = [
|
||||
'namespace' => $power['namespace'],
|
||||
'type' => $power['type'],
|
||||
'name' => $power['name'],
|
||||
'link' => $this->indexLinkPower($power),
|
||||
'diagram' => $this->plantuml->classBasicDiagram($power, $power_object->parsed_class_code)
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
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, $this->defineTypeOrder());
|
||||
|
||||
$result = $this->generateIndex($classes);
|
||||
|
||||
$diagram_bucket = $this->generateDiagramBucket($classes);
|
||||
|
||||
return $result . $diagram_bucket;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 powers\n";
|
||||
$current_namespace = null;
|
||||
|
||||
foreach ($classes as $class)
|
||||
{
|
||||
if ($class['namespace'] !== $current_namespace)
|
||||
{
|
||||
$current_namespace = $class['namespace'];
|
||||
$result .= "\n- **Namespace**: [{$current_namespace}](#" .
|
||||
strtolower(str_replace('\\', '-', $current_namespace)) . ")\n";
|
||||
}
|
||||
|
||||
// Add the class details
|
||||
$result .= "\n - " . $class['link'];
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the diagram bucket string for classes
|
||||
*
|
||||
* @param array $classes The sorted classes
|
||||
*
|
||||
* @return string The diagram bucket string
|
||||
*/
|
||||
private function generateDiagramBucket(array &$classes): string
|
||||
{
|
||||
$diagram_bucket = "\n\n# Class Diagrams\n";
|
||||
$current_namespace = null;
|
||||
$diagrams = '';
|
||||
|
||||
foreach ($classes as $class)
|
||||
{
|
||||
if ($class['namespace'] !== $current_namespace)
|
||||
{
|
||||
if ($current_namespace !== null)
|
||||
{
|
||||
$diagram_bucket .= $this->generateNamespaceDiagram($current_namespace, $diagrams);
|
||||
}
|
||||
$current_namespace = $class['namespace'];
|
||||
$diagrams = '';
|
||||
}
|
||||
|
||||
$diagrams .= $class['diagram'];
|
||||
}
|
||||
|
||||
// Add the last namespace diagram
|
||||
$diagram_bucket .= $this->generateNamespaceDiagram($current_namespace, $diagrams);
|
||||
|
||||
return $diagram_bucket;
|
||||
}
|
||||
|
||||
/**
|
||||
* Define the order of types for sorting purposes
|
||||
*
|
||||
* @return array The order of types
|
||||
* @since 3.2.0
|
||||
*/
|
||||
private function defineTypeOrder(): array
|
||||
{
|
||||
return [
|
||||
'interface' => 1,
|
||||
'abstract' => 2,
|
||||
'abstract class' => 2,
|
||||
'final' => 3,
|
||||
'final class' => 3,
|
||||
'class' => 4,
|
||||
'trait' => 5
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort the flattened array using a single sorting function
|
||||
*
|
||||
* @param array $classes The classes to sort
|
||||
* @param array $typeOrder The order of types
|
||||
* @since 3.2.0
|
||||
*/
|
||||
private function sortClasses(array &$classes, array $typeOrder): void
|
||||
{
|
||||
usort($classes, function ($a, $b) use ($typeOrder) {
|
||||
$namespaceDiff = $this->compareNamespace($a, $b);
|
||||
|
||||
if ($namespaceDiff !== 0)
|
||||
{
|
||||
return $namespaceDiff;
|
||||
}
|
||||
|
||||
$typeDiff = $this->compareType($a, $b, $typeOrder);
|
||||
|
||||
if ($typeDiff !== 0)
|
||||
{
|
||||
return $typeDiff;
|
||||
}
|
||||
|
||||
return $this->compareName($a, $b);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare the namespace of two classes
|
||||
*
|
||||
* @param array $a First class
|
||||
* @param array $b Second class
|
||||
*
|
||||
* @return int Comparison result
|
||||
* @since 3.2.0
|
||||
*/
|
||||
private function compareNamespace(array $a, array $b): int
|
||||
{
|
||||
$namespaceDepthDiff = substr_count($a['namespace'], '\\') - substr_count($b['namespace'], '\\');
|
||||
|
||||
if ($namespaceDepthDiff === 0)
|
||||
{
|
||||
return strcmp($a['namespace'], $b['namespace']);
|
||||
}
|
||||
|
||||
return $namespaceDepthDiff;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare the type of two classes
|
||||
*
|
||||
* @param array $a First class
|
||||
* @param array $b Second class
|
||||
* @param array $typeOrder The order of types
|
||||
*
|
||||
* @return int Comparison result
|
||||
* @since 3.2.0
|
||||
*/
|
||||
private function compareType(array $a, array $b, array $typeOrder): int
|
||||
{
|
||||
return $typeOrder[$a['type']] - $typeOrder[$b['type']];
|
||||
}
|
||||
|
||||
/**
|
||||
* 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']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a namespace diagram string
|
||||
*
|
||||
* @param string $current_namespace The current namespace
|
||||
* @param string $diagrams The diagrams for the namespace
|
||||
*
|
||||
* @return string The namespace diagram string
|
||||
*/
|
||||
private function generateNamespaceDiagram(string $current_namespace, string $diagrams): string
|
||||
{
|
||||
$namespace_title = str_replace('\\', ' ', $current_namespace);
|
||||
$diagram_code = "\n## {$namespace_title}\n> namespace {$current_namespace}\n";
|
||||
$diagram_code .= "```uml\n@startuml\n\n" .
|
||||
$this->plantuml->namespaceDiagram($current_namespace, $diagrams) . "\n\n@enduml\n```\n";
|
||||
|
||||
return $diagram_code;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the Link to the power in this repository
|
||||
*
|
||||
* @param string $power The power details.
|
||||
*
|
||||
* @return string
|
||||
* @since 3.2.0
|
||||
*/
|
||||
private function indexLinkPower(array &$power): string
|
||||
{
|
||||
return '**' . $power['type'] . ' ' . $power['name'] . "** | "
|
||||
. $this->linkPowerRepo($power) . ' | '
|
||||
. $this->linkPowerCode($power) . ' | '
|
||||
. $this->linkPowerSettings($power) . ' | '
|
||||
. $this->linkPowerSPK($power);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the Link to the power in this repository
|
||||
*
|
||||
* @param string $power The power details.
|
||||
*
|
||||
* @return string
|
||||
* @since 3.2.0
|
||||
*/
|
||||
private function linkPowerRepo(array &$power): string
|
||||
{
|
||||
return '[Details](' . $power['path'] . ')';
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the Link to the power settings in this repository
|
||||
*
|
||||
* @param string $power The power details.
|
||||
*
|
||||
* @return string
|
||||
* @since 3.2.0
|
||||
*/
|
||||
private function linkPowerCode(array &$power): string
|
||||
{
|
||||
return '[Code](' . $power['code'] . ')';
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the Link to the power settings in this repository
|
||||
*
|
||||
* @param string $power The power details.
|
||||
*
|
||||
* @return string
|
||||
* @since 3.2.0
|
||||
*/
|
||||
private function linkPowerSettings(array &$power): string
|
||||
{
|
||||
return '[Settings](' . $power['settings'] . ')';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the SuperPowerKey (SPK)
|
||||
*
|
||||
* @param string $power The power details.
|
||||
*
|
||||
* @return string
|
||||
* @since 3.2.0
|
||||
*/
|
||||
private function linkPowerSPK(array &$power): string
|
||||
{
|
||||
return $power['spk'];
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -0,0 +1 @@
|
||||
<html><body bgcolor="#FFFFFF"></body></html>
|
@@ -181,6 +181,9 @@ class Structure
|
||||
// for plugin event TODO change event api signatures
|
||||
$this->power->active = $powers;
|
||||
|
||||
// set super power details
|
||||
$this->setSuperPowerDetails();
|
||||
|
||||
foreach ($this->power->active as $power)
|
||||
{
|
||||
if (ObjectHelper::check($power)
|
||||
@@ -209,11 +212,6 @@ class Structure
|
||||
$this->folder->create($power->full_path_parent);
|
||||
$this->folder->create($power->full_path);
|
||||
|
||||
// set power file
|
||||
$fileDetails = array('path' => $power->full_path . '/'
|
||||
. $power->file_name . '.php',
|
||||
'name' => $power->file_name . '.php',
|
||||
'zip' => $power->file_name . '.php');
|
||||
$bom = '<?php' . PHP_EOL . '// A POWER FILE' .
|
||||
PHP_EOL . Placefix::_h('BOM') . PHP_EOL;
|
||||
|
||||
@@ -222,15 +220,13 @@ class Structure
|
||||
{
|
||||
$bom = '<?php' . PHP_EOL . $power->licensing_template;
|
||||
}
|
||||
$this->file->write(
|
||||
$fileDetails['path'],
|
||||
$bom . PHP_EOL . Placefix::_h('POWERCODE')
|
||||
. PHP_EOL . Placefix::_h('POWERLINKER')
|
||||
);
|
||||
$this->files->appendArray($power->key, $fileDetails);
|
||||
|
||||
// count the file created
|
||||
$this->counter->file++;
|
||||
// set the main power php file
|
||||
$this->createFile($bom . PHP_EOL . Placefix::_h('POWERCODE') . PHP_EOL,
|
||||
$power->full_path, $power->file_name . '.php', $power->key);
|
||||
|
||||
// set super power files
|
||||
$this->setSuperPowerFiles($power, $bom);
|
||||
|
||||
// set htaccess once per path
|
||||
$this->setHtaccess($power);
|
||||
@@ -239,6 +235,35 @@ class Structure
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a file with optional custom content and save it to the given path.
|
||||
*
|
||||
* @param string $content The content.
|
||||
* @param string $fullPath The full path to the destination folder.
|
||||
* @param string $fileName The file name without the extension.
|
||||
* @param string $key The key to append the file details.
|
||||
*
|
||||
* @return void
|
||||
* @since 3.2.0
|
||||
*/
|
||||
private function createFile(string $content, string $fullPath, string $fileName, string $key)
|
||||
{
|
||||
$file_details = [
|
||||
'path' => $fullPath . '/' . $fileName,
|
||||
'name' => $fileName,
|
||||
'zip' => $fileName
|
||||
];
|
||||
|
||||
// Write the content to the file
|
||||
$this->file->write($file_details['path'], $content);
|
||||
|
||||
// Append the file details to the files array
|
||||
$this->files->appendArray($key, $file_details);
|
||||
|
||||
// Increment the file counter
|
||||
$this->counter->file++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the .htaccess for this power path
|
||||
*
|
||||
@@ -247,7 +272,7 @@ class Structure
|
||||
* @return void
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected function setHtaccess(object &$power)
|
||||
private function setHtaccess(object &$power)
|
||||
{
|
||||
if (!isset($this->htaccess[$power->path_jcb]))
|
||||
{
|
||||
@@ -320,7 +345,7 @@ class Structure
|
||||
// check if we should add the dynamic folder moving script to the installer script
|
||||
if (!$this->registry->get('set_move_folders_install_script'))
|
||||
{
|
||||
// add the setDynamicF0ld3rs() method to the install scipt.php file
|
||||
// add the setDynamicF0ld3rs() method to the install script.php file
|
||||
$this->registry->set('set_move_folders_install_script', true);
|
||||
|
||||
// set message that this was done (will still add a tutorial link later)
|
||||
@@ -334,6 +359,71 @@ class Structure
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the super powers details structure
|
||||
*
|
||||
* @return void
|
||||
* @since 3.2.0
|
||||
*/
|
||||
private function setSuperPowerDetails()
|
||||
{
|
||||
if ($this->config->add_super_powers && ArrayHelper::check($this->power->superpowers))
|
||||
{
|
||||
foreach ($this->power->superpowers as $path => $powers)
|
||||
{
|
||||
// create the path if it does not exist
|
||||
$this->folder->create($path, false);
|
||||
|
||||
$key = StringHelper::safe($path);
|
||||
|
||||
// set the super powers readme file
|
||||
$this->createFile(Placefix::_h('POWERREADME'),
|
||||
$path, 'README.md', $key);
|
||||
|
||||
// set the super power index file
|
||||
$this->createFile(Placefix::_h('POWERINDEX'), $path,
|
||||
'super-powers.json', $key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the super power file paths
|
||||
*
|
||||
* @param object $power The power object
|
||||
* @param string $bom The bom for the top of the PHP files
|
||||
*
|
||||
* @return void
|
||||
* @since 3.2.0
|
||||
*/
|
||||
private function setSuperPowerFiles(object &$power, string $bom)
|
||||
{
|
||||
if ($this->config->add_super_powers && is_array($power->super_power_paths) && $power->super_power_paths !== [])
|
||||
{
|
||||
foreach ($power->super_power_paths as $path)
|
||||
{
|
||||
// create the path if it does not exist
|
||||
$this->folder->create($path, false);
|
||||
|
||||
// set the super power php file
|
||||
$this->createFile($bom . PHP_EOL . Placefix::_h('POWERCODE') . PHP_EOL,
|
||||
$path, 'code.php', $power->key);
|
||||
|
||||
// set the super power php RAW file
|
||||
$this->createFile(Placefix::_h('CODEPOWER'),
|
||||
$path, 'code.power', $power->key);
|
||||
|
||||
// set the super power json file
|
||||
$this->createFile(Placefix::_h('POWERLINKER'), $path,
|
||||
'settings.json', $power->key);
|
||||
|
||||
// set the super power readme file
|
||||
$this->createFile(Placefix::_h('POWERREADME'), $path,
|
||||
'README.md', $power->key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@@ -0,0 +1,55 @@
|
||||
<?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\Service;
|
||||
|
||||
|
||||
use Joomla\DI\Container;
|
||||
use Joomla\DI\ServiceProviderInterface;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Builder\Update\Mysql;
|
||||
|
||||
|
||||
/**
|
||||
* Builder Service Provider
|
||||
*
|
||||
* @since 3.2.0
|
||||
*/
|
||||
class Builder implements ServiceProviderInterface
|
||||
{
|
||||
/**
|
||||
* Registers the service provider with a DI container.
|
||||
*
|
||||
* @param Container $container The DI container.
|
||||
*
|
||||
* @return void
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function register(Container $container)
|
||||
{
|
||||
$container->alias(Mysql::class, 'Builder.Update.Mysql')
|
||||
->share('Builder.Update.Mysql', [$this, 'getMysql'], true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Compiler Builder Mysql
|
||||
*
|
||||
* @param Container $container The DI container.
|
||||
*
|
||||
* @return Mysql
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function getMysql(Container $container): Mysql
|
||||
{
|
||||
return new Mysql();
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -81,6 +81,7 @@ class Customcode implements ServiceProviderInterface
|
||||
$container->get('Config'),
|
||||
$container->get('Placeholder'),
|
||||
$container->get('Language.Extractor'),
|
||||
$container->get('Power.Extractor'),
|
||||
$container->get('Customcode.External')
|
||||
);
|
||||
}
|
||||
|
@@ -16,6 +16,7 @@ use Joomla\DI\Container;
|
||||
use Joomla\DI\ServiceProviderInterface;
|
||||
use VDM\Joomla\Componentbuilder\Database\Load;
|
||||
use VDM\Joomla\Componentbuilder\Database\Insert;
|
||||
use VDM\Joomla\Componentbuilder\Database\Update;
|
||||
|
||||
|
||||
/**
|
||||
@@ -40,6 +41,9 @@ class Database implements ServiceProviderInterface
|
||||
|
||||
$container->alias(Insert::class, 'Insert')
|
||||
->share('Insert', [$this, 'getInsert'], true);
|
||||
|
||||
$container->alias(Update::class, 'Update')
|
||||
->share('Update', [$this, 'getUpdate'], true);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -67,6 +71,18 @@ class Database implements ServiceProviderInterface
|
||||
{
|
||||
return new Insert();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the Core Update Database
|
||||
*
|
||||
* @param Container $container The DI container.
|
||||
*
|
||||
* @return Update
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function getUpdate(Container $container): Update
|
||||
{
|
||||
return new Update();
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -772,9 +772,7 @@ class Model implements ServiceProviderInterface
|
||||
*/
|
||||
public function getUpdateserver(Container $container): Updateserver
|
||||
{
|
||||
return new Updateserver(
|
||||
$container->get('Registry')
|
||||
);
|
||||
return new Updateserver();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -71,7 +71,8 @@ class Placeholder implements ServiceProviderInterface
|
||||
$container->get('Config'),
|
||||
$container->get('Placeholder'),
|
||||
$container->get('Language'),
|
||||
$container->get('Language.Extractor')
|
||||
$container->get('Language.Extractor'),
|
||||
$container->get('Power.Extractor')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@@ -15,9 +15,20 @@ namespace VDM\Joomla\Componentbuilder\Compiler\Service;
|
||||
use Joomla\DI\Container;
|
||||
use Joomla\DI\ServiceProviderInterface;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Power as Powers;
|
||||
use VDM\Joomla\Componentbuilder\Power\Grep;
|
||||
use VDM\Joomla\Componentbuilder\Power\Super as Superpower;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Power\Infusion;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Power\Autoloader;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Power\Structure;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Power\Parser;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Power\Plantuml;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Power\Repo\Readme as RepoReadme;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Power\Repos\Readme as ReposReadme;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Power\Extractor;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Power\Injector;
|
||||
use VDM\Joomla\Componentbuilder\Power\Model;
|
||||
use VDM\Joomla\Componentbuilder\Power\Database\Insert;
|
||||
use VDM\Joomla\Componentbuilder\Power\Database\Update;
|
||||
|
||||
|
||||
/**
|
||||
@@ -40,6 +51,12 @@ class Power implements ServiceProviderInterface
|
||||
$container->alias(Powers::class, 'Power')
|
||||
->share('Power', [$this, 'getPowers'], true);
|
||||
|
||||
$container->alias(Superpower::class, 'Superpower')
|
||||
->share('Superpower', [$this, 'getSuperpower'], true);
|
||||
|
||||
$container->alias(Grep::class, 'Power.Grep')
|
||||
->share('Power.Grep', [$this, 'getGrep'], true);
|
||||
|
||||
$container->alias(Autoloader::class, 'Power.Autoloader')
|
||||
->share('Power.Autoloader', [$this, 'getAutoloader'], true);
|
||||
|
||||
@@ -48,6 +65,33 @@ class Power implements ServiceProviderInterface
|
||||
|
||||
$container->alias(Structure::class, 'Power.Structure')
|
||||
->share('Power.Structure', [$this, 'getStructure'], true);
|
||||
|
||||
$container->alias(Parser::class, 'Power.Parser')
|
||||
->share('Power.Parser', [$this, 'getParser'], true);
|
||||
|
||||
$container->alias(Plantuml::class, 'Power.Plantuml')
|
||||
->share('Power.Plantuml', [$this, 'getPlantuml'], true);
|
||||
|
||||
$container->alias(RepoReadme::class, 'Power.Repo.Readme')
|
||||
->share('Power.Repo.Readme', [$this, 'getRepoReadme'], true);
|
||||
|
||||
$container->alias(ReposReadme::class, 'Power.Repos.Readme')
|
||||
->share('Power.Repos.Readme', [$this, 'getReposReadme'], true);
|
||||
|
||||
$container->alias(Extractor::class, 'Power.Extractor')
|
||||
->share('Power.Extractor', [$this, 'getExtractor'], true);
|
||||
|
||||
$container->alias(Injector::class, 'Power.Injector')
|
||||
->share('Power.Injector', [$this, 'getInjector'], true);
|
||||
|
||||
$container->alias(Model::class, 'Power.Model')
|
||||
->share('Power.Model', [$this, 'getModel'], true);
|
||||
|
||||
$container->alias(Insert::class, 'Power.Insert')
|
||||
->share('Power.Insert', [$this, 'getInsert'], true);
|
||||
|
||||
$container->alias(Update::class, 'Power.Update')
|
||||
->share('Power.Update', [$this, 'getUpdate'], true);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -68,6 +112,40 @@ class Power implements ServiceProviderInterface
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Superpower
|
||||
*
|
||||
* @param Container $container The DI container.
|
||||
*
|
||||
* @return Superpower
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function getSuperpower(Container $container): Superpower
|
||||
{
|
||||
return new Superpower(
|
||||
$container->get('Power.Grep'),
|
||||
$container->get('Power.Insert'),
|
||||
$container->get('Power.Update')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Grep
|
||||
*
|
||||
* @param Container $container The DI container.
|
||||
*
|
||||
* @return Grep
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function getGrep(Container $container): Grep
|
||||
{
|
||||
return new Grep(
|
||||
$container->get('Config')->local_powers_repository_path,
|
||||
$container->get('Config')->approved_paths,
|
||||
$container->get('Gitea.Repository.Contents')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Compiler Autoloader
|
||||
*
|
||||
@@ -100,6 +178,9 @@ class Power implements ServiceProviderInterface
|
||||
$container->get('Power'),
|
||||
$container->get('Content'),
|
||||
$container->get('Power.Autoloader'),
|
||||
$container->get('Power.Parser'),
|
||||
$container->get('Power.Repo.Readme'),
|
||||
$container->get('Power.Repos.Readme'),
|
||||
$container->get('Placeholder'),
|
||||
$container->get('Event')
|
||||
);
|
||||
@@ -127,6 +208,141 @@ class Power implements ServiceProviderInterface
|
||||
$container->get('Utilities.Files')
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the Compiler Power Parser
|
||||
*
|
||||
* @param Container $container The DI container.
|
||||
*
|
||||
* @return Structure
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function getParser(Container $container): Parser
|
||||
{
|
||||
return new Parser();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Compiler Power Plantuml Builder
|
||||
*
|
||||
* @param Container $container The DI container.
|
||||
*
|
||||
* @return Plantuml
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function getPlantuml(Container $container): Plantuml
|
||||
{
|
||||
return new Plantuml();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Compiler Power Repo Readme Builder
|
||||
*
|
||||
* @param Container $container The DI container.
|
||||
*
|
||||
* @return RepoReadme
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function getRepoReadme(Container $container): RepoReadme
|
||||
{
|
||||
return new RepoReadme(
|
||||
$container->get('Power'),
|
||||
$container->get('Power.Plantuml')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Compiler Power Repos Readme Builder
|
||||
*
|
||||
* @param Container $container The DI container.
|
||||
*
|
||||
* @return ReposReadme
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function getReposReadme(Container $container): ReposReadme
|
||||
{
|
||||
return new ReposReadme(
|
||||
$container->get('Power'),
|
||||
$container->get('Power.Plantuml')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Compiler Power Extractor
|
||||
*
|
||||
* @param Container $container The DI container.
|
||||
*
|
||||
* @return Extractor
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function getExtractor(Container $container): Extractor
|
||||
{
|
||||
return new Extractor();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Compiler Power Injector
|
||||
*
|
||||
* @param Container $container The DI container.
|
||||
*
|
||||
* @return Injector
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function getInjector(Container $container): Injector
|
||||
{
|
||||
return new Injector(
|
||||
$container->get('Power'),
|
||||
$container->get('Power.Extractor'),
|
||||
$container->get('Power.Parser'),
|
||||
$container->get('Placeholder')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Power Model
|
||||
*
|
||||
* @param Container $container The DI container.
|
||||
*
|
||||
* @return Model
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function getModel(Container $container): Model
|
||||
{
|
||||
return new Model(
|
||||
$container->get('Table')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Power Insert
|
||||
*
|
||||
* @param Container $container The DI container.
|
||||
*
|
||||
* @return Insert
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function getInsert(Container $container): Insert
|
||||
{
|
||||
return new Insert(
|
||||
$container->get('Power.Model'),
|
||||
$container->get('Insert')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Power Update
|
||||
*
|
||||
* @param Container $container The DI container.
|
||||
*
|
||||
* @return Update
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function getUpdate(Container $container): Update
|
||||
{
|
||||
return new Update(
|
||||
$container->get('Power.Model'),
|
||||
$container->get('Update')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -60,12 +60,13 @@ class Folder
|
||||
/**
|
||||
* Create Path if not exist
|
||||
*
|
||||
* @param string $path The path to folder to create
|
||||
* @param string $path The path to folder to create
|
||||
* @param bool $addHtml The the switch to add the HTML
|
||||
*
|
||||
* @return void
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function create(string $path)
|
||||
public function create(string $path, bool $addHtml = true)
|
||||
{
|
||||
// check if the path exist
|
||||
if (!JoomlaFolder::exists($path))
|
||||
@@ -78,10 +79,13 @@ class Folder
|
||||
// count the folder created
|
||||
$this->counter->folder++;
|
||||
|
||||
// add index.html (boring I know)
|
||||
$this->file->html(
|
||||
$path, ''
|
||||
);
|
||||
if ($addHtml)
|
||||
{
|
||||
// add index.html (boring I know)
|
||||
$this->file->html(
|
||||
$path, ''
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -23,7 +23,7 @@ use VDM\Joomla\Componentbuilder\Abstraction\Database;
|
||||
*
|
||||
* @since 3.2.0
|
||||
*/
|
||||
class Insert extends Database implements InsertInterface
|
||||
final class Insert extends Database implements InsertInterface
|
||||
{
|
||||
/**
|
||||
* Switch to set the defaults
|
||||
@@ -31,33 +31,156 @@ class Insert extends Database implements InsertInterface
|
||||
* @var bool
|
||||
* @since 1.2.0
|
||||
**/
|
||||
public bool $defaults = true;
|
||||
protected bool $defaults = true;
|
||||
|
||||
/**
|
||||
* Set rows to the database
|
||||
* Switch to prevent/allow defaults from being added.
|
||||
*
|
||||
* @param bool $trigger toggle the defaults
|
||||
*
|
||||
* @return void
|
||||
* @since 3.2.0
|
||||
**/
|
||||
public function defaults(bool $trigger = true)
|
||||
{
|
||||
$this->defaults = $trigger;
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert rows to the database (with remapping and filtering columns option)
|
||||
*
|
||||
* @param array $data Dataset to store in database [array of arrays (key => value)]
|
||||
* @param string $table The table where the data is being added
|
||||
* @param array $columns Data columns for remapping and filtering
|
||||
*
|
||||
* @return bool
|
||||
* @since 3.2.0
|
||||
**/
|
||||
public function rows(array $data, string $table, array $columns = []): bool
|
||||
{
|
||||
if (!ArrayHelper::check($data))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($columns === [])
|
||||
{
|
||||
$columns = $this->getArrayColumns($data);
|
||||
}
|
||||
|
||||
return ($columns === []) ? false : $this->insert($data, $table, $columns, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert items to the database (with remapping and filtering columns option)
|
||||
*
|
||||
* @param array $data Data to store in database (array of objects)
|
||||
* @param string $table The table where the data is being added
|
||||
* @param array $columns Data columns for remapping and filtering
|
||||
*
|
||||
* @return bool
|
||||
* @since 3.2.0
|
||||
**/
|
||||
public function items(array $data, string $table, array $columns = []): bool
|
||||
{
|
||||
if (!ArrayHelper::check($data))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($columns === [])
|
||||
{
|
||||
$columns = $this->getObjectsColumns($data);
|
||||
}
|
||||
|
||||
return ($columns === []) ? false : $this->insert($data, $table, $columns, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert row to the database
|
||||
*
|
||||
* @param array $data Dataset to store in database (key => value)
|
||||
* @param string $table The table where the data is being added
|
||||
*
|
||||
* @return bool
|
||||
* @since 3.2.0
|
||||
**/
|
||||
public function rows(array $data, string $table): bool
|
||||
public function row(array $data, string $table): bool
|
||||
{
|
||||
// get a query object
|
||||
$query = $this->db->getQuery(true);
|
||||
return $this->rows([$data], $table);
|
||||
}
|
||||
|
||||
// get the first row
|
||||
/**
|
||||
* Insert item to the database
|
||||
*
|
||||
* @param object $data Dataset to store in database (key => value)
|
||||
* @param string $table The table where the data is being added
|
||||
*
|
||||
* @return bool
|
||||
* @since 3.2.0
|
||||
**/
|
||||
public function item(object $data, string $table): bool
|
||||
{
|
||||
return $this->items([$data], $table);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get columns from data array
|
||||
*
|
||||
* @param array $data Data array
|
||||
*
|
||||
* @return array
|
||||
* @since 3.2.0
|
||||
**/
|
||||
protected function getArrayColumns(array &$data): array
|
||||
{
|
||||
$row = array_values($data)[0];
|
||||
|
||||
// set the insert columns
|
||||
if (!ArrayHelper::check($row))
|
||||
{
|
||||
return false;
|
||||
return [];
|
||||
}
|
||||
|
||||
$columns = array_keys($row);
|
||||
|
||||
return array_combine($columns, $columns);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get columns from data objects
|
||||
*
|
||||
* @param array $data Data objects
|
||||
*
|
||||
* @return array
|
||||
* @since 3.2.0
|
||||
**/
|
||||
protected function getObjectsColumns(array &$data): array
|
||||
{
|
||||
$row = array_values($data)[0];
|
||||
|
||||
if (!is_object($row))
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
$columns = get_object_vars($row);
|
||||
|
||||
return array_combine(array_keys($columns), array_keys($columns));
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert data into the database
|
||||
*
|
||||
* @param array $data Data to store in database
|
||||
* @param string $table The table where the data is being added
|
||||
* @param array $columns Data columns for remapping and filtering
|
||||
* @param bool $isArray Whether the data is an array of arrays or an array of objects
|
||||
*
|
||||
* @return bool
|
||||
* @since 3.2.0
|
||||
**/
|
||||
protected function insert(array &$data, string $table, array $columns, bool $isArray): bool
|
||||
{
|
||||
// set joomla default columns
|
||||
$add_created = false;
|
||||
$add_version = false;
|
||||
@@ -69,31 +192,37 @@ class Insert extends Database implements InsertInterface
|
||||
// get the date
|
||||
$date = (new Date())->toSql();
|
||||
|
||||
if (!in_array('created', $columns))
|
||||
if (!isset($columns['created']))
|
||||
{
|
||||
$columns[] = 'created';
|
||||
$columns['created'] = ' (o_O) ';
|
||||
$add_created = true;
|
||||
}
|
||||
if (!in_array('version', $columns))
|
||||
|
||||
if (!isset($columns['version']))
|
||||
{
|
||||
$columns[] = 'version';
|
||||
$columns['version'] = ' (o_O) ';
|
||||
$add_version = true;
|
||||
}
|
||||
if (!in_array('published', $columns))
|
||||
|
||||
if (!isset($columns['version']))
|
||||
{
|
||||
$columns[] = 'published';
|
||||
$columns['published'] = ' (o_O) ';
|
||||
$add_published = true;
|
||||
}
|
||||
// the (o_O) prevents an empty value from being loaded
|
||||
}
|
||||
|
||||
// get a query object
|
||||
$query = $this->db->getQuery(true);
|
||||
|
||||
// set the query targets
|
||||
$query->insert($this->db->quoteName($table))->columns($this->db->quoteName($columns));
|
||||
$query->insert($this->db->quoteName($this->getTable($table)))->columns($this->db->quoteName(array_keys($columns)));
|
||||
|
||||
// limiting factor on the amount of rows to insert before we reset the query
|
||||
$limit = 300;
|
||||
|
||||
// set the insert values
|
||||
foreach ($data as $set)
|
||||
foreach ($data as $nr => $value)
|
||||
{
|
||||
// check the limit
|
||||
if ($limit <= 1)
|
||||
@@ -109,13 +238,17 @@ class Insert extends Database implements InsertInterface
|
||||
$query = $this->db->getQuery(true);
|
||||
|
||||
// set the query targets
|
||||
$query->insert($this->db->quoteName($table))->columns($this->db->quoteName($columns));
|
||||
$query->insert($this->db->quoteName($this->getTable($table)))->columns($this->db->quoteName(array_keys($columns)));
|
||||
}
|
||||
|
||||
$row = [];
|
||||
foreach ($set as $value)
|
||||
foreach ($columns as $column => $key)
|
||||
{
|
||||
$row[] = $this->quote($value);
|
||||
if (' (o_O) ' !== $key)
|
||||
{
|
||||
$row[] = ($isArray && isset($value[$key])) ? $this->quote($value[$key])
|
||||
: ((!$isArray && isset($value->{$key})) ? $this->quote($value->{$key}) : '');
|
||||
}
|
||||
}
|
||||
|
||||
// set joomla default columns
|
||||
@@ -123,10 +256,12 @@ class Insert extends Database implements InsertInterface
|
||||
{
|
||||
$row[] = $this->db->quote($date);
|
||||
}
|
||||
|
||||
if ($add_version)
|
||||
{
|
||||
$row[] = 1;
|
||||
}
|
||||
|
||||
if ($add_published)
|
||||
{
|
||||
$row[] = 1;
|
||||
@@ -137,71 +272,6 @@ class Insert extends Database implements InsertInterface
|
||||
|
||||
// decrement the limiter
|
||||
$limit--;
|
||||
}
|
||||
|
||||
// execute the final query
|
||||
$this->db->setQuery($query);
|
||||
$this->db->execute();
|
||||
|
||||
// always reset the default switch
|
||||
$this->defaults = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set items to the database
|
||||
*
|
||||
* @param array $data Data to store in database (array of objects)
|
||||
* @param array $columns Data columns
|
||||
* @param string $table The table where the data is being added
|
||||
*
|
||||
* @return bool
|
||||
* @since 3.2.0
|
||||
**/
|
||||
public function items(array $data, array $columns, string $table): bool
|
||||
{
|
||||
// get a query object
|
||||
$query = $this->db->getQuery(true);
|
||||
|
||||
// set the query targets
|
||||
$query->insert($this->db->quoteName($table))->columns($this->db->quoteName(array_keys($columns)));
|
||||
|
||||
// limiting factor on the amount of rows to insert before we reset the query
|
||||
$limit = 400;
|
||||
|
||||
// set the insert values
|
||||
foreach ($data as $nr => $value)
|
||||
{
|
||||
// check the limit
|
||||
if ($limit <= 1)
|
||||
{
|
||||
// execute and reset the query
|
||||
$this->db->setQuery($query);
|
||||
$this->db->execute();
|
||||
|
||||
// reset limit
|
||||
$limit = 400;
|
||||
|
||||
// get a query object
|
||||
$query = $this->db->getQuery(true);
|
||||
|
||||
// set the query targets
|
||||
$query->insert($this->db->quoteName($table))->columns($this->db->quoteName(array_keys($columns)));
|
||||
}
|
||||
|
||||
$row = [];
|
||||
// load only what is part of the columns set
|
||||
foreach ($columns as $key)
|
||||
{
|
||||
$row[] = isset($value->{$key}) ? $this->quote($value->{$key}) : '';
|
||||
}
|
||||
|
||||
// add to query
|
||||
$query->values(implode(',', $row));
|
||||
|
||||
// decrement the limiter
|
||||
$limit--;
|
||||
|
||||
// clear the data from memory
|
||||
unset($data[$nr]);
|
||||
@@ -211,89 +281,10 @@ class Insert extends Database implements InsertInterface
|
||||
$this->db->setQuery($query);
|
||||
$this->db->execute();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set row to the database
|
||||
*
|
||||
* @param array $data Dataset to store in database (key => value)
|
||||
* @param string $table The table where the data is being added
|
||||
*
|
||||
* @return bool
|
||||
* @since 3.2.0
|
||||
**/
|
||||
public function row(array $data, string $table): bool
|
||||
{
|
||||
// get a query object
|
||||
$query = $this->db->getQuery(true);
|
||||
|
||||
$columns = array_keys($data);
|
||||
|
||||
// set joomla default columns
|
||||
$add_created = false;
|
||||
$add_version = false;
|
||||
$add_published = false;
|
||||
|
||||
// check if we should load the defaults
|
||||
if ($this->defaults)
|
||||
{
|
||||
// get the date
|
||||
$date = (new Date())->toSql();
|
||||
|
||||
if (!in_array('created', $columns))
|
||||
{
|
||||
$columns[] = 'created';
|
||||
$add_created = true;
|
||||
}
|
||||
if (!in_array('version', $columns))
|
||||
{
|
||||
$columns[] = 'version';
|
||||
$add_version = true;
|
||||
}
|
||||
if (!in_array('published', $columns))
|
||||
{
|
||||
$columns[] = 'published';
|
||||
$add_published = true;
|
||||
}
|
||||
}
|
||||
|
||||
// set the query targets
|
||||
$query->insert($this->db->quoteName($table))->columns($this->db->quoteName($columns));
|
||||
|
||||
// set the insert values
|
||||
$row = [];
|
||||
foreach ($data as $value)
|
||||
{
|
||||
$row[] = $this->quote($value);
|
||||
}
|
||||
|
||||
// set joomla default columns
|
||||
if ($add_created)
|
||||
{
|
||||
$row[] = $this->db->quote($date);
|
||||
}
|
||||
if ($add_version)
|
||||
{
|
||||
$row[] = 1;
|
||||
}
|
||||
if ($add_published)
|
||||
{
|
||||
$row[] = 1;
|
||||
}
|
||||
|
||||
// add to query
|
||||
$query->values(implode(',', $row));
|
||||
|
||||
// execute the final query
|
||||
$this->db->setQuery($query);
|
||||
$this->db->execute();
|
||||
|
||||
// always reset the default switch
|
||||
$this->defaults = true;
|
||||
$this->defaults();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -22,7 +22,7 @@ use VDM\Joomla\Componentbuilder\Abstraction\Database;
|
||||
*
|
||||
* @since 3.2.0
|
||||
*/
|
||||
class Load extends Database implements LoadInterface
|
||||
final class Load extends Database implements LoadInterface
|
||||
{
|
||||
/**
|
||||
* Load data rows as an array of associated arrays
|
||||
|
@@ -0,0 +1,189 @@
|
||||
<?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\Database;
|
||||
|
||||
|
||||
use VDM\Joomla\Componentbuilder\Interfaces\UpdateInterface;
|
||||
use VDM\Joomla\Componentbuilder\Abstraction\Database;
|
||||
|
||||
|
||||
/**
|
||||
* Database Update Class
|
||||
*
|
||||
* @since 3.2.0
|
||||
*/
|
||||
final class Update extends Database implements UpdateInterface
|
||||
{
|
||||
/**
|
||||
* Update rows in the database (with remapping and filtering columns option)
|
||||
*
|
||||
* @param array $data Dataset to update in database [array of arrays (key => value)]
|
||||
* @param string $key Dataset key column to use in updating the values in the Database
|
||||
* @param string $table The table where the data is being updated
|
||||
* @param array $columns Data columns for remapping and filtering
|
||||
*
|
||||
* @return bool
|
||||
* @since 3.2.0
|
||||
**/
|
||||
public function rows(array $data, string $key, string $table, array $columns = []): bool
|
||||
{
|
||||
// set the update columns
|
||||
if ($data === [] || strlen($key) == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// set the update values
|
||||
foreach ($data as $values)
|
||||
{
|
||||
if ($columns !== [])
|
||||
{
|
||||
// load only what is part of the columns set
|
||||
$row = [];
|
||||
foreach ($columns as $column => $key_)
|
||||
{
|
||||
if (isset($values[$key_]))
|
||||
{
|
||||
$row[$column] = $values[$key_];
|
||||
}
|
||||
}
|
||||
|
||||
// update the row
|
||||
$this->row($row, $key, $table);
|
||||
}
|
||||
else
|
||||
{
|
||||
// update the row
|
||||
$this->row((array) $values, $key, $table);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update items in the database (with remapping and filtering columns option)
|
||||
*
|
||||
* @param array $data Data to updated in database (array of objects)
|
||||
* @param string $key Dataset key column to use in updating the values in the Database
|
||||
* @param string $table The table where the data is being update
|
||||
* @param array $columns Data columns for remapping and filtering
|
||||
*
|
||||
* @return bool
|
||||
* @since 3.2.0
|
||||
**/
|
||||
public function items(array $data, string $key, string $table, array $columns = []): bool
|
||||
{
|
||||
// set the update columns
|
||||
if ($data === [] || strlen($key) == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// set the update values
|
||||
foreach ($data as $nr => $values)
|
||||
{
|
||||
if ($columns !== [])
|
||||
{
|
||||
// load only what is part of the columns set
|
||||
$row = [];
|
||||
foreach ($columns as $column => $key_)
|
||||
{
|
||||
if (isset($values->{$key_}))
|
||||
{
|
||||
$row[$column] = $values->{$key_};
|
||||
}
|
||||
}
|
||||
|
||||
// update the row
|
||||
$this->row($row, $key, $table);
|
||||
}
|
||||
else
|
||||
{
|
||||
// update the row
|
||||
$this->row((array) $values, $key, $table);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update row in the database
|
||||
*
|
||||
* @param array $data Dataset to update in database (key => value)
|
||||
* @param string $key Dataset key column to use in updating the values in the Database
|
||||
* @param string $table The table where the data is being updated
|
||||
*
|
||||
* @return bool
|
||||
* @since 3.2.0
|
||||
**/
|
||||
public function row(array $data, string $key, string $table): bool
|
||||
{
|
||||
// set the update columns
|
||||
if ($data === [] || strlen($key) == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// get a query object
|
||||
$query = $this->db->getQuery(true);
|
||||
|
||||
// set the query targets
|
||||
$query->update($this->db->quoteName($this->getTable($table)));
|
||||
|
||||
// set the update values
|
||||
$key_ = null;
|
||||
foreach ($data as $column => $value)
|
||||
{
|
||||
if ($column === $key)
|
||||
{
|
||||
$key_ = $value;
|
||||
}
|
||||
else
|
||||
{
|
||||
$query->set($this->db->quoteName($column) . ' = ' . $this->quote($value));
|
||||
}
|
||||
}
|
||||
|
||||
// add the key condition
|
||||
if ($key_ !== null)
|
||||
{
|
||||
$query->where($this->db->quoteName($key) . ' = ' . $this->quote($key_));
|
||||
|
||||
// execute the final query
|
||||
$this->db->setQuery($query);
|
||||
|
||||
return $this->db->execute();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update item in the database
|
||||
*
|
||||
* @param object $data Dataset to update in database (key => value)
|
||||
* @param string $key Dataset key column to use in updating the values in the Database
|
||||
* @param string $table The table where the data is being updated
|
||||
*
|
||||
* @return bool
|
||||
* @since 3.2.0
|
||||
**/
|
||||
public function item(object $data, string $key, string $table): bool
|
||||
{
|
||||
// convert to an array
|
||||
return $this->row((array) get_object_vars($data), $key, $table);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -20,30 +20,41 @@ namespace VDM\Joomla\Componentbuilder\Interfaces;
|
||||
interface InsertInterface
|
||||
{
|
||||
/**
|
||||
* Set rows to the database
|
||||
* Switch to prevent/allow defaults from being added.
|
||||
*
|
||||
* @param bool $trigger toggle the defaults
|
||||
*
|
||||
* @return void
|
||||
* @since 3.2.0
|
||||
**/
|
||||
public function defaults(bool $trigger = true);
|
||||
|
||||
/**
|
||||
* Insert rows to the database (with remapping and filtering columns option)
|
||||
*
|
||||
* @param array $data Dataset to store in database [array of arrays (key => value)]
|
||||
* @param string $table The table where the data is being added
|
||||
* @param array $columns Data columns for remapping and filtering
|
||||
*
|
||||
* @return bool
|
||||
* @since 3.2.0
|
||||
**/
|
||||
public function rows(array $data, string $table): bool;
|
||||
public function rows(array $data, string $table, array $columns = []): bool;
|
||||
|
||||
/**
|
||||
* Set items to the database
|
||||
* Insert items to the database (with remapping and filtering columns option)
|
||||
*
|
||||
* @param array $data Data to store in database (array of objects)
|
||||
* @param array $columns Data columns
|
||||
* @param string $table The table where the data is being added
|
||||
* @param string $table The table where the data is being added
|
||||
* @param array $columns Data columns for remapping and filtering
|
||||
*
|
||||
* @return bool
|
||||
* @since 3.2.0
|
||||
**/
|
||||
public function items(array $data, array $columns, string $table): bool;
|
||||
public function items(array $data, string $table, array $columns = []): bool;
|
||||
|
||||
/**
|
||||
* Set row to the database
|
||||
* Insert row to the database
|
||||
*
|
||||
* @param array $data Dataset to store in database (key => value)
|
||||
* @param string $table The table where the data is being added
|
||||
@@ -52,6 +63,17 @@ interface InsertInterface
|
||||
* @since 3.2.0
|
||||
**/
|
||||
public function row(array $data, string $table): bool;
|
||||
|
||||
/**
|
||||
* Insert item to the database
|
||||
*
|
||||
* @param object $data Dataset to store in database (key => value)
|
||||
* @param string $table The table where the data is being added
|
||||
*
|
||||
* @return bool
|
||||
* @since 3.2.0
|
||||
**/
|
||||
public function item(object $data, string $table): bool;
|
||||
|
||||
}
|
||||
|
||||
|
@@ -17,6 +17,16 @@ namespace VDM\Joomla\Componentbuilder\Interfaces;
|
||||
*/
|
||||
interface Mapperdoubleinterface
|
||||
{
|
||||
/**
|
||||
* Check if any values are set in the active array.
|
||||
*
|
||||
* @param string|null $firstKey Optional. The first key to check for values.
|
||||
*
|
||||
* @return bool True if the active array or the specified subarray is not empty, false otherwise.
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function isActive_(string $firstKey = null): bool;
|
||||
|
||||
/**
|
||||
* Set dynamic content
|
||||
*
|
||||
|
@@ -17,6 +17,14 @@ namespace VDM\Joomla\Componentbuilder\Interfaces;
|
||||
*/
|
||||
interface Mappersingleinterface
|
||||
{
|
||||
/**
|
||||
* Check if any values are set in the active array
|
||||
*
|
||||
* @return bool Returns true if the active array is not empty, false otherwise
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function isActive(): bool;
|
||||
|
||||
/**
|
||||
* Set content
|
||||
*
|
||||
|
@@ -23,9 +23,9 @@ interface ModelInterface
|
||||
* Model the value
|
||||
* Example: $this->value(value, 'value_key', 'table_name');
|
||||
*
|
||||
* @param mixed $value The value to model
|
||||
* @param string $field The field key
|
||||
* @param string|null $table The table
|
||||
* @param mixed $value The value to model
|
||||
* @param string $field The field key
|
||||
* @param string|null $table The table
|
||||
*
|
||||
* @return mixed
|
||||
* @since 3.2.0
|
||||
@@ -56,6 +56,30 @@ interface ModelInterface
|
||||
*/
|
||||
public function items(?array $items = null, ?string $table = null): ?array;
|
||||
|
||||
/**
|
||||
* Model the values of an row
|
||||
* Example: $this->item(Array, 'table_name');
|
||||
*
|
||||
* @param array $item The item array
|
||||
* @param string|null $table The table
|
||||
*
|
||||
* @return array|null
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function row(array $item, ?string $table = null): ?array;
|
||||
|
||||
/**
|
||||
* Model the values of multiple rows
|
||||
* Example: $this->items(Array, 'table_name');
|
||||
*
|
||||
* @param array|null $items The array of item array
|
||||
* @param string|null $table The table
|
||||
*
|
||||
* @return array|null
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function rows(?array $items = null, ?string $table = null): ?array;
|
||||
|
||||
/**
|
||||
* Get last modeled ID
|
||||
* Example: $this->last('table_name');
|
||||
|
@@ -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\Componentbuilder\Interfaces;
|
||||
|
||||
|
||||
/**
|
||||
* Database Update Interface
|
||||
*
|
||||
* @since 3.2.0
|
||||
*/
|
||||
interface UpdateInterface
|
||||
{
|
||||
/**
|
||||
* Update rows in the database (with remapping and filtering columns option)
|
||||
*
|
||||
* @param array $data Dataset to update in database [array of arrays (key => value)]
|
||||
* @param string $key Dataset key column to use in updating the values in the Database
|
||||
* @param string $table The table where the data is being updated
|
||||
* @param array $columns Data columns for remapping and filtering
|
||||
*
|
||||
* @return bool
|
||||
* @since 3.2.0
|
||||
**/
|
||||
public function rows(array $data, string $key, string $table, array $columns = []): bool;
|
||||
|
||||
/**
|
||||
* Update items in the database (with remapping and filtering columns option)
|
||||
*
|
||||
* @param array $data Data to updated in database (array of objects)
|
||||
* @param string $key Dataset key column to use in updating the values in the Database
|
||||
* @param string $table The table where the data is being update
|
||||
* @param array $columns Data columns for remapping and filtering
|
||||
*
|
||||
* @return bool
|
||||
* @since 3.2.0
|
||||
**/
|
||||
public function items(array $data, string $key, string $table, array $columns = []): bool;
|
||||
|
||||
/**
|
||||
* Update row in the database
|
||||
*
|
||||
* @param array $data Dataset to update in database (key => value)
|
||||
* @param string $key Dataset key column to use in updating the values in the Database
|
||||
* @param string $table The table where the data is being updated
|
||||
*
|
||||
* @return bool
|
||||
* @since 3.2.0
|
||||
**/
|
||||
public function row(array $data, string $key, string $table): bool;
|
||||
|
||||
/**
|
||||
* Update item in the database
|
||||
*
|
||||
* @param object $data Dataset to update in database (key => value)
|
||||
* @param string $key Dataset key column to use in updating the values in the Database
|
||||
* @param string $table The table where the data is being updated
|
||||
*
|
||||
* @return bool
|
||||
* @since 3.2.0
|
||||
**/
|
||||
public function item(object $data, string $key, string $table): bool;
|
||||
|
||||
}
|
||||
|
@@ -0,0 +1,160 @@
|
||||
<?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\Database;
|
||||
|
||||
|
||||
use VDM\Joomla\Componentbuilder\Power\Model as Model;
|
||||
use VDM\Joomla\Componentbuilder\Database\Insert as Database;
|
||||
|
||||
|
||||
/**
|
||||
* Power Database Insert
|
||||
*
|
||||
* @since 3.2.0
|
||||
*/
|
||||
final class Insert
|
||||
{
|
||||
/**
|
||||
* Model
|
||||
*
|
||||
* @var Model
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected Model $model;
|
||||
|
||||
/**
|
||||
* Database
|
||||
*
|
||||
* @var Database
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected Database $database;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param Model $model The set model object.
|
||||
* @param Database $database The insert database object.
|
||||
*
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function __construct(Model $model, Database $database)
|
||||
{
|
||||
$this->model = $model;
|
||||
$this->database = $database;
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert a value to a given table
|
||||
* Example: $this->value(Value, 'value_key', 'GUID');
|
||||
*
|
||||
* @param mixed $value The field value
|
||||
* @param string $field The field key
|
||||
* @param string $keyValue The key value
|
||||
* @param string $key The key name
|
||||
*
|
||||
* @return bool
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function value($value, string $field, string $keyValue, string $key = 'guid'): bool
|
||||
{
|
||||
// build the array
|
||||
$item = [];
|
||||
$item[$key] = $keyValue;
|
||||
$item[$field] = $value;
|
||||
|
||||
// Insert the column of this table
|
||||
return $this->row($item);
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert single row with multiple values to a given table
|
||||
* Example: $this->item(Array);
|
||||
*
|
||||
* @param array $item The item to save
|
||||
*
|
||||
* @return bool
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function row(array $item): bool
|
||||
{
|
||||
// check if object could be modelled
|
||||
if (($item = $this->model->row($item, 'power')) !== null)
|
||||
{
|
||||
// Insert the column of this table
|
||||
return $this->database->row($item, 'power');
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert multiple rows to a given table
|
||||
* Example: $this->items(Array);
|
||||
*
|
||||
* @param array|null $items The items updated in database (array of arrays)
|
||||
*
|
||||
* @return bool
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function rows(?array $items): bool
|
||||
{
|
||||
// check if object could be modelled
|
||||
if (($items = $this->model->rows($items, 'power')) !== null)
|
||||
{
|
||||
// Insert the column of this table
|
||||
return $this->database->rows($items, 'power');
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert single item with multiple values to a given table
|
||||
* Example: $this->item(Object);
|
||||
*
|
||||
* @param object $item The item to save
|
||||
*
|
||||
* @return bool
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function item(object $item): bool
|
||||
{
|
||||
// check if object could be modelled
|
||||
if (($item = $this->model->item($item, 'power')) !== null)
|
||||
{
|
||||
// Insert the column of this table
|
||||
return $this->database->item($item, 'power');
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert multiple items to a given table
|
||||
* Example: $this->items(Array);
|
||||
*
|
||||
* @param array|null $items The items updated in database (array of objects)
|
||||
*
|
||||
* @return bool
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function items(?array $items): bool
|
||||
{
|
||||
// check if object could be modelled
|
||||
if (($items = $this->model->items($items, 'power')) !== null)
|
||||
{
|
||||
// Update the column of this table using guid as the primary key.
|
||||
return $this->database->items($items, 'power');
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -0,0 +1,160 @@
|
||||
<?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\Database;
|
||||
|
||||
|
||||
use VDM\Joomla\Componentbuilder\Power\Model as Model;
|
||||
use VDM\Joomla\Componentbuilder\Database\Update as Database;
|
||||
|
||||
|
||||
/**
|
||||
* Power Database Update
|
||||
*
|
||||
* @since 3.2.0
|
||||
*/
|
||||
final class Update
|
||||
{
|
||||
/**
|
||||
* Model
|
||||
*
|
||||
* @var Model
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected Model $model;
|
||||
|
||||
/**
|
||||
* Database
|
||||
*
|
||||
* @var Database
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected Database $database;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param Model $model The set model object.
|
||||
* @param Database $database The update database object.
|
||||
*
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function __construct(Model $model, Database $database)
|
||||
{
|
||||
$this->model = $model;
|
||||
$this->database = $database;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a value to a given table
|
||||
* Example: $this->value(Value, 'value_key', 'GUID');
|
||||
*
|
||||
* @param mixed $value The field value
|
||||
* @param string $field The field key
|
||||
* @param string $keyValue The key value
|
||||
* @param string $key The key name
|
||||
*
|
||||
* @return bool
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function value($value, string $field, string $keyValue, string $key = 'guid'): bool
|
||||
{
|
||||
// build the array
|
||||
$item = [];
|
||||
$item[$key] = $keyValue;
|
||||
$item[$field] = $value;
|
||||
|
||||
// Update the column of this table using guid as the primary key.
|
||||
return $this->row($item);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update single row with multiple values to a given table
|
||||
* Example: $this->item(Array);
|
||||
*
|
||||
* @param array $item The item to save
|
||||
*
|
||||
* @return bool
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function row(array $item): bool
|
||||
{
|
||||
// check if object could be modelled
|
||||
if (($item = $this->model->row($item, 'power')) !== null)
|
||||
{
|
||||
// Update the column of this table using guid as the primary key.
|
||||
return $this->database->row($item, 'guid', 'power');
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update multiple rows to a given table
|
||||
* Example: $this->items(Array);
|
||||
*
|
||||
* @param array|null $items The items updated in database (array of arrays)
|
||||
*
|
||||
* @return bool
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function rows(?array $items): bool
|
||||
{
|
||||
// check if object could be modelled
|
||||
if (($items = $this->model->rows($items, 'power')) !== null)
|
||||
{
|
||||
// Update the column of this table using guid as the primary key.
|
||||
return $this->database->rows($items, 'guid', 'power');
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update single item with multiple values to a given table
|
||||
* Example: $this->item(Object);
|
||||
*
|
||||
* @param object $item The item to save
|
||||
*
|
||||
* @return bool
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function item(object $item): bool
|
||||
{
|
||||
// check if object could be modelled
|
||||
if (($item = $this->model->item($item, 'power')) !== null)
|
||||
{
|
||||
// Update the column of this table using guid as the primary key.
|
||||
return $this->database->item($item, 'guid', 'power');
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update multiple items to a given table
|
||||
* Example: $this->items(Array);
|
||||
*
|
||||
* @param array|null $items The items updated in database (array of objects)
|
||||
*
|
||||
* @return bool
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function items(?array $items): bool
|
||||
{
|
||||
// check if object could be modelled
|
||||
if (($items = $this->model->items($items, 'power')) !== null)
|
||||
{
|
||||
// Update the column of this table using guid as the primary key.
|
||||
return $this->database->items($items, 'guid', 'power');
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -0,0 +1 @@
|
||||
<html><body bgcolor="#FFFFFF"></body></html>
|
@@ -0,0 +1,375 @@
|
||||
<?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;
|
||||
|
||||
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\Filesystem\Folder;
|
||||
use Joomla\CMS\Application\CMSApplication;
|
||||
use Joomla\CMS\Language\Text;
|
||||
use VDM\Joomla\Gitea\Repository\Contents;
|
||||
use VDM\Joomla\Utilities\FileHelper;
|
||||
use VDM\Joomla\Utilities\JsonHelper;
|
||||
|
||||
|
||||
/**
|
||||
* Global Resource Empowerment Platform
|
||||
*
|
||||
* 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
|
||||
* Super powers of JCB. All searches are performed according the the [algorithm:cascading]
|
||||
* See documentation for more details: https://git.vdm.dev/joomla/super-powers/wiki
|
||||
*
|
||||
* @since 3.2.0
|
||||
*/
|
||||
final class Grep
|
||||
{
|
||||
/**
|
||||
* The local path
|
||||
*
|
||||
* @var string
|
||||
* @since 3.2.0
|
||||
**/
|
||||
public ?string $path;
|
||||
|
||||
/**
|
||||
* All approved paths
|
||||
*
|
||||
* @var array
|
||||
* @since 3.2.0
|
||||
**/
|
||||
public ?array $paths;
|
||||
|
||||
/**
|
||||
* Gitea Repository Contents
|
||||
*
|
||||
* @var Contents
|
||||
* @since 3.2.0
|
||||
**/
|
||||
protected Contents $contents;
|
||||
|
||||
/**
|
||||
* Joomla Application object
|
||||
*
|
||||
* @var CMSApplication
|
||||
* @since 3.2.0
|
||||
**/
|
||||
protected CMSApplication $app;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $path The local path
|
||||
* @param array $paths The approved paths
|
||||
* @param Contents $contents The Gitea Repository Contents object.
|
||||
* @param CMSApplication|null $app The CMS Application object.
|
||||
*
|
||||
* @throws \Exception
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function __construct(string $path, array $paths, Contents $contents, ?CMSApplication $app = null)
|
||||
{
|
||||
$this->path = $path;
|
||||
$this->paths = $paths;
|
||||
$this->contents = $contents;
|
||||
$this->app = $app ?: Factory::getApplication();
|
||||
|
||||
$this->init();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a power
|
||||
*
|
||||
* @param string $guid The global unique id of the power
|
||||
* @param array $order The search order
|
||||
*
|
||||
* @return object|null
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function get(string $guid, array $order = ['local', 'remote']): ?object
|
||||
{
|
||||
// we can only search if we have paths
|
||||
if (is_array($this->paths) && $this->paths !== [])
|
||||
{
|
||||
foreach ($order as $target)
|
||||
{
|
||||
if (($function_name = $this->getFunctionName($target)) !== null &&
|
||||
($power = $this->{$function_name}($guid)) !== null)
|
||||
{
|
||||
return $power;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for a local power
|
||||
*
|
||||
* @param string $guid The global unique id of the power
|
||||
*
|
||||
* @return object|null
|
||||
* @since 3.2.0
|
||||
*/
|
||||
private function searchLocal(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->localIndex($path);
|
||||
|
||||
if (!empty($path->local) && isset($path->local->{$guid}))
|
||||
{
|
||||
return $this->getLocal($path, $guid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for a remote power
|
||||
*
|
||||
* @param string $guid The global unique id of the power
|
||||
*
|
||||
* @return object|null
|
||||
* @since 3.2.0
|
||||
*/
|
||||
private function searchRemote(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->remoteIndex($path);
|
||||
|
||||
if (!empty($path->index) && isset($path->index->{$guid}))
|
||||
{
|
||||
return $this->getRemote($path, $guid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a local power
|
||||
*
|
||||
* @param object $path The repository path details
|
||||
* @param string $guid The global unique id of the power
|
||||
*
|
||||
* @return object|null
|
||||
* @since 3.2.0
|
||||
*/
|
||||
private function getLocal(object $path, string $guid): ?object
|
||||
{
|
||||
if (empty($path->local->{$guid}->settings) || empty($path->local->{$guid}->code))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// get the settings
|
||||
if (($settings = FileHelper::getContent($path->full_path . '/' . $path->local->{$guid}->settings, null)) !== null &&
|
||||
JsonHelper::check($settings))
|
||||
{
|
||||
$power = json_decode($settings);
|
||||
|
||||
// get the code
|
||||
if (($code = FileHelper::getContent($path->full_path . '/' . $path->local->{$guid}->power, null)) !== null)
|
||||
{
|
||||
$power->main_class_code = $code;
|
||||
return $power;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a remote power
|
||||
*
|
||||
* @param object $path The repository path details
|
||||
* @param string $guid The global unique id of the power
|
||||
*
|
||||
* @return object|null
|
||||
* @since 3.2.0
|
||||
*/
|
||||
private function getRemote(object $path, string $guid): ?object
|
||||
{
|
||||
if (empty($path->index->{$guid}->settings) || empty($path->index->{$guid}->code))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// get the settings
|
||||
if (($power = $this->loadRemoteFile($path->owner, $path->repo, $path->index->{$guid}->settings, $path->branch)) !== null &&
|
||||
isset($power->guid))
|
||||
{
|
||||
// get the code
|
||||
if (($code = $this->loadRemoteFile($path->owner, $path->repo, $path->index->{$guid}->power, $path->branch)) !== null)
|
||||
{
|
||||
$power->main_class_code = $code;
|
||||
return $power;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set path details
|
||||
*
|
||||
* @return void
|
||||
* @since 3.2.0
|
||||
*/
|
||||
private function init()
|
||||
{
|
||||
if (is_array($this->paths) && $this->paths !== [])
|
||||
{
|
||||
foreach ($this->paths as $n => &$path)
|
||||
{
|
||||
if (isset($path->owner) && strlen($path->owner) > 1 &&
|
||||
isset($path->repo) && strlen($path->repo) > 1)
|
||||
{
|
||||
// build the path
|
||||
$path->path = trim($path->owner) . '/' . trim($path->repo);
|
||||
|
||||
// update the branch
|
||||
if ($path->branch === 'default' || empty($path->branch))
|
||||
{
|
||||
$path->branch = null;
|
||||
}
|
||||
|
||||
// set local path
|
||||
if ($this->path && Folder::exists($this->path . '/' . $path->path))
|
||||
{
|
||||
$path->full_path = $this->path . '/' . $path->path;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
unset($this->paths[$n]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the local repository index of powers
|
||||
*
|
||||
* @param object $path The repository path details
|
||||
*
|
||||
* @return void
|
||||
* @since 3.2.0
|
||||
*/
|
||||
private function localIndex(object &$path)
|
||||
{
|
||||
if (isset($path->local) || !isset($path->full_path))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (($content = FileHelper::getContent($path->full_path . '/super-powers.json', null)) !== null &&
|
||||
JsonHelper::check($content))
|
||||
{
|
||||
$path->local = json_decode($content);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$path->local = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the remote repository index of powers
|
||||
*
|
||||
* @param object $path The repository path details
|
||||
*
|
||||
* @return void
|
||||
* @since 3.2.0
|
||||
*/
|
||||
private function remoteIndex(object &$path)
|
||||
{
|
||||
if (isset($path->index))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
$path->index = $this->contents->get($path->owner, $path->repo, 'super-powers.json', $path->branch);
|
||||
}
|
||||
catch (\DomainException $e)
|
||||
{
|
||||
$this->app->enqueueMessage(
|
||||
Text::sprintf('COM_COMPONENTBUILDER_PSUPER_POWERB_REPOSITORY_AT_BGITVDMDEVSB_GAVE_THE_FOLLOWING_ERRORBR_SP', $path->path, $e->getMessage()),
|
||||
'Error'
|
||||
);
|
||||
|
||||
$path->index = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the remote file
|
||||
*
|
||||
* @param string $owner The repository owner
|
||||
* @param string $repo 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
|
||||
*/
|
||||
private function loadRemoteFile(string $owner, string $repo, string $path, ?string $branch)
|
||||
{
|
||||
try
|
||||
{
|
||||
$data = $this->contents->get($owner, $repo, $path, $branch);
|
||||
}
|
||||
catch (\DomainException $e)
|
||||
{
|
||||
$this->app->enqueueMessage(
|
||||
Text::sprintf('COM_COMPONENTBUILDER_PFILE_AT_BGITEAREMOTESB_GAVE_THE_FOLLOWING_ERRORBR_SP', $path, $e->getMessage()),
|
||||
'Error'
|
||||
);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get function name
|
||||
*
|
||||
* @param string $name The targeted function name
|
||||
*
|
||||
* @return string|null
|
||||
* @since 3.2.0
|
||||
*/
|
||||
private function getFunctionName(string $name): ?string
|
||||
{
|
||||
$function_name = 'search' . ucfirst(strtolower($name));
|
||||
|
||||
return method_exists($this, $function_name) ? $function_name : null;
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,120 @@
|
||||
<?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;
|
||||
|
||||
|
||||
use VDM\Joomla\Componentbuilder\Abstraction\Model as AbstractionModel;
|
||||
use VDM\Joomla\Utilities\StringHelper;
|
||||
use VDM\Joomla\Utilities\ArrayHelper;
|
||||
use VDM\Joomla\Utilities\ObjectHelper;
|
||||
use VDM\Joomla\Componentbuilder\Interfaces\ModelInterface;
|
||||
|
||||
|
||||
/**
|
||||
* Power Model
|
||||
*
|
||||
* @since 3.2.0
|
||||
*/
|
||||
final class Model extends AbstractionModel implements ModelInterface
|
||||
{
|
||||
/**
|
||||
* Model the value
|
||||
* Example: $this->value(value, 'field_key', 'table_name');
|
||||
*
|
||||
* @param mixed $value The value to model
|
||||
* @param string $field The field key
|
||||
* @param string|null $table The table
|
||||
*
|
||||
* @return mixed
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function value($value, string $field, ?string $table = null)
|
||||
{
|
||||
// set the table name
|
||||
if (empty($table))
|
||||
{
|
||||
$table = $this->getTable();
|
||||
}
|
||||
|
||||
// check if this is a valid table
|
||||
if (($store = $this->table->get($table, $field, 'store')) !== null)
|
||||
{
|
||||
// open the value based on the store method
|
||||
switch($store)
|
||||
{
|
||||
case 'base64':
|
||||
$value = base64_encode((string) $value);
|
||||
break;
|
||||
case 'json':
|
||||
$value = json_encode($value, JSON_FORCE_OBJECT);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate before the value is modelled
|
||||
*
|
||||
* @param mixed $value The field value
|
||||
* @param string|null $field The field key
|
||||
* @param string|null $table The table
|
||||
*
|
||||
* @return bool
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected function validateBefore(&$value, ?string $field = null, ?string $table = null): bool
|
||||
{
|
||||
// check values
|
||||
if (StringHelper::check($value) || ArrayHelper::check($value, true) || ObjectHelper::check($value) || is_numeric($value))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
// remove empty values
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate after the value is modelled
|
||||
*
|
||||
* @param mixed $value The field value
|
||||
* @param string|null $field The field key
|
||||
* @param string|null $table The table
|
||||
*
|
||||
* @return bool
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected function validateAfter(&$value, ?string $field = null, ?string $table = null): bool
|
||||
{
|
||||
// only strings or numbers allowed
|
||||
if (StringHelper::check($value) || is_numeric($value))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
// remove empty values
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current active table
|
||||
*
|
||||
* @return string
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected function getTable(): string
|
||||
{
|
||||
return 'power';
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -0,0 +1,133 @@
|
||||
<?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;
|
||||
|
||||
|
||||
use VDM\Joomla\Componentbuilder\Power\Database\Insert;
|
||||
use VDM\Joomla\Componentbuilder\Power\Database\Update;
|
||||
use VDM\Joomla\Componentbuilder\Power\Grep;
|
||||
use VDM\Joomla\Utilities\GuidHelper;
|
||||
|
||||
|
||||
/**
|
||||
* Superpower of JCB
|
||||
*
|
||||
* @since 3.2.0
|
||||
*/
|
||||
final class Super
|
||||
{
|
||||
/**
|
||||
* The Power Search Tool
|
||||
*
|
||||
* @var Grep
|
||||
* @since 3.2.0
|
||||
**/
|
||||
protected Grep $grep;
|
||||
|
||||
/**
|
||||
* Insert Data Class
|
||||
*
|
||||
* @var Insert
|
||||
* @since 3.2.0
|
||||
**/
|
||||
protected Insert $insert;
|
||||
|
||||
/**
|
||||
* Update Data Class
|
||||
*
|
||||
* @var Update
|
||||
* @since 3.2.0
|
||||
**/
|
||||
protected Update $update;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param Grep $grep The Power Grep object.
|
||||
* @param Insert $insert The Power Database Insert object.
|
||||
* @param Update $update The Power Database Update object.
|
||||
*
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function __construct(Grep $grep, Insert $insert, Update $update)
|
||||
{
|
||||
$this->grep = $grep;
|
||||
$this->insert = $insert;
|
||||
$this->update = $update;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a superpower
|
||||
*
|
||||
* @param string $guid The global unique id of the power
|
||||
* @param array $order The search order
|
||||
* @param string|null $action The action to load power
|
||||
*
|
||||
* @return bool
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function load(string $guid, array $order = ['remote', 'local'], ?string $action = null): bool
|
||||
{
|
||||
if (($power = $this->grep->get($guid, $order)) !== null &&
|
||||
($action !== null || ($action = $this->action($power->guid)) !== null))
|
||||
{
|
||||
return method_exists($this, $action) ? $this->{$action}($power) : false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert a superpower
|
||||
*
|
||||
* @param object $power The power
|
||||
*
|
||||
* @return bool
|
||||
* @since 3.2.0
|
||||
*/
|
||||
private function insert(object $power): bool
|
||||
{
|
||||
return $this->insert->item($power);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a superpower
|
||||
*
|
||||
* @param object $power The power
|
||||
*
|
||||
* @return bool
|
||||
* @since 3.2.0
|
||||
*/
|
||||
private function update(object $power): bool
|
||||
{
|
||||
return $this->update->item($power);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get loading action
|
||||
*
|
||||
* @param string $guid The global unique id of the power
|
||||
*
|
||||
* @return string
|
||||
* @since 3.2.0
|
||||
*/
|
||||
private function action(string $guid): string
|
||||
{
|
||||
if (($id = GuidHelper::item($guid, 'power')) !== null && $id > 0)
|
||||
{
|
||||
return 'update';
|
||||
}
|
||||
|
||||
return 'insert';
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1 @@
|
||||
<html><body bgcolor="#FFFFFF"></body></html>
|
@@ -115,7 +115,7 @@ class Insert implements InsertInterface
|
||||
|
||||
/**
|
||||
* Set values to a given table
|
||||
* Example: $this->item(Object, 23, 'table_name');
|
||||
* Example: $this->item(Object, 'table_name');
|
||||
*
|
||||
* @param object $item The item to save
|
||||
* @param string|null $table The table
|
||||
|
@@ -15,6 +15,7 @@ namespace VDM\Joomla\Componentbuilder\Search\Model;
|
||||
use VDM\Joomla\Componentbuilder\Search\Factory;
|
||||
use VDM\Joomla\Componentbuilder\Table;
|
||||
use VDM\Joomla\Componentbuilder\Search\Config;
|
||||
use VDM\Joomla\Utilities\ArrayHelper;
|
||||
use VDM\Joomla\Componentbuilder\Interfaces\ModelInterface;
|
||||
use VDM\Joomla\Componentbuilder\Abstraction\Model;
|
||||
|
||||
@@ -86,6 +87,42 @@ class Insert extends Model implements ModelInterface
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate before the value is modelled (basic, override in child class)
|
||||
*
|
||||
* @param mixed $value The field value
|
||||
* @param string|null $field The field key
|
||||
* @param string|null $table The table
|
||||
*
|
||||
* @return bool
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected function validateBefore(&$value, ?string $field = null, ?string $table = null): bool
|
||||
{
|
||||
// check values
|
||||
if (StringHelper::check($value) || ArrayHelper::check($value, true))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
// remove empty values
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate after the value is modelled (basic, override in child class)
|
||||
*
|
||||
* @param mixed $value The field value
|
||||
* @param string|null $field The field key
|
||||
* @param string|null $table The table
|
||||
*
|
||||
* @return bool
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected function validateAfter(&$value, ?string $field = null, ?string $table = null): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current active table
|
||||
*
|
||||
|
@@ -15,6 +15,7 @@ namespace VDM\Joomla\Componentbuilder\Search\Model;
|
||||
use VDM\Joomla\Componentbuilder\Search\Factory;
|
||||
use VDM\Joomla\Componentbuilder\Table;
|
||||
use VDM\Joomla\Componentbuilder\Search\Config;
|
||||
use VDM\Joomla\Utilities\ArrayHelper;
|
||||
use VDM\Joomla\Utilities\JsonHelper;
|
||||
use VDM\Joomla\Utilities\StringHelper;
|
||||
use VDM\Joomla\Componentbuilder\Interfaces\ModelInterface;
|
||||
@@ -91,6 +92,42 @@ class Load extends Model implements ModelInterface
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate before the value is modelled (basic, override in child class)
|
||||
*
|
||||
* @param mixed $value The field value
|
||||
* @param string|null $field The field key
|
||||
* @param string|null $table The table
|
||||
*
|
||||
* @return bool
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected function validateBefore(&$value, ?string $field = null, ?string $table = null): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate after the value is modelled (basic, override in child class)
|
||||
*
|
||||
* @param mixed $value The field value
|
||||
* @param string|null $field The field key
|
||||
* @param string|null $table The table
|
||||
*
|
||||
* @return bool
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected function validateAfter(&$value, ?string $field = null, ?string $table = null): bool
|
||||
{
|
||||
// check values
|
||||
if (StringHelper::check($value) || ArrayHelper::check($value, true))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
// remove empty values
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current active table
|
||||
*
|
||||
|
@@ -108,7 +108,7 @@ class Load extends Model implements ModelInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the values (basic, override in child class)
|
||||
* Validate before the value is modelled
|
||||
*
|
||||
* @param mixed $value The field value
|
||||
* @param string|null $field The field key
|
||||
@@ -117,12 +117,27 @@ class Load extends Model implements ModelInterface
|
||||
* @return bool
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected function validate(&$value, ?string $field = null, ?string $table = null): bool
|
||||
protected function validateBefore(&$value, ?string $field = null, ?string $table = null): bool
|
||||
{
|
||||
// remove none
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate after the value is modelled
|
||||
*
|
||||
* @param mixed $value The field value
|
||||
* @param string|null $field The field key
|
||||
* @param string|null $table The table
|
||||
*
|
||||
* @return bool
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected function validateAfter(&$value, ?string $field = null, ?string $table = null): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current active table
|
||||
*
|
||||
|
@@ -0,0 +1,84 @@
|
||||
<?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\Service;
|
||||
|
||||
|
||||
use Joomla\DI\Container;
|
||||
use Joomla\DI\ServiceProviderInterface;
|
||||
use VDM\Joomla\Gitea\Utilities\Uri;
|
||||
use VDM\Joomla\Gitea\Utilities\Http;
|
||||
|
||||
|
||||
/**
|
||||
* The Gitea Utilities Service
|
||||
*
|
||||
* @since 3.2.0
|
||||
*/
|
||||
class Gitea implements ServiceProviderInterface
|
||||
{
|
||||
/**
|
||||
* Registers the service provider with a DI container.
|
||||
*
|
||||
* @param Container $container The DI container.
|
||||
*
|
||||
* @return void
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function register(Container $container)
|
||||
{
|
||||
$container->alias(Uri::class, 'Gitea.Dynamic.Uri')
|
||||
->share('Gitea.Dynamic.Uri', [$this, 'getUri'], true);
|
||||
|
||||
$container->alias(Http::class, 'Gitea.Utilities.Http')
|
||||
->share('Gitea.Utilities.Http', [$this, 'getHttp'], true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Dynamic Uri class
|
||||
*
|
||||
* @param Container $container The DI container.
|
||||
*
|
||||
* @return Uri
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function getUri(Container $container): Uri
|
||||
{
|
||||
// get the global gitea URL
|
||||
$add_gitea_url = $container->get('Config')->get('add_custom_gitea_url', 1);
|
||||
$gitea_url = $container->get('Config')->get('custom_gitea_url');
|
||||
|
||||
// only load this if we have a custom URL set
|
||||
if ($add_gitea_url == 2 && is_string($gitea_url) && strpos($gitea_url, 'http') !== false)
|
||||
{
|
||||
return new Uri($gitea_url);
|
||||
}
|
||||
|
||||
return $container->get('Gitea.Utilities.Uri');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Http class
|
||||
*
|
||||
* @param Container $container The DI container.
|
||||
*
|
||||
* @return Http
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function getHttp(Container $container): Http
|
||||
{
|
||||
return new Http(
|
||||
$container->get('Config')->get('gitea_token')
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1593,6 +1593,15 @@ class Table implements Tableinterface
|
||||
'store' => NULL,
|
||||
'tab_name' => 'Code',
|
||||
],
|
||||
'method_selection' => [
|
||||
'name' => 'method_selection',
|
||||
'label' => 'COM_COMPONENTBUILDER_POWER_METHOD_SELECTION_LABEL',
|
||||
'type' => 'subform',
|
||||
'title' => false,
|
||||
'list' => 'powers',
|
||||
'store' => 'json',
|
||||
'tab_name' => 'Code',
|
||||
],
|
||||
'load_selection' => [
|
||||
'name' => 'load_selection',
|
||||
'label' => 'COM_COMPONENTBUILDER_POWER_LOAD_SELECTION_LABEL',
|
||||
@@ -1602,15 +1611,6 @@ class Table implements Tableinterface
|
||||
'store' => 'json',
|
||||
'tab_name' => 'Code',
|
||||
],
|
||||
'description' => [
|
||||
'name' => 'description',
|
||||
'label' => 'COM_COMPONENTBUILDER_POWER_DESCRIPTION_LABEL',
|
||||
'type' => 'textarea',
|
||||
'title' => false,
|
||||
'list' => 'powers',
|
||||
'store' => NULL,
|
||||
'tab_name' => 'Code',
|
||||
],
|
||||
'licensing_template' => [
|
||||
'name' => 'licensing_template',
|
||||
'label' => 'COM_COMPONENTBUILDER_POWER_LICENSING_TEMPLATE_LABEL',
|
||||
@@ -1620,6 +1620,15 @@ class Table implements Tableinterface
|
||||
'store' => 'base64',
|
||||
'tab_name' => 'Licensing',
|
||||
],
|
||||
'description' => [
|
||||
'name' => 'description',
|
||||
'label' => 'COM_COMPONENTBUILDER_POWER_DESCRIPTION_LABEL',
|
||||
'type' => 'textarea',
|
||||
'title' => false,
|
||||
'list' => 'powers',
|
||||
'store' => NULL,
|
||||
'tab_name' => 'Code',
|
||||
],
|
||||
'composer' => [
|
||||
'name' => 'composer',
|
||||
'label' => 'COM_COMPONENTBUILDER_POWER_COMPOSER_LABEL',
|
||||
@@ -1629,6 +1638,24 @@ class Table implements Tableinterface
|
||||
'store' => 'json',
|
||||
'tab_name' => 'Composer',
|
||||
],
|
||||
'extends' => [
|
||||
'name' => 'extends',
|
||||
'label' => 'COM_COMPONENTBUILDER_POWER_EXTENDS_LABEL',
|
||||
'type' => 'classpowers',
|
||||
'title' => false,
|
||||
'list' => 'powers',
|
||||
'store' => NULL,
|
||||
'tab_name' => 'Code',
|
||||
],
|
||||
'approved' => [
|
||||
'name' => 'approved',
|
||||
'label' => 'COM_COMPONENTBUILDER_POWER_APPROVED_LABEL',
|
||||
'type' => 'radio',
|
||||
'title' => false,
|
||||
'list' => 'powers',
|
||||
'store' => NULL,
|
||||
'tab_name' => 'Super Power',
|
||||
],
|
||||
'property_selection' => [
|
||||
'name' => 'property_selection',
|
||||
'label' => 'COM_COMPONENTBUILDER_POWER_PROPERTY_SELECTION_LABEL',
|
||||
@@ -1647,6 +1674,15 @@ class Table implements Tableinterface
|
||||
'store' => NULL,
|
||||
'tab_name' => 'Code',
|
||||
],
|
||||
'extends_custom' => [
|
||||
'name' => 'extends_custom',
|
||||
'label' => 'COM_COMPONENTBUILDER_POWER_EXTENDS_CUSTOM_LABEL',
|
||||
'type' => 'text',
|
||||
'title' => false,
|
||||
'list' => 'powers',
|
||||
'store' => NULL,
|
||||
'tab_name' => 'Code',
|
||||
],
|
||||
'implements_custom' => [
|
||||
'name' => 'implements_custom',
|
||||
'label' => 'COM_COMPONENTBUILDER_POWER_IMPLEMENTS_CUSTOM_LABEL',
|
||||
@@ -1665,33 +1701,6 @@ class Table implements Tableinterface
|
||||
'store' => 'json',
|
||||
'tab_name' => 'Code',
|
||||
],
|
||||
'extends_custom' => [
|
||||
'name' => 'extends_custom',
|
||||
'label' => 'COM_COMPONENTBUILDER_POWER_EXTENDS_CUSTOM_LABEL',
|
||||
'type' => 'text',
|
||||
'title' => false,
|
||||
'list' => 'powers',
|
||||
'store' => NULL,
|
||||
'tab_name' => 'Code',
|
||||
],
|
||||
'extends' => [
|
||||
'name' => 'extends',
|
||||
'label' => 'COM_COMPONENTBUILDER_POWER_EXTENDS_LABEL',
|
||||
'type' => 'classpowers',
|
||||
'title' => false,
|
||||
'list' => 'powers',
|
||||
'store' => NULL,
|
||||
'tab_name' => 'Code',
|
||||
],
|
||||
'method_selection' => [
|
||||
'name' => 'method_selection',
|
||||
'label' => 'COM_COMPONENTBUILDER_POWER_METHOD_SELECTION_LABEL',
|
||||
'type' => 'subform',
|
||||
'title' => false,
|
||||
'list' => 'powers',
|
||||
'store' => 'json',
|
||||
'tab_name' => 'Code',
|
||||
],
|
||||
'head' => [
|
||||
'name' => 'head',
|
||||
'label' => 'COM_COMPONENTBUILDER_POWER_HEAD_LABEL',
|
||||
@@ -1701,6 +1710,15 @@ class Table implements Tableinterface
|
||||
'store' => 'base64',
|
||||
'tab_name' => 'Code',
|
||||
],
|
||||
'approved_paths' => [
|
||||
'name' => 'approved_paths',
|
||||
'label' => 'COM_COMPONENTBUILDER_POWER_APPROVED_PATHS_LABEL',
|
||||
'type' => 'superpowerpaths',
|
||||
'title' => false,
|
||||
'list' => 'powers',
|
||||
'store' => 'json',
|
||||
'tab_name' => 'Super Power',
|
||||
],
|
||||
'use_selection' => [
|
||||
'name' => 'use_selection',
|
||||
'label' => 'COM_COMPONENTBUILDER_POWER_USE_SELECTION_LABEL',
|
||||
@@ -1710,15 +1728,6 @@ class Table implements Tableinterface
|
||||
'store' => 'json',
|
||||
'tab_name' => 'Code',
|
||||
],
|
||||
'add_licensing_template' => [
|
||||
'name' => 'add_licensing_template',
|
||||
'label' => 'COM_COMPONENTBUILDER_POWER_ADD_LICENSING_TEMPLATE_LABEL',
|
||||
'type' => 'radio',
|
||||
'title' => false,
|
||||
'list' => 'powers',
|
||||
'store' => NULL,
|
||||
'tab_name' => 'Licensing',
|
||||
],
|
||||
'main_class_code' => [
|
||||
'name' => 'main_class_code',
|
||||
'label' => 'COM_COMPONENTBUILDER_POWER_MAIN_CLASS_CODE_LABEL',
|
||||
@@ -1728,6 +1737,15 @@ class Table implements Tableinterface
|
||||
'store' => 'base64',
|
||||
'tab_name' => 'Code',
|
||||
],
|
||||
'add_licensing_template' => [
|
||||
'name' => 'add_licensing_template',
|
||||
'label' => 'COM_COMPONENTBUILDER_POWER_ADD_LICENSING_TEMPLATE_LABEL',
|
||||
'type' => 'radio',
|
||||
'title' => false,
|
||||
'list' => 'powers',
|
||||
'store' => NULL,
|
||||
'tab_name' => 'Licensing',
|
||||
],
|
||||
'guid' => [
|
||||
'name' => 'guid',
|
||||
'label' => 'COM_COMPONENTBUILDER_POWER_GUID_LABEL',
|
||||
|
@@ -0,0 +1,814 @@
|
||||
<?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\Utilities;
|
||||
|
||||
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\Language\Text;
|
||||
use VDM\Joomla\Utilities\ArrayHelper;
|
||||
use VDM\Joomla\Utilities\JsonHelper;
|
||||
use VDM\Joomla\Utilities\GetHelper;
|
||||
|
||||
|
||||
/**
|
||||
* Filter Helper
|
||||
*
|
||||
* @since 3.2.0
|
||||
*/
|
||||
abstract class FilterHelper
|
||||
{
|
||||
/**
|
||||
* get extensions grouped list xml
|
||||
*
|
||||
* @return string The XML string of Extentions
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public static function extensions(): string
|
||||
{
|
||||
// the extension types
|
||||
$extensions = array(
|
||||
'joomla_component' => 'COM_COMPONENTBUILDER_COMPONENT',
|
||||
'joomla_module' => 'COM_COMPONENTBUILDER_MODULE',
|
||||
'joomla_plugin' => 'COM_COMPONENTBUILDER_PLUGIN'
|
||||
);
|
||||
|
||||
// get the extension values
|
||||
foreach ($extensions as $extension => $label)
|
||||
{
|
||||
${$extension} = self::names($extension);
|
||||
}
|
||||
|
||||
$xml = new \DOMDocument();
|
||||
$xml->formatOutput = true;
|
||||
|
||||
$root = $xml->createElement('field');
|
||||
$root->setAttributeNode(new \DOMAttr('name', 'extension'));
|
||||
$root->setAttributeNode(new \DOMAttr('type', 'groupedlist'));
|
||||
$root->setAttributeNode(new \DOMAttr('onchange', 'this.form.submit();'));
|
||||
|
||||
$root
|
||||
->appendChild($xml->createElement('option', '- ' . Text::_('COM_COMPONENTBUILDER_SELECT_EXTENSION') . ' -'))
|
||||
->setAttributeNode(new \DOMAttr('value', ''));
|
||||
|
||||
foreach ($extensions as $extension => $label)
|
||||
{
|
||||
$extension_node = $xml->createElement('group');
|
||||
$extension_node->setAttributeNode(new \DOMAttr('label', $label));
|
||||
if (!ArrayHelper::check(${$extension}))
|
||||
{
|
||||
$extension_node
|
||||
->appendChild($xml->createElement('option', '- ' . Text::_('COM_COMPONENTBUILDER_NONE') . ' -'))
|
||||
->setAttributeNode(new \DOMAttr('disabled', 'true'));
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (${$extension} as $id => $element)
|
||||
{
|
||||
$extension_node
|
||||
->appendChild($xml->createElement('option', $element))
|
||||
->setAttributeNode(new \DOMAttr('value', $extension . '__' . $id));
|
||||
}
|
||||
}
|
||||
$root->appendChild($extension_node);
|
||||
}
|
||||
$xml->appendChild($root);
|
||||
|
||||
return $xml->saveXML();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get by type the ids and system names
|
||||
*
|
||||
* @param string $type The table name to get system names for
|
||||
* @param string|null $limiter The to limit by limiter table
|
||||
*
|
||||
* @return array|null The array of system name and IDs
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public static function names(string $type, ?string $limiter = null): ?array
|
||||
{
|
||||
$db = Factory::getDbo();
|
||||
$query = $db->getQuery(true);
|
||||
|
||||
$query
|
||||
->select($db->quoteName(array('id', 'system_name')))
|
||||
->from($db->quoteName('#__componentbuilder_' . $type))
|
||||
->where($db->quoteName('published') . ' >= 1')
|
||||
->order($db->quoteName('modified') . ' desc')
|
||||
->order($db->quoteName('created') . ' desc');
|
||||
|
||||
// check if we have a limiter for admin views
|
||||
if ($type === 'admin_view' && $limiter)
|
||||
{
|
||||
// first get all views
|
||||
$admin_view_ids = array();
|
||||
|
||||
// if this is a plugin or a module, then no views
|
||||
if (strpos($limiter, 'joomla_component') !== false)
|
||||
{
|
||||
$component = (int) str_replace('joomla_component__', '', $limiter);
|
||||
// get the views of this component
|
||||
if ($add_views = GetHelper::var('component_admin_views', (int) $component, 'joomla_component', 'addadmin_views'))
|
||||
{
|
||||
if (JsonHelper::check($add_views))
|
||||
{
|
||||
$add_views = json_decode($add_views, true);
|
||||
if (ArrayHelper::check($add_views))
|
||||
{
|
||||
foreach($add_views as $add_view)
|
||||
{
|
||||
if (isset($add_view['adminview']))
|
||||
{
|
||||
$admin_view_ids[(int) $add_view['adminview']] = (int) $add_view['adminview'];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// now check if we still have admin views
|
||||
if (ArrayHelper::check($admin_view_ids))
|
||||
{
|
||||
$query->where($db->quoteName('id') . ' IN (' . implode(',', $admin_view_ids) . ')');
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
$db->setQuery($query);
|
||||
$db->execute();
|
||||
|
||||
if ($db->getNumRows())
|
||||
{
|
||||
return $db->loadAssocList('id', 'system_name');
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* get any area linked IDs
|
||||
*
|
||||
* @param int $id The target ID
|
||||
* @param string $method The target method
|
||||
*
|
||||
* @return array|null The result ids
|
||||
* @since 3.2.0
|
||||
**/
|
||||
public static function linked(int $id, string $method): ?array
|
||||
{
|
||||
// check if method exist
|
||||
if (method_exists(__CLASS__, $method))
|
||||
{
|
||||
return self::{$method}($id);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the substrings of the namespace until the last "\" or "."
|
||||
*
|
||||
* @return array|null The result substrings
|
||||
* @since 3.2.0
|
||||
**/
|
||||
public static function namespaces(): ?array
|
||||
{
|
||||
$db = Factory::getDbo();
|
||||
$query = $db->getQuery(true);
|
||||
$query
|
||||
->select(
|
||||
'DISTINCT REPLACE(SUBSTRING('
|
||||
. $db->quoteName('namespace')
|
||||
. ', 1, LENGTH('
|
||||
. $db->quoteName('namespace')
|
||||
. ') - LEAST('
|
||||
. 'IF(LOCATE('
|
||||
. $db->quote('\\')
|
||||
. ', ' . $db->quoteName('namespace')
|
||||
. ') > 0, LOCATE('
|
||||
. $db->quote('\\')
|
||||
. ', REVERSE('
|
||||
. $db->quoteName('namespace')
|
||||
. ')), 0), '
|
||||
. 'IF(LOCATE('
|
||||
. $db->quote('.')
|
||||
. ', ' . $db->quoteName('namespace')
|
||||
. ') > 0, LOCATE('
|
||||
. $db->quote('.')
|
||||
. ', REVERSE('
|
||||
. $db->quoteName('namespace')
|
||||
. ')), 0))), ".", "\\\") AS trimmed_namespace'
|
||||
)
|
||||
->from($db->quoteName('#__componentbuilder_power'))
|
||||
->where($db->quoteName('published') . ' = 1')
|
||||
->order('LENGTH(trimmed_namespace) ASC, trimmed_namespace ASC');
|
||||
$db->setQuery($query);
|
||||
$db->execute();
|
||||
|
||||
if ($db->getNumRows())
|
||||
{
|
||||
return $db->loadAssocList('trimmed_namespace', 'trimmed_namespace');
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* get get IDs of powers matching namespaces
|
||||
*
|
||||
* @param string $namespace The target namespace
|
||||
*
|
||||
* @return array|null The result ids
|
||||
* @since 3.2.0
|
||||
**/
|
||||
public static function namegroup(string $namespace): ?array
|
||||
{
|
||||
$db = Factory::getDbo();
|
||||
$query = $db->getQuery(true);
|
||||
$query
|
||||
->select($db->quoteName(array('id')))
|
||||
->from($db->quoteName('#__componentbuilder_power'))
|
||||
->where($db->quoteName('published') . ' = 1');
|
||||
|
||||
// we get only those that match the owner and repo (smaller set)
|
||||
$paths = explode('\\', $namespace);
|
||||
foreach ($paths as $path)
|
||||
{
|
||||
$query->where($db->quoteName('namespace') . ' REGEXP ' . $db->quote($path));
|
||||
}
|
||||
|
||||
$db->setQuery($query);
|
||||
$db->execute();
|
||||
|
||||
if ($db->getNumRows())
|
||||
{
|
||||
return $db->loadColumn();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* get translation extension ids
|
||||
*
|
||||
* @param int $extension The target ID
|
||||
* @param string $type The target method
|
||||
*
|
||||
* @return array|null The result ids
|
||||
* @since 3.2.0
|
||||
**/
|
||||
public static function translation(int $extension, string $type): ?array
|
||||
{
|
||||
// only allow these columns (extension types)
|
||||
$columns = array(
|
||||
'joomla_component' => 'components',
|
||||
'joomla_module' => 'modules',
|
||||
'joomla_plugin' => 'plugins'
|
||||
);
|
||||
|
||||
// check if the column name is correct
|
||||
if (isset($columns[$type]))
|
||||
{
|
||||
$column = $columns[$type];
|
||||
$db = Factory::getDbo();
|
||||
$query = $db->getQuery(true);
|
||||
$query
|
||||
->select($db->quoteName(array('id', $column)))
|
||||
->from($db->quoteName('#__componentbuilder_language_translation'))
|
||||
->where($db->quoteName($column) . ' != ' . $db->quote(''));
|
||||
|
||||
$db->setQuery($query);
|
||||
$db->execute();
|
||||
|
||||
if ($db->getNumRows())
|
||||
{
|
||||
$results = $db->loadAssocList();
|
||||
$matches = [];
|
||||
foreach ($results as $k => $v)
|
||||
{
|
||||
$value = json_decode($v[$column], true);
|
||||
if (in_array($extension, $value))
|
||||
{
|
||||
$matches[$v['id']] = $v['id'];
|
||||
}
|
||||
}
|
||||
|
||||
// Checks that we found matches
|
||||
if (ArrayHelper::check($matches))
|
||||
{
|
||||
return array_values($matches);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* get translation ids
|
||||
*
|
||||
* @param int $id The target ID
|
||||
*
|
||||
* @return array|null The result ids
|
||||
* @since 3.2.0
|
||||
**/
|
||||
public static function translations($language, $translated = true): ?array
|
||||
{
|
||||
$db = Factory::getDbo();
|
||||
$query = $db->getQuery(true);
|
||||
|
||||
$query
|
||||
->select($db->quoteName('id'))
|
||||
->from($db->quoteName('#__componentbuilder_language_translation'));
|
||||
|
||||
// Build the where condition
|
||||
if ($translated === true) // Translated
|
||||
{
|
||||
if ($language === 'all')
|
||||
{
|
||||
if (($languages = self::languages()) !== null)
|
||||
{
|
||||
$wheres = [];
|
||||
foreach ($languages as $k => $v)
|
||||
{
|
||||
$wheres[] = $db->quoteName('translation') . ' LIKE ' . $db->quote('%' . $k . '%');
|
||||
}
|
||||
$query->where($wheres);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$query->where($db->quoteName('translation') . ' LIKE ' . $db->quote('%' . $language . '%'));
|
||||
}
|
||||
}
|
||||
else // Not translated
|
||||
{
|
||||
if ($language === 'none')
|
||||
{
|
||||
$query->where(
|
||||
array(
|
||||
$db->quoteName('translation') . ' = ' . $db->quote(''),
|
||||
$db->quoteName('translation') . ' = ' . $db->quote('[]'),
|
||||
$db->quoteName('translation') . ' = ' . $db->quote('{}')
|
||||
), 'OR'
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
$query->where($db->quoteName('translation') . ' NOT LIKE ' . $db->quote('%' . $language . '%'));
|
||||
}
|
||||
}
|
||||
|
||||
$db->setQuery($query);
|
||||
$db->execute();
|
||||
|
||||
if ($db->getNumRows())
|
||||
{
|
||||
return array_unique($db->loadColumn());
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* get available languages
|
||||
*
|
||||
* @return array|null The result ids
|
||||
* @since 3.2.0
|
||||
**/
|
||||
public static function languages(): ?array
|
||||
{
|
||||
$db = Factory::getDbo();
|
||||
$query = $db->getQuery(true);
|
||||
$query
|
||||
->select($db->quoteName(array('langtag', 'name')))
|
||||
->from($db->quoteName('#__componentbuilder_language'))
|
||||
->where($db->quoteName('published') . ' = 1')
|
||||
->order($db->quoteName('name') . ' desc');
|
||||
$db->setQuery($query);
|
||||
$db->execute();
|
||||
|
||||
if ($db->getNumRows())
|
||||
{
|
||||
return $db->loadAssocList('langtag', 'name');
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* get get IDs of powers link to this path
|
||||
*
|
||||
* @param string $path The target PATH
|
||||
*
|
||||
* @return array|null The result ids
|
||||
* @since 3.2.0
|
||||
**/
|
||||
public static function paths(string $path): ?array
|
||||
{
|
||||
// get all this power ids
|
||||
$ids = [];
|
||||
|
||||
$db = Factory::getDbo();
|
||||
$query = $db->getQuery(true);
|
||||
$query
|
||||
->select($db->quoteName(array('id', 'approved_paths')))
|
||||
->from($db->quoteName('#__componentbuilder_power'))
|
||||
->where($db->quoteName('published') . ' = 1');
|
||||
|
||||
// we get only those that match the owner and repo (smaller set)
|
||||
if (($pos = strpos($path, '/')) !== false)
|
||||
{
|
||||
$owner = substr($path, 0, $pos);
|
||||
$repo = substr($path, $pos + 1);
|
||||
$query
|
||||
->where($db->quoteName('approved_paths') . ' REGEXP ' . $db->quote($owner))
|
||||
->where($db->quoteName('approved_paths') . ' REGEXP ' . $db->quote($repo));
|
||||
}
|
||||
|
||||
$db->setQuery($query);
|
||||
$db->execute();
|
||||
|
||||
if ($db->getNumRows())
|
||||
{
|
||||
$result = $db->loadAssocList('id', 'approved_paths');
|
||||
foreach ($result as $id => $paths)
|
||||
{
|
||||
if (JsonHelper::check($paths))
|
||||
{
|
||||
$paths = json_decode($paths, true);
|
||||
if (ArrayHelper::check($paths) && in_array($path, $paths, true))
|
||||
{
|
||||
$ids[$id] = $id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ArrayHelper::check($ids))
|
||||
{
|
||||
return $ids;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a component admin views IDs
|
||||
*
|
||||
* @param int $id The target ID
|
||||
*
|
||||
* @return array|null The result ids
|
||||
* @since 3.2.0
|
||||
*/
|
||||
private static function joomla_component_admin_views(int $id): ?array
|
||||
{
|
||||
// get all this components views
|
||||
$admin_view_ids = [];
|
||||
|
||||
// get the views of this component
|
||||
if ($add_views = GetHelper::var('component_admin_views', (int) $id, 'joomla_component', 'addadmin_views'))
|
||||
{
|
||||
if (JsonHelper::check($add_views))
|
||||
{
|
||||
$add_views = json_decode($add_views, true);
|
||||
if (ArrayHelper::check($add_views))
|
||||
{
|
||||
foreach($add_views as $add_view)
|
||||
{
|
||||
if (isset($add_view['adminview']))
|
||||
{
|
||||
$admin_view_ids[(int) $add_view['adminview']] = (int) $add_view['adminview'];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check that we have fields
|
||||
if (ArrayHelper::check($admin_view_ids))
|
||||
{
|
||||
return array_values($admin_view_ids);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* get a component custom admin views IDs
|
||||
*
|
||||
* @param int $id The target ID
|
||||
*
|
||||
* @return array|null The result ids
|
||||
* @since 3.2.0
|
||||
*/
|
||||
private static function joomla_component_custom_admin_views($id): ?array
|
||||
{
|
||||
// get all this components views
|
||||
$admin_view_ids = [];
|
||||
|
||||
// get the views of this component
|
||||
if ($add_views = GetHelper::var('component_custom_admin_views', (int) $id, 'joomla_component', 'addcustom_admin_views'))
|
||||
{
|
||||
if (JsonHelper::check($add_views))
|
||||
{
|
||||
$add_views = json_decode($add_views, true);
|
||||
if (ArrayHelper::check($add_views))
|
||||
{
|
||||
foreach($add_views as $add_view)
|
||||
{
|
||||
if (isset($add_view['customadminview']))
|
||||
{
|
||||
$admin_view_ids[(int) $add_view['customadminview']] = (int) $add_view['customadminview'];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check that we have fields
|
||||
if (ArrayHelper::check($admin_view_ids))
|
||||
{
|
||||
return array_values($admin_view_ids);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* get a component site views IDs
|
||||
*
|
||||
* @param int $id The target ID
|
||||
*
|
||||
* @return array|null The result ids
|
||||
* @since 3.2.0
|
||||
*/
|
||||
private static function joomla_component_site_views($id): ?array
|
||||
{
|
||||
// get all this components views
|
||||
$admin_view_ids = [];
|
||||
|
||||
// get the views of this component
|
||||
if ($add_views = GetHelper::var('component_site_views', (int) $id, 'joomla_component', 'addsite_views'))
|
||||
{
|
||||
if (JsonHelper::check($add_views))
|
||||
{
|
||||
$add_views = json_decode($add_views, true);
|
||||
if (ArrayHelper::check($add_views))
|
||||
{
|
||||
foreach($add_views as $add_view)
|
||||
{
|
||||
if (isset($add_view['siteview']))
|
||||
{
|
||||
$admin_view_ids[(int) $add_view['siteview']] = (int) $add_view['siteview'];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check that we have fields
|
||||
if (ArrayHelper::check($admin_view_ids))
|
||||
{
|
||||
return array_values($admin_view_ids);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* get a component fields IDs
|
||||
*
|
||||
* @param int $id The target ID
|
||||
*
|
||||
* @return array|null The result ids
|
||||
* @since 3.2.0
|
||||
*/
|
||||
private static function joomla_component($id): ?array
|
||||
{
|
||||
// we start the field array
|
||||
$field_ids = [];
|
||||
|
||||
// first get all views
|
||||
$admin_view_ids = [];
|
||||
|
||||
// get the views of this component
|
||||
if ($add_views = GetHelper::var('component_admin_views', (int) $id, 'joomla_component', 'addadmin_views'))
|
||||
{
|
||||
if (JsonHelper::check($add_views))
|
||||
{
|
||||
$add_views = json_decode($add_views, true);
|
||||
if (ArrayHelper::check($add_views))
|
||||
{
|
||||
foreach($add_views as $add_view)
|
||||
{
|
||||
if (isset($add_view['adminview']))
|
||||
{
|
||||
$admin_view_ids[(int) $add_view['adminview']] = (int) $add_view['adminview'];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check that we have views
|
||||
if (ArrayHelper::check($admin_view_ids))
|
||||
{
|
||||
foreach ($admin_view_ids as $admin_view)
|
||||
{
|
||||
// get all the fields linked to the admin view
|
||||
if ($add_fields = GetHelper::var('admin_fields', (int) $admin_view, 'admin_view', 'addfields'))
|
||||
{
|
||||
if (JsonHelper::check($add_fields))
|
||||
{
|
||||
$add_fields = json_decode($add_fields, true);
|
||||
if (ArrayHelper::check($add_fields))
|
||||
{
|
||||
foreach($add_fields as $add_field)
|
||||
{
|
||||
if (isset($add_field['field']))
|
||||
{
|
||||
$field_ids[(int) $add_field['field']] = (int) $add_field['field'];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// get config values
|
||||
if ($add_config = GetHelper::var('component_config', (int) $id, 'joomla_component', 'addconfig'))
|
||||
{
|
||||
if (JsonHelper::check($add_config))
|
||||
{
|
||||
$add_config = json_decode($add_config, true);
|
||||
if (ArrayHelper::check($add_config))
|
||||
{
|
||||
foreach($add_config as $add_conf)
|
||||
{
|
||||
if (isset($add_conf['field']))
|
||||
{
|
||||
$field_ids[(int) $add_conf['field']] = (int) $add_conf['field'];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check that we have fields
|
||||
if (ArrayHelper::check($field_ids))
|
||||
{
|
||||
return array_values($field_ids);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* get a module fields IDs
|
||||
*
|
||||
* @param int $id The target ID
|
||||
*
|
||||
* @return array|null The result ids
|
||||
* @since 3.2.0
|
||||
*/
|
||||
private static function joomla_module($id): ?array
|
||||
{
|
||||
// we start the field array
|
||||
$field_ids = [];
|
||||
|
||||
if ($fields = GetHelper::var('joomla_module', (int) $id, 'id', 'fields'))
|
||||
{
|
||||
if (JsonHelper::check($fields))
|
||||
{
|
||||
$fields = json_decode($fields, true);
|
||||
if (ArrayHelper::check($fields))
|
||||
{
|
||||
foreach($fields as $form)
|
||||
{
|
||||
if (isset($form['fields']) && ArrayHelper::check($form['fields']))
|
||||
{
|
||||
foreach ($form['fields'] as $field)
|
||||
{
|
||||
if (isset($field['field']))
|
||||
{
|
||||
$field_ids[(int) $field['field']] = (int) $field['field'];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check that we have fields
|
||||
if (ArrayHelper::check($field_ids))
|
||||
{
|
||||
return array_values($field_ids);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* get a plugin fields IDs
|
||||
*
|
||||
* @param int $id The target ID
|
||||
*
|
||||
* @return array|null The result ids
|
||||
* @since 3.2.0
|
||||
*/
|
||||
private static function joomla_plugin($id): ?array
|
||||
{
|
||||
// we start the field array
|
||||
$field_ids = [];
|
||||
|
||||
if ($fields = GetHelper::var('joomla_plugin', (int) $id, 'id', 'fields'))
|
||||
{
|
||||
if (JsonHelper::check($fields))
|
||||
{
|
||||
$fields = json_decode($fields, true);
|
||||
if (ArrayHelper::check($fields))
|
||||
{
|
||||
foreach($fields as $form)
|
||||
{
|
||||
if (isset($form['fields']) && ArrayHelper::check($form['fields']))
|
||||
{
|
||||
foreach ($form['fields'] as $field)
|
||||
{
|
||||
if (isset($field['field']))
|
||||
{
|
||||
$field_ids[(int) $field['field']] = (int) $field['field'];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check that we have fields
|
||||
if (ArrayHelper::check($field_ids))
|
||||
{
|
||||
return array_values($field_ids);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* get an admin view fields IDs
|
||||
*
|
||||
* @param int $id The target ID
|
||||
*
|
||||
* @return array|null The result ids
|
||||
* @since 3.2.0
|
||||
*/
|
||||
private static function admin_view($id): ?array
|
||||
{
|
||||
// we start the field array
|
||||
$field_ids = [];
|
||||
|
||||
// get all the fields linked to the admin view
|
||||
if ($add_fields = GetHelper::var('admin_fields', (int) $id, 'admin_view', 'addfields'))
|
||||
{
|
||||
if (JsonHelper::check($add_fields))
|
||||
{
|
||||
$add_fields = json_decode($add_fields, true);
|
||||
if (ArrayHelper::check($add_fields))
|
||||
{
|
||||
foreach($add_fields as $add_field)
|
||||
{
|
||||
if (isset($add_field['field']))
|
||||
{
|
||||
$field_ids[(int) $add_field['field']] = (int) $add_field['field'];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check that we have fields
|
||||
if (ArrayHelper::check($field_ids))
|
||||
{
|
||||
return array_values($field_ids);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -0,0 +1,189 @@
|
||||
<?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\Utilities;
|
||||
|
||||
|
||||
use Joomla\CMS\Form\FormHelper as JoomlaFormHelper;
|
||||
use Joomla\CMS\Form\FormField;
|
||||
use VDM\Joomla\Utilities\ArrayHelper;
|
||||
|
||||
|
||||
/**
|
||||
* Form Helper
|
||||
*
|
||||
* @since 3.2.0
|
||||
*/
|
||||
abstract class FormHelper
|
||||
{
|
||||
/**
|
||||
* get the field xml
|
||||
*
|
||||
* @param array $attributes The array of attributes
|
||||
* @param array $options The options to apply to the XML element
|
||||
*
|
||||
* @return \SimpleXMLElement|null
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public static function xml(array $attributes, ?array $options = null): ?\SimpleXMLElement
|
||||
{
|
||||
// make sure we have attributes and a type value
|
||||
if (ArrayHelper::check($attributes))
|
||||
{
|
||||
// start field xml
|
||||
$XML = new \SimpleXMLElement('<field/>');
|
||||
|
||||
// load the attributes
|
||||
self::attributes($XML, $attributes);
|
||||
|
||||
// check if we have options
|
||||
if (ArrayHelper::check($options))
|
||||
{
|
||||
// load the options
|
||||
self::options($XML, $options);
|
||||
}
|
||||
|
||||
// return the field xml
|
||||
return $XML;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* xmlAppend
|
||||
*
|
||||
* @param \SimpleXMLElement $xml The XML element reference in which to inject a comment
|
||||
* @param mixed $node A SimpleXMLElement node to append to the XML element reference,
|
||||
* or a stdClass object containing a comment attribute to be injected
|
||||
* before the XML node and a fieldXML attribute containing a SimpleXMLElement
|
||||
*
|
||||
* @return void
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public static function append(\SimpleXMLElement &$xml, $node)
|
||||
{
|
||||
if (!$node)
|
||||
{
|
||||
// element was not returned
|
||||
return;
|
||||
}
|
||||
switch (get_class($node))
|
||||
{
|
||||
case 'stdClass':
|
||||
if (property_exists($node, 'comment'))
|
||||
{
|
||||
self::comment($xml, $node->comment);
|
||||
}
|
||||
if (property_exists($node, 'fieldXML'))
|
||||
{
|
||||
self::append($xml, $node->fieldXML);
|
||||
}
|
||||
break;
|
||||
case 'SimpleXMLElement':
|
||||
$domXML = \dom_import_simplexml($xml);
|
||||
$domNode = \dom_import_simplexml($node);
|
||||
$domXML->appendChild($domXML->ownerDocument->importNode($domNode, true));
|
||||
$xml = \simplexml_import_dom($domXML);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* xmlComment
|
||||
*
|
||||
* @param \SimpleXMLElement $xml The XML element reference in which to inject a comment
|
||||
* @param string $comment The comment to inject
|
||||
*
|
||||
* @return void
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public static function comment(\SimpleXMLElement &$xml, string $comment)
|
||||
{
|
||||
$domXML = \dom_import_simplexml($xml);
|
||||
$domComment = new \DOMComment($comment);
|
||||
$nodeTarget = $domXML->ownerDocument->importNode($domComment, true);
|
||||
$domXML->appendChild($nodeTarget);
|
||||
$xml = \simplexml_import_dom($domXML);
|
||||
}
|
||||
|
||||
/**
|
||||
* xmlAddAttributes
|
||||
*
|
||||
* @param \SimpleXMLElement $xml The XML element reference in which to inject a comment
|
||||
* @param array $attributes The attributes to apply to the XML element
|
||||
*
|
||||
* @return void
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public static function attributes(\SimpleXMLElement &$xml, array $attributes = [])
|
||||
{
|
||||
foreach ($attributes as $key => $value)
|
||||
{
|
||||
$xml->addAttribute($key, $value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* xmlAddOptions
|
||||
*
|
||||
* @param \SimpleXMLElement $xml The XML element reference in which to inject a comment
|
||||
* @param array $options The options to apply to the XML element
|
||||
*
|
||||
* @return void
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public static function options(\SimpleXMLElement &$xml, array $options = [])
|
||||
{
|
||||
foreach ($options as $key => $value)
|
||||
{
|
||||
$addOption = $xml->addChild('option');
|
||||
$addOption->addAttribute('value', $key);
|
||||
$addOption[] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* get the field object
|
||||
*
|
||||
* @param array $attributes The array of attributes
|
||||
* @param string $default The default of the field
|
||||
* @param array $options The options to apply to the XML element
|
||||
*
|
||||
* @return FormField|null
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public static function field(array $attributes, string $default = '', ?array $options = null): ?FormField
|
||||
{
|
||||
// make sure we have attributes and a type value
|
||||
if (ArrayHelper::check($attributes) && isset($attributes['type']))
|
||||
{
|
||||
// get field type
|
||||
if (($field = JoomlaFormHelper::loadFieldType($attributes['type'], true)) === false)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// get field xml
|
||||
$XML = self::xml($attributes, $options);
|
||||
|
||||
// setup the field
|
||||
$field->setup($XML, $default);
|
||||
|
||||
// return the field object
|
||||
return $field;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -185,7 +185,8 @@ abstract class GuidHelper
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
Reference in New Issue
Block a user