Release of v5.0.0-alpha8
Add power path override option on component level. Fix the sql build feature. #1032.
This commit is contained in:
@@ -0,0 +1,283 @@
|
||||
<?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\Customcode;
|
||||
|
||||
|
||||
use VDM\Joomla\Utilities\StringHelper;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Factory as Compiler;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Customcode;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Placeholder;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Customcode\Gui;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Customcode\Hash;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Customcode\LockBase;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Interfaces\Customcode\DispenserInterface;
|
||||
|
||||
|
||||
/**
|
||||
* Compiler Custom Code Dispenser
|
||||
*
|
||||
* @since 3.2.0
|
||||
*/
|
||||
class Dispenser implements DispenserInterface
|
||||
{
|
||||
/**
|
||||
* Customcode Dispenser Hub
|
||||
*
|
||||
* @var array
|
||||
* @since 3.2.0
|
||||
**/
|
||||
public array $hub;
|
||||
|
||||
/**
|
||||
* Compiler Placeholder
|
||||
*
|
||||
* @var Placeholder
|
||||
* @since 3.2.0
|
||||
**/
|
||||
protected Placeholder $placeholder;
|
||||
|
||||
/**
|
||||
* Compiler Customcode
|
||||
*
|
||||
* @var Customcode
|
||||
* @since 3.2.0
|
||||
**/
|
||||
protected Customcode $customcode;
|
||||
|
||||
/**
|
||||
* Compiler Customcode in Gui
|
||||
*
|
||||
* @var Gui
|
||||
* @since 3.2.0
|
||||
**/
|
||||
protected Gui $gui;
|
||||
|
||||
/**
|
||||
* Compiler Customcode to Hash
|
||||
*
|
||||
* @var Hash
|
||||
* @since 3.2.0
|
||||
**/
|
||||
protected Hash $hash;
|
||||
|
||||
/**
|
||||
* Compiler Customcode to LockBase
|
||||
*
|
||||
* @var LockBase
|
||||
* @since 3.2.0
|
||||
**/
|
||||
protected LockBase $base64;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @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 Hash|null $hash The compiler customcode hash object.
|
||||
* @param LockBase|null $base64 The compiler customcode lock base64 object.
|
||||
*
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function __construct(?Placeholder $placeholder = null, ?Customcode $customcode = null,
|
||||
?Gui $gui = null, ?Hash $hash = null, ?LockBase $base64 = null)
|
||||
{
|
||||
$this->placeholder = $placeholder ?: Compiler::_('Placeholder');
|
||||
$this->customcode = $customcode ?: Compiler::_('Customcode');
|
||||
$this->gui = $gui ?: Compiler::_('Customcode.Gui');
|
||||
$this->hash = $hash ?: Compiler::_('Customcode.Hash');
|
||||
$this->base64 = $base64 ?: Compiler::_('Customcode.LockBase');
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the script for the customcode dispenser
|
||||
*
|
||||
* @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 array $config The config options
|
||||
* @param bool $base64 The switch to decode base64 the script
|
||||
* default: true
|
||||
* @param bool $dynamic The switch to dynamic update the script
|
||||
* default: true
|
||||
* @param bool $add The switch to add to exiting instead of replace
|
||||
* default: false
|
||||
*
|
||||
* @return bool true on success
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function set(&$script, string $first, ?string $second = null, ?string $third = null,
|
||||
array $config = [], bool $base64 = true, bool $dynamic = true, bool $add = false): bool
|
||||
{
|
||||
// only load if we have a string
|
||||
if (!StringHelper::check($script))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// init all needed arrays
|
||||
$this->initHub($first, $second, $third, $add);
|
||||
|
||||
// prep the script string
|
||||
if ($base64 && $dynamic)
|
||||
{
|
||||
$script = $this->customcode->update(base64_decode($script));
|
||||
}
|
||||
elseif ($base64)
|
||||
{
|
||||
$script = base64_decode($script);
|
||||
}
|
||||
elseif ($dynamic) // this does not happen (just in-case)
|
||||
{
|
||||
$script = $this->customcode->update($script);
|
||||
}
|
||||
// check if we still have a string
|
||||
if (StringHelper::check($script))
|
||||
{
|
||||
// now load the placeholder snippet if needed
|
||||
if ($base64 || $dynamic)
|
||||
{
|
||||
$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
|
||||
$this->setHub($script, $first, $second, $third, $add);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the script from the customcode dispenser
|
||||
*
|
||||
* @param string $first The first key
|
||||
* @param string $second The second key
|
||||
* @param string $prefix The prefix to add in front of the script if found
|
||||
* @param string|null $note The switch/note to add to the script
|
||||
* @param bool $unset The switch to unset the value if found
|
||||
* @param mixed|null $default The switch/string to use as default return if script not found
|
||||
* @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,
|
||||
bool $unset = false, $default = null, string $suffix = '')
|
||||
{
|
||||
// default is to return an empty string
|
||||
$script = '';
|
||||
// check if there is any custom script
|
||||
if (isset($this->hub[$first][$second])
|
||||
&& StringHelper::check(
|
||||
$this->hub[$first][$second]
|
||||
))
|
||||
{
|
||||
// add not if set
|
||||
if ($note)
|
||||
{
|
||||
$script .= $note;
|
||||
}
|
||||
// load the actual script
|
||||
$script .= $prefix . $this->placeholder->update_(
|
||||
(string) $this->hub[$first][$second]
|
||||
) . $suffix;
|
||||
// clear some memory
|
||||
if ($unset)
|
||||
{
|
||||
unset($this->hub[$first][$second]);
|
||||
}
|
||||
}
|
||||
// if not found return default
|
||||
if (!StringHelper::check($script) && $default)
|
||||
{
|
||||
return $default;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,392 @@
|
||||
<?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\Customcode;
|
||||
|
||||
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\User\User;
|
||||
use Joomla\CMS\Application\CMSApplication;
|
||||
use Joomla\CMS\Language\Text;
|
||||
use Joomla\CMS\Filesystem\Path;
|
||||
use VDM\Joomla\Utilities\ArrayHelper;
|
||||
use VDM\Joomla\Utilities\StringHelper;
|
||||
use VDM\Joomla\Utilities\GetHelper;
|
||||
use VDM\Joomla\Utilities\FileHelper;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Factory as Compiler;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Placeholder;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Interfaces\Customcode\ExternalInterface;
|
||||
|
||||
|
||||
/**
|
||||
* Compiler External Custom Code
|
||||
*
|
||||
* @since 3.2.0
|
||||
*/
|
||||
class External implements ExternalInterface
|
||||
{
|
||||
/**
|
||||
* The external code/string to be added
|
||||
*
|
||||
* @var array
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected array $code = [];
|
||||
|
||||
/**
|
||||
* The external code/string cutter
|
||||
*
|
||||
* @var array
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected array $cutter = [];
|
||||
|
||||
/**
|
||||
* Compiler Placeholder
|
||||
*
|
||||
* @var Placeholder
|
||||
* @since 3.2.0
|
||||
**/
|
||||
protected Placeholder $placeholder;
|
||||
|
||||
/**
|
||||
* Database object to query local DB
|
||||
*
|
||||
* @since 3.2.0
|
||||
**/
|
||||
protected $db;
|
||||
|
||||
/**
|
||||
* User object
|
||||
*
|
||||
* @since 3.2.0
|
||||
**/
|
||||
protected $user;
|
||||
|
||||
/**
|
||||
* Database object to query local DB
|
||||
*
|
||||
* @since 3.2.0
|
||||
**/
|
||||
protected $app;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param Placeholder|null $placeholder The compiler placeholder object.
|
||||
*
|
||||
* @throws \Exception
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function __construct(?Placeholder $placeholder = null)
|
||||
{
|
||||
$this->placeholder = $placeholder ?: Compiler::_('Placeholder');
|
||||
$this->db = Factory::getDbo();
|
||||
$this->user = Factory::getUser();
|
||||
$this->app = Factory::getApplication();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the external code string & load it in to string
|
||||
*
|
||||
* @param string $string The content to check
|
||||
* @param int $debug The switch to debug the update
|
||||
*
|
||||
* @return string
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function set(string $string, int $debug = 0): string
|
||||
{
|
||||
// check if content has custom code placeholder
|
||||
if (strpos($string, '[EXTERNA' . 'LCODE=') !== false)
|
||||
{
|
||||
// if debug
|
||||
if ($debug)
|
||||
{
|
||||
echo 'External Code String:';
|
||||
var_dump($string);
|
||||
}
|
||||
// target content
|
||||
$bucket = [];
|
||||
$found = GetHelper::allBetween(
|
||||
$string, '[EXTERNA' . 'LCODE=', ']'
|
||||
);
|
||||
if (ArrayHelper::check($found))
|
||||
{
|
||||
// build local bucket
|
||||
foreach ($found as $target)
|
||||
{
|
||||
// check for cutting sequence
|
||||
// example: >{3|4
|
||||
// will cut 3 rows at top and 4 rows at bottom
|
||||
// if the external code has 8 or more lines
|
||||
if (($pos = strpos((string) $target, '>{')) !== false)
|
||||
{
|
||||
// the length
|
||||
$target_len = strlen((string) $target);
|
||||
// where to cut
|
||||
$cutting = $target_len - $pos;
|
||||
// get the sequence
|
||||
$sequence = substr((string) $target, "-$cutting");
|
||||
// remove from the URL
|
||||
$target_url = str_replace($sequence, '', (string) $target);
|
||||
// set the cut key for this target if not set
|
||||
$this->cutter[trim((string) $target)] = str_replace('>{', '', $sequence);
|
||||
}
|
||||
else
|
||||
{
|
||||
$target_url = $target;
|
||||
}
|
||||
// check if the target is valid URL or path
|
||||
if ((!filter_var($target_url, FILTER_VALIDATE_URL) === false
|
||||
&& FileHelper::exists($target_url))
|
||||
|| (Path::clean($target_url) === $target_url
|
||||
&& FileHelper::exists($target_url)))
|
||||
{
|
||||
$this->getCode($target, $bucket);
|
||||
}
|
||||
// give notice that target is not a valid url/path
|
||||
else
|
||||
{
|
||||
// set key
|
||||
$key = '[EXTERNA' . 'LCODE=' . $target . ']';
|
||||
// set the notice
|
||||
$this->app->enqueueMessage(
|
||||
Text::_('COM_COMPONENTBUILDER_HR_HTHREEEXTERNAL_CODE_WARNINGHTHREE'
|
||||
), 'Warning'
|
||||
);
|
||||
$this->app->enqueueMessage(
|
||||
Text::sprintf('COM_COMPONENTBUILDER_THE_BSB_IS_NOT_A_VALID_URLPATH',
|
||||
$key
|
||||
), 'Warning'
|
||||
);
|
||||
// remove the placeholder
|
||||
$bucket[$key] = '';
|
||||
}
|
||||
}
|
||||
// now update local string if bucket has values
|
||||
if (ArrayHelper::check($bucket))
|
||||
{
|
||||
$string = $this->placeholder->update($string, $bucket);
|
||||
}
|
||||
}
|
||||
// if debug
|
||||
if ($debug)
|
||||
{
|
||||
echo 'External Code String After Update:';
|
||||
var_dump($string);
|
||||
}
|
||||
}
|
||||
|
||||
return $string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the External Code/String
|
||||
*
|
||||
* @param string $string The content to check
|
||||
* @param array $bucket The Placeholders bucket
|
||||
*
|
||||
* @return void
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected function getCode(string $target, array &$bucket)
|
||||
{
|
||||
// set URL key
|
||||
$target_key = trim($target);
|
||||
// set key
|
||||
$key = '[EXTERNA' . 'LCODE=' . $target . ']';
|
||||
// remove the cut sequence from the url
|
||||
if (isset($this->cutter[$target_key]))
|
||||
{
|
||||
// remove from the URL
|
||||
$target_url = trim(str_replace('>{' . $this->cutter[$target_key], '', $target));
|
||||
}
|
||||
else
|
||||
{
|
||||
$target_url = trim($target);
|
||||
}
|
||||
// check if we already fetched this
|
||||
if (!isset($this->code[$target_key]))
|
||||
{
|
||||
// get the data string (code)
|
||||
$this->code[$target_key]
|
||||
= FileHelper::getContent($target_url);
|
||||
// check if we must cut this
|
||||
if (isset($this->cutter[$target_key]) &&
|
||||
$this->cutter[$target_key])
|
||||
{
|
||||
$this->code[$target_key] = $this->cut(
|
||||
$this->code[$target_key],
|
||||
$this->cutter[$target_key],
|
||||
$key
|
||||
);
|
||||
}
|
||||
// did we get any value
|
||||
if (StringHelper::check(
|
||||
$this->code[$target_key]
|
||||
))
|
||||
{
|
||||
// check for changes
|
||||
$live_hash = md5($this->code[$target_key]);
|
||||
// check if it exists local
|
||||
if ($hash = GetHelper::var(
|
||||
'external_code', $target_key, 'target', 'hash'
|
||||
))
|
||||
{
|
||||
// must be an admin make a change to use EXTERNAL code (we may add a custom access switch - use ADMIN for now)
|
||||
if ($hash !== $live_hash && $this->user->authorise(
|
||||
'core.admin', 'com_componentbuilder'
|
||||
))
|
||||
{
|
||||
// update the hash since it changed
|
||||
$object = new \stdClass();
|
||||
$object->target = $target_key;
|
||||
$object->hash = $live_hash;
|
||||
// update local hash
|
||||
$this->db->updateObject(
|
||||
'#__componentbuilder_external_code', $object,
|
||||
'target'
|
||||
);
|
||||
// give notice of the change
|
||||
$this->app->enqueueMessage(
|
||||
Text::_('COM_COMPONENTBUILDER_HR_HTHREEEXTERNAL_CODE_WARNINGHTHREE'),
|
||||
'Warning'
|
||||
);
|
||||
$this->app->enqueueMessage(
|
||||
Text::sprintf('COM_COMPONENTBUILDER_THE_CODESTRING_FROM_BSB_HAS_BEEN_BCHANGEDB_SINCE_THE_LAST_COMPILATION_PLEASE_INVESTIGATE_TO_ENSURE_THE_CHANGES_ARE_SAFE_BSHOULD_YOU_NOT_EXPECT_THIS_CHANGE_TO_THE_EXTERNAL_CODESTRING_BEING_ADDED_THEN_THIS_IS_A_SERIOUS_ISSUE_AND_REQUIRES_IMMEDIATE_ATTENTIONB_DO_NOT_IGNORE_THIS_WARNING_AS_IT_WILL_ONLY_SHOW_BONCEB',
|
||||
$key
|
||||
), 'Warning'
|
||||
);
|
||||
}
|
||||
elseif ($hash !== $live_hash)
|
||||
{
|
||||
// set the notice
|
||||
$this->app->enqueueMessage(
|
||||
Text::_('COM_COMPONENTBUILDER_HR_HTHREEEXTERNAL_CODE_ERRORHTHREE'),
|
||||
'Error'
|
||||
);
|
||||
$this->app->enqueueMessage(
|
||||
Text::sprintf('COM_COMPONENTBUILDER_S_WE_DETECTED_A_CHANGE_IN_BEXTERNALCODEB_BUT_YOU_DO_NOT_HAVE_PERMISSION_TO_ALLOW_THIS_CHANGE_SO_BSB_WAS_REMOVED_FROM_THE_COMPILATION_PLEASE_CONTACT_YOUR_SYSTEM_ADMINISTRATOR_FOR_MORE_INFOBR_SMALLADMIN_ACCESS_REQUIREDSMALL',
|
||||
$this->user->get('name'), $key
|
||||
), 'Error'
|
||||
);
|
||||
// remove the code/string
|
||||
$this->code[$target_key] = '';
|
||||
}
|
||||
}
|
||||
// only an admin can add new EXTERNAL code (we may add a custom access switch - use ADMIN for now)
|
||||
elseif ($this->user->authorise(
|
||||
'core.admin', 'com_componentbuilder'
|
||||
))
|
||||
{
|
||||
// add the hash to track changes
|
||||
$object = new \stdClass();
|
||||
$object->target = $target_key;
|
||||
$object->hash = $live_hash;
|
||||
// insert local hash
|
||||
$this->db->insertObject(
|
||||
'#__componentbuilder_external_code', $object
|
||||
);
|
||||
// give notice the first time this is added
|
||||
$this->app->enqueueMessage(
|
||||
Text::_('COM_COMPONENTBUILDER_HR_HTHREEEXTERNAL_CODE_NOTICEHTHREE'),
|
||||
'Warning'
|
||||
);
|
||||
$this->app->enqueueMessage(
|
||||
Text::sprintf('COM_COMPONENTBUILDER_THE_CODESTRING_FROM_BSB_HAS_BEEN_ADDED_FOR_THE_BFIRST_TIMEB_PLEASE_IINVESTIGATEI_TO_ENSURE_THE_CORRECT_CODESTRING_WAS_USED_BSHOULD_YOU_NOT_KNOW_ABOUT_THIS_NEW_EXTERNAL_CODESTRING_BEING_ADDED_THEN_THIS_IS_A_SERIOUS_DANGER_AND_REQUIRES_IMMEDIATE_ATTENTIONB_DO_NOT_IGNORE_THIS_WARNING_AS_IT_WILL_ONLY_SHOW_BONCEB',
|
||||
$key
|
||||
), 'Warning'
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
// set the notice
|
||||
$this->app->enqueueMessage(
|
||||
Text::_('COM_COMPONENTBUILDER_HR_HTHREEEXTERNAL_CODE_ERRORHTHREE'),
|
||||
'Error'
|
||||
);
|
||||
$this->app->enqueueMessage(
|
||||
Text::sprintf('COM_COMPONENTBUILDER_S_WE_DETECTED_BNEW_EXTERNALCODEB_BUT_YOU_DO_NOT_HAVE_PERMISSION_TO_ALLOW_THIS_NEW_CODESTRING_SO_BSB_WAS_REMOVED_FROM_THE_COMPILATION_PLEASE_CONTACT_YOU_SYSTEM_ADMINISTRATOR_FOR_MORE_INFOBR_SMALLADMIN_ACCESS_REQUIREDSMALL',
|
||||
$this->user->get('name'), $key
|
||||
), 'Error'
|
||||
);
|
||||
// remove the code/string
|
||||
$this->code[$target_key] = '';
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// set notice that we could not get a valid string from the target
|
||||
$this->app->enqueueMessage(
|
||||
Text::_('COM_COMPONENTBUILDER_HR_HTHREEEXTERNAL_CODE_WARNINGHTHREE'), 'Error'
|
||||
);
|
||||
$this->app->enqueueMessage(
|
||||
Text::sprintf('COM_COMPONENTBUILDER_THE_BSB_RETURNED_AN_INVALID_STRING', $key
|
||||
), 'Error'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// add to local bucket
|
||||
$bucket[$key] = $this->code[$target_key] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Cut the External Code/String
|
||||
*
|
||||
* @param string $string The content to cut
|
||||
* @param string $sequence The cutting sequence
|
||||
* @param string $key The content key
|
||||
*
|
||||
* @return string
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected function cut(string $string, string $sequence, string $key): string
|
||||
{
|
||||
// we first break the string up in rows
|
||||
$rows = (array) explode(PHP_EOL, $string);
|
||||
// get the cutting sequence
|
||||
$cutter = (array) explode('|', $sequence);
|
||||
// we only continue if we have more rows than we have to cut
|
||||
if (array_sum($cutter) < ArrayHelper::check($rows))
|
||||
{
|
||||
// remove the rows at the bottom if needed
|
||||
if (isset($cutter[1]) && $cutter[1] > 0)
|
||||
{
|
||||
array_splice($rows, "-$cutter[1]");
|
||||
}
|
||||
// remove the rows at the top if needed
|
||||
if ($cutter[0] > 0)
|
||||
{
|
||||
$rows = array_splice($rows, $cutter[0]);
|
||||
}
|
||||
|
||||
// return the remaining rows
|
||||
return implode(PHP_EOL, $rows);
|
||||
}
|
||||
|
||||
// we set an error message about too few lines to cut
|
||||
$this->app->enqueueMessage(
|
||||
Text::_('COM_COMPONENTBUILDER_HR_HTHREEEXTERNAL_CODE_NOTICEHTHREE'),
|
||||
'Error'
|
||||
);
|
||||
$this->app->enqueueMessage(
|
||||
Text::sprintf('COM_COMPONENTBUILDER_THE_BSB_CUT_SEQUENCE_FAILED_ON_THE_RETURNED_EXTERNAL_CODESTRING_AS_MORE_LINES_HAS_TO_BE_CUT_THEN_WAS_FOUND_IN_THE_CODESTRING_WE_HAVE_COMPLETELY_REMOVED_THE_CODE_PLEASE_CHECK_THIS_CODESTRING',
|
||||
$key
|
||||
), 'Error'
|
||||
);
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -0,0 +1,940 @@
|
||||
<?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\Customcode;
|
||||
|
||||
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\User\User;
|
||||
use Joomla\CMS\Filesystem\Folder;
|
||||
use Joomla\CMS\Application\CMSApplication;
|
||||
use Joomla\CMS\Language\Text;
|
||||
use Joomla\CMS\Version;
|
||||
use VDM\Joomla\Utilities\ArrayHelper;
|
||||
use VDM\Joomla\Utilities\StringHelper;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Factory as Compiler;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Config;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Customcode\Gui;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Customcode\Extractor\Paths;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Placeholder\Reverse;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Component\Placeholder;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Utilities\Pathfix;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Utilities\Placefix;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Interfaces\Customcode\ExtractorInterface;
|
||||
|
||||
|
||||
/**
|
||||
* Compiler Custom Code Extractor
|
||||
*
|
||||
* The custom script placeholders - we use the (xxx) to avoid detection it should be (***)
|
||||
* ##################################---> PHP/JS ---####################################
|
||||
*
|
||||
* New Insert Code = /xxx[INSERT>$$$$]xxx/ /xxx[/INSERT>$$$$]xxx/
|
||||
* New Replace Code = /xxx[REPLACE>$$$$]xxx/ /xxx[/REPLACE>$$$$]xxx/
|
||||
*
|
||||
* //////////////////////////////// when JCB adds it back //////////////////////////////////
|
||||
* JCB Add Inserted Code = /xxx[INSERTED$$$$]xxx//xx23xx/ /xxx[/INSERTED$$$$]xxx/
|
||||
* JCB Add Replaced Code = /xxx[REPLACED$$$$]xxx//xx25xx/ /xxx[/REPLACED$$$$]xxx/
|
||||
*
|
||||
* /////////////////////////////// changeing existing custom code /////////////////////////
|
||||
* Update Inserted Code = /xxx[INSERTED>$$$$]xxx//xx23xx/ /xxx[/INSERTED>$$$$]xxx/
|
||||
* Update Replaced Code = /xxx[REPLACED>$$$$]xxx//xx25xx/ /xxx[/REPLACED>$$$$]xxx/
|
||||
*
|
||||
* The custom script placeholders - we use the (==) to avoid detection it should be (--)
|
||||
* ###################################---> HTML ---#####################################
|
||||
*
|
||||
* New Insert Code = !==[INSERT>$$$$]==> !==[/INSERT>$$$$]==>
|
||||
* New Replace Code = !==[REPLACE>$$$$]==> !==[/REPLACE>$$$$]==>
|
||||
*
|
||||
* ///////////////////////////////// when JCB adds it back ///////////////////////////////
|
||||
* JCB Add Inserted Code =
|
||||
* JCB Add Replaced Code =
|
||||
*
|
||||
* //////////////////////////// changeing existing custom code ///////////////////////////
|
||||
* Update Inserted Code = !==[INSERTED>$$$$]==> !==[/INSERTED>$$$$]==>
|
||||
* Update Replaced Code = !==[REPLACED>$$$$]==> !==[/REPLACED>$$$$]==>
|
||||
*
|
||||
* ////////23 is the ID of the code in the system don't change it!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
*
|
||||
* More info read: https://git.vdm.dev/joomla/Component-Builder/wiki/TIPS:-Custom-Code
|
||||
*
|
||||
* @since 3.2.0
|
||||
*/
|
||||
class Extractor implements ExtractorInterface
|
||||
{
|
||||
/**
|
||||
* The placeholder keys
|
||||
*
|
||||
* @var array
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected array $PKeys
|
||||
= [
|
||||
1 => 'REPLACE<>$$$$]',
|
||||
2 => 'INSERT<>$$$$]',
|
||||
3 => 'REPLACED<>$$$$]',
|
||||
4 => 'INSERTED<>$$$$]'
|
||||
];
|
||||
|
||||
/**
|
||||
* Current Joomla Version We are IN
|
||||
*
|
||||
* @var int
|
||||
* @since 3.2.0
|
||||
**/
|
||||
protected int $currentVersion;
|
||||
|
||||
/**
|
||||
* The custom code in local files that already exist in system
|
||||
*
|
||||
* @var array
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected array $existing = [];
|
||||
|
||||
/**
|
||||
* The custom code in local files that are new
|
||||
*
|
||||
* @var array
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected array $new = [];
|
||||
|
||||
/**
|
||||
* The index of code already loaded
|
||||
*
|
||||
* @var array
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected array $done = [];
|
||||
|
||||
/**
|
||||
* The search counter
|
||||
*
|
||||
* @var array
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected array $counter = [1 => 0, 2 => 0];
|
||||
|
||||
/**
|
||||
* The file types to search
|
||||
*
|
||||
* @var array
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected array $fileTypes = ['\.php', '\.js', '\.xml'];
|
||||
|
||||
/**
|
||||
* The local placeholders
|
||||
*
|
||||
* @var array
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected array $placeholders;
|
||||
|
||||
/**
|
||||
* Today's date in SQL format
|
||||
*
|
||||
* @var string
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected string $today;
|
||||
|
||||
/**
|
||||
* Compiler Config
|
||||
*
|
||||
* @var Config
|
||||
* @since 3.2.0
|
||||
**/
|
||||
protected Config $config;
|
||||
|
||||
/**
|
||||
* Compiler Customcode Gui
|
||||
*
|
||||
* @var Gui
|
||||
* @since 3.2.0
|
||||
**/
|
||||
protected Gui $gui;
|
||||
|
||||
/**
|
||||
* Compiler Customcode Extractor Paths
|
||||
*
|
||||
* @var Paths
|
||||
* @since 3.2.0
|
||||
**/
|
||||
protected Paths $paths;
|
||||
|
||||
/**
|
||||
* Compiler Placeholder Reverse
|
||||
*
|
||||
* @var Reverse
|
||||
* @since 3.2.0
|
||||
**/
|
||||
protected Reverse $reverse;
|
||||
|
||||
/**
|
||||
* Compiler Component Placeholder
|
||||
*
|
||||
* @var Placeholder
|
||||
* @since 3.2.0
|
||||
**/
|
||||
protected Placeholder $componentPlaceholder;
|
||||
|
||||
/**
|
||||
* Compiler Component Pathfix
|
||||
*
|
||||
* @var Pathfix
|
||||
* @since 3.2.0
|
||||
**/
|
||||
protected Pathfix $pathfix;
|
||||
|
||||
/**
|
||||
* Current User Object
|
||||
*
|
||||
* @since 3.2.0
|
||||
**/
|
||||
protected $user;
|
||||
|
||||
/**
|
||||
* Database object to query local DB
|
||||
*
|
||||
* @since 3.2.0
|
||||
**/
|
||||
protected $db;
|
||||
|
||||
/**
|
||||
* Database object to query local DB
|
||||
*
|
||||
* @since 3.2.0
|
||||
**/
|
||||
protected $app;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param Config|null $config The compiler config object.
|
||||
* @param Gui|null $gui The compiler customcode gui object.
|
||||
* @param Paths|null $paths The compiler customcode extractor paths object.
|
||||
* @param Reverse|null $reverse The compiler placeholder reverse object.
|
||||
* @param Placeholder|null $placeholder The compiler component placeholder object.
|
||||
* @param Pathfix|null $pathfix The compiler path fixing object.
|
||||
*
|
||||
* @throws \Exception
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function __construct(?Config $config = null, ?Gui $gui = null, ?Paths $paths = null,
|
||||
?Reverse $reverse = null, ?Placeholder $placeholder = null, ?Pathfix $pathfix = null)
|
||||
{
|
||||
$this->config = $config ?: Compiler::_('Config');
|
||||
$this->gui = $gui ?: Compiler::_('Customcode.Gui');
|
||||
$this->paths = $paths ?: Compiler::_('Customcode.Extractor.Paths');
|
||||
$this->reverse = $reverse ?: Compiler::_('Placeholder.Reverse');
|
||||
$this->componentPlaceholder = $placeholder ?: Compiler::_('Component.Placeholder');
|
||||
$this->pathfix = $pathfix ?: Compiler::_('Utilities.Pathfix');
|
||||
$this->user = Factory::getUser();
|
||||
$this->db = Factory::getDbo();
|
||||
$this->app = Factory::getApplication();
|
||||
|
||||
// set today's date
|
||||
$this->today = Factory::getDate()->toSql();
|
||||
|
||||
// set some local placeholders
|
||||
$placeholders = array_flip(
|
||||
$this->componentPlaceholder->get()
|
||||
);
|
||||
|
||||
$placeholders[StringHelper::safe(
|
||||
$this->config->component_code_name, 'F'
|
||||
) . 'Helper::'] = Placefix::_('Component') . 'Helper::';
|
||||
|
||||
$placeholders['COM_' . StringHelper::safe(
|
||||
$this->config->component_code_name, 'U'
|
||||
)] = 'COM_' . Placefix::_('COMPONENT');
|
||||
|
||||
$placeholders['com_' . $this->config->component_code_name] = 'com_' . Placefix::_('component');
|
||||
|
||||
// set the local placeholders
|
||||
$this->placeholders = array_reverse($placeholders, true);
|
||||
|
||||
// set the current version
|
||||
$this->currentVersion = (int) Version::MAJOR_VERSION;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the custom code from the local files
|
||||
*
|
||||
* @return void
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
// we must first store the current working directory
|
||||
$joomla = getcwd();
|
||||
|
||||
foreach ($this->paths->active as $target => $path)
|
||||
{
|
||||
// we are changing the working directory to the component path
|
||||
chdir($path);
|
||||
foreach ($this->fileTypes as $type)
|
||||
{
|
||||
// get a list of files in the current directory tree (only PHP, JS and XML for now)
|
||||
$files = Folder::files('.', $type, true, true);
|
||||
|
||||
// check if files found
|
||||
if (ArrayHelper::check($files))
|
||||
{
|
||||
foreach ($files as $file)
|
||||
{
|
||||
// search the file
|
||||
$this->searchFileContent($file, $target);
|
||||
|
||||
// insert new code
|
||||
$this->insert(100);
|
||||
|
||||
// update existing custom code
|
||||
$this->update(30);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// change back to Joomla working directory
|
||||
chdir($joomla);
|
||||
|
||||
// make sure all code is stored
|
||||
$this->insert();
|
||||
// update existing custom code
|
||||
$this->update();
|
||||
}
|
||||
|
||||
/**
|
||||
* search a file for placeholders and store result
|
||||
*
|
||||
* @param string $file The file path to search
|
||||
*
|
||||
* @return array on success
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected function searchFileContent(&$file, &$target)
|
||||
{
|
||||
// we add a new search for the GUI CODE Blocks
|
||||
$this->gui->search($file, $this->placeholders, $this->today, $target);
|
||||
|
||||
// reset each time per file
|
||||
$loadEndFingerPrint = false;
|
||||
$endFingerPrint = [];
|
||||
$fingerPrint = [];
|
||||
$codeBucket = [];
|
||||
$pointer = [];
|
||||
$reading = [];
|
||||
$reader = 0;
|
||||
|
||||
// reset found Start type
|
||||
$commentType = 0;
|
||||
|
||||
// make sure we have the path correct (the script file is not in admin path for example)
|
||||
// there may be more... will nead to keep our eye on this... since files could be moved during install
|
||||
$file = str_replace('./', '', (string) $file); # TODO (windows path issues)
|
||||
$path = $file !== 'script.php' ? $target . '/' . $file : $file;
|
||||
|
||||
// now we go line by line
|
||||
foreach (new \SplFileObject($file) as $lineNumber => $lineContent)
|
||||
{
|
||||
// we must keep last few lines to dynamic find target entry later
|
||||
$fingerPrint[$lineNumber] = trim($lineContent);
|
||||
|
||||
// load the end fingerprint
|
||||
if ($loadEndFingerPrint)
|
||||
{
|
||||
$endFingerPrint[$lineNumber] = trim($lineContent);
|
||||
}
|
||||
|
||||
foreach ($this->PKeys as $type => $search)
|
||||
{
|
||||
$i = (int) ($type == 3 || $type == 4) ? 2 : 1;
|
||||
$_type = (int) ($type == 1 || $type == 3) ? 1 : 2;
|
||||
|
||||
if ($reader === 0 || $reader === $i)
|
||||
{
|
||||
$targetKey = $type;
|
||||
|
||||
$start = '/***[' . $search . '***/';
|
||||
$end = '/***[/' . $search . '***/';
|
||||
$startHTML = '<!--[' . $search . '-->';
|
||||
$endHTML = '<!--[/' . $search . '-->';
|
||||
|
||||
// check if the ending placeholder was found
|
||||
if (isset($reading[$targetKey]) && $reading[$targetKey]
|
||||
&& ((trim((string) $lineContent) === $end
|
||||
|| strpos((string) $lineContent, $end) !== false)
|
||||
|| (trim((string) $lineContent) === $endHTML
|
||||
|| strpos((string) $lineContent, $endHTML) !== false)))
|
||||
{
|
||||
// trim the placeholder and if there is still data then load it
|
||||
if (isset($endReplace)
|
||||
&& ($_line = $this->addLineChecker($endReplace, 2, $lineContent)) !== false)
|
||||
{
|
||||
$codeBucket[$pointer[$targetKey]][] = $_line;
|
||||
}
|
||||
|
||||
// deactivate the reader
|
||||
$reading[$targetKey] = false;
|
||||
|
||||
if ($_type == 2)
|
||||
{
|
||||
// deactivate search
|
||||
$reader = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// activate fingerPrint for replacement end target
|
||||
$loadEndFingerPrint = true;
|
||||
$backupTargetKey = $targetKey;
|
||||
$backupI = $i;
|
||||
}
|
||||
|
||||
// all new records we can do a bulk insert
|
||||
if ($i === 1)
|
||||
{
|
||||
// end the bucket info for this code block
|
||||
$this->new[$pointer[$targetKey]][]
|
||||
= $this->db->quote(
|
||||
(int) $lineNumber
|
||||
); // 'toline'
|
||||
|
||||
// first reverse engineer this code block
|
||||
$c0de = $this->reverse->engine(
|
||||
implode('', $codeBucket[$pointer[$targetKey]]),
|
||||
$this->placeholders, $target
|
||||
);
|
||||
|
||||
$this->new[$pointer[$targetKey]][]
|
||||
= $this->db->quote(
|
||||
base64_encode((string) $c0de)
|
||||
); // 'code'
|
||||
|
||||
if ($_type == 2)
|
||||
{
|
||||
// load the last value
|
||||
$this->new[$pointer[$targetKey]][]
|
||||
= $this->db->quote(0); // 'hashendtarget'
|
||||
}
|
||||
}
|
||||
// the record already exist so we must update instead
|
||||
elseif ($i === 2)
|
||||
{
|
||||
// end the bucket info for this code block
|
||||
$this->existing[$pointer[$targetKey]]['fields'][]
|
||||
= $this->db->quoteName('to_line') . ' = '
|
||||
. $this->db->quote($lineNumber);
|
||||
|
||||
// first reverse engineer this code block
|
||||
$c0de = $this->reverse->engine(
|
||||
implode('', $codeBucket[$pointer[$targetKey]]),
|
||||
$this->placeholders, $target,
|
||||
$this->existing[$pointer[$targetKey]]['id']
|
||||
);
|
||||
|
||||
$this->existing[$pointer[$targetKey]]['fields'][]
|
||||
= $this->db->quoteName('code') . ' = '
|
||||
. $this->db->quote(base64_encode((string) $c0de));
|
||||
|
||||
if ($_type == 2)
|
||||
{
|
||||
// load the last value
|
||||
$this->existing[$pointer[$targetKey]]['fields'][]
|
||||
= $this->db->quoteName('hashendtarget')
|
||||
. ' = ' . $this->db->quote(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check if the endfingerprint is ready to save
|
||||
if (count((array) $endFingerPrint) === 3)
|
||||
{
|
||||
$hashendtarget = '3__' . md5(
|
||||
implode('', $endFingerPrint)
|
||||
);
|
||||
|
||||
// all new records we can do a bulk insert
|
||||
if ($i === 1)
|
||||
{
|
||||
// load the last value
|
||||
$this->new[$pointer[$targetKey]][]
|
||||
= $this->db->quote(
|
||||
$hashendtarget
|
||||
); // 'hashendtarget'
|
||||
}
|
||||
// the record already exist so we must update
|
||||
elseif ($i === 2)
|
||||
{
|
||||
$this->existing[$pointer[$targetKey]]['fields'][]
|
||||
= $this->db->quoteName('hashendtarget') . ' = '
|
||||
. $this->db->quote($hashendtarget);
|
||||
}
|
||||
|
||||
// reset the needed values
|
||||
$endFingerPrint = [];
|
||||
$loadEndFingerPrint = false;
|
||||
|
||||
// deactivate reader (to allow other search)
|
||||
$reader = 0;
|
||||
}
|
||||
|
||||
// then read in the code
|
||||
if (isset($reading[$targetKey]) && $reading[$targetKey])
|
||||
{
|
||||
$codeBucket[$pointer[$targetKey]][] = $lineContent;
|
||||
}
|
||||
|
||||
// see if the custom code line starts now with PHP/JS comment type
|
||||
if ((!isset($reading[$targetKey]) || !$reading[$targetKey])
|
||||
&& (($i === 1 && trim((string) $lineContent) === $start)
|
||||
|| strpos((string) $lineContent, $start) !== false))
|
||||
{
|
||||
$commentType = 1; // PHP/JS type
|
||||
$startReplace = $start;
|
||||
$endReplace = $end;
|
||||
}
|
||||
// see if the custom code line starts now with HTML comment type
|
||||
elseif ((!isset($reading[$targetKey])
|
||||
|| !$reading[$targetKey])
|
||||
&& (($i === 1 && trim((string) $lineContent) === $startHTML)
|
||||
|| strpos((string) $lineContent, $startHTML) !== false))
|
||||
{
|
||||
$commentType = 2; // HTML type
|
||||
$startReplace = $startHTML;
|
||||
$endReplace = $endHTML;
|
||||
}
|
||||
|
||||
// check if the starting place holder was found
|
||||
if ($commentType > 0)
|
||||
{
|
||||
// if we have all on one line we have a problem (don't load it TODO)
|
||||
if (strpos((string) $lineContent, (string) $endReplace) !== false)
|
||||
{
|
||||
// reset found comment type
|
||||
$commentType = 0;
|
||||
$this->app->enqueueMessage(
|
||||
Text::_('COM_COMPONENTBUILDER_HR_HTHREECUSTOM_CODES_WARNINGHTHREE'),
|
||||
'Warning'
|
||||
);
|
||||
$this->app->enqueueMessage(
|
||||
Text::sprintf('COM_COMPONENTBUILDER_WE_FOUND_DYNAMIC_CODE_BALL_IN_ONE_LINEB_AND_IGNORED_IT_PLEASE_REVIEW_S_FOR_MORE_DETAILS',
|
||||
$path
|
||||
), 'Warning'
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
// do a quick check to insure we have an id
|
||||
$id = false;
|
||||
if ($i === 2)
|
||||
{
|
||||
$id = $this->getSystemID(
|
||||
$lineContent,
|
||||
array(1 => $start, 2 => $startHTML),
|
||||
$commentType
|
||||
);
|
||||
}
|
||||
|
||||
if ($i === 2 && $id > 0)
|
||||
{
|
||||
// make sure we update it only once even if found again.
|
||||
if (isset($this->done[$id]))
|
||||
{
|
||||
// reset found comment type
|
||||
$commentType = 0;
|
||||
continue;
|
||||
}
|
||||
// store the id to avoid duplication
|
||||
$this->done[$id] = (int) $id;
|
||||
}
|
||||
|
||||
// start replace
|
||||
$startReplace = $this->setStartReplace(
|
||||
$id, $commentType, $startReplace
|
||||
);
|
||||
|
||||
// set active reader (to lock out other search)
|
||||
$reader = $i;
|
||||
|
||||
// set pointer
|
||||
$pointer[$targetKey] = $this->counter[$i];
|
||||
|
||||
// activate the reader
|
||||
$reading[$targetKey] = true;
|
||||
|
||||
// start code bucket
|
||||
$codeBucket[$pointer[$targetKey]] = [];
|
||||
|
||||
// trim the placeholder and if there is still data then load it
|
||||
if ($_line = $this->addLineChecker(
|
||||
$startReplace, 1, $lineContent
|
||||
))
|
||||
{
|
||||
$codeBucket[$pointer[$targetKey]][] = $_line;
|
||||
}
|
||||
|
||||
// get the finger print around the custom code
|
||||
$inFinger = count($fingerPrint);
|
||||
$getFinger = $inFinger - 1;
|
||||
$hasharray = array_slice(
|
||||
$fingerPrint, -$inFinger, $getFinger, true
|
||||
);
|
||||
$hasleng = count($hasharray);
|
||||
$hashtarget = $hasleng . '__' . md5(
|
||||
implode('', $hasharray)
|
||||
);
|
||||
|
||||
// for good practice
|
||||
$this->pathfix->set($path);
|
||||
|
||||
// all new records we can do a bulk insert
|
||||
if ($i === 1 || !$id)
|
||||
{
|
||||
// start the bucket for this code
|
||||
$this->new[$pointer[$targetKey]] = [];
|
||||
$this->new[$pointer[$targetKey]][]
|
||||
= $this->db->quote(
|
||||
$path
|
||||
); // 'path'
|
||||
|
||||
$this->new[$pointer[$targetKey]][]
|
||||
= $this->db->quote(
|
||||
(int) $_type
|
||||
); // 'type'
|
||||
|
||||
$this->new[$pointer[$targetKey]][]
|
||||
= $this->db->quote(
|
||||
1
|
||||
); // 'target'
|
||||
|
||||
$this->new[$pointer[$targetKey]][]
|
||||
= $this->db->quote(
|
||||
$this->currentVersion
|
||||
); // 'joomla_version'
|
||||
|
||||
$this->new[$pointer[$targetKey]][]
|
||||
= $this->db->quote(
|
||||
$commentType
|
||||
); // 'comment_type'
|
||||
|
||||
$this->new[$pointer[$targetKey]][]
|
||||
= $this->db->quote(
|
||||
(int) $this->config->component_id
|
||||
); // 'component'
|
||||
|
||||
$this->new[$pointer[$targetKey]][]
|
||||
= $this->db->quote(
|
||||
1
|
||||
); // 'published'
|
||||
|
||||
$this->new[$pointer[$targetKey]][]
|
||||
= $this->db->quote(
|
||||
$this->today
|
||||
); // 'created'
|
||||
|
||||
$this->new[$pointer[$targetKey]][]
|
||||
= $this->db->quote(
|
||||
(int) $this->user->id
|
||||
); // 'created_by'
|
||||
|
||||
$this->new[$pointer[$targetKey]][]
|
||||
= $this->db->quote(
|
||||
1
|
||||
); // 'version'
|
||||
|
||||
$this->new[$pointer[$targetKey]][]
|
||||
= $this->db->quote(
|
||||
1
|
||||
); // 'access'
|
||||
|
||||
$this->new[$pointer[$targetKey]][]
|
||||
= $this->db->quote(
|
||||
$hashtarget
|
||||
); // 'hashtarget'
|
||||
|
||||
$this->new[$pointer[$targetKey]][]
|
||||
= $this->db->quote(
|
||||
(int) $lineNumber
|
||||
); // 'fromline'
|
||||
|
||||
}
|
||||
// the record already exist so we must update instead
|
||||
elseif ($i === 2 && $id > 0)
|
||||
{
|
||||
// start the bucket for this code
|
||||
$this->existing[$pointer[$targetKey]] = [];
|
||||
$this->existing[$pointer[$targetKey]]['id']
|
||||
= (int) $id;
|
||||
$this->existing[$pointer[$targetKey]]['conditions'] = [];
|
||||
$this->existing[$pointer[$targetKey]]['conditions'][]
|
||||
= $this->db->quoteName('id') . ' = '
|
||||
. $this->db->quote($id);
|
||||
$this->existing[$pointer[$targetKey]]['fields'] = [];
|
||||
$this->existing[$pointer[$targetKey]]['fields'][]
|
||||
= $this->db->quoteName('path') . ' = '
|
||||
. $this->db->quote($path);
|
||||
$this->existing[$pointer[$targetKey]]['fields'][]
|
||||
= $this->db->quoteName('type') . ' = '
|
||||
. $this->db->quote($_type);
|
||||
$this->existing[$pointer[$targetKey]]['fields'][]
|
||||
= $this->db->quoteName('comment_type') . ' = '
|
||||
. $this->db->quote($commentType);
|
||||
$this->existing[$pointer[$targetKey]]['fields'][]
|
||||
= $this->db->quoteName('component') . ' = '
|
||||
. $this->db->quote($this->config->component_id);
|
||||
$this->existing[$pointer[$targetKey]]['fields'][]
|
||||
= $this->db->quoteName('from_line') . ' = '
|
||||
. $this->db->quote($lineNumber);
|
||||
$this->existing[$pointer[$targetKey]]['fields'][]
|
||||
= $this->db->quoteName('modified') . ' = '
|
||||
. $this->db->quote($this->today);
|
||||
$this->existing[$pointer[$targetKey]]['fields'][]
|
||||
= $this->db->quoteName('modified_by') . ' = '
|
||||
. $this->db->quote($this->user->id);
|
||||
$this->existing[$pointer[$targetKey]]['fields'][]
|
||||
= $this->db->quoteName('hashtarget') . ' = '
|
||||
. $this->db->quote($hashtarget);
|
||||
}
|
||||
else // this should actualy never happen
|
||||
{
|
||||
// de activate the reader
|
||||
$reading[$targetKey] = false;
|
||||
$reader = 0;
|
||||
}
|
||||
|
||||
// reset found comment type
|
||||
$commentType = 0;
|
||||
// update the counter
|
||||
$this->counter[$i]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// make sure only a few lines is kept at a time
|
||||
if (count((array) $fingerPrint) > 10)
|
||||
{
|
||||
$fingerPrint = array_slice($fingerPrint, -6, 6, true);
|
||||
}
|
||||
}
|
||||
|
||||
// if the code is at the end of the page and there were not three more lines
|
||||
if (count((array) $endFingerPrint) > 0 || $loadEndFingerPrint)
|
||||
{
|
||||
if (count((array) $endFingerPrint) > 0)
|
||||
{
|
||||
$leng = count($endFingerPrint);
|
||||
$hashendtarget = $leng . '__' . md5(
|
||||
implode('', $endFingerPrint)
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
$hashendtarget = 0;
|
||||
}
|
||||
|
||||
// all new records we can do a buldk insert
|
||||
if ($backupI === 1)
|
||||
{
|
||||
// load the last value
|
||||
$this->new[$pointer[$backupTargetKey]][]
|
||||
= $this->db->quote($hashendtarget); // 'hashendtarget'
|
||||
}
|
||||
// the record already exist so we must use module to update
|
||||
elseif ($backupI === 2)
|
||||
{
|
||||
$this->existing[$pointer[$backupTargetKey]]['fields'][]
|
||||
= $this->db->quoteName('hashendtarget') . ' = '
|
||||
. $this->db->quote($hashendtarget);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert the code
|
||||
*
|
||||
* @param int $when To set when to update
|
||||
*
|
||||
* @return void
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected function insert(int $when = 1)
|
||||
{
|
||||
if (ArrayHelper::check($this->new) >= $when)
|
||||
{
|
||||
// Create a new query object.
|
||||
$query = $this->db->getQuery(true);
|
||||
$continue = false;
|
||||
// Insert columns.
|
||||
$columns = array('path', 'type', 'target', 'joomla_version', 'comment_type',
|
||||
'component', 'published', 'created', 'created_by',
|
||||
'version', 'access', 'hashtarget', 'from_line',
|
||||
'to_line', 'code', 'hashendtarget');
|
||||
// Prepare the insert query.
|
||||
$query->insert(
|
||||
$this->db->quoteName('#__componentbuilder_custom_code')
|
||||
);
|
||||
$query->columns($this->db->quoteName($columns));
|
||||
foreach ($this->new as $values)
|
||||
{
|
||||
if (count((array) $values) == 15)
|
||||
{
|
||||
$query->values(implode(',', $values));
|
||||
$continue = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO line mismatch... should not happen
|
||||
}
|
||||
}
|
||||
// clear the values array
|
||||
$this->new = [];
|
||||
if (!$continue)
|
||||
{
|
||||
return; // insure we don't continue if no values were loaded
|
||||
}
|
||||
// Set the query using our newly populated query object and execute it.
|
||||
$this->db->setQuery($query);
|
||||
$this->db->execute();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the code
|
||||
*
|
||||
* @param int $when To set when to update
|
||||
*
|
||||
* @return void
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected function update(int $when = 1)
|
||||
{
|
||||
if (ArrayHelper::check($this->existing) >= $when)
|
||||
{
|
||||
foreach ($this->existing as $code)
|
||||
{
|
||||
// Create a new query object.
|
||||
$query = $this->db->getQuery(true);
|
||||
// Prepare the update query.
|
||||
$query->update(
|
||||
$this->db->quoteName('#__componentbuilder_custom_code')
|
||||
)->set($code['fields'])->where($code['conditions']);
|
||||
// Set the query using our newly populated query object and execute it.
|
||||
$this->db->setQuery($query);
|
||||
$this->db->execute();
|
||||
}
|
||||
// clear the values array
|
||||
$this->existing = [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* set the start replace placeholder
|
||||
*
|
||||
* @param int $id The comment id
|
||||
* @param int $commentType The comment type
|
||||
* @param string $startReplace The main replace string
|
||||
*
|
||||
* @return string on success
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected function setStartReplace(int $id, int $commentType, string $startReplace): string
|
||||
{
|
||||
if ($id > 0)
|
||||
{
|
||||
switch ($commentType)
|
||||
{
|
||||
case 1: // the PHP & JS type
|
||||
$startReplace .= '/*' . $id . '*/';
|
||||
break;
|
||||
case 2: // the HTML type
|
||||
$startReplace .= '<!--' . $id . '-->';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $startReplace;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this line should be added
|
||||
*
|
||||
* @param string $replaceKey The key to remove from line
|
||||
* @param int $type The line type
|
||||
* @param string $lineContent The line to check
|
||||
*
|
||||
* @return bool|int true on success
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected function addLineChecker(string $replaceKey, int $type, string $lineContent)
|
||||
{
|
||||
$check = explode($replaceKey, $lineContent);
|
||||
switch ($type)
|
||||
{
|
||||
case 1:
|
||||
// beginning of code
|
||||
if (isset($check[1]) && StringHelper::check($check[1]))
|
||||
{
|
||||
return trim($check[1]);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
// end of code
|
||||
if (isset($check[0]) && StringHelper::check($check[0]))
|
||||
{
|
||||
return trim($check[0]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* search for the system id in the line given
|
||||
*
|
||||
* @param string $lineContent The file path to search
|
||||
* @param array $placeholders The values to search for
|
||||
* @param int $commentType The comment type
|
||||
*
|
||||
* @return mixed on success
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected function getSystemID(string &$lineContent, array $placeholders, int $commentType)
|
||||
{
|
||||
$trim = '/';
|
||||
if ($commentType == 2)
|
||||
{
|
||||
$trim = '<!--';
|
||||
}
|
||||
// remove place holder from content
|
||||
$string = trim(
|
||||
str_replace($placeholders[$commentType] . $trim, '', $lineContent)
|
||||
);
|
||||
// now get all numbers
|
||||
$numbers = [];
|
||||
preg_match_all('!\d+!', $string, $numbers);
|
||||
// return the first number
|
||||
if (isset($numbers[0])
|
||||
&& ArrayHelper::check(
|
||||
$numbers[0]
|
||||
))
|
||||
{
|
||||
return reset($numbers[0]);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -0,0 +1,418 @@
|
||||
<?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\Customcode\Extractor;
|
||||
|
||||
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\Filesystem\Folder;
|
||||
use VDM\Joomla\Utilities\ArrayHelper;
|
||||
use VDM\Joomla\Utilities\JsonHelper;
|
||||
use VDM\Joomla\Utilities\GetHelper;
|
||||
use VDM\Joomla\Utilities\String\ClassfunctionHelper;
|
||||
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\Component\Placeholder as ComponentPlaceholder;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Customcode;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Language\Extractor;
|
||||
|
||||
|
||||
/**
|
||||
* Compiler Custom Code Paths
|
||||
*
|
||||
* @since 3.2.0
|
||||
*/
|
||||
class Paths
|
||||
{
|
||||
/**
|
||||
* The local paths
|
||||
*
|
||||
* @var array
|
||||
* @since 3.2.0
|
||||
**/
|
||||
public array $active = [];
|
||||
|
||||
/**
|
||||
* Compiler Component Placeholder
|
||||
*
|
||||
* @var array
|
||||
* @since 3.2.0
|
||||
**/
|
||||
protected array $componentPlaceholder;
|
||||
|
||||
/**
|
||||
* Compiler Config
|
||||
*
|
||||
* @var Config
|
||||
* @since 3.2.0
|
||||
**/
|
||||
protected Config $config;
|
||||
|
||||
/**
|
||||
* Compiler Placeholder
|
||||
*
|
||||
* @var Placeholder
|
||||
* @since 3.2.0
|
||||
**/
|
||||
protected Placeholder $placeholder;
|
||||
|
||||
/**
|
||||
* Compiler Customcode
|
||||
*
|
||||
* @var Customcode
|
||||
* @since 3.2.0
|
||||
**/
|
||||
protected Customcode $customcode;
|
||||
|
||||
/**
|
||||
* Compiler Language Extractor
|
||||
*
|
||||
* @var Extractor
|
||||
* @since 3.2.0
|
||||
**/
|
||||
protected Extractor $extractor;
|
||||
|
||||
/**
|
||||
* Database object to query local DB
|
||||
*
|
||||
* @since 3.2.0
|
||||
**/
|
||||
protected $db;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param Config|null $config The compiler config object.
|
||||
* @param Placeholder|null $placeholder The compiler placeholder object.
|
||||
* @param ComponentPlaceholder|null $componentPlaceholder The compiler component placeholder object.
|
||||
* @param Customcode|null $customcode The compiler customcode object.
|
||||
* @param Extractor|null $extractor The compiler language extractor object.
|
||||
*
|
||||
* @throws \Exception
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function __construct(?Config $config = null, ?Placeholder $placeholder = null,
|
||||
?ComponentPlaceholder $componentPlaceholder = null, ?Customcode $customcode = null,
|
||||
?Extractor $extractor = null)
|
||||
{
|
||||
$this->config = $config ?: Compiler::_('Config');
|
||||
$this->placeholder = $placeholder ?: Compiler::_('Placeholder');
|
||||
/** @var ComponentPlaceholder $componentPlaceholder */
|
||||
$componentPlaceholder = $componentPlaceholder ?: Compiler::_('Component.Placeholder');
|
||||
$this->customcode = $customcode ?: Compiler::_('Customcode');
|
||||
$this->extractor = $extractor ?: Compiler::_('Language.Extractor');
|
||||
$this->db = Factory::getDbo();
|
||||
|
||||
// load the placeholders to local array
|
||||
$this->componentPlaceholder = $componentPlaceholder->get();
|
||||
|
||||
// load the paths on initialization
|
||||
$this->load();
|
||||
}
|
||||
|
||||
/**
|
||||
* get the local installed path of this component
|
||||
*
|
||||
* @return void
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected function load()
|
||||
{
|
||||
// set the local paths to search
|
||||
$local_paths = [];
|
||||
|
||||
// admin path
|
||||
$local_paths['admin'] = JPATH_ADMINISTRATOR . '/components/com_'
|
||||
. $this->config->component_code_name;
|
||||
|
||||
// site path
|
||||
$local_paths['site'] = JPATH_ROOT . '/components/com_'
|
||||
. $this->config->component_code_name;
|
||||
|
||||
// media path
|
||||
$local_paths['media'] = JPATH_ROOT . '/media/com_'
|
||||
. $this->config->component_code_name;
|
||||
|
||||
// power path
|
||||
$local_paths['power'] = JPATH_ROOT . '/' . $this->config->get('jcb_powers_path', 'libraries/jcb_powers');
|
||||
|
||||
// lets also go over the REPOS - TODO
|
||||
|
||||
// Painful but we need to folder paths for the linked modules
|
||||
if (($module_ids = $this->getModuleIDs()) !== false)
|
||||
{
|
||||
foreach ($module_ids as $module_id)
|
||||
{
|
||||
// get the module folder path
|
||||
if (($path = $this->getModulePath($module_id)) !== false)
|
||||
{
|
||||
// set the path
|
||||
$local_paths['module_' . str_replace('/', '_', (string) $path)] = $path;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Painful but we need to folder paths for the linked plugins
|
||||
if (($plugin_ids = $this->getPluginIDs()) !== false)
|
||||
{
|
||||
foreach ($plugin_ids as $plugin_id)
|
||||
{
|
||||
// get the plugin group and folder name
|
||||
if (($path = $this->getPluginPath($plugin_id)) !== false)
|
||||
{
|
||||
// set the path
|
||||
$local_paths['plugin_' . str_replace('/', '_', (string) $path)] = JPATH_ROOT . '/plugins/' . $path;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check if the local install is found
|
||||
foreach ($local_paths as $key => $localPath)
|
||||
{
|
||||
if (!Folder::exists($localPath))
|
||||
{
|
||||
unset($local_paths[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
if (ArrayHelper::check($local_paths))
|
||||
{
|
||||
$this->active = $local_paths;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* get the Joomla Modules IDs
|
||||
*
|
||||
* @return mixed of IDs on success
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected function getModuleIDs()
|
||||
{
|
||||
if (($addjoomla_modules = GetHelper::var(
|
||||
'component_modules', $this->config->component_id, 'joomla_component',
|
||||
'addjoomla_modules'
|
||||
)) !== false)
|
||||
{
|
||||
$addjoomla_modules = (JsonHelper::check(
|
||||
$addjoomla_modules
|
||||
)) ? json_decode((string) $addjoomla_modules, true) : null;
|
||||
|
||||
if (ArrayHelper::check($addjoomla_modules))
|
||||
{
|
||||
$joomla_modules = array_filter(
|
||||
array_values($addjoomla_modules),
|
||||
// only load the modules whose target association call for it
|
||||
fn($array): bool => !isset($array['target']) || $array['target'] != 2
|
||||
);
|
||||
// if we have values we return IDs
|
||||
if (ArrayHelper::check($joomla_modules))
|
||||
{
|
||||
return array_map(
|
||||
fn($array) => (int) $array['module'], $joomla_modules
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the Joomla module path
|
||||
*
|
||||
* @return mixed of module path and target site area on success
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected function getModulePath($id)
|
||||
{
|
||||
if (is_numeric($id) && $id > 0)
|
||||
{
|
||||
// Create a new query object.
|
||||
$query = $this->db->getQuery(true);
|
||||
|
||||
$query->select('a.*');
|
||||
$query->select(
|
||||
$this->db->quoteName(
|
||||
array(
|
||||
'a.name',
|
||||
'a.target'
|
||||
), array(
|
||||
'name',
|
||||
'target'
|
||||
)
|
||||
)
|
||||
);
|
||||
// from these tables
|
||||
$query->from('#__componentbuilder_joomla_module AS a');
|
||||
$query->where($this->db->quoteName('a.id') . ' = ' . (int) $id);
|
||||
$this->db->setQuery($query);
|
||||
$this->db->execute();
|
||||
if ($this->db->getNumRows())
|
||||
{
|
||||
// get the module data
|
||||
$module = $this->db->loadObject();
|
||||
// update the name if it has dynamic values
|
||||
$module->name = $this->placeholder->update(
|
||||
$this->customcode->update($module->name),
|
||||
$this->componentPlaceholder
|
||||
);
|
||||
|
||||
// set safe class function name
|
||||
$module->code_name
|
||||
= ClassfunctionHelper::safe(
|
||||
$module->name
|
||||
);
|
||||
// set module folder name
|
||||
$module->folder_name = 'mod_' . strtolower((string) $module->code_name);
|
||||
|
||||
// set the lang key
|
||||
$this->extractor->langKeys[strtoupper($module->folder_name)] =
|
||||
$module->id . '_M0dUl3';
|
||||
|
||||
// return the path
|
||||
if ($module->target == 2)
|
||||
{
|
||||
// administrator client area
|
||||
return JPATH_ADMINISTRATOR . '/modules/'
|
||||
. $module->folder_name;
|
||||
}
|
||||
else
|
||||
{
|
||||
// default is the site client area
|
||||
return JPATH_ROOT . '/modules/' . $module->folder_name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the Joomla plugins IDs
|
||||
*
|
||||
* @return mixed of IDs on success
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected function getPluginIDs()
|
||||
{
|
||||
if (($addjoomla_plugins = GetHelper::var(
|
||||
'component_plugins', $this->config->component_id, 'joomla_component',
|
||||
'addjoomla_plugins'
|
||||
)) !== false)
|
||||
{
|
||||
$addjoomla_plugins = (JsonHelper::check(
|
||||
$addjoomla_plugins
|
||||
)) ? json_decode((string) $addjoomla_plugins, true) : null;
|
||||
|
||||
if (ArrayHelper::check($addjoomla_plugins))
|
||||
{
|
||||
$joomla_plugins = array_filter(
|
||||
array_values($addjoomla_plugins),
|
||||
function ($array) {
|
||||
// only load the plugins whose target association call for it
|
||||
if (!isset($array['target']) || $array['target'] != 2)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
);
|
||||
// if we have values we return IDs
|
||||
if (ArrayHelper::check($joomla_plugins))
|
||||
{
|
||||
return array_map(
|
||||
fn($array) => (int) $array['plugin'], $joomla_plugins
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the Joomla plugin path
|
||||
*
|
||||
* @return mixed of plugin path on success
|
||||
* @deprecated 3.3
|
||||
*/
|
||||
protected function getPluginPath($id)
|
||||
{
|
||||
if (is_numeric($id) && $id > 0)
|
||||
{
|
||||
// Create a new query object.
|
||||
$query = $this->db->getQuery(true);
|
||||
|
||||
$query->select('a.*');
|
||||
$query->select(
|
||||
$this->db->quoteName(
|
||||
array(
|
||||
'a.name',
|
||||
'g.name'
|
||||
), array(
|
||||
'name',
|
||||
'group'
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
// from these tables
|
||||
$query->from('#__componentbuilder_joomla_plugin AS a');
|
||||
$query->join(
|
||||
'LEFT', $this->db->quoteName(
|
||||
'#__componentbuilder_joomla_plugin_group', 'g'
|
||||
) . ' ON (' . $this->db->quoteName('a.joomla_plugin_group')
|
||||
. ' = ' . $this->db->quoteName('g.id') . ')'
|
||||
);
|
||||
$query->where($this->db->quoteName('a.id') . ' = ' . (int) $id);
|
||||
$this->db->setQuery($query);
|
||||
$this->db->execute();
|
||||
|
||||
if ($this->db->getNumRows())
|
||||
{
|
||||
// get the plugin data
|
||||
$plugin = $this->db->loadObject();
|
||||
|
||||
// update the name if it has dynamic values
|
||||
$plugin->name = $this->placeholder->update(
|
||||
$this->customcode->update($plugin->name),
|
||||
$this->componentPlaceholder
|
||||
);
|
||||
|
||||
// update the name if it has dynamic values
|
||||
$plugin->code_name
|
||||
= ClassfunctionHelper::safe(
|
||||
$plugin->name
|
||||
);
|
||||
|
||||
// set plugin folder name
|
||||
$plugin->group = strtolower((string) $plugin->group);
|
||||
// set plugin file name
|
||||
$plugin->file_name = strtolower((string) $plugin->code_name);
|
||||
|
||||
// set the lang key
|
||||
$this->extractor->langKeys['PLG_' . strtoupper(
|
||||
$plugin->group . '_' . $plugin->file_name
|
||||
)] = $plugin->id . '_pLuG!n';
|
||||
|
||||
// return the path
|
||||
return $plugin->group . '/' . $plugin->file_name;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -0,0 +1 @@
|
||||
<html><body bgcolor="#FFFFFF"></body></html>
|
@@ -0,0 +1,261 @@
|
||||
<?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\Customcode;
|
||||
|
||||
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\Application\CMSApplication;
|
||||
use Joomla\CMS\Language\Text;
|
||||
use VDM\Joomla\Utilities\ArrayHelper;
|
||||
use VDM\Joomla\Utilities\StringHelper;
|
||||
use VDM\Joomla\Utilities\GetHelper;
|
||||
use VDM\Joomla\Utilities\FileHelper;
|
||||
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;
|
||||
|
||||
|
||||
/**
|
||||
* Compiler Gui Custom Code
|
||||
*
|
||||
* @since 3.2.0
|
||||
*/
|
||||
class Gui implements GuiInterface
|
||||
{
|
||||
/**
|
||||
* Compiler Config
|
||||
*
|
||||
* @var Config
|
||||
* @since 3.2.0
|
||||
**/
|
||||
protected Config $config;
|
||||
|
||||
/**
|
||||
* Compiler Placeholder Reverse
|
||||
*
|
||||
* @var Reverse
|
||||
* @since 3.2.0
|
||||
**/
|
||||
protected Reverse $reverse;
|
||||
|
||||
/**
|
||||
* Compiler Powers Parser
|
||||
*
|
||||
* @var Parser
|
||||
* @since 3.2.0
|
||||
**/
|
||||
protected Parser $parser;
|
||||
|
||||
/**
|
||||
* Database object to query local DB
|
||||
*
|
||||
* @since 3.2.0
|
||||
**/
|
||||
protected $db;
|
||||
|
||||
/**
|
||||
* Database object to query local DB
|
||||
*
|
||||
* @since 3.2.0
|
||||
**/
|
||||
protected $app;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* @throws \Exception
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function __construct(?Config $config = null, ?Reverse $reverse = null, ?Parser $parser = null)
|
||||
{
|
||||
$this->config = $config ?: Compiler::_('Config');
|
||||
$this->reverse = $reverse ?: Compiler::_('Placeholder.Reverse');
|
||||
$this->parser = $parser ?: Compiler::_('Power.Parser');
|
||||
$this->db = Factory::getDbo();
|
||||
$this->app = Factory::getApplication();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the JCB GUI code placeholder
|
||||
*
|
||||
* @param string $string The code string
|
||||
* @param array $config The placeholder config values
|
||||
*
|
||||
* @return string
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function set(string $string, array $config): string
|
||||
{
|
||||
if (StringHelper::check($string))
|
||||
{
|
||||
if ($this->config->get('add_placeholders', false)
|
||||
&& $this->check($string) && ArrayHelper::check($config)
|
||||
&& isset($config['table']) && StringHelper::check($config['table'])
|
||||
&& isset($config['field']) && StringHelper::check($config['field'])
|
||||
&& isset($config['type']) && StringHelper::check($config['type'])
|
||||
&& isset($config['id']) && is_numeric($config['id']))
|
||||
{
|
||||
// if we have a key we must get the ID
|
||||
if (isset($config['key']) && StringHelper::check($config['key']) && $config['key'] !== 'id')
|
||||
{
|
||||
if (($id = GetHelper::var($config['table'], $config['id'], $config['key'], 'id')) !== false && is_numeric($id))
|
||||
{
|
||||
$config['id'] = $id;
|
||||
}
|
||||
else
|
||||
{
|
||||
// we must give a error message to inform the user of this issue. (should never happen)
|
||||
$this->app->enqueueMessage(
|
||||
Text::sprintf('COM_COMPONENTBUILDER_ID_MISMATCH_WAS_DETECTED_WITH_THE_SSSS_GUI_CODE_FIELD_SO_THE_PLACEHOLDER_WAS_NOT_SET',
|
||||
$config['table'], $config['field'],
|
||||
$config['key'], $config['id']
|
||||
), 'Error'
|
||||
);
|
||||
// check some config
|
||||
if (!isset($config['prefix']))
|
||||
{
|
||||
$config['prefix'] = '';
|
||||
}
|
||||
|
||||
return $config['prefix'] . $string;
|
||||
}
|
||||
}
|
||||
// check some config
|
||||
if (!isset($config['prefix']))
|
||||
{
|
||||
$config['prefix'] = PHP_EOL;
|
||||
}
|
||||
// add placeholder based on type of code
|
||||
switch (strtolower((string) $config['type']))
|
||||
{
|
||||
// adding with html commenting
|
||||
case 'html':
|
||||
$front = $config['prefix'] . '<!--' . '[JCBGUI.';
|
||||
$sufix = '$$$$]-->' . PHP_EOL;
|
||||
$back = '<!--[/JCBGUI' . $sufix;
|
||||
break;
|
||||
// adding with php commenting
|
||||
default:
|
||||
$front = $config['prefix'] . '/***' . '[JCBGUI.';
|
||||
$sufix = '$$$$]***/' . PHP_EOL;
|
||||
$back = '/***[/JCBGUI' . $sufix;
|
||||
break;
|
||||
}
|
||||
|
||||
return $front . $config['table'] . '.' . $config['field'] . '.'
|
||||
. $config['id'] . '.' . $sufix . $string . $back;
|
||||
}
|
||||
// check some config
|
||||
if (!isset($config['prefix']))
|
||||
{
|
||||
$config['prefix'] = '';
|
||||
}
|
||||
|
||||
return $config['prefix'] . $string;
|
||||
}
|
||||
|
||||
return $string;
|
||||
}
|
||||
|
||||
/**
|
||||
* search a file for gui code blocks that were updated in the IDE
|
||||
*
|
||||
* @param string $file The file path to search
|
||||
* @param array $placeholders The values to replace in the code being stored
|
||||
* @param string $today The date for today
|
||||
* @param string $target The target path type
|
||||
*
|
||||
* @return void
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function search(string &$file, array &$placeholders, string &$today, string &$target)
|
||||
{
|
||||
// get file content
|
||||
$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_content, '/***[JCB' . 'GUI<>', '/***[/JCBGUI' . '$$$$]***/'
|
||||
);
|
||||
$guiCode[] = GetHelper::allBetween(
|
||||
$file_content, '<!--[JCB' . 'GUI<>', '<!--[/JCBGUI' . '$$$$]-->'
|
||||
);
|
||||
|
||||
if (($guiCode = ArrayHelper::merge($guiCode)) !== false
|
||||
&& ArrayHelper::check($guiCode, true))
|
||||
{
|
||||
foreach ($guiCode as $code)
|
||||
{
|
||||
$first_line = strtok($code, PHP_EOL);
|
||||
// get the GUI target details
|
||||
$query = explode('.', trim($first_line, '.'));
|
||||
// only continue if we have 3 values in the query
|
||||
if (is_array($query) && count($query) >= 3)
|
||||
{
|
||||
// cleanup the newlines around the code
|
||||
$code = trim(str_replace($first_line, '', (string) $code), PHP_EOL)
|
||||
. PHP_EOL;
|
||||
// set the ID
|
||||
$id = (int) $query[2];
|
||||
// make the field name save
|
||||
$field = FieldHelper::safe($query[1]);
|
||||
// make the table name save
|
||||
$table = StringHelper::safe($query[0]);
|
||||
// reverse placeholder as much as we can
|
||||
$code = $this->reverse->engine(
|
||||
$code, $placeholders, $target, $id, $field, $table, $use_statements
|
||||
);
|
||||
// update the GUI/Tables/Database
|
||||
$object = new \stdClass();
|
||||
$object->id = $id;
|
||||
$object->{$field} = base64_encode(
|
||||
(string) $code
|
||||
); // (TODO) this may not always work...
|
||||
// update the value in GUI
|
||||
$this->db->updateObject(
|
||||
'#__componentbuilder_' . (string) $table, $object, 'id'
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* search a code to see if there is already any custom
|
||||
* code or other reasons not to add the GUI code placeholders
|
||||
*
|
||||
* @param string $code The code to check
|
||||
*
|
||||
* @return bool true if GUI code placeholders can be added
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected function check(string &$code): bool
|
||||
{
|
||||
// check for customcode placeholders
|
||||
// we do not add GUI wrapper placeholder to code
|
||||
// that already has any customcode placeholders
|
||||
return strpos($code, '$$$$') === false;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -0,0 +1,111 @@
|
||||
<?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\Customcode;
|
||||
|
||||
|
||||
use VDM\Joomla\Utilities\GetHelper;
|
||||
use VDM\Joomla\Utilities\FileHelper;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Factory as Compiler;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Placeholder;
|
||||
|
||||
|
||||
/**
|
||||
* Compiler Custom Code MD5
|
||||
*
|
||||
* @since 3.2.0
|
||||
*/
|
||||
class Hash
|
||||
{
|
||||
/**
|
||||
* Compiler Placeholder
|
||||
*
|
||||
* @var Placeholder
|
||||
* @since 3.2.0
|
||||
**/
|
||||
protected Placeholder $placeholder;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param Placeholder|null $placeholder The compiler placeholder object.
|
||||
*
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function __construct(?Placeholder $placeholder = null)
|
||||
{
|
||||
$this->placeholder = $placeholder ?: Compiler::_('Placeholder');
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the MD5 hashed string or file or string
|
||||
*
|
||||
* @param string $script The code string
|
||||
*
|
||||
* @return string
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function set(string $script): string
|
||||
{
|
||||
// check if we should hash a string
|
||||
if (strpos($script, 'HASH' . 'STRING((((') !== false)
|
||||
{
|
||||
// get the strings
|
||||
$values = GetHelper::allBetween(
|
||||
$script, 'HASH' . 'STRING((((', '))))'
|
||||
);
|
||||
$locker = [];
|
||||
// convert them
|
||||
foreach ($values as $value)
|
||||
{
|
||||
$locker['HASH' . 'STRING((((' . $value . '))))']
|
||||
= md5((string) $value);
|
||||
}
|
||||
|
||||
// update the script
|
||||
return $this->placeholder->update($script, $locker);
|
||||
}
|
||||
|
||||
// check if we should hash a file
|
||||
if (strpos($script, 'HASH' . 'FILE((((') !== false)
|
||||
{
|
||||
// get the strings
|
||||
$values = GetHelper::allBetween(
|
||||
$script, 'HASH' . 'FILE((((', '))))'
|
||||
);
|
||||
$locker = [];
|
||||
// convert them
|
||||
foreach ($values as $path)
|
||||
{
|
||||
// we first get the file if it exists
|
||||
if (FileHelper::exists($path) && $value = FileHelper::getContent($path))
|
||||
{
|
||||
// now we hash the file content
|
||||
$locker['HASH' . 'FILE((((' . $path . '))))']
|
||||
= md5((string) $value);
|
||||
}
|
||||
else
|
||||
{
|
||||
// could not retrieve the file so we show error
|
||||
$locker['HASH' . 'FILE((((' . $path . '))))']
|
||||
= 'ERROR';
|
||||
}
|
||||
}
|
||||
|
||||
// update the script
|
||||
return $this->placeholder->update($script, $locker);
|
||||
}
|
||||
|
||||
return $script;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -0,0 +1,85 @@
|
||||
<?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\Customcode;
|
||||
|
||||
|
||||
use VDM\Joomla\Utilities\GetHelper;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Utilities\Indent;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Factory as Compiler;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Placeholder;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Interfaces\Customcode\LockBaseInterface;
|
||||
|
||||
|
||||
/**
|
||||
* Compiler Custom Code Base64
|
||||
*
|
||||
* @since 3.2.0
|
||||
*/
|
||||
class LockBase implements LockBaseInterface
|
||||
{
|
||||
/**
|
||||
* Compiler Placeholder
|
||||
*
|
||||
* @var Placeholder
|
||||
* @since 3.2.0
|
||||
**/
|
||||
protected Placeholder $placeholder;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param Placeholder|null $placeholder The compiler placeholder object.
|
||||
*
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function __construct(?Placeholder $placeholder = null)
|
||||
{
|
||||
$this->placeholder = $placeholder ?: Compiler::_('Placeholder');
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a string as bsae64 (basic)
|
||||
*
|
||||
* @param string $script The code string
|
||||
*
|
||||
* @return string
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function set(string $script): string
|
||||
{
|
||||
if (\strpos($script, 'LOCK'.'BASE64((((') !== false)
|
||||
{
|
||||
// get the strings
|
||||
$values = GetHelper::allBetween(
|
||||
$script, 'LOCK'.'BASE64((((', '))))'
|
||||
);
|
||||
$locker = [];
|
||||
// convert them
|
||||
foreach ($values as $value)
|
||||
{
|
||||
$locker['LOCK'.'BASE64((((' . $value . '))))']
|
||||
= "base64_decode( preg_replace('/\s+/', ''," .
|
||||
PHP_EOL . Indent::_(2) . "'" .
|
||||
wordwrap(
|
||||
base64_encode((string) $value), 64, PHP_EOL . Indent::_(2), true
|
||||
) .
|
||||
"'))";
|
||||
}
|
||||
|
||||
// update the script
|
||||
return $this->placeholder->update($script, $locker);
|
||||
}
|
||||
|
||||
return $script;
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1 @@
|
||||
<html><body bgcolor="#FFFFFF"></body></html>
|
Reference in New Issue
Block a user