Adds the code.power needed for importing, and more.

This commit is contained in:
Llewellyn van der Merwe 2023-04-13 17:44:10 +02:00
parent ebaeeeb4b3
commit 8d4935414b
Signed by: Llewellyn
GPG Key ID: A9201372263741E7
177 changed files with 29586 additions and 119 deletions

View File

@ -43,9 +43,14 @@ This repository contains an index (see below) of all the approved powers within
- **interface LoadInterface** | [Details](src/2ad31f74-f579-499d-b98b-c4f54fd615dd) | [Code](src/2ad31f74-f579-499d-b98b-c4f54fd615dd/code.php) | [Settings](src/2ad31f74-f579-499d-b98b-c4f54fd615dd/settings.json) | [2ad31f74-f579-499d-b98b-c4f54fd615dd](src/2ad31f74-f579-499d-b98b-c4f54fd615dd)
- **interface Mapperdoubleinterface** | [Details](src/fbc58009-fa16-4d49-a0dd-419c3b62d42f) | [Code](src/fbc58009-fa16-4d49-a0dd-419c3b62d42f/code.php) | [Settings](src/fbc58009-fa16-4d49-a0dd-419c3b62d42f/settings.json) | [fbc58009-fa16-4d49-a0dd-419c3b62d42f](src/fbc58009-fa16-4d49-a0dd-419c3b62d42f)
- **interface Mappersingleinterface** | [Details](src/78527c29-24ad-4735-ad4c-ec33a4952d9b) | [Code](src/78527c29-24ad-4735-ad4c-ec33a4952d9b/code.php) | [Settings](src/78527c29-24ad-4735-ad4c-ec33a4952d9b/settings.json) | [78527c29-24ad-4735-ad4c-ec33a4952d9b](src/78527c29-24ad-4735-ad4c-ec33a4952d9b)
- **interface ModelInterface** | [Details](src/8aef58c1-3f70-4bd4-b9e4-3f29fcd41cff) | [Code](src/8aef58c1-3f70-4bd4-b9e4-3f29fcd41cff/code.php) | [Settings](src/8aef58c1-3f70-4bd4-b9e4-3f29fcd41cff/settings.json) | [8aef58c1-3f70-4bd4-b9e4-3f29fcd41cff](src/8aef58c1-3f70-4bd4-b9e4-3f29fcd41cff)
- **interface Serverinterface** | [Details](src/86ac0760-26f5-4746-9c7f-ce77860f80f8) | [Code](src/86ac0760-26f5-4746-9c7f-ce77860f80f8/code.php) | [Settings](src/86ac0760-26f5-4746-9c7f-ce77860f80f8/settings.json) | [86ac0760-26f5-4746-9c7f-ce77860f80f8](src/86ac0760-26f5-4746-9c7f-ce77860f80f8)
- **interface Tableinterface** | [Details](src/2da6d6c4-eb29-4d69-8bc2-36d96e916adf) | [Code](src/2da6d6c4-eb29-4d69-8bc2-36d96e916adf/code.php) | [Settings](src/2da6d6c4-eb29-4d69-8bc2-36d96e916adf/settings.json) | [2da6d6c4-eb29-4d69-8bc2-36d96e916adf](src/2da6d6c4-eb29-4d69-8bc2-36d96e916adf)
- **Namespace**: [VDM\Joomla\Componentbuilder\Power](#vdm-joomla-componentbuilder-power)
- **final class Grep** | [Details](src/6784dd52-0909-451a-a872-9a942a023c68) | [Code](src/6784dd52-0909-451a-a872-9a942a023c68/code.php) | [Settings](src/6784dd52-0909-451a-a872-9a942a023c68/settings.json) | [6784dd52-0909-451a-a872-9a942a023c68](src/6784dd52-0909-451a-a872-9a942a023c68)
- **Namespace**: [VDM\Joomla\Componentbuilder\Utilities](#vdm-joomla-componentbuilder-utilities)
- **class Constantpaths** | [Details](src/e0c8c931-52a0-4171-9909-e8769505bb1f) | [Code](src/e0c8c931-52a0-4171-9909-e8769505bb1f/code.php) | [Settings](src/e0c8c931-52a0-4171-9909-e8769505bb1f/settings.json) | [e0c8c931-52a0-4171-9909-e8769505bb1f](src/e0c8c931-52a0-4171-9909-e8769505bb1f)
- **Namespace**: [VDM\Joomla\Componentbuilder\Compiler\Adminview](#vdm-joomla-componentbuilder-compiler-adminview)
- **class Data** | [Details](src/cef2815b-f72b-402a-b769-f028f676692d) | [Code](src/cef2815b-f72b-402a-b769-f028f676692d/code.php) | [Settings](src/cef2815b-f72b-402a-b769-f028f676692d/settings.json) | [cef2815b-f72b-402a-b769-f028f676692d](src/cef2815b-f72b-402a-b769-f028f676692d)
@ -194,7 +199,6 @@ This repository contains an index (see below) of all the approved powers within
- **abstract class FieldHelper** | [Details](src/7a5fd3f3-199e-43ba-a8e8-f473d6c030ec) | [Code](src/7a5fd3f3-199e-43ba-a8e8-f473d6c030ec/code.php) | [Settings](src/7a5fd3f3-199e-43ba-a8e8-f473d6c030ec/settings.json) | [7a5fd3f3-199e-43ba-a8e8-f473d6c030ec](src/7a5fd3f3-199e-43ba-a8e8-f473d6c030ec)
- **abstract class Indent** | [Details](src/a68c010b-e92e-47d5-8a44-d23cfddeb6c6) | [Code](src/a68c010b-e92e-47d5-8a44-d23cfddeb6c6/code.php) | [Settings](src/a68c010b-e92e-47d5-8a44-d23cfddeb6c6/settings.json) | [a68c010b-e92e-47d5-8a44-d23cfddeb6c6](src/a68c010b-e92e-47d5-8a44-d23cfddeb6c6)
- **abstract class Line** | [Details](src/4e6ff11d-bebf-42f5-8fd7-b2f882857222) | [Code](src/4e6ff11d-bebf-42f5-8fd7-b2f882857222/code.php) | [Settings](src/4e6ff11d-bebf-42f5-8fd7-b2f882857222/settings.json) | [4e6ff11d-bebf-42f5-8fd7-b2f882857222](src/4e6ff11d-bebf-42f5-8fd7-b2f882857222)
- **abstract class Minify** | [Details](src/b591855d-d106-4fe5-90ad-8e706f6267cf) | [Code](src/b591855d-d106-4fe5-90ad-8e706f6267cf/code.php) | [Settings](src/b591855d-d106-4fe5-90ad-8e706f6267cf/settings.json) | [b591855d-d106-4fe5-90ad-8e706f6267cf](src/b591855d-d106-4fe5-90ad-8e706f6267cf)
- **abstract class Placefix** | [Details](src/500f3a7f-c16d-4dd4-81b2-2df6776b5388) | [Code](src/500f3a7f-c16d-4dd4-81b2-2df6776b5388/code.php) | [Settings](src/500f3a7f-c16d-4dd4-81b2-2df6776b5388/settings.json) | [500f3a7f-c16d-4dd4-81b2-2df6776b5388](src/500f3a7f-c16d-4dd4-81b2-2df6776b5388)
- **abstract class Unique** | [Details](src/f02fb1df-f4b6-4be1-9595-2e72084a5e6e) | [Code](src/f02fb1df-f4b6-4be1-9595-2e72084a5e6e/code.php) | [Settings](src/f02fb1df-f4b6-4be1-9595-2e72084a5e6e/settings.json) | [f02fb1df-f4b6-4be1-9595-2e72084a5e6e](src/f02fb1df-f4b6-4be1-9595-2e72084a5e6e)
- **class Counter** | [Details](src/e6d871a6-bbe7-497d-af01-68f6bb9a87f4) | [Code](src/e6d871a6-bbe7-497d-af01-68f6bb9a87f4/code.php) | [Settings](src/e6d871a6-bbe7-497d-af01-68f6bb9a87f4/settings.json) | [e6d871a6-bbe7-497d-af01-68f6bb9a87f4](src/e6d871a6-bbe7-497d-af01-68f6bb9a87f4)
@ -266,6 +270,7 @@ namespace VDM\Joomla\Componentbuilder\Compiler #Olive {
class Config #Gold {
# JoomlaRegistry $config
+ __construct()
# getGiteatoken() : ?string
# getAddcontributors() : bool
# getAddajax() : bool
# getAddsiteajax() : bool
@ -303,6 +308,7 @@ namespace VDM\Joomla\Componentbuilder\Compiler #Olive {
# getCompilerpath() : string
# getJcbpowerspath() : string
# getLocalpowersrepositorypath() : string
# getApprovedpaths() : array
# getBompath() : string
# getCustomfolderpath() : string
# getAddassetstablefix() : int
@ -312,6 +318,7 @@ namespace VDM\Joomla\Componentbuilder\Compiler #Olive {
# getAddplaceholders() : bool
# getAddpower() : bool
# getAddsuperpowers() : bool
# getAddownpowers() : bool
# getBuildtarget() : string
# getCryptiontypes() : array
# getBasicencryption() : bool
@ -464,9 +471,11 @@ namespace VDM\Joomla\Componentbuilder\Interfaces #Olive {
}
interface InsertInterface #Lavender {
+ defaults() : void
+ rows() : bool
+ items() : bool
+ row() : bool
+ item() : bool
}
interface LoadInterface #Lavender {
@ -495,13 +504,6 @@ namespace VDM\Joomla\Componentbuilder\Interfaces #Olive {
+ remove() : void
}
interface ModelInterface #Lavender {
+ value() : mixed
+ item() : ?object
+ items() : ?array
+ last() : ?int
}
interface Serverinterface #Lavender {
+ set() : self
+ move() : bool
@ -518,6 +520,56 @@ namespace VDM\Joomla\Componentbuilder\Interfaces #Olive {
}
@enduml
```
## VDM Joomla Componentbuilder Power
> namespace VDM\Joomla\Componentbuilder\Power
```uml
@startuml
namespace VDM\Joomla\Componentbuilder\Power #Olive {
class Grep << (F,LightGreen) >> #Green {
+ string $path
+ ?array $paths
# Contents $contents
# CMSApplication $app
+ __construct()
+ get() : ?object
- searchLocal() : ?object
- searchRemote() : ?object
- getLocal() : ?object
- getRemote() : ?object
- init() : void
- localIndex() : void
- remoteIndex() : void
- loadRemoteFile() : mixed
- getCode() : ?string
- getLicense() : ?string
}
}
@enduml
```
## VDM Joomla Componentbuilder Utilities
> namespace VDM\Joomla\Componentbuilder\Utilities
```uml
@startuml
namespace VDM\Joomla\Componentbuilder\Utilities #Olive {
class Constantpaths #Gold {
# array $paths
+ get() : array|string|null
}
}
@enduml
```
@ -1607,6 +1659,7 @@ namespace VDM\Joomla\Componentbuilder\Compiler\Power #LightGreen {
- setPowers() : void
- index() : string
- code() : string
- raw() : string
- linker() : string
}
@ -1832,6 +1885,7 @@ namespace VDM\Joomla\Componentbuilder\Compiler\Service #LightGreen {
class Power #Gold {
+ register() : void
+ getPowers() : Powers
+ getGrep() : Grep
+ getAutoloader() : Autoloader
+ getInfusion() : Infusion
+ getStructure() : Structure
@ -1911,11 +1965,6 @@ namespace VDM\Joomla\Componentbuilder\Compiler\Utilities #LightGreen {
- {static} init() : void
}
abstract Minify #Orange {
+ {static} js() : string
+ {static} css() : string
}
abstract Placefix #Orange {
+ {static} _() : string
+ {static} b() : string

View File

@ -0,0 +1,856 @@
/**
* The placeholder keys
*
* @var array
* @since 3.2.0
*/
protected array $PKeys
= [
1 => 'REPLACE<>$$$$]',
2 => 'INSERT<>$$$$]',
3 => 'REPLACED<>$$$$]',
4 => 'INSERTED<>$$$$]'
];
/**
* 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
*
* @var User
* @since 3.2.0
**/
protected User $user;
/**
* Database object to query local DB
*
* @var \JDatabaseDriver
* @since 3.2.0
**/
protected \JDatabaseDriver $db;
/**
* Database object to query local DB
*
* @var CMSApplication
* @since 3.2.0
**/
protected CMSApplication $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.
* @param User|null $user The current User 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, ?Gui $gui = null, ?Paths $paths = null,
?Reverse $reverse = null, ?Placeholder $placeholder = null, ?Pathfix $pathfix = null,
?User $user = null, ?\JDatabaseDriver $db = null, ?CMSApplication $app = 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 = $user ?: Factory::getUser();
$this->db = $db ?: Factory::getDbo();
$this->app = $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);
}
/**
* 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::_('<hr /><h3>Custom Codes Warning</h3>'),
'Warning'
);
$this->app->enqueueMessage(
Text::sprintf('We found dynamic code <b>all in one line</b>, 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(
$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', '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;
}

View File

@ -0,0 +1,102 @@
/**
* The areas add array
*
* @var array
* @since 3.2.0
*/
protected array $areas = [
'php_import_ext',
'php_import_display',
'php_import',
'php_import_setdata',
'php_import_save',
'php_import_headers',
'html_import_view'
];
/**
* The gui mapper array
*
* @var array
* @since 3.2.0
*/
protected array $guiMapper = [
'table' => 'admin_view',
'id' => null,
'field' => null,
'type' => 'php'
];
/**
* Compiler Customcode Dispenser
*
* @var Dispenser
* @since 3.2.0
*/
protected Dispenser $dispenser;
/**
* Constructor
*
* @param Dispenser|null $dispenser The compiler customcode dispenser
*
* @since 3.2.0
*/
public function __construct(?Dispenser $dispenser = null)
{
$this->dispenser = $dispenser ?: Compiler::_('Customcode.Dispenser');
}
/**
* Set Custom Import Scripts
*
* @param object $item The item data
* @param string $table The table
*
* @return void
* @since 3.2.0
*/
public function set(object &$item, string $table = 'admin_view')
{
// set custom import scripts
if (isset($item->add_custom_import)
&& $item->add_custom_import == 1)
{
// set some gui mapper values
$this->guiMapper['table'] = $table;
$this->guiMapper['id'] = (int) $item->id;
foreach ($this->areas as $area)
{
if (isset($item->$area)
&& StringHelper::check($item->$area))
{
// update GUI mapper field
$this->guiMapper['field'] = $area;
$this->guiMapper['type'] = 'php';
// Make sure html gets HTML comment for placeholder
if ('html_import_view' === $area)
{
$this->guiMapper['type'] = 'html';
}
$this->dispenser->set(
$item->$area,
$area,
'import_' . $item->name_list_code,
null,
$this->guiMapper
);
unset($item->$area);
}
else
{
// load the default TODO: convert getDynamicScripts to a class
$this->dispenser->hub[$area]['import_' . $item->name_list_code]
= Helper::_('getDynamicScripts', [$area, true]);
}
}
}
}

View File

@ -28,6 +28,7 @@ class Infusion #Gold {
- setPowers() : void
- index(array $powers) : string
- code(object $power) : string
- raw(object $power) : string
- linker(object $power) : string
}
@ -90,7 +91,14 @@ note right of Infusion::code
return: string
end note
note left of Infusion::linker
note left of Infusion::raw
Get the Raw (unchanged) Power code
since: 3.2.0
return: string
end note
note right of Infusion::linker
Get the Power Linker
since: 3.2.0

View File

@ -271,6 +271,9 @@ class Infusion
// POWERCODE
$this->content->set_($power->key, 'POWERCODE', $this->code($power));
// CODEPOWER
$this->content->set_($power->key, 'CODEPOWER', $this->raw($power));
// POWERLINKER
$this->content->set_($power->key, 'POWERLINKER', $this->linker($power));
@ -365,6 +368,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->raw_class_code) && StringHelper::check($power->raw_class_code))
{
return $power->raw_class_code;
}
return '';
}
/**
* Get the Power Linker
*

View File

@ -0,0 +1,376 @@
/**
* Compiler Config
*
* @var Config
* @since 3.2.0
**/
protected Config $config;
/**
* Power Objects
*
* @var Power
* @since 3.2.0
**/
protected Power $power;
/**
* Compiler Content
*
* @var Content
* @since 3.2.0
**/
protected Content $content;
/**
* Compiler Powers Autoloader
*
* @var Autoloader
* @since 3.2.0
**/
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
*
* @var Placeholder
* @since 3.2.0
**/
protected Placeholder $placeholder;
/**
* Compiler Event
*
* @var Event
* @since 3.2.0
**/
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',
'extends_custom' => 'extends_custom',
'guid' => 'guid',
'unchanged_head' => 'head',
'use_selection' => 'use_selection',
'implements' => 'implements',
'implements_custom' => 'implements_custom',
'load_selection' => 'load_selection',
'name' => 'name',
'power_version' => 'power_version',
'system_name' => 'system_name',
'type' => 'type',
'unchanged_namespace' => 'namespace'
];
/**
* Constructor.
*
* @param Config|null $config The Config object.
* @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, ?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');
}
/**
* Infuse the powers data with the content
*
* @return void
* @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))
{
// TODO we need to update the event signatures
$context = $this->config->component_context;
foreach ($this->power->active as $power)
{
if (ObjectHelper::check($power))
{
// Trigger Event: jcb_ce_onBeforeInfusePowerData
$this->event->trigger(
'jcb_ce_onBeforeInfusePowerData',
array(&$context, &$power)
);
// POWERCODE
$this->content->set_($power->key, 'POWERCODE', $this->code($power));
// CODEPOWER
$this->content->set_($power->key, 'CODEPOWER', $this->raw($power));
// 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(
'jcb_ce_onAfterInfusePowerData',
array(&$context, &$power)
);
}
}
// now set the power autoloader
$this->autoloader->set();
}
}
/**
* 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
*
* @param object $power A power object.
*
* @return string
* @since 3.2.0
*/
private function code(object &$power): string
{
$code = [];
// set the name space
$code[] = 'namespace ' . $power->_namespace . ';' . PHP_EOL;
// check if we have header data
if (StringHelper::check($power->head))
{
$code[] = PHP_EOL . $power->head;
}
// add description if set
if (StringHelper::check($power->description))
{
// check if this is escaped
if (strpos((string) $power->description, '/*') === false)
{
// make this description escaped
$power->description = '/**' . PHP_EOL . ' * ' . implode(PHP_EOL . ' * ', explode(PHP_EOL, (string) $power->description)) . PHP_EOL . ' */';
}
$code[] = PHP_EOL . $power->description;
}
// build power declaration
$declaration = $power->type . ' ' . $power->class_name;
// check if we have extends
if (StringHelper::check($power->extends_name))
{
$declaration .= ' extends ' . $power->extends_name;
}
// check if we have implements
if (ArrayHelper::check($power->implement_names))
{
$declaration .= ' implements ' . implode(', ', $power->implement_names);
}
$code[] = $declaration;
$code[] = '{';
// add the main code if set
if (StringHelper::check($power->main_class_code))
{
$code[] = $power->main_class_code;
}
$code[] = '}' . PHP_EOL;
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->raw_class_code) && StringHelper::check($power->raw_class_code))
{
return $power->raw_class_code;
}
return '';
}
/**
* Get the Power Linker
*
* @param object $power A power object.
*
* @return string
* @since 3.2.0
*/
private function linker(object &$power): string
{
$linker = [];
// set the linking values
foreach ($power as $key => $value)
{
if (isset($this->linker[$key]))
{
$linker[$this->linker[$key]] = $value;
}
}
return json_encode($linker, JSON_PRETTY_PRINT);
}

View File

@ -35,31 +35,31 @@
"use": "95d0e03f-24fd-4412-bc2e-f0899fcc3205",
"as": "default"
},
"use_selection12": {
"use_selection6": {
"use": "efb1d0f8-2d14-4d2c-8b5f-4fcdd9df45a5",
"as": "RepoReadme"
},
"use_selection6": {
"use_selection7": {
"use": "0d08c583-04d5-454e-b756-48ca05e1651a",
"as": "ReposReadme"
},
"use_selection7": {
"use_selection8": {
"use": "06453ada-e370-49f0-b262-e3f5a8ed0c2c",
"as": "default"
},
"use_selection8": {
"use_selection9": {
"use": "20ed72b0-fcac-4344-aee1-8a65e3bf221d",
"as": "Event"
},
"use_selection9": {
"use_selection10": {
"use": "1f28cb53-60d9-4db1-b517-3c7dc6b429ef",
"as": "default"
},
"use_selection10": {
"use_selection11": {
"use": "0a59c65c-9daf-4bc9-baf4-e063ff9e6a8a",
"as": "default"
},
"use_selection11": {
"use_selection12": {
"use": "91004529-94a9-4590-b842-e7c6b624ecf5",
"as": "default"
}

View File

@ -0,0 +1,382 @@
/**
* 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
*
* @var \JDatabaseDriver
* @since 3.2.0
**/
protected \JDatabaseDriver $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.
* @param \JDatabaseDriver|null $db The Database Driver 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, ?\JDatabaseDriver $db = 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 = $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 . '_M0dU|3';
// 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 . '_P|uG!n';
// return the path
return $plugin->group . '/' . $plugin->file_name;
}
}
return false;
}

View File

@ -0,0 +1,287 @@
/**
* The gui mapper array
*
* @var array
* @since 3.2.0
*/
protected array $guiMapper = [
'table' => 'dynamic_get',
'id' => null,
'field' => null,
'type' => 'php'
];
/**
* Compiler Config
*
* @var Config
* @since 3.2.0
*/
protected Config $config;
/**
* The compiler registry
*
* @var Registry
* @since 3.2.0
*/
protected Registry $registry;
/**
* Compiler Event
*
* @var EventInterface
* @since 3.2.0
*/
protected EventInterface $event;
/**
* Compiler Customcode
*
* @var Customcode
* @since 3.2.0
*/
protected Customcode $customcode;
/**
* Compiler Customcode Dispenser
*
* @var Dispenser
* @since 3.2.0
*/
protected Dispenser $dispenser;
/**
* Compiler Customcode in Gui
*
* @var Gui
* @since 3.2.0
**/
protected Gui $gui;
/**
* Compiler Dynamicget Model
*
* @var Dynamicget
* @since 3.2.0
*/
protected Dynamicget $dynamic;
/**
* Database object to query local DB
*
* @var \JDatabaseDriver
* @since 3.2.0
**/
protected \JDatabaseDriver $db;
/**
* Constructor
*
* @param Config|null $config The compiler config object.
* @param Registry|null $registry The compiler registry object.
* @param EventInterface|null $event The compiler event api object.
* @param Customcode|null $customcode The compiler customcode object.
* @param Dispenser|null $dispenser The compiler customcode dispenser object.
* @param Gui|null $gui The compiler customcode gui.
* @param Dynamicget|null $dynamic The compiler dynamicget modeller object.
* @param \JDatabaseDriver|null $db The database object.
*
* @since 3.2.0
*/
public function __construct(?Config $config = null, ?Registry $registry = null,
?EventInterface $event = null, ?Customcode $customcode = null,
?Dispenser $dispenser = null, ?Gui $gui = null,
?Dynamicget $dynamic = null, ?\JDatabaseDriver $db = null)
{
$this->config = $config ?: Compiler::_('Config');
$this->registry = $registry ?: Compiler::_('Registry');
$this->event = $event ?: Compiler::_('Event');
$this->customcode = $customcode ?: Compiler::_('Customcode');
$this->dispenser = $dispenser ?: Compiler::_('Customcode.Dispenser');
$this->gui = $gui ?: Compiler::_('Customcode.Gui');
$this->dynamic = $dynamic ?: Compiler::_('Model.Dynamicget');
$this->db = $db ?: Factory::getDbo();
}
/**
* Get Dynamic Get Data
*
* @param array $ids The ids of the dynamic get
* @param string $view_code The view code name
* @param string $context The context for events
*
* @return array|null array of object/s on success
* @since 3.2.0
*/
public function get(array $ids, string $view_code, string $context): ?array
{
if ($ids === [])
{
return null;
}
$ids = implode(',', $ids);
// for plugin event TODO change event api signatures
$component_context = $this->config->component_context;
// Create a new query object.
$query = $this->db->getQuery(true);
$query->select('a.*');
$query->from('#__componentbuilder_dynamic_get AS a');
$query->where('a.id IN (' . $ids . ')');
$this->db->setQuery($query);
$this->db->execute();
if ($this->db->getNumRows())
{
$results = $this->db->loadObjectList();
foreach ($results as $_nr => &$result)
{
// Trigger Event: jcb_ce_onBeforeModelDynamicGetData
$this->event->trigger(
'jcb_ce_onBeforeModelDynamicGetData',
array(&$component_context, &$result, &$result->id, &$view_code, &$context)
);
// set GUI mapper id
$this->guiMapper['id'] = (int) $result->id;
// add calculations if set
if ($result->addcalculation == 1
&& StringHelper::check(
$result->php_calculation
))
{
// set GUI mapper field
$guiMapper['field'] = 'php_calculation';
$result->php_calculation = $this->gui->set(
$this->customcode->update(
base64_decode((string) $result->php_calculation)
),
$this->guiMapper
);
}
// setup the router parse
if (isset($result->add_php_router_parse)
&& $result->add_php_router_parse == 1
&& isset($result->php_router_parse)
&& StringHelper::check(
$result->php_router_parse
))
{
// set GUI mapper field
$this->guiMapper['field'] = 'php_router_parse';
$result->php_router_parse = $this->gui->set(
$this->customcode->update(
base64_decode((string) $result->php_router_parse)
),
$this->guiMapper
);
}
else
{
$result->add_php_router_parse = 0;
}
// The array of the php scripts that should be added to the script builder
$phpSripts = [
'php_before_getitem',
'php_after_getitem',
'php_before_getitems',
'php_after_getitems',
'php_getlistquery'
];
// load the php scripts
foreach ($phpSripts as $script)
{
// add php script to the script builder
if (isset($result->{'add_' . $script})
&& $result->{'add_' . $script} == 1
&& isset($result->{$script})
&& StringHelper::check(
$result->{$script}
))
{
// move all main gets out to the custom script builder
if ($result->gettype <= 2)
{
// set GUI mapper field
$this->guiMapper['field'] = $script;
$this->guiMapper['prefix'] = PHP_EOL . PHP_EOL;
$this->dispenser->set(
$result->{$script},
$this->config->build_target . '_' . $script,
$view_code,
null,
$this->guiMapper,
true,
true,
true
);
unset($this->guiMapper['prefix']);
// remove from local item
unset($result->{$script});
unset($result->{'add_' . $script});
}
else
{
// set GUI mapper field
$this->guiMapper['field'] = $script;
$this->guiMapper['prefix'] = PHP_EOL;
// only for custom gets
$result->{$script} = $this->gui->set(
$this->customcode->update(
base64_decode((string) $result->{$script})
),
$this->guiMapper
);
unset($this->guiMapper['prefix']);
}
}
else
{
// remove from local item
unset($result->{$script});
unset($result->{'add_' . $script});
}
}
// set the getmethod code name
$result->key = StringHelper::safe(
$view_code . ' ' . $result->name . ' ' . $result->id
);
// set the dynamic get
$this->dynamic->set($result, $view_code, $context);
// load the events if any is set
if ($result->gettype == 1
&& JsonHelper::check(
$result->plugin_events
))
{
$result->plugin_events = json_decode(
(string) $result->plugin_events, true
);
}
else
{
$result->plugin_events = '';
}
// Trigger Event: jcb_ce_onAfterModelDynamicGetData
$this->event->trigger(
'jcb_ce_onAfterModelDynamicGetData',
array(&$component_context, &$result, &$result->id, &$view_code, &$context)
);
}
return $results;
}
return null;
}

View File

@ -0,0 +1,741 @@
/**
* 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(Joomlaplugins::class, 'Model.Joomlaplugins')
->share('Model.Joomlaplugins', [$this, 'getModelJoomlaplugins'], true);
$container->alias(Joomlamodules::class, 'Model.Joomlamodules')
->share('Model.Joomlamodules', [$this, 'getModelJoomlamodules'], true);
$container->alias(Historycomponent::class, 'Model.Historycomponent')
->share('Model.Historycomponent', [$this, 'getModelHistorycomponent'], true);
$container->alias(Customadminviews::class, 'Model.Customadminviews')
->share('Model.Customadminviews', [$this, 'getModelCustomadminviews'], true);
$container->alias(Ajaxcustomview::class, 'Model.Ajaxcustomview')
->share('Model.Ajaxcustomview', [$this, 'getModelAjaxcustomview'], true);
$container->alias(Javascriptcustomview::class, 'Model.Javascriptcustomview')
->share('Model.Javascriptcustomview', [$this, 'getModelJavascriptcustomview'], true);
$container->alias(Csscustomview::class, 'Model.Csscustomview')
->share('Model.Csscustomview', [$this, 'getModelCsscustomview'], true);
$container->alias(Phpcustomview::class, 'Model.Phpcustomview')
->share('Model.Phpcustomview', [$this, 'getModelPhpcustomview'], true);
$container->alias(Dynamicget::class, 'Model.Dynamicget')
->share('Model.Dynamicget', [$this, 'getModelDynamicget'], true);
$container->alias(Libraries::class, 'Model.Libraries')
->share('Model.Libraries', [$this, 'getModelLibraries'], true);
$container->alias(Siteviews::class, 'Model.Siteviews')
->share('Model.Siteviews', [$this, 'getModelSiteviews'], true);
$container->alias(Permissions::class, 'Model.Permissions')
->share('Model.Permissions', [$this, 'getModelPermissions'], true);
$container->alias(Historyadminview::class, 'Model.Historyadminview')
->share('Model.Historyadminview', [$this, 'getModelHistoryadminview'], true);
$container->alias(Mysqlsettings::class, 'Model.Mysqlsettings')
->share('Model.Mysqlsettings', [$this, 'getModelMysqlsettings'], true);
$container->alias(Sql::class, 'Model.Sql')
->share('Model.Sql', [$this, 'getModelSql'], true);
$container->alias(Customalias::class, 'Model.Customalias')
->share('Model.Customalias', [$this, 'getModelCustomalias'], true);
$container->alias(Ajaxadmin::class, 'Model.Ajaxadmin')
->share('Model.Ajaxadmin', [$this, 'getModelAjaxadmin'], true);
$container->alias(Customimportscripts::class, 'Model.Customimportscripts')
->share('Model.Customimportscripts', [$this, 'getModelCustomimportscripts'], true);
$container->alias(Custombuttons::class, 'Model.Custombuttons')
->share('Model.Custombuttons', [$this, 'getModelCustombuttons'], true);
$container->alias(Loader::class, 'Model.Loader')
->share('Model.Loader', [$this, 'getModelLoader'], true);
$container->alias(Phpadminview::class, 'Model.Phpadminview')
->share('Model.Phpadminview', [$this, 'getModelPhpadminview'], true);
$container->alias(Cssadminview::class, 'Model.Cssadminview')
->share('Model.Cssadminview', [$this, 'getModelCssadminview'], true);
$container->alias(Javascriptadminview::class, 'Model.Javascriptadminview')
->share('Model.Javascriptadminview', [$this, 'getModelJavascriptadminview'], true);
$container->alias(Linkedviews::class, 'Model.Linkedviews')
->share('Model.Linkedviews', [$this, 'getModelLinkedviews'], true);
$container->alias(Relations::class, 'Model.Relations')
->share('Model.Relations', [$this, 'getModelRelations'], true);
$container->alias(Conditions::class, 'Model.Conditions')
->share('Model.Conditions', [$this, 'getModelConditions'], true);
$container->alias(Fields::class, 'Model.Fields')
->share('Model.Fields', [$this, 'getModelFields'], true);
$container->alias(Updatesql::class, 'Model.Updatesql')
->share('Model.Updatesql', [$this, 'getModelUpdatesql'], true);
$container->alias(Tabs::class, 'Model.Tabs')
->share('Model.Tabs', [$this, 'getModelTabs'], true);
$container->alias(Customtabs::class, 'Model.Customtabs')
->share('Model.Customtabs', [$this, 'getModelCustomtabs'], true);
$container->alias(Adminviews::class, 'Model.Adminviews')
->share('Model.Adminviews', [$this, 'getModelAdminviews'], true);
$container->alias(Sqltweaking::class, 'Model.Sqltweaking')
->share('Model.Sqltweaking', [$this, 'getModelSqltweaking'], true);
$container->alias(Sqldump::class, 'Model.Sqldump')
->share('Model.Sqldump', [$this, 'getModelSqldump'], true);
$container->alias(Whmcs::class, 'Model.Whmcs')
->share('Model.Whmcs', [$this, 'getModelWhmcs'], true);
$container->alias(Modifieddate::class, 'Model.Modifieddate')
->share('Model.Modifieddate', [$this, 'getModifieddate'], true);
$container->alias(Createdate::class, 'Model.Createdate')
->share('Model.Createdate', [$this, 'getCreatedate'], true);
$container->alias(Updateserver::class, 'Model.Updateserver')
->share('Model.Updateserver', [$this, 'getUpdateserver'], true);
$container->alias(Filesfolders::class, 'Model.Filesfolders')
->share('Model.Filesfolders', [$this, 'getModelFilesfolders'], true);
$container->alias(ServerLoad::class, 'Model.Server.Load')
->share('Model.Server.Load', [$this, 'getServerLoad'], true);
}
/**
* Get the Joomla plugins Model
*
* @param Container $container The DI container.
*
* @return Joomlaplugins
* @since 3.2.0
*/
public function getModelJoomlaplugins(Container $container): Joomlaplugins
{
return new Joomlaplugins(
$container->get('Joomlaplugin.Data')
);
}
/**
* Get the Joomla modules Model
*
* @param Container $container The DI container.
*
* @return Joomlamodules
* @since 3.2.0
*/
public function getModelJoomlamodules(Container $container): Joomlamodules
{
return new Joomlamodules(
$container->get('Joomlamodule.Data')
);
}
/**
* Get the history component Model
*
* @param Container $container The DI container.
*
* @return Historycomponent
* @since 3.2.0
*/
public function getModelHistorycomponent(Container $container): Historycomponent
{
return new Historycomponent(
$container->get('Config'),
$container->get('History'),
$container->get('Model.Updatesql')
);
}
/**
* Get the custom admin views Model
*
* @param Container $container The DI container.
*
* @return Customadminviews
* @since 3.2.0
*/
public function getModelCustomadminviews(Container $container): Customadminviews
{
return new Customadminviews(
$container->get('Customview.Data'),
$container->get('Config')
);
}
/**
* Get the ajax custom view Model
*
* @param Container $container The DI container.
*
* @return Ajaxcustomview
* @since 3.2.0
*/
public function getModelAjaxcustomview(Container $container): Ajaxcustomview
{
return new Ajaxcustomview(
$container->get('Config'),
$container->get('Customcode.Dispenser')
);
}
/**
* Get the javascript custom view Model
*
* @param Container $container The DI container.
*
* @return Javascriptcustomview
* @since 3.2.0
*/
public function getModelJavascriptcustomview(Container $container): Javascriptcustomview
{
return new Javascriptcustomview(
$container->get('Customcode'),
$container->get('Customcode.Gui')
);
}
/**
* Get the css custom view Model
*
* @param Container $container The DI container.
*
* @return Csscustomview
* @since 3.2.0
*/
public function getModelCsscustomview(Container $container): Csscustomview
{
return new Csscustomview(
$container->get('Customcode')
);
}
/**
* Get the php custom view Model
*
* @param Container $container The DI container.
*
* @return Phpcustomview
* @since 3.2.0
*/
public function getModelPhpcustomview(Container $container): Phpcustomview
{
return new Phpcustomview(
$container->get('Customcode'),
$container->get('Customcode.Gui'),
$container->get('Model.Loader'),
$container->get('Templatelayout.Data')
);
}
/**
* Get the dynamic get Model
*
* @param Container $container The DI container.
*
* @return Dynamicget
* @since 3.2.0
*/
public function getModelDynamicget(Container $container): Dynamicget
{
return new Dynamicget(
$container->get('Config'),
$container->get('Registry'),
$container->get('Customcode'),
$container->get('Customcode.Gui'),
$container->get('Placeholder'),
$container->get('Dynamicget.Selection')
);
}
/**
* Get the libraries Model
*
* @param Container $container The DI container.
*
* @return Libraries
* @since 3.2.0
*/
public function getModelLibraries(Container $container): Libraries
{
return new Libraries(
$container->get('Config'),
$container->get('Registry'),
$container->get('Library.Data')
);
}
/**
* Get the site views Model
*
* @param Container $container The DI container.
*
* @return Siteviews
* @since 3.2.0
*/
public function getModelSiteviews(Container $container): Siteviews
{
return new Siteviews(
$container->get('Customview.Data'),
$container->get('Config')
);
}
/**
* Get the permissions Model
*
* @param Container $container The DI container.
*
* @return Permissions
* @since 3.2.0
*/
public function getModelPermissions(Container $container): Permissions
{
return new Permissions();
}
/**
* Get the admin view history Model
*
* @param Container $container The DI container.
*
* @return Historyadminview
* @since 3.2.0
*/
public function getModelHistoryadminview(Container $container): Historyadminview
{
return new Historyadminview(
$container->get('Config'),
$container->get('History'),
$container->get('Model.Updatesql')
);
}
/**
* Get the MySQL settings Model
*
* @param Container $container The DI container.
*
* @return Mysqlsettings
* @since 3.2.0
*/
public function getModelMysqlsettings(Container $container): Mysqlsettings
{
return new Mysqlsettings(
$container->get('Config'),
$container->get('Registry')
);
}
/**
* Get the Sql Model
*
* @param Container $container The DI container.
*
* @return Sql
* @since 3.2.0
*/
public function getModelSql(Container $container): Sql
{
return new Sql(
$container->get('Customcode.Dispenser'),
$container->get('Model.Sqldump')
);
}
/**
* Get the custom alias Model
*
* @param Container $container The DI container.
*
* @return Customalias
* @since 3.2.0
*/
public function getModelCustomalias(Container $container): Customalias
{
return new Customalias(
$container->get('Registry'),
$container->get('Field.Name')
);
}
/**
* Get the Admin Ajax Model
*
* @param Container $container The DI container.
*
* @return Ajaxadmin
* @since 3.2.0
*/
public function getModelAjaxadmin(Container $container): Ajaxadmin
{
return new Ajaxadmin(
$container->get('Config'),
$container->get('Registry'),
$container->get('Customcode.Dispenser')
);
}
/**
* Get the custom import scripts Model
*
* @param Container $container The DI container.
*
* @return Customimportscripts
* @since 3.2.0
*/
public function getModelCustomimportscripts(Container $container): Customimportscripts
{
return new Customimportscripts(
$container->get('Customcode.Dispenser')
);
}
/**
* Get the custom import scripts Model
*
* @param Container $container The DI container.
*
* @return Custombuttons
* @since 3.2.0
*/
public function getModelCustombuttons(Container $container): Custombuttons
{
return new Custombuttons(
$container->get('Customcode'),
$container->get('Customcode.Gui'),
$container->get('Templatelayout.Data')
);
}
/**
* Get the Model Auto Loader
*
* @param Container $container The DI container.
*
* @return Loader
* @since 3.2.0
*/
public function getModelLoader(Container $container): Loader
{
return new Loader(
$container->get('Config'),
$container->get('Registry')
);
}
/**
* Get the php admin view Model
*
* @param Container $container The DI container.
*
* @return Phpadminview
* @since 3.2.0
*/
public function getModelPhpadminview(Container $container): Phpadminview
{
return new Phpadminview(
$container->get('Customcode.Dispenser'),
$container->get('Templatelayout.Data')
);
}
/**
* Get the Css Adminview Model
*
* @param Container $container The DI container.
*
* @return Cssadminview
* @since 3.2.0
*/
public function getModelCssadminview(Container $container): Cssadminview
{
return new Cssadminview(
$container->get('Customcode.Dispenser')
);
}
/**
* Get the Javascript Adminview Model
*
* @param Container $container The DI container.
*
* @return Javascriptadminview
* @since 3.2.0
*/
public function getModelJavascriptadminview(Container $container): Javascriptadminview
{
return new Javascriptadminview(
$container->get('Customcode.Dispenser')
);
}
/**
* Get the linked views Model
*
* @param Container $container The DI container.
*
* @return Linkedviews
* @since 3.2.0
*/
public function getModelLinkedviews(Container $container): Linkedviews
{
return new Linkedviews(
$container->get('Registry')
);
}
/**
* Get the relations Model
*
* @param Container $container The DI container.
*
* @return Relations
* @since 3.2.0
*/
public function getModelRelations(Container $container): Relations
{
return new Relations(
$container->get('Config'),
$container->get('Registry'),
$container->get('Language'),
$container->get('Customcode')
);
}
/**
* Get the conditions Model
*
* @param Container $container The DI container.
*
* @return Conditions
* @since 3.2.0
*/
public function getModelConditions(Container $container): Conditions
{
return new Conditions(
$container->get('Field.Type.Name'),
$container->get('Field.Name')
);
}
/**
* Get the fields Model
*
* @param Container $container The DI container.
*
* @return Fields
* @since 3.2.0
*/
public function getModelFields(Container $container): Fields
{
return new Fields(
$container->get('Config'),
$container->get('Registry'),
$container->get('History'),
$container->get('Customcode'),
$container->get('Field'),
$container->get('Field.Name'),
$container->get('Model.Updatesql')
);
}
/**
* Get the update sql Model
*
* @param Container $container The DI container.
*
* @return Updatesql
* @since 3.2.0
*/
public function getModelUpdatesql(Container $container): Updatesql
{
return new Updatesql(
$container->get('Registry')
);
}
/**
* Get the tabs Model
*
* @param Container $container The DI container.
*
* @return Updatesql
* @since 3.2.0
*/
public function getModelTabs(Container $container): Tabs
{
return new Tabs();
}
/**
* Get the custom tabs Model
*
* @param Container $container The DI container.
*
* @return Customtabs
* @since 3.2.0
*/
public function getModelCustomtabs(Container $container): Customtabs
{
return new Customtabs(
$container->get('Config'),
$container->get('Registry'),
$container->get('Language'),
$container->get('Placeholder'),
$container->get('Customcode')
);
}
/**
* Get the admin views Model
*
* @param Container $container The DI container.
*
* @return Adminviews
* @since 3.2.0
*/
public function getModelAdminviews(Container $container): Adminviews
{
return new Adminviews(
$container->get('Adminview.Data'),
$container->get('Registry'),
$container->get('Config')
);
}
/**
* Get the SQL tweaking Model
*
* @param Container $container The DI container.
*
* @return Sqltweaking
* @since 3.2.0
*/
public function getModelSqltweaking(Container $container): Sqltweaking
{
return new Sqltweaking(
$container->get('Registry')
);
}
/**
* Get the SQL dump Model
*
* @param Container $container The DI container.
*
* @return Sqldump
* @since 3.2.0
*/
public function getModelSqldump(Container $container): Sqldump
{
return new Sqldump(
$container->get('Registry')
);
}
/**
* Get the whmcs Model
*
* @param Container $container The DI container.
*
* @return Whmcs
* @since 3.2.0
*/
public function getModelWhmcs(Container $container): Whmcs
{
return new Whmcs();
}
/**
* Get the modified date Model
*
* @param Container $container The DI container.
*
* @return Modifieddate
* @since 3.2.0
*/
public function getModifieddate(Container $container): Modifieddate
{
return new Modifieddate();
}
/**
* Get the create date Model
*
* @param Container $container The DI container.
*
* @return Createdate
* @since 3.2.0
*/
public function getCreatedate(Container $container): Createdate
{
return new Createdate();
}
/**
* Get the update server Model
*
* @param Container $container The DI container.
*
* @return Updateserver
* @since 3.2.0
*/
public function getUpdateserver(Container $container): Updateserver
{
return new Updateserver();
}
/**
* Get the files folders Model
*
* @param Container $container The DI container.
*
* @return Filesfolders
* @since 3.2.0
*/
public function getModelFilesfolders(Container $container): Filesfolders
{
return new Filesfolders();
}
/**
* Get the Server Model Server Loader class
*
* @param Container $container The DI container.
*
* @return ServerLoad
* @since 3.2.0
*/
public function getServerLoad(Container $container): ServerLoad
{
return new ServerLoad(
$container->get('Crypt'),
$container->get('Table')
);
}

View File

@ -0,0 +1,477 @@
/**
* The active placeholders
*
* @var array
* @since 3.2.0
**/
public array $active = [];
/**
* Compiler Config
*
* @var Config
* @since 3.2.0
**/
protected Config $config;
/**
* Constructor.
*
* @param Config|null $config The compiler config object.
*
* @since 3.2.0
*/
public function __construct(?Config $config = null)
{
$this->config = $config ?: Compiler::_('Config');
}
/**
* Set content
*
* @param string $key The main string key
* @param mixed $value The values to set
* @param bool $hash Add the hash around the key
*
* @return void
* @since 3.2.0
*/
public function set(string $key, $value, bool $hash = true)
{
if ($hash)
{
$this->set_($key, $value);
$this->set_h($key, $value);
}
else
{
$this->active[$key] = $value;
}
}
/**
* Get content by key
*
* @param string $key The main string key
*
* @return mixed
* @since 3.2.0
*/
public function get(string $key)
{
return $this->active[$key] ?? $this->get_($key) ?? $this->get_h($key) ?? null;
}
/**
* Does key exist at all in any variation
*
* @param string $key The main string key
*
* @return bool
* @since 3.2.0
*/
public function exist(string $key): bool
{
return isset($this->active[$key]) || $this->exist_($key) || $this->exist_h($key);
}
/**
* Add content
*
* @param string $key The main string key
* @param mixed $value The values to set
* @param bool $hash Add the hash around the key
*
* @return void
* @since 3.2.0
*/
public function add(string $key, $value, bool $hash = true)
{
if ($hash)
{
$this->add_($key, $value);
$this->add_h($key, $value);
}
elseif (isset($this->active[$key]))
{
$this->active[$key] .= $value;
}
else
{
$this->active[$key] = $value;
}
}
/**
* Remove content
*
* @param string $key The main string key
*
* @return void
* @since 3.2.0
*/
public function remove(string $key)
{
if (isset($this->active[$key]))
{
unset($this->active[$key]);
}
else
{
$this->remove_($key);
$this->remove_h($key);
}
}
/**
* Set content with [ [ [ ... ] ] ] hash
*
* @param string $key The main string key
* @param mixed $value The values to set
*
* @return void
* @since 3.2.0
*/
public function set_(string $key, $value)
{
$this->active[Placefix::_($key)] = $value;
}
/**
* Get content with [ [ [ ... ] ] ] hash
*
* @param string $key The main string key
*
* @return mixed
* @since 3.2.0
*/
public function get_(string $key)
{
return $this->active[Placefix::_($key)] ?? null;
}
/**
* Does key exist with [ [ [ ... ] ] ] hash
*
* @param string $key The main string key
*
* @return bool
* @since 3.2.0
*/
public function exist_(string $key): bool
{
return isset($this->active[Placefix::_($key)]);
}
/**
* Add content with [ [ [ ... ] ] ] hash
*
* @param string $key The main string key
* @param mixed $value The values to set
*
* @return void
* @since 3.2.0
*/
public function add_(string $key, $value)
{
if (isset($this->active[Placefix::_($key)]))
{
$this->active[Placefix::_($key)] .= $value;
}
else
{
$this->active[Placefix::_($key)] = $value;
}
}
/**
* Remove content with [ [ [ ... ] ] ] hash
*
* @param string $key The main string key
*
* @return void
* @since 3.2.0
*/
public function remove_(string $key)
{
if ($this->exist_($key))
{
unset($this->active[Placefix::_($key)]);
}
}
/**
* Set content with # # # hash
*
* @param string $key The main string key
* @param mixed $value The values to set
*
* @return void
* @since 3.2.0
*/
public function set_h(string $key, $value)
{
$this->active[Placefix::_h($key)] = $value;
}
/**
* Get content with # # # hash
*
* @param string $key The main string key
*
* @return mixed
* @since 3.2.0
*/
public function get_h(string $key)
{
return $this->active[Placefix::_h($key)] ?? null;
}
/**
* Does key exist with # # # hash
*
* @param string $key The main string key
*
* @return bool
* @since 3.2.0
*/
public function exist_h(string $key): bool
{
return isset($this->active[Placefix::_h($key)]);
}
/**
* Add content with # # # hash
*
* @param string $key The main string key
* @param mixed $value The values to set
*
* @return void
* @since 3.2.0
*/
public function add_h(string $key, $value)
{
if ($this->exist_h($key))
{
$this->active[Placefix::_h($key)] .= $value;
}
else
{
$this->active[Placefix::_h($key)] = $value;
}
}
/**
* Remove content with # # # hash
*
* @param string $key The main string key
*
* @return void
* @since 3.2.0
*/
public function remove_h(string $key)
{
if ($this->exist_h($key))
{
unset($this->active[Placefix::_h($key)]);
}
}
/**
* Set a type of placeholder with set of values
*
* @param string $key The main string for placeholder key
* @param array $values The values to add
*
* @return void
* @since 3.2.0
*/
public function setType(string $key, array $values)
{
// always fist reset the type
$this->clearType($key);
// only add if there are values
if (ArrayHelper::check($values))
{
$number = 0;
foreach ($values as $value)
{
$this->set($key . $number, $value);
$number++;
}
}
}
/**
* Remove a type of placeholder by main key
*
* @param string $key The main string for placeholder key
*
* @return void
* @since 3.2.0
*/
public function clearType(string $key)
{
$keys = [Placefix::_($key), Placefix::_h($key), $key];
foreach ($keys as $_key)
{
$this->active = array_filter(
$this->active,
fn(string $k) => preg_replace('/\d/', '', $k) !== $_key,
ARRAY_FILTER_USE_KEY
);
}
}
/**
* Update the data with the placeholders
*
* @param string $data The actual data
* @param array $placeholder The placeholders
* @param int $action The action to use
*
* THE ACTION OPTIONS ARE
* 1 -> Just replace (default)
* 2 -> Check if data string has placeholders
* 3 -> Remove placeholders not in data string
*
* @return string
* @since 3.2.0
*/
public function update(string $data, array $placeholder, int $action = 1): string
{
// make sure the placeholders is an array
if (!ArrayHelper::check($placeholder))
{
return $data;
}
// continue with the work of replacement
if (1 == $action) // <-- just replace (default)
{
return str_replace(
array_keys($placeholder), array_values($placeholder), $data
);
}
elseif (2 == $action) // <-- check if data string has placeholders
{
$replace = false;
foreach (array_keys($placeholder) as $key)
{
if (strpos($data, $key) !== false)
{
$replace = true;
break;
}
}
// only replace if the data has these placeholder values
if ($replace)
{
return str_replace(
array_keys($placeholder), array_values($placeholder), $data
);
}
}
elseif (3 == $action) // <-- remove placeholders not in data string
{
$replace = $placeholder;
foreach (array_keys($replace) as $key)
{
if (strpos($data, $key) === false)
{
unset($replace[$key]);
}
}
// only replace if the data has these placeholder values
if (ArrayHelper::check($replace))
{
return str_replace(
array_keys($replace), array_values($replace), $data
);
}
}
return $data;
}
/**
* Update the data with the active placeholders
*
* @param string $data The actual data
*
* @return string
* @since 3.2.0
*/
public function update_(string $data): string
{
// just replace the placeholders in data
return str_replace(
array_keys($this->active), array_values($this->active), $data
);
}
/**
* return the placeholders for inserted and replaced code
*
* @param int $type The type of placement
* @param int|null $id The code id in the system
*
* @return array with start and end keys
* @since 3.2.0
*/
public function keys(int $type, ?int $id = null): array
{
switch ($type)
{
case 11:
//***[REPLACED$$$$]***//**1**/
if ($this->config->get('add_placeholders', false) === true)
{
return [
'start' => '/***[REPLACED$$$$]***//**' . $id . '**/',
'end' => '/***[/REPLACED$$$$]***/'
];
}
break;
case 12:
//***[INSERTED$$$$]***//**1**/
if ($this->config->get('add_placeholders', false) === true)
{
return [
'start' => '/***[INSERTED$$$$]***//**' . $id . '**/',
'end' => '/***[/INSERTED$$$$]***/'
];
}
break;
case 21:
//<!--[REPLACED$$$$]--><!--1-->
if ($this->config->get('add_placeholders', false) === true)
{
return [
'start' => '<!--[REPLACED$$$$]--><!--' . $id . '-->',
'end' => '<!--[/REPLACED$$$$]-->'
];
}
break;
case 22:
//<!--[INSERTED$$$$]--><!--1-->
if ($this->config->get('add_placeholders', false) === true)
{
return [
'start' => '<!--[INSERTED$$$$]--><!--' . $id . '-->',
'end' => '<!--[/INSERTED$$$$]-->'
];
}
break;
case 33:
return ['start' => Placefix::h(), 'end' => Placefix::h()];
break;
case 66:
return ['start' => Placefix::b(), 'end' => Placefix::d()];
break;
}
return [ 'start' => "", 'end' => ""];
}

View File

@ -0,0 +1,840 @@
/**
* Compiler Joomla Module Data Class
*
* @var Module
* @since 3.2.0
*/
protected Module $module;
/**
* Compiler Component
*
* @var Component
* @since 3.2.0
**/
protected Component $component;
/**
* Compiler Config
*
* @var Config
* @since 3.2.0
*/
protected Config $config;
/**
* The compiler registry
*
* @var Registry
* @since 3.2.0
*/
protected Registry $registry;
/**
* Compiler Customcode Dispenser
*
* @var Dispenser
* @since 3.2.0
*/
protected Dispenser $dispenser;
/**
* Compiler Event
*
* @var EventInterface
* @since 3.2.0
*/
protected EventInterface $event;
/**
* Compiler Counter
*
* @var Counter
* @since 3.2.0
*/
protected Counter $counter;
/**
* Compiler Utilities Folder
*
* @var Folder
* @since 3.2.0
*/
protected Folder $folder;
/**
* Compiler Utilities File
*
* @var File
* @since 3.2.0
*/
protected File $file;
/**
* Compiler Utilities Files
*
* @var Files
* @since 3.2.0
*/
protected Files $files;
/**
* Constructor
*
* @param Module|null $module The compiler Joomla module data object.
* @param Component|null $component The component class.
* @param Config|null $config The compiler config object.
* @param Registry|null $registry The compiler registry object.
* @param Dispenser|null $dispenser The compiler customcode dispenser object.
* @param EventInterface|null $event The compiler event api object.
* @param Counter|null $counter The compiler counter object.
* @param Folder|null $folder The compiler folder object.
* @param File|null $file The compiler file object.
* @param Files|null $files The compiler files object.
*
* @since 3.2.0
*/
public function __construct(?Module $module = null, ?Component $component = null,
?Config $config = null, ?Registry $registry = null,
?Dispenser $dispenser = null, ?EventInterface $event = null,
?Counter $counter = null, ?Folder $folder = null,
?File $file = null, ?Files $files = null)
{
$this->module = $module ?: Compiler::_('Joomlamodule.Data');
$this->component = $component ?: Compiler::_('Component');
$this->config = $config ?: Compiler::_('Config');
$this->registry = $registry ?: Compiler::_('Registry');
$this->dispenser = $dispenser ?: Compiler::_('Customcode.Dispenser');
$this->event = $event ?: Compiler::_('Event');
$this->counter = $counter ?: Compiler::_('Utilities.Counter');
$this->folder = $folder ?: Compiler::_('Utilities.Folder');
$this->file = $file ?: Compiler::_('Utilities.File');
$this->files = $files ?: Compiler::_('Utilities.Files');
}
/**
* Build the Modules files, folders, url's and config
*
* @return void
* @since 3.2.0
*/
public function build()
{
if ($this->module->exists())
{
// for plugin event TODO change event api signatures
$component_context = $this->config->component_context;
$modules = $this->module->get();
// Trigger Event: jcb_ce_onBeforeSetModules
$this->event->trigger(
'jcb_ce_onBeforeBuildModules',
array(&$component_context, &$modules)
);
foreach ($modules as $module)
{
if (ObjectHelper::check($module)
&& isset($module->folder_name)
&& StringHelper::check(
$module->folder_name
))
{
// module path
$module->folder_path = $this->config->get('compiler_path', JPATH_COMPONENT_ADMINISTRATOR . '/compiler') . '/'
. $module->folder_name;
// set the module paths
$this->registry->set('dynamic_paths.' . $module->key, $module->folder_path);
// make sure there is no old build
$this->folder->remove($module->folder_path);
// creat the main module folder
$this->folder->create($module->folder_path);
// set main mod file
$fileDetails = array('path' => $module->folder_path . '/'
. $module->file_name . '.php',
'name' => $module->file_name . '.php',
'zip' => $module->file_name . '.php');
$this->file->write(
$fileDetails['path'],
'<?php' . PHP_EOL . '// main modfile' .
PHP_EOL . Placefix::_h('BOM') . PHP_EOL .
PHP_EOL . '// No direct access to this file' . PHP_EOL .
"defined('_JEXEC') or die('Restricted access');"
. PHP_EOL .
Placefix::_h('MODCODE')
);
$this->files->appendArray($module->key, $fileDetails);
// count the file created
$this->counter->file++;
// set custom_get
if ($module->custom_get)
{
$fileDetails = array(
'path' => $module->folder_path . '/data.php',
'name' => 'data.php',
'zip' => 'data.php'
);
$this->file->write(
$fileDetails['path'],
'<?php' . PHP_EOL . '// get data file' .
PHP_EOL . Placefix::_h('BOM') . PHP_EOL
.
PHP_EOL . '// No direct access to this file'
. PHP_EOL .
"defined('_JEXEC') or die('Restricted access');"
. PHP_EOL . PHP_EOL .
'/**' . PHP_EOL .
' * Module ' . $module->official_name . ' Data'
. PHP_EOL .
' */' . PHP_EOL .
"class " . $module->class_data_name
. ' extends \JObject' . PHP_EOL .
"{" . Placefix::_h('DYNAMICGETS') . "}"
. PHP_EOL
);
$this->files->appendArray($module->key, $fileDetails);
// count the file created
$this->counter->file++;
}
// set helper file
if ($module->add_class_helper >= 1)
{
$fileDetails = array('path' => $module->folder_path
. '/helper.php',
'name' => 'helper.php',
'zip' => 'helper.php');
$this->file->write(
$fileDetails['path'],
'<?php' . PHP_EOL . '// helper file' .
PHP_EOL . Placefix::_h('BOM') . PHP_EOL
.
PHP_EOL . '// No direct access to this file'
. PHP_EOL .
"defined('_JEXEC') or die('Restricted access');"
. PHP_EOL .
Placefix::_h('HELPERCODE')
);
$this->files->appendArray($module->key, $fileDetails);
// count the file created
$this->counter->file++;
}
// set main xml file
$fileDetails = array('path' => $module->folder_path . '/'
. $module->file_name . '.xml',
'name' => $module->file_name . '.xml',
'zip' => $module->file_name . '.xml');
$this->file->write(
$fileDetails['path'],
$this->getXML($module)
);
$this->files->appendArray($module->key, $fileDetails);
// count the file created
$this->counter->file++;
// set tmpl folder
$this->folder->create($module->folder_path . '/tmpl');
// set default file
$fileDetails = array('path' => $module->folder_path
. '/tmpl/default.php',
'name' => 'default.php',
'zip' => 'tmpl/default.php');
$this->file->write(
$fileDetails['path'],
'<?php' . PHP_EOL . '// default tmpl' .
PHP_EOL . Placefix::_h('BOM') . PHP_EOL .
PHP_EOL . '// No direct access to this file' . PHP_EOL .
"defined('_JEXEC') or die('Restricted access');"
. PHP_EOL .
Placefix::_h('MODDEFAULT')
);
$this->files->appendArray($module->key, $fileDetails);
// count the file created
$this->counter->file++;
// set install script if needed
if ($module->add_install_script)
{
$fileDetails = [
'path' => $module->folder_path . '/script.php',
'name' => 'script.php',
'zip' => 'script.php'
];
$this->file->write(
$fileDetails['path'],
'<?php' . PHP_EOL . '// Script template' .
PHP_EOL . Placefix::_h('BOM') . PHP_EOL .
PHP_EOL . '// No direct access to this file' . PHP_EOL .
"defined('_JEXEC') or die('Restricted access');" . PHP_EOL .
Placefix::_h('INSTALLCLASS')
);
$this->files->appendArray($module->key, $fileDetails);
// count the file created
$this->counter->file++;
}
// set readme if found
if ($module->addreadme)
{
$fileDetails = [
'path' => $module->folder_path . '/README.md',
'name' => 'README.md',
'zip' => 'README.md'
];
$this->file->write($fileDetails['path'], $module->readme);
$this->files->appendArray($module->key, $fileDetails);
// count the file created
$this->counter->file++;
}
// set the folders target path
$target_path = '';
if ($module->target_client === 'administrator')
{
$target_path = '/administrator';
}
// check if we have custom fields needed for scripts
$module->add_scripts_field = false;
$field_script_bucket = [];
// add any css from the fields
if (($css = $this->dispenser->get(
'css_view', $module->key
)) !== null
&& StringHelper::check($css))
{
// make sure this script does not have PHP
if (strpos((string) $css, '<?php') === false)
{
// make sure the field is added
$module->add_scripts_field = true;
// create the css folder
$this->folder->create($module->folder_path . '/css');
// add the CSS file
$fileDetails = [
'path' => $module->folder_path . '/css/mod_admin.css',
'name' => 'mod_admin.css',
'zip' => 'mod_admin.css'
];
$this->file->write(
$fileDetails['path'],
Placefix::_h('BOM') . PHP_EOL
. PHP_EOL . $css
);
$this->files->appendArray($module->key, $fileDetails);
// count the file created
$this->counter->file++;
// add the field script
$field_script_bucket[] = Indent::_(2) . "//"
. Line::_(__Line__, __Class__) . " Custom CSS";
$field_script_bucket[] = Indent::_(2)
. "\$document->addStyleSheet('" . $target_path
. "/modules/" . $module->folder_name
. "/css/mod_admin.css', ['version' => 'auto', 'relative' => true]);";
}
}
// add any JavaScript from the fields
if (($javascript = $this->dispenser->get(
'view_footer', $module->key
)) !== null
&& StringHelper::check($javascript))
{
// make sure this script does not have PHP
if (strpos((string) $javascript, '<?php') === false)
{
// make sure the field is added
$module->add_scripts_field = true;
// add the JavaScript file
$this->folder->create($module->folder_path . '/js');
// add the CSS file
$fileDetails = [
'path' => $module->folder_path . '/js/mod_admin.js',
'name' => 'mod_admin.js',
'zip' => 'mod_admin.js'
];
$this->file->write(
$fileDetails['path'],
Placefix::_h('BOM') . PHP_EOL
. PHP_EOL . $javascript
);
$this->files->appendArray($module->key, $fileDetails);
// count the file created
$this->counter->file++;
// add the field script
$field_script_bucket[] = Indent::_(2) . "//"
. Line::_(__Line__, __Class__) . " Custom JS";
$field_script_bucket[] = Indent::_(2)
. "\$document->addScript('" . $target_path
. "/modules/" . $module->folder_name
. "/js/mod_admin.js', ['version' => 'auto', 'relative' => true]);";
}
}
// set fields folders if needed
if ($module->add_scripts_field
|| (isset($module->fields_rules_paths)
&& $module->fields_rules_paths == 2))
{
// create fields folder
$this->folder->create($module->folder_path . '/fields');
// add the custom script field
if ($module->add_scripts_field)
{
$fileDetails = [
'path' => $module->folder_path
. '/fields/modadminvvvvvvvdm.php',
'name' => 'modadminvvvvvvvdm.php',
'zip' => 'modadminvvvvvvvdm.php'
];
$this->file->write(
$fileDetails['path'],
$this->getCustomScriptField(
$field_script_bucket
)
);
$this->files->appendArray($module->key, $fileDetails);
// count the file created
$this->counter->file++;
}
}
// set rules folders if needed
if (isset($module->fields_rules_paths)
&& $module->fields_rules_paths == 2)
{
// create rules folder
$this->folder->create($module->folder_path . '/rules');
}
// set forms folder if needed
if (isset($module->form_files)
&& ArrayHelper::check(
$module->form_files
))
{
// create forms folder
$this->folder->create($module->folder_path . '/forms');
// set the template files
foreach ($module->form_files as $file => $fields)
{
// set file details
$fileDetails = [
'path' => $module->folder_path . '/forms/' . $file . '.xml',
'name' => $file . '.xml',
'zip' => 'forms/' . $file . '.xml'
];
// build basic XML
$xml = '<?xml version="1.0" encoding="utf-8"?>';
$xml .= PHP_EOL . '<!--' . Line::_(__Line__, __Class__)
. ' default paths of ' . $file
. ' form points to ' . $this->config->component_code_name
. ' -->';
// search if we must add the component path
$add_component_path = false;
foreach ($fields as $field_name => $fieldsets)
{
if (!$add_component_path)
{
foreach ($fieldsets as $fieldset => $field)
{
if (!$add_component_path
&& isset(
$module->fieldsets_paths[$file
. $field_name . $fieldset]
)
&& $module->fieldsets_paths[$file
. $field_name . $fieldset] == 1)
{
$add_component_path = true;
}
}
}
}
// only add if part of the component field types path is required
if ($add_component_path)
{
$xml .= PHP_EOL . '<form';
$xml .= PHP_EOL . Indent::_(1)
. 'addrulepath="/administrator/components/com_'
. $this->config->component_code_name
. '/models/rules"';
$xml .= PHP_EOL . Indent::_(1)
. 'addfieldpath="/administrator/components/com_'
. $this->config->component_code_name
. '/models/fields"';
$xml .= PHP_EOL . '>';
}
else
{
$xml .= PHP_EOL . '<form>';
}
// add the fields
foreach ($fields as $field_name => $fieldsets)
{
// check if we have an double fields naming set
$field_name_inner = '';
$field_name_outer = $field_name;
if (strpos((string) $field_name, '.') !== false)
{
$field_names = explode('.', (string) $field_name);
if (count((array) $field_names) == 2)
{
$field_name_outer = $field_names[0];
$field_name_inner = $field_names[1];
}
}
$xml .= PHP_EOL . Indent::_(1)
. '<fields name="' . $field_name_outer
. '">';
foreach ($fieldsets as $fieldset => $field)
{
// default to the field set name
$label = $fieldset;
if (isset($module->fieldsets_label[$file . $field_name . $fieldset]))
{
$label = $module->fieldsets_label[$file . $field_name . $fieldset];
}
// add path to module rules and custom fields
if (isset($module->fieldsets_paths[$file . $field_name . $fieldset])
&& ($module->fieldsets_paths[$file . $field_name . $fieldset] == 2
|| $module->fieldsets_paths[$file . $field_name . $fieldset] == 3))
{
if ($module->target == 2)
{
if (!isset($module->add_rule_path[$file . $field_name . $fieldset]))
{
$module->add_rule_path[$file . $field_name . $fieldset] =
'/administrator/modules/'
. $module->file_name . '/rules';
}
if (!isset($module->add_field_path[$file . $field_name . $fieldset]))
{
$module->add_field_path[$file . $field_name . $fieldset] =
'/administrator/modules/'
. $module->file_name . '/fields';
}
}
else
{
if (!isset($module->add_rule_path[$file . $field_name . $fieldset]))
{
$module->add_rule_path[$file . $field_name . $fieldset] =
'/modules/' . $module->file_name
. '/rules';
}
if (!isset($module->add_field_path[$file . $field_name . $fieldset]))
{
$module->add_field_path[$file . $field_name . $fieldset] =
'/modules/' . $module->file_name
. '/fields';
}
}
}
// add path to module rules and custom fields
if (isset($module->add_rule_path[$file . $field_name . $fieldset])
|| isset($module->add_field_path[$file . $field_name . $fieldset]))
{
$xml .= PHP_EOL . Indent::_(1) . '<!--'
. Line::_(__Line__, __Class__) . ' default paths of '
. $fieldset . ' fieldset points to the module -->';
$xml .= PHP_EOL . Indent::_(1) . '<fieldset name="'
. $fieldset . '" label="' . $label . '"';
if (isset($module->add_rule_path[$file . $field_name . $fieldset]))
{
$xml .= PHP_EOL . Indent::_(2)
. 'addrulepath="' . $module->add_rule_path[$file . $field_name . $fieldset] . '"';
}
if (isset($module->add_field_path[$file . $field_name . $fieldset]))
{
$xml .= PHP_EOL . Indent::_(2)
. 'addfieldpath="' . $module->add_field_path[$file . $field_name . $fieldset] . '"';
}
$xml .= PHP_EOL . Indent::_(1) . '>';
}
else
{
$xml .= PHP_EOL . Indent::_(1) . '<fieldset name="'
. $fieldset . '" label="' . $label . '">';
}
// check if we have an inner field set
if (StringHelper::check(
$field_name_inner
))
{
$xml .= PHP_EOL . Indent::_(1)
. '<fields name="'
. $field_name_inner . '">';
}
// add the placeholder of the fields
$xml .= Placefix::_h('FIELDSET_' . $file
. $field_name . $fieldset );
// check if we have an inner field set
if (StringHelper::check(
$field_name_inner
))
{
$xml .= PHP_EOL . Indent::_(1)
. '</fields>';
}
$xml .= PHP_EOL . Indent::_(1)
. '</fieldset>';
}
$xml .= PHP_EOL . Indent::_(1) . '</fields>';
}
$xml .= PHP_EOL . '</form>';
// add xml to file
$this->file->write($fileDetails['path'], $xml);
$this->files->appendArray($module->key, $fileDetails);
// count the file created
$this->counter->file++;
}
}
// set SQL stuff if needed
if ($module->add_sql || $module->add_sql_uninstall)
{
// create SQL folder
$this->folder->create($module->folder_path . '/sql');
// create mysql folder
$this->folder->create(
$module->folder_path . '/sql/mysql'
);
// now set the install file
if ($module->add_sql)
{
$this->file->write(
$module->folder_path . '/sql/mysql/install.sql',
$module->sql
);
// count the file created
$this->counter->file++;
}
// now set the uninstall file
if ($module->add_sql_uninstall)
{
$this->file->write(
$module->folder_path
. '/sql/mysql/uninstall.sql',
$module->sql_uninstall
);
// count the file created
$this->counter->file++;
}
}
// creat the language folder
$this->folder->create($module->folder_path . '/language');
// also create the lang tag folder
$this->folder->create(
$module->folder_path . '/language/' . $this->config->get('lang_tag', 'en-GB')
);
// check if this lib has files
if (isset($module->files)
&& ArrayHelper::check($module->files))
{
// add to component files
foreach ($module->files as $file)
{
// set the pathfinder
$file['target_type'] = $module->target_type;
$file['target_id'] = $module->id;
$this->component->appendArray('files', $file);
}
}
// check if this lib has folders
if (isset($module->folders)
&& ArrayHelper::check($module->folders))
{
// add to component folders
foreach ($module->folders as $folder)
{
// set the pathfinder
$folder['target_type'] = $module->target_type;
$folder['target_id'] = $module->id;
$this->component->appendArray('folders', $folder);
}
}
// check if this module has urls
if (isset($module->urls)
&& ArrayHelper::check($module->urls))
{
// add to component urls
foreach ($module->urls as $n => &$url)
{
// should we add the local folder
if (isset($url['type']) && $url['type'] > 1
&& isset($url['url'])
&& StringHelper::check(
$url['url']
))
{
// set file name
$fileName = basename((string) $url['url']);
// get the file contents
$data = FileHelper::getContent(
$url['url']
);
// build sub path
if (strpos($fileName, '.js') !== false)
{
$path = '/js';
}
elseif (strpos($fileName, '.css') !== false)
{
$path = '/css';
}
else
{
$path = '';
}
// create sub media path if not set
$this->folder->create(
$module->folder_path . $path
);
// set the path to module file
$url['path'] = $module->folder_path . $path
. '/' . $fileName; // we need this for later
// write data to path
$this->file->write($url['path'], $data);
// count the file created
$this->counter->file++;
}
}
}
}
}
}
}
/**
* get the module xml template
*
* @param object $module The module object
*
* @return string
* @since 3.2.0
*/
protected function getXML(object &$module): string
{
$xml = '<?xml version="1.0" encoding="utf-8"?>';
$xml .= PHP_EOL . '<extension type="module" version="'
. $this->config->joomla_versions[$this->config->joomla_version]['xml_version'] . '" client="'
. $module->target_client . '" method="upgrade">';
$xml .= PHP_EOL . Indent::_(1) . '<name>' . $module->lang_prefix
. '</name>';
$xml .= PHP_EOL . Indent::_(1) . '<creationDate>' . Placefix::_h('BUILDDATE') . '</creationDate>';
$xml .= PHP_EOL . Indent::_(1) . '<author>' . Placefix::_h('AUTHOR') . '</author>';
$xml .= PHP_EOL . Indent::_(1) . '<authorEmail>' . Placefix::_h('AUTHOREMAIL') . '</authorEmail>';
$xml .= PHP_EOL . Indent::_(1) . '<authorUrl>' . Placefix::_h('AUTHORWEBSITE') . '</authorUrl>';
$xml .= PHP_EOL . Indent::_(1) . '<copyright>' . Placefix::_h('COPYRIGHT') . '</copyright>';
$xml .= PHP_EOL . Indent::_(1) . '<license>' . Placefix::_h('LICENSE') . '</license>';
$xml .= PHP_EOL . Indent::_(1) . '<version>' . $module->module_version
. '</version>';
$xml .= PHP_EOL . Indent::_(1) . '<description>' . $module->lang_prefix
. '_XML_DESCRIPTION</description>';
$xml .= Placefix::_h('MAINXML');
$xml .= PHP_EOL . '</extension>';
return $xml;
}
/**
* get the module admin custom script field
*
* @param array $fieldScriptBucket The field
*
* @return string
* @since 3.2.0
*
*/
protected function getCustomScriptField(array $fieldScriptBucket): string
{
$form_field_class = [];
$form_field_class[] = Placefix::_h('BOM') . PHP_EOL;
$form_field_class[] = "//" . Line::_(__Line__, __Class__)
. " No direct access to this file";
$form_field_class[] = "defined('_JEXEC') or die('Restricted access');";
$form_field_class[] = PHP_EOL . "use Joomla\CMS\Form\FormField;";
$form_field_class[] = "use Joomla\CMS\Factory;";
$form_field_class[] = PHP_EOL
. "class JFormFieldModadminvvvvvvvdm extends FormField";
$form_field_class[] = "{";
$form_field_class[] = Indent::_(1)
. "protected \$type = 'modadminvvvvvvvdm';";
$form_field_class[] = PHP_EOL . Indent::_(1)
. "protected function getLabel()";
$form_field_class[] = Indent::_(1) . "{";
$form_field_class[] = Indent::_(2) . "return;";
$form_field_class[] = Indent::_(1) . "}";
$form_field_class[] = PHP_EOL . Indent::_(1)
. "protected function getInput()";
$form_field_class[] = Indent::_(1) . "{";
$form_field_class[] = Indent::_(2) . "//" . Line::_(__Line__, __Class__)
. " Get the document";
$form_field_class[] = Indent::_(2)
. "\$document = Factory::getDocument();";
$form_field_class[] = implode(PHP_EOL, $fieldScriptBucket);
$form_field_class[] = Indent::_(2) . "return; // noting for now :)";
$form_field_class[] = Indent::_(1) . "}";
$form_field_class[] = "}";
return implode(PHP_EOL, $form_field_class);
}

View File

@ -0,0 +1,379 @@
/**
* 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 (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,
'final' => 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->linkPowerGuid($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'] . ')';
}
/**
* Build the Link with GUID text to the power in this repository
*
* @param string $power The power details.
*
* @return string
* @since 3.2.0
*/
private function linkPowerGuid(array &$power): string
{
return '[' . $power['guid'] . '](' . $power['path'] . ')';
}

View File

@ -0,0 +1,155 @@
/**
* Compiler Config
*
* @var Config
* @since 3.2.0
*/
protected Config $config;
/**
* The compiler registry
*
* @var Registry
* @since 3.2.0
*/
protected Registry $registry;
/**
* Constructor
*
* @param Config|null $config The compiler config object.
* @param Registry|null $registry The compiler registry object.
*
* @since 3.2.0
*/
public function __construct(?Config $config = null, ?Registry $registry = null)
{
$this->config = $config ?: Compiler::_('Config');
$this->registry = $registry ?: Compiler::_('Registry');
}
/**
* Automatically load some stuff
*
* @param string $key The key mapper
* @param string $content The content to search through
* @param string|null $target The area being targeted
*
* @return void
* @since 3.2.0
*/
public function set(string $key, string $content, ?string $target = null)
{
// set the target
$target = $target ?: $this->config->build_target;
// check for footable
if (!$this->registry->
exists('builder.footable_scripts.' . $target . '.' . $key))
{
if ($this->getFootableScripts($content))
{
$this->registry->
set('builder.footable_scripts.' . $target . '.' . $key, true);
$this->config->set('footable', true);
}
}
// check for google chart
if (!$this->registry->
exists('builder.google_chart.' . $target . '.' . $key))
{
if ($this->getGoogleChart($content))
{
$this->registry->
set('builder.google_chart.' . $target . '.' . $key, true);
$this->config->set('google_chart', true);
}
}
// check for get module
if (!$this->registry->
exists('builder.get_module.' . $target . '.' . $key))
{
if ($this->getGetModule($content))
{
$this->registry->
set('builder.get_module.' . $target . '.' . $key, true);
}
}
}
/**
* Automatically load uikit version 2 data files
*
* @param string $key The key mapper
* @param string $content The content to search through
*
* @return void
* @since 3.2.0
*/
public function uikit(string $key, string $content)
{
// get/set uikit state
$uikit = false;
$uikit_ = $this->config->get('uikit', 0);
// add uikit if required
if (2 == $uikit_ || 1 == $uikit_)
{
$uikit = true;
}
// load uikit
if ($uikit)
{
// set uikit to views TODO: convert this getUikitComp to a class
if (($found = Helper::_('getUikitComp',
[$content, (array) $this->registry->get('builder.uikit_comp.' . $key, [])]
)) !== false)
{
$this->registry->set('builder.uikit_comp.' . $key, $found);
}
}
}
/**
* Check for footable scripts
*
* @param string $content The content to check
*
* @return boolean True if found
* @since 3.2.0
*/
protected function getFootableScripts(string &$content): bool
{
return strpos($content, 'footable') !== false;
}
/**
* Check for getModules script
*
* @param string $content The content to check
*
* @return boolean True if found
* @since 3.2.0
*/
protected function getGetModule(string &$content): bool
{
return strpos($content, 'this->getModules(') !== false;
}
/**
* Check for get Google Chart script
*
* @param string $content The content to check
*
* @return boolean True if found
* @since 3.2.0
*/
protected function getGoogleChart(string &$content): bool
{
return strpos($content, 'Chartbuilder(') !== false;
}

View File

@ -0,0 +1,21 @@
/**
* Set the local tabs
*
* @param object $item The view data
*
* @return void
* @since 3.2.0
*/
public function set(object &$item)
{
$item->addpermissions = (isset($item->addpermissions)
&& JsonHelper::check($item->addpermissions))
? json_decode((string) $item->addpermissions, true) : null;
if (ArrayHelper::check($item->addpermissions))
{
$item->permissions = array_values($item->addpermissions);
}
unset($item->addpermissions);
}

View File

@ -0,0 +1,20 @@
/**
* load all the powers linked to this component
*
* @param array $guids The global unique ids of the linked powers
*
* @return void
* @since 3.2.0
*/
public function load(array $guids);
/**
* Get a power
*
* @param string $guid The global unique id of the power
* @param int $build Force build switch (to override global switch)
*
* @return mixed
* @since 3.2.0
*/
public function get(string $guid, int $build = 0);

View File

@ -0,0 +1,43 @@
/**
* Set the local tabs
*
* @param object $item The view data
*
* @return void
* @since 3.2.0
*/
public function set(object &$item)
{
$item->addtabs = (isset($item->addtabs)
&& JsonHelper::check($item->addtabs))
? json_decode((string) $item->addtabs, true) : null;
if (ArrayHelper::check($item->addtabs))
{
$nr = 1;
foreach ($item->addtabs as $tab)
{
$item->tabs[$nr] = trim((string) $tab['name']);
$nr++;
}
}
// if Details tab is not set, then set it here
if (!isset($item->tabs[1]))
{
$item->tabs[1] = 'Details';
}
// always make sure that publishing is lowercase
if (($removeKey = array_search(
'publishing', array_map('strtolower', $item->tabs)
)) !== false)
{
$item->tabs[$removeKey] = 'publishing';
}
// make sure to set the publishing tab (just in case we need it)
$item->tabs[15] = 'publishing';
unset($item->addtabs);
}

View File

@ -0,0 +1,117 @@
/**
* The compiler Config
*
* @var Config
* @since 3.2.0
*/
protected Config $config;
/**
* The compiler history
*
* @var HistoryInterface
* @since 3.2.0
*/
protected HistoryInterface $history;
/**
* The compiler update sql
*
* @var Updatesql
* @since 3.2.0
*/
protected Updatesql $updatesql;
/**
* Constructor
*
* @param Config|null $config The compiler config object.
* @param HistoryInterface|null $history The compiler history object.
* @param Updatesql|null $updatesql The compiler updatesql object.
*
* @since 3.2.0
*/
public function __construct(?Config $config = null, ?HistoryInterface $history = null,
?Updatesql $updatesql = null)
{
$this->config = $config ?: Compiler::_('Config');
$this->history = $history ?: Compiler::_('History');
$this->updatesql = $updatesql ?: Compiler::_('Model.Updatesql');
}
/**
* check if an update SQL is needed
*
* @param object $item The item data
*
* @return void
* @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
);
// check if a new version was manually set
if ($old_component && 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;
}
}
}

View File

@ -0,0 +1,23 @@
/**
* The extension official name
*
* @return string
* @since 3.2.0
*/
public function getOfficialName(): string;
/**
* The extension class name
*
* @return string
* @since 3.2.0
*/
public function getClassName(): string;
/**
* The extension installer class name
*
* @return string
* @since 3.2.0
*/
public function getInstallerClassName(): string;

View File

@ -0,0 +1,214 @@
/**
* Compiler Config
*
* @var Config
* @since 3.2.0
**/
protected Config $config;
/**
* Compiler Placeholder Reverse
*
* @var Reverse
* @since 3.2.0
**/
protected Reverse $reverse;
/**
* Database object to query local DB
*
* @var \JDatabaseDriver
* @since 3.2.0
**/
protected \JDatabaseDriver $db;
/**
* Database object to query local DB
*
* @var CMSApplication
* @since 3.2.0
**/
protected CMSApplication $app;
/**
* Constructor.
*
* @param Config|null $config The compiler config object.
* @param Reverse|null $reverse The compiler placeholder reverse 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,
?\JDatabaseDriver $db = null, ?CMSApplication $app = null)
{
$this->config = $config ?: Compiler::_('Config');
$this->reverse = $reverse ?: Compiler::_('Placeholder.Reverse');
$this->db = $db ?: Factory::getDbo();
$this->app = $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('ID mismatch was detected with the %s.%s.%s.%s 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_conent = FileHelper::getContent($file);
$guiCode = [];
// we add a new search for the GUI CODE Blocks
$guiCode[] = GetHelper::allBetween(
$file_conent, '/***[JCB' . 'GUI<>', '/***[/JCBGUI' . '$$$$]***/'
);
$guiCode[] = GetHelper::allBetween(
$file_conent, '<!--[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
);
// 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;
}

View File

@ -0,0 +1,361 @@
/**
* 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
*
* @var \JDatabaseDriver
* @since 3.2.0
**/
protected \JDatabaseDriver $db;
/**
* User object
*
* @var User
* @since 3.2.0
**/
protected User $user;
/**
* Database object to query local DB
*
* @var CMSApplication
* @since 3.2.0
**/
protected CMSApplication $app;
/**
* Constructor.
*
* @param Placeholder|null $placeholder The compiler placeholder object.
* @param \JDatabaseDriver|null $db The Database Driver object.
* @param User|null $user The User object.
* @param CMSApplication|null $app The CMS Application object.
*
* @throws \Exception
* @since 3.2.0
*/
public function __construct(?Placeholder $placeholder = null,
?\JDatabaseDriver $db = null, ?User $user = null, ?CMSApplication $app = null)
{
$this->placeholder = $placeholder ?: Compiler::_('Placeholder');
$this->db = $db ?: Factory::getDbo();
$this->user = $user ?: Factory::getUser();
$this->app = $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::_('<hr /><h3>External Code Warning</h3>'
), 'Warning'
);
$this->app->enqueueMessage(
Text::sprintf('The <b>%s</b> is not a valid url/path!',
$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::_('<hr /><h3>External Code Warning</h3>'),
'Warning'
);
$this->app->enqueueMessage(
Text::sprintf('The code/string from <b>%s</b> has been <b>changed</b> since the last compilation. Please investigate to ensure the changes are safe! <b>Should you not expect this change to the external code/string being added, then this is a serious issue! and requires immediate attention!</b> Do not ignore this warning as it will only show <b>once</b>.',
$key
), 'Warning'
);
}
elseif ($hash !== $live_hash)
{
// set the notice
$this->app->enqueueMessage(
Text::_('<hr /><h3>External Code Error</h3>'),
'Error'
);
$this->app->enqueueMessage(
Text::sprintf('%s, we detected a change in <b>EXTERNALCODE</b>, but you do not have permission to allow this change so <b>%s</b> was removed from the compilation. Please contact your system administrator for more info!<br /><small>(admin access required)</small>',
$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::_('<hr /><h3>External Code Notice</h3>'),
'Warning'
);
$this->app->enqueueMessage(
Text::sprintf('The code/string from <b>%s</b> has been added for the <b>first time</b>. Please <i>investigate</i> to ensure the correct code/string was used! <b>Should you not know about this NEW external code/string being added, then this is a serious danger! and requires immediate attention!</b> Do not ignore this warning as it will only show <b>once</b>.',
$key
), 'Warning'
);
}
else
{
// set the notice
$this->app->enqueueMessage(
Text::_('<hr /><h3>External Code Error</h3>'),
'Error'
);
$this->app->enqueueMessage(
Text::sprintf('%s, we detected <b>NEW EXTERNALCODE</b>, but you do not have permission to allow this new code/string so <b>%s</b> was removed from the compilation. Please contact you system administrator for more info!<br /><small>(admin access required)</small>',
$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::_('<hr /><h3>External Code Warning</h3>'), 'Error'
);
$this->app->enqueueMessage(
Text::sprintf('The <b>%s</b> 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::_('<hr /><h3>External Code Notice</h3>'),
'Error'
);
$this->app->enqueueMessage(
Text::sprintf('The <b>%s</b> cut sequence failed on the returned external code/string as more lines has to be cut then was found in the code/string. We have completely removed the code. Please check this code/string!',
$key
), 'Error'
);
return '';
}

View File

@ -0,0 +1,51 @@
/**
* Set version updates
*
* @param object $item The item data
*
* @return void
* @since 3.2.0
*/
public function set(object &$item)
{
// set the version updates
$item->version_update = (isset($item->version_update)
&& JsonHelper::check($item->version_update))
? json_decode((string) $item->version_update, true) : null;
if (ArrayHelper::check($item->version_update))
{
$item->version_update = array_values(
$item->version_update
);
// set the change log details
$this->changelog($item);
}
}
/**
* Set changelog values to component changelog
*
* @param object $item The item data
*
* @return void
* @since 3.2.0
*/
protected function changelog(object &$item)
{
// set the version updates
$bucket = [];
foreach ($item->version_update as $update)
{
if (isset($update['change_log']) && StringHelper::check($update['change_log'])
&& isset($update['version']) && StringHelper::check($update['version']))
{
$bucket[] = '# v' . $update['version'] . PHP_EOL . PHP_EOL . $update['change_log'];
}
}
if (ArrayHelper::check($bucket))
{
$item->changelog = implode(PHP_EOL . PHP_EOL, $bucket);
}
}

View File

@ -0,0 +1,339 @@
/**
* The extension
*
* @var InstallInterface|Object
* @since 3.2.0
*/
protected object $extension;
/**
* The methods
*
* @var array
* @since 3.2.0
*/
protected array $methods = ['php_script', 'php_preflight', 'php_postflight', 'php_method'];
/**
* The types
*
* @var array
* @since 3.2.0
*/
protected array $types = ['construct', 'install', 'update', 'uninstall', 'discover_install'];
/**
* The construct bucket
*
* @var array
* @since 3.2.0
*/
protected array $construct = [];
/**
* The install bucket
*
* @var array
* @since 3.2.0
*/
protected array $install = [];
/**
* The update bucket
*
* @var array
* @since 3.2.0
*/
protected array $update = [];
/**
* The uninstall bucket
*
* @var array
* @since 3.2.0
*/
protected array $uninstall = [];
/**
* The preflight switch
*
* @var bool
* @since 3.2.0
*/
protected bool $preflightActive = false;
/**
* The preflight bucket
*
* @var array
* @since 3.2.0
*/
protected array $preflightBucket = ['install' => [], 'uninstall' => [], 'discover_install' => [], 'update' => []];
/**
* The postflight switch
*
* @var bool
* @since 3.2.0
*/
protected bool $postflightActive = false;
/**
* The postflight bucket
*
* @var array
* @since 3.2.0
*/
protected array $postflightBucket = ['install' => [], 'uninstall' => [], 'discover_install' => [], 'update' => []];
/**
* get install script
*
* @param Object $extension The extension object
*
* @return string
* @since 3.2.0
*/
public function get(object $extension): string
{
// loop over methods and types
foreach ($this->methods as $method)
{
foreach ($this->types as $type)
{
if (isset($extension->{'add_' . $method . '_' . $type})
&& $extension->{'add_' . $method . '_' . $type} == 1
&& StringHelper::check(
$extension->{$method . '_' . $type}
))
{
// add to the main methods
if ('php_method' === $method || 'php_script' === $method)
{
$this->{$type}[] = $extension->{$method . '_' . $type};
}
else
{
// get the flight key
$flight = str_replace('php_', '', (string) $method);
// load the script to our bucket
$this->{$flight . 'Bucket'}[$type][] = $extension->{$method . '_' . $type};
// show that the method is active
$this->{$flight . 'Active'} = true;
}
}
}
}
$this->extension = $extension;
// return the class
return $this->build();
}
/**
* build the install class
*
* @return string
* @since 3.2.0
*/
protected function build(): string
{
// start build
$script = $this->head();
// load constructor if set
$script .= $this->construct();
// load install method if set
$script .= $this->main('install');
// load update method if set
$script .= $this->main('update');
// load uninstall method if set
$script .= $this->main('uninstall');
// load preflight method if set
$script .= $this->flight('preflight');
// load postflight method if set
$script .= $this->flight('postflight');
// close the class
$script .= PHP_EOL . '}' . PHP_EOL;
return $script;
}
/**
* get install script head
*
* @return string
* @since 3.2.0
*/
protected function head(): string
{
// get the extension
$extension = $this->extension;
// start build
$script = PHP_EOL . '/**';
$script .= PHP_EOL . ' * ' . $extension->official_name
. ' script file.';
$script .= PHP_EOL . ' *';
$script .= PHP_EOL . ' * @package ' . $extension->class_name;
$script .= PHP_EOL . ' */';
$script .= PHP_EOL . 'class ' . $extension->installer_class_name;
$script .= PHP_EOL . '{';
return $script;
}
/**
* get constructor
*
* @return string
* @since 3.2.0
*/
protected function construct(): string
{
// return empty string if not set
if (!ArrayHelper::check($this->construct))
{
return '';
}
// the __construct script
$script = PHP_EOL . PHP_EOL . Indent::_(1) . '/**';
$script .= PHP_EOL . Indent::_(1) . ' * Constructor';
$script .= PHP_EOL . Indent::_(1) . ' *';
$script .= PHP_EOL . Indent::_(1)
. ' * @param Joomla\CMS\Installer\InstallerAdapter $adapter The object responsible for running this script';
$script .= PHP_EOL . Indent::_(1) . ' */';
$script .= PHP_EOL . Indent::_(1)
. 'public function __construct($adapter)';
$script .= PHP_EOL . Indent::_(1) . '{';
$script .= PHP_EOL . implode(PHP_EOL . PHP_EOL, $this->construct);
// close the function
$script .= PHP_EOL . Indent::_(1) . '}';
return $script;
}
/**
* build main methods
*
* @param string $name the method being called
*
* @return string
* @since 3.2.0
*/
protected function main(string $name): string
{
// return empty string if not set
if (!ArrayHelper::check($this->{$name}))
{
return '';
}
// load the install method
$script = PHP_EOL . PHP_EOL . Indent::_(1) . '/**';
$script .= PHP_EOL . Indent::_(1) . " * Called on $name";
$script .= PHP_EOL . Indent::_(1) . ' *';
$script .= PHP_EOL . Indent::_(1)
. ' * @param Joomla\CMS\Installer\InstallerAdapter $adapter The object responsible for running this script';
$script .= PHP_EOL . Indent::_(1) . ' *';
$script .= PHP_EOL . Indent::_(1)
. ' * @return boolean True on success';
$script .= PHP_EOL . Indent::_(1) . ' */';
$script .= PHP_EOL . Indent::_(1) . 'public function '
. $name . '($adapter)';
$script .= PHP_EOL . Indent::_(1) . '{';
$script .= PHP_EOL . implode(PHP_EOL . PHP_EOL, $this->{$name});
// return true
if ('uninstall' !== $name)
{
$script .= PHP_EOL . Indent::_(2) . 'return true;';
}
// close the function
$script .= PHP_EOL . Indent::_(1) . '}';
return $script;
}
/**
* build flight methods
*
* @param string $name the method being called
*
* @return string
* @since 3.2.0
*/
protected function flight(string $name): string
{
// return empty string if not set
if (empty($this->{$name . 'Active'}))
{
return '';
}
// the pre/post function types
$script = PHP_EOL . PHP_EOL . Indent::_(1) . '/**';
$script .= PHP_EOL . Indent::_(1)
. ' * Called before any type of action';
$script .= PHP_EOL . Indent::_(1) . ' *';
$script .= PHP_EOL . Indent::_(1)
. ' * @param string $route Which action is happening (install|uninstall|discover_install|update)';
$script .= PHP_EOL . Indent::_(1)
. ' * @param Joomla\CMS\Installer\InstallerAdapter $adapter The object responsible for running this script';
$script .= PHP_EOL . Indent::_(1) . ' *';
$script .= PHP_EOL . Indent::_(1)
. ' * @return boolean True on success';
$script .= PHP_EOL . Indent::_(1) . ' */';
$script .= PHP_EOL . Indent::_(1) . 'public function '
. $name . '($route, $adapter)';
$script .= PHP_EOL . Indent::_(1) . '{';
$script .= PHP_EOL . Indent::_(2) . '//' . Line::_(__Line__, __Class__)
. ' get application';
$script .= PHP_EOL . Indent::_(2)
. '$app = JFactory::getApplication();' . PHP_EOL;
// add the default version check (TODO) must make this dynamic
if ('preflight' === $name)
{
$script .= PHP_EOL . Indent::_(2) . '//' . Line::_(__Line__, __Class__)
.' the default for both install and update';
$script .= PHP_EOL . Indent::_(2)
. '$jversion = new JVersion();';
$script .= PHP_EOL . Indent::_(2)
. "if (!\$jversion->isCompatible('3.8.0'))";
$script .= PHP_EOL . Indent::_(2) . '{';
$script .= PHP_EOL . Indent::_(3)
. "\$app->enqueueMessage('Please upgrade to at least Joomla! 3.8.0 before continuing!', 'error');";
$script .= PHP_EOL . Indent::_(3) . 'return false;';
$script .= PHP_EOL . Indent::_(2) . '}' . PHP_EOL;
}
// now add the scripts
foreach ($this->{$name . 'Bucket'} as $route => $_script)
{
if (ArrayHelper::check($_script))
{
// set the if and script
$script .= PHP_EOL . Indent::_(2) . "if ('" . $route
. "' === \$route)";
$script .= PHP_EOL . Indent::_(2) . '{';
$script .= PHP_EOL . implode(
PHP_EOL . PHP_EOL, $_script
);
$script .= PHP_EOL . Indent::_(2) . '}' . PHP_EOL;
}
}
// return true
$script .= PHP_EOL . Indent::_(2) . 'return true;';
// close the function
$script .= PHP_EOL . Indent::_(1) . '}';
return $script;
}

View File

@ -0,0 +1 @@
###CODEPOWER###

View File

@ -0,0 +1,274 @@
/**
* Compiler Component Joomla Version Settings
*
* @var Settings
* @since 3.2.0
*/
protected Settings $settings;
/**
* Compiler Utilities Paths
*
* @var Paths
* @since 3.2.0
*/
protected Paths $paths;
/**
* Compiler Counter
*
* @var Counter
* @since 3.2.0
*/
protected Counter $counter;
/**
* Compiler Utilities File
*
* @var File
* @since 3.2.0
*/
protected File $file;
/**
* Compiler Utilities Files
*
* @var Files
* @since 3.2.0
*/
protected Files $files;
/**
* Database object to query local DB
*
* @var CMSApplication
* @since 3.2.0
**/
protected CMSApplication $app;
/**
* Constructor.
*
* @param Settings|null $settings The compiler component joomla version settings object.
* @param Paths|null $paths The compiler paths object.
* @param Counter|null $counter The compiler counter object.
* @param File|null $file The compiler file object.
* @param Files|null $files The compiler files object.
* @param CMSApplication|null $app The CMS Application object.
*
* @since 3.2.0
* @throws \Exception
*/
public function __construct(?Settings $settings = null, ?Paths $paths = null,
?Counter $counter = null, ?File $file = null, ?Files $files = null,
?CMSApplication $app = null)
{
$this->settings = $settings ?: Compiler::_('Component.Settings');
$this->paths = $paths ?: Compiler::_('Utilities.Paths');
$this->counter = $counter ?: Compiler::_('Utilities.Counter');
$this->file = $file ?: Compiler::_('Utilities.File');
$this->files = $files ?: Compiler::_('Utilities.Files');
$this->app = $app ?: Factory::getApplication();
}
/**
* Build Structural Needed Files & Folders
*
* @param array $target The main target and name
* @param string $type The type in the target
* @param string|null $fileName The custom file name
* @param array|null $config To add more data to the files info
*
* @return bool true on success
* @since 3.2.0
*/
public function build(array $target, string $type,
?string $fileName = null, ?array $config = null): bool
{
// did we build the files (any number)
$build_status = false;
// check that we have the target values
if (ArrayHelper::check($target))
{
// search the target
foreach ($target as $main => $name)
{
// make sure it is lower case
$name = StringHelper::safe($name);
// setup the files
foreach ($this->settings->multiple()->{$main} as $item => $details)
{
if ($details->type === $type)
{
$file_details = $this->getFileDetails(
$details,
(string) $item,
$name,
$fileName,
$config
);
if (is_array($file_details))
{
// store the new files
$this->files->appendArray('dynamic.' . $file_details['view'],
$file_details);
// we have build at least one
$build_status = true;
}
}
}
}
}
return $build_status;
}
/**
* Get the details
*
* @param object $details The item details
* @param string $item The item name
* @param string $name The given name
* @param string|null $fileName The custom file name
* @param array|null $config To add more data to the files info
*
* @return array|null The details
* @since 3.2.0
*/
private function getFileDetails(object $details, string $item,
string $name, ?string $fileName = null, ?array $config = null): ?array
{
$zip_path = '';
if (($path = $this->getPath($details, $zip_path, $name)) === null)
{
return null;
}
// setup the folder
if (!Folder::exists($path))
{
Folder::create($path);
$this->file->html($zip_path);
// count the folder created
$this->counter->folder++;
}
$new_name = $this->getNewName($details, $item, $name, $fileName);
if (!JoomlaFile::exists($path . '/' . $new_name))
{
// move the file to its place
JoomlaFile::copy(
$this->paths->template_path . '/' . $item,
$path . '/' . $new_name
);
// count the file created
$this->counter->file++;
}
// we can't have dots in a view name
if (strpos($name, '.') !== false)
{
$name = preg_replace('/[\.]+/', '_', (string) $name);
}
// setup array for new file
$file = [
'path' => $path . '/' . $new_name,
'name' => $new_name,
'view' => $name,
'zip' => $zip_path . '/' . $new_name
];
if (ArrayHelper::check($config))
{
$file['config'] = $config;
}
return $file;
}
/**
* Get the path
*
* @param object $details The item details
* @param string $zipPath The zip path
* @param string $name The name
*
* @return string|null The path
* @since 3.2.0
*/
private function getPath(object $details, string &$zipPath, string $name): ?string
{
// set destination path
if (strpos((string) $details->path, 'VIEW') !== false)
{
$path = str_replace('VIEW', $name, (string) $details->path);
}
else
{
$path = $details->path;
}
// make sure we have component to replace
if (strpos((string) $path, 'c0mp0n3nt') !== false)
{
$zipPath = str_replace('c0mp0n3nt/', '', (string) $path);
return str_replace(
'c0mp0n3nt/', $this->paths->component_path . '/', (string) $path
);
}
$this->app->enqueueMessage(
Text::sprintf('<hr /><h3>c0mp0n3nt issue found</h3><p>The path (%s) could not be used.</p>',
$path
), 'Error'
);
return null;
}
/**
* Get the new name
*
* @param object $details The item details
* @param string $item The item name
* @param string $name The name
* @param string|null $fileName The custom file name
*
* @return string The new name
* @since 3.2.0
*/
private function getNewName(object $details, string $item,
string &$name, ?string $fileName = null): string
{
// do the file need renaming
if ($details->rename)
{
if (!empty($fileName))
{
$name = $name . '_' . $fileName;
return str_replace(
$details->rename, $fileName, $item
);
}
elseif ($details->rename === 'new')
{
return $details->newName;
}
return str_replace(
$details->rename, $name, $item
);
}
return $item;
}

View File

@ -0,0 +1,10 @@
/**
* 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;

View File

@ -0,0 +1,10 @@
/**
* Trigger an event
*
* @param string $event The event to trigger
* @param mixed $data The values to pass to the event/plugin
*
* @return void
* @since 3.2.0
*/
public function trigger(string $event, $data);

View File

@ -0,0 +1,26 @@
/**
* 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(Content::class, 'Content')
->share('Content', [$this, 'getContent'], true);
}
/**
* Get the Compiler Content
*
* @param Container $container The DI container.
*
* @return Content
* @since 3.2.0
*/
public function getContent(Container $container): Content
{
return new Content();
}

View File

@ -0,0 +1,87 @@
/**
* Local Core Joomla Rules
*
* @var array|null
* @since 3.2.0
**/
protected ?array $rules = null;
/**
* Local Core Joomla Rules Path
*
* @var string
* @since 3.2.0
**/
protected string $path;
/**
* Constructor
*
* @since 3.2.0
*/
public function __construct()
{
// set the path to the form validation rules
$this->path = JPATH_LIBRARIES . '/src/Form/Rule';
}
/**
* Get the Array of Existing Validation Rule Names
*
* @param bool $lowercase Switch to set rules lowercase
*
* @return array
* @since 3.2.0
*/
public function get(bool $lowercase = false): array
{
if (!$this->rules)
{
// check if the path exist
if (!Folder::exists($this->path))
{
return [];
}
// we must first store the current working directory
$joomla = getcwd();
// go to that folder
chdir($this->path);
// load all the files in this path
$rules = Folder::files('.', '\.php', true, true);
// change back to Joomla working directory
chdir($joomla);
// make sure we have an array
if (!ArrayHelper::check($rules))
{
return false;
}
// remove the Rule.php from the name
$this->rules = array_map(
fn($name): string => str_replace(array('./','Rule.php'), '', (string) $name),
$rules
);
}
// return rules if found
if (is_array($this->rules))
{
// check if the names should be all lowercase
if ($lowercase)
{
return array_map(
fn($item): string => strtolower((string) $item),
$this->rules
);
}
return $this->rules;
}
// return empty array
return [];
}

View File

@ -0,0 +1,59 @@
/**
* 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(Data::class, 'Library.Data')
->share('Library.Data', [$this, 'getData'], true);
$container->alias(Structure::class, 'Library.Structure')
->share('Library.Structure', [$this, 'getStructure'], true);
}
/**
* Get the Compiler Library Data
*
* @param Container $container The DI container.
*
* @return Data
* @since 3.2.0
*/
public function getData(Container $container): Data
{
return new Data(
$container->get('Config'),
$container->get('Registry'),
$container->get('Customcode'),
$container->get('Customcode.Gui'),
$container->get('Field.Data'),
$container->get('Model.Filesfolders')
);
}
/**
* Get the Compiler Library Structure Builder
*
* @param Container $container The DI container.
*
* @return Structure
* @since 3.2.0
*/
public function getStructure(Container $container): Structure
{
return new Structure(
$container->get('Config'),
$container->get('Registry'),
$container->get('Event'),
$container->get('Component'),
$container->get('Content'),
$container->get('Utilities.Counter'),
$container->get('Utilities.Paths'),
$container->get('Utilities.Folder'),
$container->get('Utilities.File')
);
}

View File

@ -0,0 +1,49 @@
/**
* Compiler Placeholder
*
* @var Placeholder
* @since 3.2.0
**/
protected Placeholder $placeholder;
/**
* Constant Paths
*
* @var array
* @since 3.2.0
**/
protected array $paths;
/**
* Constructor.
*
* @param Placeholder|null $placeholder The Compiler Placeholder object.
* @param Constantpaths|null $paths The Constant Paths object.
*
* @since 3.2.0
*/
public function __construct(?Placeholder $placeholder = null, ?Constantpaths $paths = null)
{
$this->placeholder = $placeholder ?: Compiler::_('Placeholder');
$paths = $paths ?: Compiler::_('Utilities.Constantpaths');
// load the constant paths
$this->paths = $paths->get();
}
/**
* Update path with dynamic value
*
* @param string $path The path to update
*
* @return string The updated path
* @since 3.2.0
*/
public function update(string $path): string
{
return $this->placeholder->update_(
$this->placeholder->update(
$path, $this->paths
)
);
}

View File

@ -0,0 +1,86 @@
/**
* The areas add array
*
* @var array
* @since 3.2.0
*/
protected array $areas = [
'javascript_file',
'js_document'
];
/**
* The gui mapper array
*
* @var array
* @since 3.2.0
*/
protected array $guiMapper = [
'table' => null,
'id' => null,
'field' => null,
'type' => 'js'
];
/**
* Compiler Customcode
*
* @var Customcode
* @since 3.2.0
*/
protected Customcode $customcode;
/**
* Compiler Customcode in Gui
*
* @var Gui
* @since 3.2.0
**/
protected Gui $gui;
/**
* Constructor
*
* @param Customcode|null $customcode The compiler customcode object.
* @param Gui|null $gui The compiler customcode gui.
*
* @since 3.2.0
*/
public function __construct(?Customcode $customcode = null, ?Gui $gui = null)
{
$this->customcode = $customcode ?: Compiler::_('Customcode');
$this->gui = $gui ?: Compiler::_('Customcode.Gui');
}
/**
* Set Javascript code
*
* @param object $item The item data
* @param string $table The table
*
* @return void
* @since 3.2.0
*/
public function set(object &$item, string $table = 'site_view')
{
// set some gui mapper values
$this->guiMapper['table'] = $table;
$this->guiMapper['id'] = (int) $item->id;
foreach ($this->areas as $area)
{
if (isset($item->{'add_' . $area})
&& $item->{'add_' . $area} == 1
&& StringHelper::check($item->{$area}))
{
// update GUI mapper field
$this->guiMapper['field'] = $area;
$item->{$area} = $this->gui->set(
$this->customcode->update(
base64_decode((string) $item->{$area})
),
$this->guiMapper
);
}
}
}

View File

@ -0,0 +1,64 @@
/**
* 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(Data::class, 'Joomlamodule.Data')
->share('Joomlamodule.Data', [$this, 'getData'], true);
$container->alias(Structure::class, 'Joomlamodule.Structure')
->share('Joomlamodule.Structure', [$this, 'getStructure'], true);
}
/**
* Get the Joomla Module Data
*
* @param Container $container The DI container.
*
* @return Data
* @since 3.2.0
*/
public function getData(Container $container): Data
{
return new Data(
$container->get('Config'),
$container->get('Customcode'),
$container->get('Customcode.Gui'),
$container->get('Placeholder'),
$container->get('Language'),
$container->get('Field'),
$container->get('Field.Name'),
$container->get('Model.Filesfolders'),
$container->get('Model.Libraries'),
$container->get('Dynamicget.Data')
);
}
/**
* Get the Joomla Module Structure Builder
*
* @param Container $container The DI container.
*
* @return Structure
* @since 3.2.0
*/
public function getStructure(Container $container): Structure
{
return new Structure(
$container->get('Joomlamodule.Data'),
$container->get('Component'),
$container->get('Config'),
$container->get('Registry'),
$container->get('Customcode.Dispenser'),
$container->get('Event'),
$container->get('Utilities.Counter'),
$container->get('Utilities.Folder'),
$container->get('Utilities.File'),
$container->get('Utilities.Files')
);
}

View File

@ -0,0 +1,68 @@
/**
* Load data rows as an array of associated arrays
*
* @param array $select Array of selection keys
* @param array $tables Array of tables to search
* @param array|null $where Array of where key=>value match exist
* @param array|null $order Array of how to order the data
* @param int|null $limit Limit the number of values returned
*
* @return array|null
* @since 3.2.0
**/
public function rows(array $select, array $tables, ?array $where = null,
?array $order = null, ?int $limit = null): ?array;
/**
* Load data rows as an array of objects
*
* @param array $select Array of selection keys
* @param array $tables Array of tables to search
* @param array|null $where Array of where key=>value match exist
* @param array|null $order Array of how to order the data
* @param int|null $limit Limit the number of values returned
*
* @return array|null
* @since 3.2.0
**/
public function items(array $select, array $tables, ?array $where = null,
?array $order = null, ?int $limit = null): ?array;
/**
* Load data row as an associated array
*
* @param array $select Array of selection keys
* @param array $tables Array of tables to search
* @param array|null $where Array of where key=>value match exist
* @param array|null $order Array of how to order the data
*
* @return array|null
* @since 3.2.0
**/
public function row(array $select, array $tables, ?array $where = null, ?array $order = null): ?array;
/**
* Load data row as an object
*
* @param array $select Array of selection keys
* @param array $tables Array of tables to search
* @param array|null $where Array of where key=>value match exist
* @param array|null $order Array of how to order the data
*
* @return object|null
* @since 3.2.0
**/
public function item(array $select, array $tables, ?array $where = null, ?array $order = null): ?object;
/**
* Load one value from a row
*
* @param array $select Array of selection keys
* @param array $tables Array of tables to search
* @param array|null $where Array of where key=>value match exist
* @param array|null $order Array of how to order the data
*
* @return mixed
* @since 3.2.0
**/
public function value(array $select, array $tables, ?array $where = null, ?array $order = null);

View File

@ -0,0 +1,12 @@
/**
* 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);
}

View File

@ -0,0 +1,26 @@
/**
* 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();
}

View File

@ -0,0 +1,23 @@
/**
* 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;
/**
* 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);

View File

@ -0,0 +1,68 @@
/**
* Get any value from a item/field/column of an area/view/table
* Example: $this->get('table_name', 'field_name', 'value_key');
* Get an item/field/column of an area/view/table
* Example: $this->get('table_name', 'field_name');
* Get all items/fields/columns of an area/view/table
* Example: $this->get('table_name');
* Get all areas/views/tables with all their item/field/column details
* Example: $this->get();
*
* @param string $table The table
* @param string|null $field The field
* @param string|null $key The value key
*
* @return mixed
* @since 3.2.0
*/
public function get(string $table, ?string $field = null, ?string $key = null);
/**
* Get title field from an area/view/table
*
* @param string|null $table The area
*
* @return ?array
* @since 3.2.0
*/
public function title(string $table): ?array;
/**
* Get title field name
*
* @param string|null $table The area
*
* @return string
* @since 3.2.0
*/
public function titleName(string $table): string;
/**
* Get all tables
*
* @return array
* @since 3.2.0
*/
public function tables(): array;
/**
* Check if a table (and field) exist
*
* @param string|null $table The area
* @param string|null $field The area
*
* @return bool
* @since 3.2.0
*/
public function exist(string $table, ?string $field = null): bool;
/**
* Get all fields of an area/view/table
*
* @param string $table The area
* @param bool $default Add the default fields
*
* @return array|null On success an array of fields
* @since 3.2.0
*/
public function fields(string $table, bool $default = false): ?array;

View File

@ -0,0 +1,49 @@
/**
* 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(AdminviewData::class, 'Adminview.Data')
->share('Adminview.Data', [$this, 'getAdminviewData'], true);
}
/**
* Get the Compiler Adminview Data
*
* @param Container $container The DI container.
*
* @return AdminviewData
* @since 3.2.0
*/
public function getAdminviewData(Container $container): AdminviewData
{
return new AdminviewData(
$container->get('Config'),
$container->get('Registry'),
$container->get('Event'),
$container->get('Placeholder'),
$container->get('Customcode.Dispenser'),
$container->get('Model.Customtabs'),
$container->get('Model.Tabs'),
$container->get('Model.Fields'),
$container->get('Model.Historyadminview'),
$container->get('Model.Permissions'),
$container->get('Model.Conditions'),
$container->get('Model.Relations'),
$container->get('Model.Linkedviews'),
$container->get('Model.Javascriptadminview'),
$container->get('Model.Cssadminview'),
$container->get('Model.Phpadminview'),
$container->get('Model.Custombuttons'),
$container->get('Model.Customimportscripts'),
$container->get('Model.Ajaxadmin'),
$container->get('Model.Customalias'),
$container->get('Model.Sql'),
$container->get('Model.Mysqlsettings')
);
}

View File

@ -0,0 +1,9 @@
/**
* get code to use
*
* @param Object $code The code object
*
* @return string
* @since 3.2.0
*/
public function get(object $extension): string;

View File

@ -0,0 +1,49 @@
/**
* 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(CompilerPlaceholder::class, 'Placeholder')
->share('Placeholder', [$this, 'getPlaceholder'], true);
$container->alias(Reverse::class, 'Placeholder.Reverse')
->share('Placeholder.Reverse', [$this, 'getPlaceholderReverse'], true);
}
/**
* Get the Compiler Placeholder
*
* @param Container $container The DI container.
*
* @return CompilerPlaceholder
* @since 3.2.0
*/
public function getPlaceholder(Container $container): CompilerPlaceholder
{
return new CompilerPlaceholder(
$container->get('Config')
);
}
/**
* Get the Compiler Placeholder Reverse
*
* @param Container $container The DI container.
*
* @return Worker
* @since 3.2.0
*/
public function getPlaceholderReverse(Container $container): Reverse
{
return new Reverse(
$container->get('Config'),
$container->get('Placeholder'),
$container->get('Language'),
$container->get('Language.Extractor')
);
}

View File

@ -0,0 +1,598 @@
/**
* The function name memory ids
*
* @var array
* @since 3.2.0
**/
public array $functionNameMemory = [];
/**
* The active custom code
*
* @var array
* @since 3.2.0
*/
public $active = [];
/**
* The custom code memory
*
* @var array
* @since 3.2.0
*/
public $memory = [];
/**
* The placeholders for custom code keys
*
* @var array
*/
protected $keys
= array(
'&#91;' => '[',
'&#93;' => ']',
'&#44;' => ',',
'&#43;' => '+',
'&#61;' => '='
);
/**
* The custom code to be added
*
* @var array
* @since 3.2.0
*/
protected $data = [];
/**
* Compiler Config
*
* @var Config
* @since 3.2.0
**/
protected Config $config;
/**
* Compiler Placeholder
*
* @var Placeholder
* @since 3.2.0
**/
protected Placeholder $placeholder;
/**
* Compiler Language Extractor
*
* @var Extractor
* @since 3.2.0
**/
protected Extractor $extractor;
/**
* Compiler Custom Code External
*
* @var External
* @since 3.2.0
**/
protected External $external;
/**
* Database object to query local DB
*
* @var \JDatabaseDriver
* @since 3.2.0
**/
protected $db;
/**
* Constructor.
*
* @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 \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)
{
$this->config = $config ?: Compiler::_('Config');
$this->placeholder = $placeholder ?: Compiler::_('Placeholder');
$this->extractor = $extractor ?: Compiler::_('Language.Extractor');
$this->external = $external ?: Compiler::_('Customcode.External');
$this->db = $db ?: Factory::getDbo();
}
/**
* Update **ALL** dynamic values in a strings here
*
* @param string $string The content to check
* @param int $debug The switch to debug the update
* We can now at any time debug the
* dynamic build values if it gets broken
*
* @return string
* @since 3.2.0
*/
public function update(string $string, int $debug = 0): string
{
if (StringHelper::check($string))
{
$string = $this->extractor->engine(
$this->set(
$this->external->set($string, $debug), $debug
)
);
}
// if debug
if ($debug)
{
jexit();
}
return $string;
}
/**
* Set the custom code data & can load it in to string
*
* @param string $string The content to check
* @param int $debug The switch to debug the update
* @param int|null $not The not switch
*
* @return string
* @since 3.2.0
*/
public function set(string $string, int $debug = 0, ?int $not = null): string
{
// insure the code is loaded
$loaded = false;
// check if content has custom code place holder
if (strpos($string, '[CUSTO' . 'MCODE=') !== false)
{
// if debug
if ($debug)
{
echo 'Custom Code String:';
var_dump($string);
}
// the ids found in this content
$bucket = [];
$found = GetHelper::allBetween(
$string, '[CUSTO' . 'MCODE=', ']'
);
if (ArrayHelper::check($found))
{
foreach ($found as $key)
{
// if debug
if ($debug)
{
echo '$key before update:';
var_dump($key);
}
// check if we have args
if (is_numeric($key))
{
$id = (int) $key;
}
elseif (StringHelper::check($key)
&& strpos((string) $key, '+') === false)
{
$getFuncName = trim((string) $key);
if (!isset($this->functionNameMemory[$getFuncName]))
{
if (!$found_local = GetHelper::var(
'custom_code', $getFuncName, 'function_name',
'id'
))
{
continue;
}
$this->functionNameMemory[$getFuncName]
= $found_local;
}
$id = (int) $this->functionNameMemory[$getFuncName];
}
elseif (StringHelper::check($key)
&& strpos(
(string) $key, '+'
) !== false)
{
$array = explode('+', (string) $key);
// set ID
if (is_numeric($array[0]))
{
$id = (int) $array[0];
}
elseif (StringHelper::check($array[0]))
{
$getFuncName = trim($array[0]);
if (!isset($this->functionNameMemory[$getFuncName]))
{
if (!$found_local
= GetHelper::var(
'custom_code', $getFuncName,
'function_name', 'id'
))
{
continue;
}
$this->functionNameMemory[$getFuncName]
= $found_local;
}
$id = (int) $this->functionNameMemory[$getFuncName];
}
else
{
continue;
}
// load args for this ID
if (isset($array[1]))
{
if (!isset($this->data[$id]['args']))
{
$this->data[$id]['args'] = [];
}
// only load if not already loaded
if (!isset($this->data[$id]['args'][$key]))
{
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(
fn($_key) => $this->placeholder->update(
$_key,
$this->keys
), (array) explode(',', $array[1])
);
}
elseif (StringHelper::check(
$array[1]
))
{
$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(
$array[1],
$this->keys
);
}
}
}
}
else
{
continue;
}
// make sure to remove the not if set
if ($not && is_numeric($not) && $not > 0 && $not == $id)
{
continue;
}
$bucket[$id] = $id;
}
}
// if debug
if ($debug)
{
echo 'Bucket:';
var_dump($bucket);
}
// check if any custom code placeholders where found
if (ArrayHelper::check($bucket))
{
$_tmpLang = $this->config->lang_target;
// insure we add the langs to both site and admin
$this->config->lang_target = 'both';
// now load the code to memory
$loaded = $this->get($bucket, false, $debug);
// revert lang to current setting
$this->config->lang_target = $_tmpLang;
}
// if debug
if ($debug)
{
echo 'Loaded:';
var_dump($loaded);
}
// when the custom code is loaded
if ($loaded === true)
{
$string = $this->insert($bucket, $string, $debug);
}
// if debug
if ($debug)
{
echo 'Custom Code String After Update:';
var_dump($string);
}
}
return $string;
}
/**
* Load the custom code from the system
*
* @param array|null $ids The custom code ides if known
* @param bool $setLang The set lang switch
* @param int $debug The switch to debug the update
*
* @return bool
* @since 3.2.0
*/
public function get(?array $ids = null, bool $setLang = true, $debug = 0): bool
{
// should the result be stored in memory
$loadInMemory = false;
// Create a new query object.
$query = $this->db->getQuery(true);
$query->from(
$this->db->quoteName('#__componentbuilder_custom_code', 'a')
);
if (ArrayHelper::check($ids))
{
if (($idArray = $this->check($ids)) !== false)
{
$query->select(
$this->db->quoteName(
array('a.id', 'a.code', 'a.comment_type')
)
);
$query->where(
$this->db->quoteName('a.id') . ' IN (' . implode(
',', $idArray
) . ')'
);
$query->where(
$this->db->quoteName('a.target') . ' = 2'
); // <--- to load the correct target
$loadInMemory = true;
}
else
{
// all values are already in memory continue
return true;
}
}
else
{
$query->select(
$this->db->quoteName(
array('a.id', 'a.code', 'a.comment_type', 'a.component',
'a.from_line', 'a.hashtarget', 'a.hashendtarget',
'a.path', 'a.to_line', 'a.type')
)
);
$query->where(
$this->db->quoteName('a.component') . ' = '
. (int) $this->config->component_id
);
$query->where(
$this->db->quoteName('a.target') . ' = 1'
); // <--- to load the correct target
$query->order(
$this->db->quoteName('a.from_line') . ' ASC'
); // <--- insure we always add code from top of file
// reset custom code
$this->active = [];
}
$query->where($this->db->quoteName('a.published') . ' >= 1');
$this->db->setQuery($query);
$this->db->execute();
if ($this->db->getNumRows())
{
$bucket = $this->db->loadAssocList('id');
// open the code
foreach ($bucket as $nr => &$customCode)
{
$customCode['code'] = base64_decode((string) $customCode['code']);
// always insure that the external code is loaded
$customCode['code'] = $this->external->set(
$customCode['code']
);
// set the lang only if needed (we do the other later when we add it to the correct position)
if ($setLang)
{
$customCode['code'] = $this->extractor->engine(
$customCode['code']
);
}
// check for more custom code (since this is a custom code placeholder)
else
{
$customCode['code'] = $this->set(
$customCode['code'], $debug, $nr
);
}
// build the hash array
if (isset($customCode['hashtarget']))
{
$customCode['hashtarget'] = explode(
"__", (string) $customCode['hashtarget']
);
// is this a replace code, set end has array
if ($customCode['type'] == 1
&& strpos((string) $customCode['hashendtarget'], '__') !== false)
{
$customCode['hashendtarget'] = explode(
"__", (string) $customCode['hashendtarget']
);
// NOW see if this is an end of page target (TODO not sure if the string is always d41d8cd98f00b204e9800998ecf8427e)
// I know this fix is not air-tight, but it should work as the value of an empty line when md5'ed is ^^^^
// Then if the line number is only >>>one<<< it is almost always end of the page.
// So I am using those two values to detect end of page replace ending, to avoid mismatching the ending target hash.
if ($customCode['hashendtarget'][0] == 1
&& 'd41d8cd98f00b204e9800998ecf8427e' === $customCode['hashendtarget'][1])
{
// unset since this will force the replacement unto end of page.
unset($customCode['hashendtarget']);
}
}
}
}
// load this code into memory if needed
if ($loadInMemory === true)
{
$this->memory = $this->memory + $bucket;
}
// add to active set
$this->active = array_merge($this->active, $bucket);
return true;
}
return false;
}
/**
* Insert the custom code into the string
*
* @param array|null $ids The custom code ides if known
* @param string $string The string to insert custom code into
* @param int $debug The switch to debug the update
*
* @return string on success
* @since 3.2.0
*/
protected function insert(array $ids, string $string, int $debug = 0): string
{
$code = [];
// load the code
foreach ($ids as $id)
{
$this->buildPlaceholders(
$this->memory[$id], $code, $debug
);
}
// if debug
if ($debug)
{
echo 'Place holders to Update String:';
var_dump($code);
echo 'Custom Code String Before Update:';
var_dump($string);
}
// now update the string
return $this->placeholder->update($string, $code);
}
/**
* Build custom code placeholders
*
* @param array $item The memory item
* @param array $code The custom code bucket
* @param int $debug The switch to debug the update
*
* @return void
* @since 3.2.0
*/
protected function buildPlaceholders(array $item, array &$code, int $debug = 0)
{
// check if there is args for this code
if (isset($this->data[$item['id']]['args'])
&& ArrayHelper::check(
$this->data[$item['id']]['args']
))
{
// since we have args we cant update this code via IDE (TODO)
$placeholder = $this->placeholder->keys(3, null);
// if debug
if ($debug)
{
echo 'Custom Code Placeholders:';
var_dump($placeholder);
}
// we have args and so need to load each
foreach (
$this->data[$item['id']]['args'] as $key => $args
)
{
$this->placeholder->setType('arg', $args);
// if debug
if ($debug)
{
echo 'Custom Code Global Placeholders:';
var_dump($this->placeholder->active);
}
$code['[CUSTOM' . 'CODE=' . $key . ']'] = $placeholder['start']
. PHP_EOL . $this->placeholder->update_(
$item['code']
) . $placeholder['end'];
}
// always clear the args
$this->placeholder->clearType('arg');
}
else
{
if (($keyPlaceholder = array_search(
$item['id'], $this->functionNameMemory
)) === false)
{
$keyPlaceholder = $item['id'];
}
// check what type of place holders we should load here
$placeholderType = (int) $item['comment_type'] . '2';
if (stripos((string) $item['code'], Placefix::b() . 'view') !== false
|| stripos((string) $item['code'], Placefix::b() . 'sview') !== false
|| stripos((string) $item['code'], Placefix::b() . 'arg') !== false)
{
// if view is being set dynamicly then we can't update this code via IDE (TODO)
$placeholderType = 3;
}
// if now ars were found, clear it
$this->placeholder->clearType('arg');
// load args for this code
$placeholder = $this->placeholder->keys(
$placeholderType, $item['id']
);
$code['[CUSTOM' . 'CODE=' . $keyPlaceholder . ']']
= $placeholder['start'] . PHP_EOL
. $this->placeholder->update_(
$item['code']
) . $placeholder['end'];
}
}
/**
* check if we already have these ids in local memory
*
* @param array $ids The custom code ids
*
* @return Mixed
* @since 3.2.0
*/
protected function check(array $ids)
{
// reset custom code
$this->active = [];
foreach ($ids as $pointer => $id)
{
if (isset($this->memory[$id]))
{
$this->active[] = $this->memory[$id];
unset($ids[$pointer]);
}
}
// check if any ids left to fetch
if (ArrayHelper::check($ids))
{
return $ids;
}
return false;
}

View File

@ -345,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)
@ -410,6 +410,10 @@ class Structure
$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);

View File

@ -0,0 +1,386 @@
/**
* we track the creation of htaccess files
*
* @var array
* @since 3.2.0
**/
protected array $htaccess = [];
/**
* Power Objects
*
* @var Power
* @since 3.2.0
**/
protected Power $power;
/**
* Compiler Config
*
* @var Config
* @since 3.2.0
*/
protected Config $config;
/**
* The compiler registry
*
* @var Registry
* @since 3.2.0
*/
protected Registry $registry;
/**
* Compiler Event
*
* @var EventInterface
* @since 3.2.0
*/
protected EventInterface $event;
/**
* Compiler Counter
*
* @var Counter
* @since 3.2.0
*/
protected Counter $counter;
/**
* Compiler Utilities Paths
*
* @var Paths
* @since 3.2.0
*/
protected Paths $paths;
/**
* Compiler Utilities Folder
*
* @var Folder
* @since 3.2.0
*/
protected Folder $folder;
/**
* Compiler Utilities File
*
* @var File
* @since 3.2.0
*/
protected File $file;
/**
* Compiler Utilities Files
*
* @var Files
* @since 3.2.0
*/
protected Files $files;
/**
* Database object to query local DB
*
* @var CMSApplication
* @since 3.2.0
**/
protected CMSApplication $app;
/**
* Constructor
*
* @param Power|null $power The power object.
* @param Config|null $config The compiler config object.
* @param Registry|null $registry The compiler registry object.
* @param EventInterface|null $event The compiler event api object.
* @param Counter|null $counter The compiler counter object.
* @param Paths|null $paths The compiler paths object.
* @param Folder|null $folder The compiler folder object.
* @param File|null $file The compiler file object.
* @param Files|null $files The compiler files object.
* @param CMSApplication|null $app The CMS Application object.
*
* @throws \Exception
* @since 3.2.0
*/
public function __construct(?Power $power = null, ?Config $config = null,
?Registry $registry = null, ?EventInterface $event = null,
?Counter $counter = null, ?Paths $paths = null, ?Folder $folder = null,
?File $file = null, ?Files $files = null, ?CMSApplication $app = null)
{
$this->power = $power ?: Compiler::_('Power');
$this->config = $config ?: Compiler::_('Config');
$this->registry = $registry ?: Compiler::_('Registry');
$this->event = $event ?: Compiler::_('Event');
$this->counter = $counter ?: Compiler::_('Utilities.Counter');
$this->paths = $paths ?: Compiler::_('Utilities.Paths');
$this->folder = $folder ?: Compiler::_('Utilities.Folder');
$this->file = $file ?: Compiler::_('Utilities.File');
$this->files = $files ?: Compiler::_('Utilities.Files');
$this->app = $app ?: Factory::getApplication();
}
/**
* Build the Powers files, folders
*
* @return void
* @since 3.2.0
*/
public function build()
{
if (ArrayHelper::check($this->power->active))
{
// for plugin event TODO change event api signatures
$powers = $this->power->active;
$component_context = $this->config->component_context;
// Trigger Event: jcb_ce_onBeforeSetModules
$this->event->trigger(
'jcb_ce_onBeforeBuildPowers',
array(&$component_context, &$powers)
);
// 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)
&& isset($power->path)
&& StringHelper::check(
$power->path
))
{
// activate dynamic folders
$this->setDynamicFolders();
// power path
$power->full_path = $this->paths->component_path . '/'
. $power->path;
$power->full_path_jcb = $this->paths->component_path . '/'
. $power->path_jcb;
$power->full_path_parent = $this->paths->component_path . '/'
. $power->path_parent;
// set the power paths
$this->registry->set('dynamic_paths.' . $power->key, $power->full_path_parent);
// create the power folder if it does not exist
// we do it like this to add html files to each part
$this->folder->create($power->full_path_jcb);
$this->folder->create($power->full_path_parent);
$this->folder->create($power->full_path);
$bom = '<?php' . PHP_EOL . '// A POWER FILE' .
PHP_EOL . Placefix::_h('BOM') . PHP_EOL;
// add custom override if found
if ($power->add_licensing_template == 2)
{
$bom = '<?php' . PHP_EOL . $power->licensing_template;
}
// 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);
}
}
}
}
/**
* 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
*
* @param object $power The power object
*
* @return void
* @since 3.2.0
*/
private function setHtaccess(object &$power)
{
if (!isset($this->htaccess[$power->path_jcb]))
{
// set the htaccess data
$data = '# Apache 2.4+' . PHP_EOL .
'<IfModule mod_authz_core.c>' . PHP_EOL .
' Require all denied' . PHP_EOL .
'</IfModule>' . PHP_EOL . PHP_EOL .
'# Apache 2.0-2.2' . PHP_EOL .
'<IfModule !mod_authz_core.c>' . PHP_EOL .
' Deny from all' . PHP_EOL .
'</IfModule>' . PHP_EOL;
// now we must add the .htaccess file
$fileDetails = array('path' => $power->full_path_jcb . '/.htaccess',
'name' => '.htaccess',
'zip' => '.htaccess');
$this->file->write(
$fileDetails['path'], $data
);
$this->files->appendArray($power->key, $fileDetails);
// count the file created
$this->counter->file++;
// now we must add the htaccess.txt file where the zip package my not get the [.] files
$fileDetails = array('path' => $power->full_path_jcb . '/htaccess.txt',
'name' => 'htaccess.txt',
'zip' => 'htaccess.txt');
$this->file->write(
$fileDetails['path'], $data
);
$this->files->appendArray($power->key, $fileDetails);
// count the file created
$this->counter->file++;
// now we must add the web.config file
$fileDetails = array('path' => $power->full_path_jcb . '/web.config',
'name' => 'web.config',
'zip' => 'web.config');
$this->file->write(
$fileDetails['path'],
'<?xml version="1.0"?>' . PHP_EOL .
' <system.web>' . PHP_EOL .
' <authorization>' . PHP_EOL .
' <deny users="*" />' . PHP_EOL .
' </authorization>' . PHP_EOL .
' </system.web>' . PHP_EOL .
'</configuration>' . PHP_EOL
);
$this->files->appendArray($power->key, $fileDetails);
// count the file created
$this->counter->file++;
// we set these files only once
$this->htaccess[$power->path_jcb] = true;
}
}
/**
* Add the dynamic folders
*
* @return void
* @since 3.2.0
*/
private function setDynamicFolders()
{
// 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 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)
$this->app->enqueueMessage(
Text::_('<hr /><h3>Dynamic folder(s) were detected.</h3>'),
'Notice'
);
$this->app->enqueueMessage(
Text::sprintf('A method (setDynamicF0ld3rs) was added to the install <b>script.php</b> of this package to insure that the folder(s) are copied into the correct place when this component is installed!'),
'Notice'
);
}
}
/**
* 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);
}
}
}

View File

@ -0,0 +1,50 @@
/**
* The areas add array
*
* @var array
* @since 3.2.0
*/
protected array $areas = ['css_document', 'css'];
/**
* Compiler Customcode Class
*
* @var Customcode
* @since 3.2.0
*/
protected Customcode $customcode;
/**
* Constructor
*
* @param Customcode|null $customcode The compiler customcode object.
*
* @since 3.2.0
*/
public function __construct(?Customcode $customcode = null)
{
$this->customcode = $customcode ?: Compiler::_('Customcode');
}
/**
* Set Css code
*
* @param object $item The item data
*
* @return void
* @since 3.2.0
*/
public function set(object &$item)
{
foreach ($this->areas as $area)
{
if (isset($item->{'add_' . $area})
&& $item->{'add_' . $area} == 1
&& StringHelper::check($item->{$area}))
{
$item->{$area} = $this->customcode->update(
base64_decode((string) $item->{$area})
);
}
}
}

View File

@ -0,0 +1,36 @@
/**
* Update **ALL** dynamic values in a strings here
*
* @param string $string The content to check
* @param int $debug The switch to debug the update
* We can now at any time debug the
* dynamic build values if it gets broken
*
* @return string
* @since 3.2.0
*/
public function update(string $string, int $debug = 0): string;
/**
* Set the custom code data & can load it in to string
*
* @param string $string The content to check
* @param int $debug The switch to debug the update
* @param int|null $not The not switch
*
* @return string
* @since 3.2.0
*/
public function set(string $string, int $debug = 0, ?int $not = null): string;
/**
* Load the custom code from the system
*
* @param array|null $ids The custom code ides if known
* @param bool $setLang The set lang switch
* @param int $debug The switch to debug the update
*
* @return bool
* @since 3.2.0
*/
public function get(?array $ids = null, bool $setLang = true, $debug = 0): bool;

View File

@ -0,0 +1,65 @@
/**
* Compiler Config
*
* @var Config
* @since 3.2.0
*/
protected Config $config;
/**
* Compiler Registry
*
* @var Registry
* @since 3.2.0
*/
protected Registry $registry;
/**
* Constructor
*
* @param Config|null $config The compiler config.
* @param Registry|null $registry The compiler registry.
*
* @since 3.2.0
*/
public function __construct(?Config $config = null, ?Registry $registry = null)
{
$this->config = $config ?: Compiler::_('Config');
$this->registry = $registry ?: Compiler::_('Registry');
}
/**
* Set MySQL table settings
*
* @param object $item The item data
*
* @return void
* @since 3.2.0
*/
public function set(object &$item)
{
foreach (
$this->config->mysql_table_keys as $mysql_table_key => $mysql_table_val
)
{
if (isset($item->{'mysql_table_' . $mysql_table_key})
&& StringHelper::check(
$item->{'mysql_table_' . $mysql_table_key}
)
&& !is_numeric($item->{'mysql_table_' . $mysql_table_key}))
{
$this->registry->set('builder.mysql_table_setting.' . $item->name_single_code . '.' .
$mysql_table_key, $item->{'mysql_table_' . $mysql_table_key}
);
}
else
{
$this->registry->set('builder.mysql_table_setting.' . $item->name_single_code . '.' .
$mysql_table_key, $mysql_table_val['default']
);
}
// remove the table values since we moved to another object
unset($item->{'mysql_table_' . $mysql_table_key});
}
}

View File

@ -0,0 +1,204 @@
/**
* Compiler Config
*
* @var Config
* @since 3.2.0
*/
protected Config $config;
/**
* The compiler registry
*
* @var Registry
* @since 3.2.0
*/
protected Registry $registry;
/**
* Compiler Alias Data
*
* @var AliasData
* @since 3.2.0
*/
protected Aliasdata $alias;
/**
* Constructor
*
* @param Config|null $config The compiler config object.
* @param Registry|null $registry The compiler registry object.
* @param Aliasdata|null $alias The compiler alias data object.
*
* @since 3.2.0
*/
public function __construct(?Config $config = null, ?Registry $registry = null,
?Aliasdata $alias = null)
{
$this->config = $config ?: Compiler::_('Config');
$this->registry = $registry ?: Compiler::_('Registry');
$this->alias = $alias ?: Compiler::_('Alias.Data');
}
/**
* Set Template and Layout Data
*
* @param string $content The content to check
* @param string $view The view code name
* @param bool $found The proof that something was found
* @param array $templates The option to pass templates keys (to avoid search)
* @param array $layouts The option to pass layout keys (to avoid search)
*
* @return bool if something was found true
* @since 3.2.0
*/
public function set(string $content, string $view, bool $found = false,
array $templates = [], array $layouts = []): bool
{
// to check inside the templates
$again = [];
// check if template keys were passed
if (!ArrayHelper::check($templates))
{
// set the Template data
$temp1 = GetHelper::allBetween(
$content, "\$this->loadTemplate('", "')"
);
$temp2 = GetHelper::allBetween(
$content, '$this->loadTemplate("', '")'
);
if (ArrayHelper::check($temp1)
&& ArrayHelper::check($temp2))
{
$templates = array_merge($temp1, $temp2);
}
else
{
if (ArrayHelper::check($temp1))
{
$templates = $temp1;
}
elseif (ArrayHelper::check($temp2))
{
$templates = $temp2;
}
}
}
// check if we found templates
if (ArrayHelper::check($templates, true))
{
foreach ($templates as $template)
{
if (!$this->registry->
get('builder.template_data.' . $this->config->build_target . '.' . $view . '.' . $template, null))
{
$data = $this->alias->get(
$template, 'template', $view
);
if (ArrayHelper::check($data))
{
// load it to the template data array
$this->registry->
set('builder.template_data.' . $this->config->build_target . '.' . $view . '.' . $template, $data);
// call self to get child data
$again[] = ['content' => $data['html'], 'view' => $view];
$again[] = ['content' => $data['php_view'], 'view' => $view];
}
}
// check if we have the template set (and nothing yet found)
if (!$found && $this->registry->
get('builder.template_data.' . $this->config->build_target . '.' . $view . '.' . $template, null))
{
// something was found
$found = true;
}
}
}
// check if layout keys were passed
if (!ArrayHelper::check($layouts))
{
// set the Layout data
$lay1 = GetHelper::allBetween(
$content, "JLayoutHelper::render('", "',"
);
$lay2 = GetHelper::allBetween(
$content, 'JLayoutHelper::render("', '",'
);
if (ArrayHelper::check($lay1)
&& ArrayHelper::check($lay2))
{
$layouts = array_merge($lay1, $lay2);
}
else
{
if (ArrayHelper::check($lay1))
{
$layouts = $lay1;
}
elseif (ArrayHelper::check($lay2))
{
$layouts = $lay2;
}
}
}
// check if we found layouts
if (ArrayHelper::check($layouts, true))
{
// get the other target if both
$_target = null;
if ($this->config->lang_target === 'both')
{
$_target = ($this->config->build_target === 'admin') ? 'site' : 'admin';
}
foreach ($layouts as $layout)
{
if (!$this->registry->
get('builder.layout_data.' . $this->config->build_target . '.' . $layout, null))
{
$data = $this->alias->get($layout, 'layout', $view);
if (ArrayHelper::check($data))
{
// load it to the layout data array
$this->registry->
set('builder.layout_data.' . $this->config->build_target . '.' . $layout, $data);
// check if other target is set
if ($this->config->lang_target === 'both' && $_target)
{
$this->registry->
set('builder.layout_data.' . $_target . '.' . $layout, $data);
}
// call self to get child data
$again[] = ['content' => $data['html'], 'view' => $view];
$again[] = ['content' => $data['php_view'], 'view' => $view];
}
}
// check if we have the layout set (and nothing yet found)
if (!$found && $this->registry->
get('builder.layout_data.' . $this->config->build_target . '.' . $layout, null))
{
// something was found
$found = true;
}
}
}
// check again
if (ArrayHelper::check($again))
{
foreach ($again as $go)
{
$found = $this->set(
$go['content'], $go['view'], $found
);
}
}
// return the proof that something was found
return $found;
}

View File

@ -0,0 +1,296 @@
/**
* Admin views
*
* @var array
* @since 3.2.0
*/
protected array $data;
/**
* Compiler Config
*
* @var Config
* @since 3.2.0
*/
protected Config $config;
/**
* Compiler Event
*
* @var EventInterface
* @since 3.2.0
*/
protected EventInterface $event;
/**
* 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 Libraries Model
*
* @var Libraries
* @since 3.2.0
*/
protected Libraries $libraries;
/**
* Compiler Template Layout
*
* @var Templatelayout
* @since 3.2.0
*/
protected Templatelayout $templateLayout;
/**
* Compiler Dynamic Get Data
*
* @var Dynamicget
* @since 3.2.0
*/
protected Dynamicget $dynamic;
/**
* Compiler Auto Loader
*
* @var Loader
* @since 3.2.0
*/
protected Loader $loader;
/**
* The modelling javascript
*
* @var Javascriptcustomview
* @since 3.2.0
*/
protected Javascriptcustomview $javascript;
/**
* The modelling css
*
* @var Csscustomview
* @since 3.2.0
*/
protected Csscustomview $css;
/**
* The modelling php admin view
*
* @var Phpcustomview
* @since 3.2.0
*/
protected Phpcustomview $php;
/**
* The modelling custom buttons
*
* @var Custombuttons
* @since 3.2.0
*/
protected Custombuttons $custombuttons;
/**
* The modelling ajax
*
* @var Ajaxcustomview
* @since 3.2.0
*/
protected Ajaxcustomview $ajax;
/**
* Database object to query local DB
*
* @var \JDatabaseDriver
* @since 3.2.0
**/
protected \JDatabaseDriver $db;
/**
* Constructor
*
* @param Config|null $config The compiler config object.
* @param EventInterface|null $event The compiler event api object.
* @param Customcode|null $customcode The compiler customcode object.
* @param Gui|null $gui The compiler customcode gui.
* @param Libraries|null $libraries The compiler libraries model object.
* @param Templatelayout|null $templateLayout The compiler template layout object.
* @param Dynamicget|null $dynamic The compiler dynamic get data object.
* @param Loader|null $loader The compiler loader object.
* @param Javascriptcustomview|null $javascript The modelling javascript object.
* @param Csscustomview|null $css The modelling css object.
* @param Phpcustomview|null $php The modelling php admin view object.
* @param Ajaxcustomview|null $ajax The modelling ajax object.
* @param Custombuttons|null $custombuttons The modelling custombuttons object.
* @param \JDatabaseDriver|null $db The database object.
*
* @since 3.2.0
*/
public function __construct(?Config $config = null, ?EventInterface $event = null,
?Customcode $customcode = null, ?Gui $gui = null, ?Libraries $libraries = null,
?Templatelayout $templateLayout = null, ?Dynamicget $dynamic = null, ?Loader $loader = null,
?Javascriptcustomview $javascript = null, ?Csscustomview $css = null, ?Phpcustomview $php = null,
?Ajaxcustomview $ajax = null, ?Custombuttons $custombuttons = null, ?\JDatabaseDriver $db = null)
{
$this->config = $config ?: Compiler::_('Config');
$this->event = $event ?: Compiler::_('Event');
$this->customcode = $customcode ?: Compiler::_('Customcode');
$this->gui = $gui ?: Compiler::_('Customcode.Gui');
$this->libraries = $libraries ?: Compiler::_('Model.Libraries');
$this->templateLayout = $templateLayout ?: Compiler::_('Templatelayout.Data');
$this->dynamic = $dynamic ?: Compiler::_('Dynamicget.Data');
$this->loader = $loader ?: Compiler::_('Model.Loader');
$this->javascript = $javascript ?: Compiler::_('Model.Javascriptcustomview');
$this->css = $css ?: Compiler::_('Model.Csscustomview');
$this->php = $php ?: Compiler::_('Model.Phpcustomview');
$this->ajax = $ajax ?: Compiler::_('Model.Ajaxcustomview');
$this->custombuttons = $custombuttons ?: Compiler::_('Model.Custombuttons');
$this->db = $db ?: Factory::getDbo();
}
/**
* Get all Custom View Data
*
* @param int $id The view ID
* @param string $table The view table
*
* @return object|null The view data
* @since 3.2.0
*/
public function get(int $id, string $table = 'site_view'): ?object
{
if (!isset($this->data[$id . $table]))
{
// Create a new query object.
$query = $this->db->getQuery(true);
$query->select('a.*');
$query->from('#__componentbuilder_' . $table . ' AS a');
$query->where($this->db->quoteName('a.id') . ' = ' . (int) $id);
// for plugin event TODO change event api signatures
$component_context = $this->config->component_context;
// Trigger Event: jcb_ce_onBeforeQueryCustomViewData
$this->event->trigger(
'jcb_ce_onBeforeQueryCustomViewData',
array(&$component_context, &$id, &$table, &$query, &$this->db)
);
// Reset the query using our newly populated query object.
$this->db->setQuery($query);
// Load the results as a list of stdClass objects (see later for more options on retrieving data).
$item = $this->db->loadObject();
// fix alias to use in code
$item->code = Unique::code(
StringHelper::safe($item->codename), $this->config->build_target
);
$item->Code = StringHelper::safe($item->code, 'F');
$item->CODE = StringHelper::safe($item->code, 'U');
// Trigger Event: jcb_ce_onBeforeModelCustomViewData
$this->event->trigger(
'jcb_ce_onBeforeModelCustomViewData',
array(&$component_context, &$item, &$id, &$table)
);
// set GUI mapper
$guiMapper = [
'table' => $table,
'id' => (int) $id,
'field' => 'default',
'type' => 'html'
];
// set the default data
$item->default = $this->gui->set(
$this->customcode->update(base64_decode((string) $item->default)),
$guiMapper
);
// load context if not set
if (!isset($item->context)
|| !StringHelper::check(
$item->context
))
{
$item->context = $item->code;
}
else
{
// always make sure context is a safe string
$item->context = StringHelper::safe($item->context);
}
// set the libraries
$this->libraries->set($item->code, $item);
// setup template and layout data
$this->templateLayout->set($item->default, $item->code);
// set uikit version 2
$this->loader->uikit($item->code, $item->default);
// auto loaders
$this->loader->set($item->code, $item->default);
// set the main get data
$main_get = $this->dynamic->get(
array($item->main_get), $item->code, $item->context
);
$item->main_get = ArrayHelper::check($main_get) ? $main_get[0] : null;
// set the custom_get data
$item->custom_get = (isset($item->custom_get)
&& JsonHelper::check($item->custom_get))
? json_decode((string) $item->custom_get, true) : null;
if (ArrayHelper::check($item->custom_get))
{
$item->custom_get = $this->dynamic->get(
$item->custom_get, $item->code, $item->context
);
}
// set php scripts
$this->php->set($item, $table);
// set javascript scripts
$this->javascript->set($item, $table);
// set css scripts
$this->css->set($item);
// set Ajax for this view
$this->ajax->set($item, $table);
// set the custom buttons
$this->custombuttons->set($item, $table);
// Trigger Event: jcb_ce_onAfterModelCustomViewData
$this->event->trigger(
'jcb_ce_onAfterModelCustomViewData',
array(&$component_context, &$item)
);
// set the found data
$this->data[$id . $table] = $item;
}
// return the found data
return $this->data[$id . $table];
}

View File

@ -0,0 +1,10 @@
/**
* Get Item History object
*
* @param string $type The type of item
* @param int $id The item ID
*
* @return ?object The history item object
* @since 3.2.0
*/
public function get(string $type, int $id): ?object;

View File

@ -0,0 +1,42 @@
/**
* 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(Load::class, 'Load')
->share('Load', [$this, 'getLoad'], true);
$container->alias(Insert::class, 'Insert')
->share('Insert', [$this, 'getInsert'], true);
}
/**
* Get the Core Load Database
*
* @param Container $container The DI container.
*
* @return Load
* @since 3.2.0
*/
public function getLoad(Container $container): Load
{
return new Load();
}
/**
* Get the Core Insert Database
*
* @param Container $container The DI container.
*
* @return Insert
* @since 3.2.0
*/
public function getInsert(Container $container): Insert
{
return new Insert();
}

View File

@ -0,0 +1,120 @@
/**
* The areas add array
*
* @var array
* @since 3.2.0
*/
protected array $areas = [
'php_view',
'php_jview',
'php_jview_display',
'php_document'
];
/**
* The gui mapper array
*
* @var array
* @since 3.2.0
*/
protected array $guiMapper = [
'table' => null,
'id' => null,
'field' => null,
'type' => 'php'
];
/**
* 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 Auto Loader
*
* @var Loader
* @since 3.2.0
*/
protected Loader $loader;
/**
* Compiler Template Layout Data
*
* @var Templatelayout
* @since 3.2.0
*/
protected Templatelayout $templateLayout;
/**
* Constructor
*
* @param Customcode|null $customcode The compiler customcode object.
* @param Gui|null $gui The compiler customcode gui.
* @param Loader|null $loader The compiler loader object.
* @param Templatelayout|null $templateLayout The template layout data.
*
* @since 3.2.0
*/
public function __construct(?Customcode $customcode = null, ?Gui $gui = null,
?Loader $loader = null, ?Templatelayout $templateLayout = null)
{
$this->customcode = $customcode ?: Compiler::_('Customcode');
$this->gui = $gui ?: Compiler::_('Customcode.Gui');
$this->loader = $loader ?: Compiler::_('Model.Loader');
$this->templateLayout = $templateLayout ?: Compiler::_('Templatelayout.Data');
}
/**
* Set PHP code
*
* @param object $item The item data
* @param string $table The table
*
* @return void
* @since 3.2.0
*/
public function set(object &$item, string $table = 'site_view')
{
// set some gui mapper values
$this->guiMapper['table'] = $table;
$this->guiMapper['id'] = (int) $item->id;
foreach ($this->areas as $area)
{
if (isset($item->{'add_' . $area})
&& $item->{'add_' . $area} == 1
&& StringHelper::check($item->$area))
{
// update GUI mapper field
$this->guiMapper['field'] = $area;
$item->{$area} = $this->gui->set(
$this->customcode->update(
base64_decode((string) $item->{$area})
),
$this->guiMapper
);
// check if we have template or layouts to load
$this->templateLayout->set(
$item->{$area}, $item->code
);
// auto loaders
$this->loader->set($item->code, $item->{$area});
// set uikit version 2
$this->loader->uikit($item->code, $item->{$area});
}
}
}

View File

@ -0,0 +1,71 @@
/**
* event plugin trigger switch
*
* @var boolean
* @since 3.2.0
*/
protected $activePlugins = false;
/**
* Constructor
*
* @param Registry|null $params The component parameters
*
* @since 3.2.0
*/
public function __construct(?Registry $params = null)
{
// Set the params
$params = $params ?: Helper::getParams('com_componentbuilder');
// get active plugins
if (($plugins = $params->get('compiler_plugin', false))
!== false)
{
foreach ($plugins as $plugin)
{
// get possible plugins
if (\JPluginHelper::isEnabled('extension', $plugin))
{
// Import the appropriate plugin group.
\JPluginHelper::importPlugin('extension', $plugin);
// activate events
$this->activePlugins = true;
}
}
}
}
/**
* Trigger and event
*
* @param string $event The event to trigger
* @param mixed $data The values to pass to the event/plugin
*
* @return void
* @throws \Exception
* @since 3.2.0
*/
public function trigger(string $event, $data)
{
// only execute if plugins were loaded (active)
if ($this->activePlugins)
{
// Get the dispatcher.
$dispatcher = \JEventDispatcher::getInstance();
// Trigger this compiler event.
$results = $dispatcher->trigger($event, $data);
// Check for errors encountered while trigger the event
if (count((array) $results) && in_array(false, $results, true))
{
// Get the last error.
$error = $dispatcher->getError();
if (!($error instanceof \Exception))
{
throw new \Exception($error);
}
}
}
}

View File

@ -0,0 +1,52 @@
/**
* Should we add debug lines
*
* @since 3.2.0
**/
private static $add = 'check';
/**
* Set the line number in comments
*
* @param int $nr The line number
* @param string $class The class name
*
* @return string
* @since 3.2.0
*/
public static function _(int $nr, string $class): string
{
if (self::add())
{
return ' [' . $class . ' ' . $nr . ']';
}
return '';
}
/**
* Check if we should add the line number
*
* @return bool
* @since 3.2.0
*/
private static function add(): bool
{
if (!is_bool(self::$add))
{
self::init();
}
return self::$add;
}
/**
* The constructor for add
*
* @return void
* @since 3.2.0
*/
private static function init()
{
self::$add = Compiler::_('Config')->debug_line_nr;
}

View File

@ -0,0 +1,141 @@
/**
* The gui mapper array
*
* @var array
* @since 3.2.0
*/
protected array $guiMapper = [
'table' => 'admin_view',
'id' => null,
'field' => null,
'type' => 'php'
];
/**
* Compiler Config
*
* @var Config
* @since 3.2.0
*/
protected Config $config;
/**
* The compiler registry
*
* @var Registry
* @since 3.2.0
*/
protected Registry $registry;
/**
* Compiler Customcode Dispenser
*
* @var Dispenser
* @since 3.2.0
*/
protected Dispenser $dispenser;
/**
* Constructor
*
* @param Config|null $config The compiler config object.
* @param Registry|null $registry The compiler registry object.
* @param Dispenser|null $dispenser The compiler customcode dispenser
*
* @since 3.2.0
*/
public function __construct(?Config $config = null, ?Registry $registry = null, ?Dispenser $dispenser = null)
{
$this->config = $config ?: Compiler::_('Config');
$this->registry = $registry ?: Compiler::_('Registry');
$this->dispenser = $dispenser ?: Compiler::_('Customcode.Dispenser');
}
/**
* Set Ajax Code
*
* @param object $item The item data
* @param string $table The table
*
* @return void
* @since 3.2.0
*/
public function set(object &$item, string $table = 'admin_view')
{
// set some gui mapper values
$this->guiMapper['table'] = $table;
$this->guiMapper['id'] = (int) $item->id;
if (isset($item->add_php_ajax) && $item->add_php_ajax == 1)
{
// insure the token is added to edit view at least
$this->dispenser->hub['token'][$item->name_single_code]
= true;
$add_ajax_site = false;
if ($this->registry->get('builder.site_edit_view.' . $item->id, false))
{
// we should add this site ajax to front ajax
$add_ajax_site = true;
$this->config->set('add_site_ajax', true);
}
// check if controller input as been set
$item->ajax_input = (isset($item->ajax_input)
&& JsonHelper::check($item->ajax_input))
? json_decode((string) $item->ajax_input, true) : null;
if (ArrayHelper::check($item->ajax_input))
{
if ($add_ajax_site)
{
$this->dispenser->hub['site']['ajax_controller'][$item->name_single_code]
= array_values($item->ajax_input);
}
$this->dispenser->hub['admin']['ajax_controller'][$item->name_single_code]
= array_values($item->ajax_input);
$this->config->set('add_ajax', true);
unset($item->ajax_input);
}
if (StringHelper::check($item->php_ajaxmethod))
{
// make sure we are still in PHP
$this->guiMapper['type'] = 'php';
// update GUI mapper field
$this->guiMapper['field'] = 'php_ajaxmethod';
$this->dispenser->set(
$item->php_ajaxmethod,
'admin',
'ajax_model',
$item->name_single_code,
$this->guiMapper
);
if ($add_ajax_site)
{
$this->dispenser->set(
$item->php_ajaxmethod,
'site',
'ajax_model',
$item->name_single_code,
$this->guiMapper,
false,
false
);
}
// switch ajax on
$this->config->set('add_ajax', true);
// unset anyway
unset($item->php_ajaxmethod);
}
}
}

View File

@ -0,0 +1,82 @@
/**
* The hash prefix and suffix
*
* @var string
* @since 3.2.0
**/
private static string $hhh = '#' . '#' . '#';
/**
* The open prefix
*
* @var string
* @since 3.2.0
**/
private static string $bbb = '[' . '[' . '[';
/**
* The close suffix
*
* @var string
* @since 3.2.0
**/
private static string $ddd = ']' . ']' . ']';
/**
* Get a prefix and suffix added to given string
*
* @param string $class The class name
*
* @return string
* @since 3.2.0
*/
public static function _(string $string): string
{
return self::b() . $string . self::d();
}
/**
* Get a open prefix
*
* @return string
* @since 3.2.0
*/
public static function b(): string
{
return self::$bbb;
}
/**
* Get a close suffix
*
* @return string
* @since 3.2.0
*/
public static function d(): string
{
return self::$ddd;
}
/**
* Get a hash prefix and suffix added to given string
*
* @param string $class The class name
*
* @return string
* @since 3.2.0
*/
public static function _h(string $string): string
{
return self::h() . $string . self::h();
}
/**
* Get a hash-fix
*
* @return string
* @since 3.2.0
*/
public static function h(): string
{
return self::$hhh;
}

View File

@ -0,0 +1,173 @@
/**
* 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(Folder::class, 'Utilities.Folder')
->share('Utilities.Folder', [$this, 'getFolder'], true);
$container->alias(File::class, 'Utilities.File')
->share('Utilities.File', [$this, 'getFile'], true);
$container->alias(Counter::class, 'Utilities.Counter')
->share('Utilities.Counter', [$this, 'getCounter'], true);
$container->alias(Paths::class, 'Utilities.Paths')
->share('Utilities.Paths', [$this, 'getPaths'], true);
$container->alias(Files::class, 'Utilities.Files')
->share('Utilities.Files', [$this, 'getFiles'], true);
$container->alias(Constantpaths::class, 'Utilities.Constantpaths')
->share('Utilities.Constantpaths', [$this, 'getConstantpaths'], true);
$container->alias(Dynamicpath::class, 'Utilities.Dynamicpath')
->share('Utilities.Dynamicpath', [$this, 'getDynamicpath'], true);
$container->alias(Pathfix::class, 'Utilities.Pathfix')
->share('Utilities.Pathfix', [$this, 'getPathfix'], true);
$container->alias(Structure::class, 'Utilities.Structure')
->share('Utilities.Structure', [$this, 'getStructure'], true);
}
/**
* Get the Compiler Folder
*
* @param Container $container The DI container.
*
* @return Folder
* @since 3.2.0
*/
public function getFolder(Container $container): Folder
{
return new Folder(
$container->get('Utilities.Counter'),
$container->get('Utilities.File')
);
}
/**
* Get the Compiler File
*
* @param Container $container The DI container.
*
* @return File
* @since 3.2.0
*/
public function getFile(Container $container): File
{
return new File(
$container->get('Utilities.Counter')
);
}
/**
* Get the Compiler Counter
*
* @param Container $container The DI container.
*
* @return Counter
* @since 3.2.0
*/
public function getCounter(Container $container): Counter
{
return new Counter(
$container->get('Content')
);
}
/**
* Get the Compiler Paths
*
* @param Container $container The DI container.
*
* @return Paths
* @since 3.2.0
*/
public function getPaths(Container $container): Paths
{
return new Paths(
$container->get('Config'),
$container->get('Component')
);
}
/**
* Get the Compiler Files Bucket
*
* @param Container $container The DI container.
*
* @return Files
* @since 3.2.0
*/
public function getFiles(Container $container): Files
{
return new Files();
}
/**
* Get the Constant Paths
*
* @param Container $container The DI container.
*
* @return Constantpaths
* @since 3.2.0
*/
public function getConstantpaths(Container $container): Constantpaths
{
return new Constantpaths();
}
/**
* Get the Compiler Dynamic Path
*
* @param Container $container The DI container.
*
* @return Dynamicpath
* @since 3.2.0
*/
public function getDynamicpath(Container $container): Dynamicpath
{
return new Dynamicpath(
$container->get('Placeholder'),
$container->get('Utilities.Constantpaths')
);
}
/**
* Get the Compiler Path Fixer
*
* @param Container $container The DI container.
*
* @return Pathfix
* @since 3.2.0
*/
public function getPathfix(Container $container): Pathfix
{
return new Pathfix();
}
/**
* Get the Compiler Structure Dynamic Builder
*
* @param Container $container The DI container.
*
* @return Structure
* @since 3.2.0
*/
public function getStructure(Container $container): Structure
{
return new Structure(
$container->get('Component.Settings'),
$container->get('Utilities.Paths'),
$container->get('Utilities.Counter'),
$container->get('Utilities.File'),
$container->get('Utilities.Files')
);
}

View File

@ -0,0 +1,24 @@
/**
* Get the create date of an item
*
* @param mixed $item The item data
*
* @return string The create data
* @since 3.2.0
*/
public function get(&$item): string
{
if (isset($item['settings']->created)
&& StringHelper::check($item['settings']->created))
{
// first set the main date
$date = strtotime((string) $item['settings']->created);
}
else
{
// first set the main date
$date = strtotime("now");
}
return Factory::getDate($date)->format('jS F, Y');
}

View File

@ -0,0 +1,139 @@
/**
* Compiler Type Name
*
* @var TypeName
* @since 3.2.0
*/
protected TypeName $typeName;
/**
* Compiler Field Name
*
* @var FieldName
* @since 3.2.0
*/
protected FieldName $fieldName;
/**
* Constructor
*
* @param TypeName|null $typeName The compiler type name object.
* @param FieldName|null $fieldName The compiler field name object.
*
* @since 3.2.0
*/
public function __construct(?TypeName $typeName = null, ?FieldName $fieldName = null)
{
$this->typeName = $typeName ?: Compiler::_('Field.Type.Name');
$this->fieldName = $fieldName ?: Compiler::_('Field.Name');
}
/**
* Set the conditions
*
* @param object $item The view data
*
* @return void
* @since 3.2.0
*/
public function set(object &$item)
{
$item->addconditions = (isset($item->addconditions)
&& JsonHelper::check($item->addconditions))
? json_decode((string) $item->addconditions, true) : null;
if (ArrayHelper::check($item->addconditions))
{
$item->conditions = [];
$ne = 0;
foreach ($item->addconditions as $nr => $conditionValue)
{
if (ArrayHelper::check(
$conditionValue['target_field']
) && ArrayHelper::check($item->fields))
{
foreach ( $conditionValue['target_field'] as $fieldKey => $fieldId)
{
foreach ($item->fields as $fieldValues)
{
if ((int) $fieldValues['field'] == (int) $fieldId)
{
// load the field details
$required = GetHelper::between(
$fieldValues['settings']->xml,
'required="', '"'
);
$required = ($required === 'true'
|| $required === '1') ? 'yes' : 'no';
$filter = GetHelper::between(
$fieldValues['settings']->xml,
'filter="', '"'
);
$filter = StringHelper::check(
$filter
) ? $filter : 'none';
// set the field name
$conditionValue['target_field'][$fieldKey] = [
'name' => $this->fieldName->get(
$fieldValues, $item->name_list_code
),
'type' => $this->typeName->get(
$fieldValues
),
'required' => $required,
'filter' => $filter
];
break;
}
}
}
}
// load match field
if (ArrayHelper::check($item->fields)
&& isset($conditionValue['match_field']))
{
foreach ($item->fields as $fieldValue)
{
if ((int) $fieldValue['field'] == (int) $conditionValue['match_field'])
{
// set the type
$type = $this->typeName->get($fieldValue);
// set the field details
$conditionValue['match_name'] = $this->fieldName->get(
$fieldValue, $item->name_list_code
);
$conditionValue['match_type'] = $type;
$conditionValue['match_xml'] = $fieldValue['settings']->xml;
// if custom field load field being extended
if (!FieldHelper::check($type))
{
$conditionValue['match_extends'] = GetHelper::between(
$fieldValue['settings']->xml,
'extends="', '"'
);
}
else
{
$conditionValue['match_extends'] = '';
}
break;
}
}
}
// set condition values
$item->conditions[$ne] = $conditionValue;
$ne++;
}
}
unset($item->addconditions);
}

View File

@ -0,0 +1,119 @@
/**
* The gui mapper array
*
* @var array
* @since 3.2.0
*/
protected array $guiMapper = [
'table' => 'site_view',
'id' => null,
'field' => null,
'type' => 'php'
];
/**
* Compiler Config
*
* @var Config
* @since 3.2.0
*/
protected Config $config;
/**
* Compiler Customcode Dispenser
*
* @var Dispenser
* @since 3.2.0
*/
protected Dispenser $dispenser;
/**
* Constructor
*
* @param Config|null $config The compiler config object.
* @param Dispenser|null $dispenser The compiler customcode dispenser
*
* @since 3.2.0
*/
public function __construct(?Config $config = null, ?Dispenser $dispenser = null)
{
$this->config = $config ?: Compiler::_('Config');
$this->dispenser = $dispenser ?: Compiler::_('Customcode.Dispenser');
}
/**
* Set Ajax Code
*
* @param object $item The item data
* @param string $table The table
*
* @return void
* @since 3.2.0
*/
public function set(object &$item, string $table = 'site_view')
{
// add_Ajax for this view
if (isset($item->add_php_ajax) && $item->add_php_ajax == 1)
{
// set some gui mapper values
$this->guiMapper['table'] = $table;
$this->guiMapper['id'] = (int) $item->id;
// ajax target (since we only have two options really)
if ('site' === $this->config->build_target)
{
$target = 'site';
}
else
{
$target = 'admin';
}
$add_ajax_site = false;
// check if controller input as been set
$item->ajax_input = (isset($item->ajax_input)
&& JsonHelper::check($item->ajax_input))
? json_decode((string) $item->ajax_input, true) : null;
if (ArrayHelper::check($item->ajax_input))
{
$this->dispenser->hub[$target]['ajax_controller'][$item->code]
= array_values($item->ajax_input);
$add_ajax_site = true;
}
unset($item->ajax_input);
// load the ajax class mathods (if set)
if (StringHelper::check($item->php_ajaxmethod))
{
// set field
$this->guiMapper['field'] = 'php_ajaxmethod';
$this->dispenser->set(
$item->php_ajaxmethod,
$target,
'ajax_model',
$item->code,
$this->guiMapper
);
$add_ajax_site = true;
}
unset($item->php_ajaxmethod);
// should ajax be set
if ($add_ajax_site)
{
// turn on ajax area
if ('site' === $this->config->build_target)
{
$this->config->set('add_site_ajax', true);
}
else
{
$this->config->set('add_ajax', true);
}
}
}
}

View File

@ -0,0 +1,83 @@
/**
* Compiler Config
*
* @var Config
* @since 3.2.0
*/
protected Config $config;
/**
* Compiler Registry
*
* @var Registry
* @since 3.2.0
*/
protected Registry $registry;
/**
* Compiler Library Data
*
* @var Library
* @since 3.2.0
*/
protected Library $library;
/**
* Constructor
*
* @param Config|null $config The compiler config.
* @param Registry|null $registry The compiler registry.
* @param Library|null $library The compiler library data object.
*
* @since 3.2.0
*/
public function __construct(?Config $config = null, ?Registry $registry = null, ?Library $library = null)
{
$this->config = $config ?: Compiler::_('Config');
$this->registry = $registry ?: Compiler::_('Registry');
$this->library = $library ?: Compiler::_('Library.Data');
}
/**
* Set Libraries
*
* @param string $key The key mapper
* @param object $item The item data
* @param string|null $target The area being targeted
*
* @return void
* @since 3.2.0
*/
public function set(string $key, object &$item, string $target = null)
{
// set the target
$target = $target ?: $this->config->build_target;
// make sure json become array
if (JsonHelper::check($item->libraries))
{
$item->libraries = json_decode((string) $item->libraries, true);
}
// if we have an array add it
if (ArrayHelper::check($item->libraries))
{
foreach ($item->libraries as $library)
{
if (!$this->registry->exists('builder.library_manager.' .
$target . '.' . $key . '.' . (int) $library) && $this->library->get((int) $library))
{
$this->registry->set('builder.library_manager.' .
$target . '.' . $key . '.' . (int) $library, true);
}
}
}
elseif (is_numeric($item->libraries)
&& !$this->registry->exists('builder.library_manager.' .
$target . '.' . $key . '.' . (int) $item->libraries)
&& $this->library->get((int) $item->libraries))
{
$this->registry->set('builder.library_manager.' .
$target . '.' . $key . '.' . (int) $item->libraries, true);
}
}

View File

@ -0,0 +1,246 @@
/**
* Admin view table names
*
* @var array
* @since 3.2.0
*/
protected array $name;
/**
* Compiler Config
*
* @var Config
* @since 3.2.0
*/
protected Config $config;
/**
* The compiler registry
*
* @var Registry
* @since 3.2.0
*/
protected Registry $registry;
/**
* Database object to query local DB
*
* @var \JDatabaseDriver
* @since 3.2.0
**/
protected \JDatabaseDriver $db;
/**
* Constructor
*
* @param Config|null $config The compiler config object.
* @param Registry|null $registry The compiler registry object.
* @param \JDatabaseDriver|null $db The database object.
*
* @since 3.2.0
*/
public function __construct(?Config $config = null, ?Registry $registry = null,
?\JDatabaseDriver $db = null)
{
$this->config = $config ?: Compiler::_('Config');
$this->registry = $registry ?: Compiler::_('Registry');
$this->db = $db ?: Factory::getDbo();
}
/**
* Get Data Selection of the dynamic get
*
* @param string $methodKey The method unique key
* @param string $viewCode The code name of the view
* @param string $string The data string
* @param string $asset The asset in question
* @param string $as The as string
* @param string $type The target type (db||view)
* @param int|null $rowType The row type
*
* @return array|null the select query
* @since 3.2.0
*/
public function get(string $methodKey, string $viewCode,
string $string, string $asset, string $as, string $type, ?int $rowType = null): ?array
{
if (StringHelper::check($string))
{
if ('db' === $type)
{
$table = '#__' . $asset;
$queryName = $asset;
$view = '';
}
elseif ('view' === $type)
{
$view = $this->name($asset);
$table = '#__' . $this->config->component_code_name . '_' . $view;
$queryName = $view;
}
else
{
return null;
}
// just get all values from table if * is found
if ($string === '*' || strpos($string, '*') !== false)
{
if ($type == 'view')
{
// TODO move getViewTableColumns to its own class
$_string = Helper::_('getViewTableColumns',
[$asset, $as, $rowType]
);
}
else
{
// TODO move getDbTableColumns to its own class
$_string = Helper::_('getDbTableColumns',
[$asset, $as, $rowType]
);
}
// get only selected values
$lines = explode(PHP_EOL, (string) $_string);
// make sure to set the string to *
$string = '*';
}
else
{
// get only selected values
$lines = explode(PHP_EOL, $string);
}
// only continue if lines are available
if (ArrayHelper::check($lines))
{
$gets = [];
$keys = [];
// first load all options
foreach ($lines as $line)
{
if (strpos($line, 'AS') !== false)
{
$lineArray = explode("AS", $line);
}
elseif (strpos($line, 'as') !== false)
{
$lineArray = explode("as", $line);
}
else
{
$lineArray = array($line, null);
}
// set the get and key
$get = trim($lineArray[0]);
$key = trim($lineArray[1]);
// only add the view (we must adapt this)
if ($this->registry->exists('builder.get_as_lookup.' . $methodKey . '.' . $get)
&& 'a' != $as
&& is_numeric($rowType) && 1 == $rowType
&& 'view' === $type
&& strpos('#' . $key, '#' . $view . '_') === false)
{
// this is a problem (TODO) since we may want to not add the view name.
$key = $view . '_' . trim($key);
}
// continue only if we have get
if (StringHelper::check($get))
{
$gets[] = $this->db->quote($get);
if (StringHelper::check($key))
{
$this->registry->
set('builder.get_as_lookup.' . $methodKey . '.' . $get, $key);
}
else
{
$key = str_replace(
$as . '.', '', $get
);
$this->registry->
set('builder.get_as_lookup.' . $methodKey . '.' . $get, $key);
}
// set the keys
$keys[] = $this->db->quote(
$key
);
// make sure we have the view name
if (StringHelper::check($view))
{
// prep the field name
$field = str_replace($as . '.', '', $get);
// load to the site fields memory bucket
$this->registry->
set('builder.site_fields.' . $view . '.' . $field . '.' . $methodKey . '___' . $as,
['site' => $viewCode, 'get' => $get, 'as' => $as, 'key' => $key]);
}
}
}
if (ArrayHelper::check($gets)
&& ArrayHelper::check($keys))
{
// single joined selection needs the prefix to the values to avoid conflict in the names
// so we must still add then AS
if ($string == '*' && (is_null($rowType) || 1 != $rowType))
{
$querySelect = "\$query->select('" . $as . ".*');";
}
else
{
$querySelect = '$query->select($db->quoteName('
. PHP_EOL . Indent::_(3) . 'array(' . implode(
',', $gets
) . '),' . PHP_EOL . Indent::_(3) . 'array('
. implode(',', $keys) . ')));';
}
$queryFrom = '$db->quoteName(' . $this->db->quote($table)
. ', ' . $this->db->quote($as) . ')';
// return the select query
return [
'select' => $querySelect,
'from' => $queryFrom,
'name' => $queryName,
'table' => $table,
'type' => $type,
'select_gets' => $gets,
'select_keys' => $keys
];
}
}
}
return null;
}
/**
* Get the Admin view table name
*
* @param int $id The item id to add
*
* @return string the admin view code name
* @since 3.2.0
*/
protected function name(int $id): string
{
// get name if not set
if (!isset($this->name[$id]))
{
$this->name[$id] = StringHelper::safe(
GetHelper::var('admin_view', $id, 'id', 'name_single')
);
}
return $this->name[$id] ?? 'error';
}

View File

@ -0,0 +1,78 @@
/**
* Compiler Utilities Counter
*
* @var Counter
* @since 3.2.0
*/
protected Counter $counter;
/**
* Compiler Utilities Paths
*
* @var Paths
* @since 3.2.0
*/
protected Paths $paths;
/**
* Constructor
*
* @param Counter|null $counter The compiler counter object.
* @param Paths|null $paths The compiler paths object.
*
* @since 3.2.0
*/
public function __construct(?Counter $counter = null, ?Paths $paths = null)
{
$this->counter = $counter ?: Compiler::_('Utilities.Counter');
$this->paths = $paths ?: Compiler::_('Utilities.Paths');
}
/**
* set HTML blank file to a path
*
* @param string $path The path to where to set the blank html file
* @param string $root The root path
*
* @return void
*/
public function html(string $path = '', string $root = 'component')
{
if ('component' === $root)
{
$root = $this->paths->component_path . '/';
}
// use path if exist
if (strlen($path) > 0)
{
JoomlaFile::copy(
$this->paths->template_path . '/index.html',
$root . $path . '/index.html'
);
}
else
{
JoomlaFile::copy(
$this->paths->template_path . '/index.html',
$root . '/index.html'
);
}
// count the file created
$this->counter->file++;
}
/**
* Create a file on the server if it does not exist, or Overwrite existing files
*
* @param string $path The path and file name where to safe the data
* @param string $data The data to safe
*
* @return bool true On success
* @since 3.2.0
*/
public function write(string $path, string $data): bool
{
return FileHelper::write($path, $data);
}

View File

@ -0,0 +1,79 @@
/**
* The compiler Registry
*
* @var Registry
* @since 3.2.0
*/
protected Registry $registry;
/**
* The compiler field name
*
* @var FieldName
* @since 3.2.0
*/
protected FieldName $fieldName;
/**
* Constructor
*
* @param Registry|null $registry The compiler registry object.
* @param FieldName|null $fieldName The compiler field name object.
*
* @since 3.2.0
*/
public function __construct(?Registry $registry = null, ?FieldName $fieldName = null)
{
$this->registry = $registry ?: Compiler::_('Registry');
$this->fieldName = $fieldName ?: Compiler::_('Field.Name');
}
/**
* Set activate alias builder
*
* @param object $item The item data
*
* @return void
* @since 3.2.0
*/
public function set(object &$item)
{
if (!$this->registry->get('builder.custom_alias.' . $item->name_single_code, null)
&& isset($item->alias_builder_type) && 2 == $item->alias_builder_type
&& isset($item->alias_builder) && JsonHelper::check($item->alias_builder))
{
// get the aliasFields
$alias_fields = (array) json_decode((string) $item->alias_builder, true);
// get the active fields
$alias_fields = (array) array_filter(
$item->fields, function ($field) use ($alias_fields) {
// check if field is in view fields
if (in_array($field['field'], $alias_fields))
{
return true;
}
return false;
}
);
// check if all is well
if (ArrayHelper::check($alias_fields))
{
// load the field names
$this->registry->set('builder.custom_alias.' . $item->name_single_code,
(array) array_map(
function ($field) use (&$item) {
return $this->fieldName->get(
$field, $item->name_list_code
);
}, $alias_fields
)
);
}
}
// unset
unset($item->alias_builder);
}

View File

@ -0,0 +1,57 @@
/**
* Current Joomla Version We are IN
*
* @var int
* @since 3.2.0
**/
protected $currentVersion;
/**
* 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(J3History::class, 'J3.History')
->share('J3.History', [$this, 'getJ3History'], true);
$container->alias(HistoryInterface::class, 'History')
->share('History', [$this, 'getHistory'], true);
}
/**
* Get the History
*
* @param Container $container The DI container.
*
* @return HistoryInterface
* @since 3.2.0
*/
public function getHistory(Container $container): HistoryInterface
{
if (empty($this->currentVersion))
{
$this->currentVersion = Version::MAJOR_VERSION;
}
return $container->get('J' . $this->currentVersion . '.History');
}
/**
* Get the Joomla 3 History
*
* @param Container $container The DI container.
*
* @return J3History
* @since 3.2.0
*/
public function getJ3History(Container $container): J3History
{
return new J3History(
$container->get('Config')
);
}

View File

@ -0,0 +1,718 @@
/**
* The standard folders
*
* @var array
* @since 3.2.0
*/
protected array $standardFolders = [
'site',
'admin',
'media'
];
/**
* The standard root files
*
* @var array
* @since 3.2.0
*/
protected array $standardRootFiles = [
'access.xml',
'config.xml',
'controller.php',
'index.html',
'README.txt'
];
/**
* Compiler Joomla Version Data
*
* @var object|null
* @since 3.2.0
*/
protected ?object $data = null;
/**
* Compiler Config
*
* @var Config
* @since 3.2.0
*/
protected Config $config;
/**
* The compiler registry
*
* @var Registry
* @since 3.2.0
*/
protected Registry $registry;
/**
* Compiler Event
*
* @var EventInterface
* @since 3.2.0
*/
protected EventInterface $event;
/**
* Compiler Placeholder
*
* @var Placeholder
* @since 3.2.0
*/
protected Placeholder $placeholder;
/**
* Compiler Component
*
* @var Component
* @since 3.2.0
**/
protected Component $component;
/**
* Compiler Utilities Paths
*
* @var Paths
* @since 3.2.0
*/
protected Paths $paths;
/**
* Compiler Component Dynamic Path
*
* @var Dynamicpath
* @since 3.2.0
**/
protected Dynamicpath $dynamicpath;
/**
* Compiler Component Pathfix
*
* @var Pathfix
* @since 3.2.0
**/
protected Pathfix $pathfix;
/**
* Constructor
*
* @param Config|null $config The compiler config object.
* @param Registry|null $registry The compiler registry object.
* @param EventInterface|null $event The compiler event api object.
* @param Placeholder|null $placeholder The compiler placeholder object.
* @param Component|null $component The component class.
* @param Paths|null $paths The compiler paths object.
* @param Dynamicpath|null $dynamicpath The compiler dynamic path object.
* @param Pathfix|null $pathfix The compiler path fixing object.
*
* @since 3.2.0
*/
public function __construct(?Config $config = null, ?Registry $registry = null,
?EventInterface $event = null, ?Placeholder $placeholder = null,
?Component $component = null, ?Paths $paths = null,
?Dynamicpath $dynamicpath = null, ?Pathfix $pathfix = null)
{
$this->config = $config ?: Compiler::_('Config');
$this->registry = $registry ?: Compiler::_('Registry');
$this->event = $event ?: Compiler::_('Event');
$this->placeholder = $placeholder ?: Compiler::_('Placeholder');
$this->component = $component ?: Compiler::_('Component');
$this->paths = $paths ?: Compiler::_('Utilities.Paths');
$this->dynamicpath = $dynamicpath ?: Compiler::_('Utilities.Dynamicpath');
$this->pathfix = $pathfix ?: Compiler::_('Utilities.Pathfix');
// add component endpoint file to stander list of root files
$this->standardRootFiles[] = $this->component->get('name_code') . '.php';
}
/**
* Check if data set is loaded
*
* @return bool
* @since 3.2.0
*/
public function exists(): bool
{
if (!$this->isSet())
{
// load the data
$this->data = $this->get();
if (!$this->isSet())
{
return false;
}
}
return true;
}
/**
* Get Joomla - Folder Structure to Create
*
* @return object The version related structure
* @since 3.2.0
*/
public function structure(): object
{
return $this->data->create;
}
/**
* Get Joomla - Move Multiple Structure
*
* @return object The version related multiple structure
* @since 3.2.0
*/
public function multiple(): object
{
return $this->data->move->dynamic;
}
/**
* Get Joomla - Move Single Structure
*
* @return object The version related single structure
* @since 3.2.0
*/
public function single(): object
{
return $this->data->move->static;
}
/**
* Check if Folder is a Standard Folder
*
* @param string $folder The folder name
*
* @return bool true if the folder exists
* @since 3.2.0
*/
public function standardFolder(string $folder): bool
{
return in_array($folder, $this->standardFolders);
}
/**
* Check if File is a Standard Root File
*
* @param string $file The file name
*
* @return bool true if the file exists
* @since 3.2.0
*/
public function standardRootFile(string $file): bool
{
return in_array($file, $this->standardRootFiles);
}
/**
* Check if Data is Set
*
* @return bool
* @since 3.2.0
*/
private function isSet(): bool
{
return is_object($this->data) &&
isset($this->data->create) &&
isset($this->data->move) &&
isset($this->data->move->static) &&
isset($this->data->move->dynamic);
}
/**
* get the Joomla Version Data
*
* @return object|null The version data
* @since 3.2.0
*/
private function get(): ?object
{
// override option
$customSettings = $this->paths->template_path . '/settings_' .
$this->config->component_code_name . '.json';
// get the data
$version_data = $this->readJsonFile($customSettings);
if (is_null($version_data) || !$this->isValidData($version_data))
{
return null;
}
$this->loadExtraFolders();
$this->loadExtraFiles();
$this->addFolders($version_data);
$this->addFiles($version_data);
// for plugin event TODO change event api signatures
$component_context = $this->config->component_context;
// Trigger Event: jcb_ce_onAfterSetJoomlaVersionData
$this->event->trigger(
'jcb_ce_onAfterSetJoomlaVersionData',
array(&$component_context, &$version_data)
);
return $version_data;
}
/**
* Read the Json file data
*
* @param string $filePath
*
* @return object|null The version data
* @since 3.2.0
*/
private function readJsonFile(string $filePath): ?object
{
if (FileHelper::exists($filePath))
{
$jsonContent = FileHelper::getContent($filePath);
}
else
{
$jsonContent = FileHelper::getContent($this->paths->template_path . '/settings.json');
}
if (JsonHelper::check($jsonContent))
{
return json_decode((string) $jsonContent);
}
return null;
}
/**
* Check if this is valid data
*
* @param object $versionData
*
* @return bool
* @since 3.2.0
*/
private function isValidData(object $versionData): bool
{
return isset($versionData->create) &&
isset($versionData->move) &&
isset($versionData->move->static) &&
isset($versionData->move->dynamic);
}
/**
* Add Extra/Dynamic folders
*
* @return void
* @since 3.2.0
*/
private function loadExtraFolders()
{
if ($this->component->isArray('folders') ||
$this->config->get('add_eximport', false) ||
$this->config->get('uikit', 0) ||
$this->config->get('footable', false))
{
$this->addImportViewFolder();
$this->addPhpSpreadsheetFolder();
$this->addUikitFolder();
$this->addFooTableFolder();
}
}
/**
* Add Import and Export Folder
*
* @return void
* @since 3.2.0
*/
private function addImportViewFolder()
{
if ($this->config->get('add_eximport', false))
{
$this->component->appendArray('folders', [
'folder' => 'importViews',
'path' => 'admin/views/import',
'rename' => 1
]);
}
}
/**
* Add Php Spreadsheet Folder
*
* @return void
* @since 3.2.0
*/
private function addPhpSpreadsheetFolder()
{
// move the phpspreadsheet Folder (TODO we must move this to a library package)
if ($this->config->get('add_eximport', false))
{
$this->component->appendArray('folders', [
'folderpath' => 'JPATH_LIBRARIES/phpspreadsheet/vendor',
'path' => '/libraries/phpspreadsheet/',
'rename' => 0
]);
}
}
/**
* Add Uikit Folders
*
* @return void
* @since 3.2.0
*/
private function addUikitFolder()
{
$uikit = $this->config->get('uikit', 0);
if (2 == $uikit || 1 == $uikit)
{
// move the UIKIT Folder into place
$this->component->appendArray('folders', [
'folder' => 'uikit-v2',
'path' => 'media',
'rename' => 0
]);
}
if (2 == $uikit || 3 == $uikit)
{
// move the UIKIT-3 Folder into place
$this->component->appendArray('folders', [
'folder' => 'uikit-v3',
'path' => 'media',
'rename' => 0
]);
}
}
/**
* Add Foo Table Folder
*
* @return void
* @since 3.2.0
*/
private function addFooTableFolder()
{
if (!$this->config->get('footable', false))
{
return;
}
$footable_version = $this->config->get('footable_version', 2);
if (2 == $footable_version)
{
// move the footable folder into place
$this->component->appendArray('folders', [
'folder' => 'footable-v2',
'path' => 'media',
'rename' => 0
]);
}
elseif (3 == $footable_version)
{
// move the footable folder into place
$this->component->appendArray('folders', [
'folder' => 'footable-v3',
'path' => 'media',
'rename' => 0
]);
}
}
/**
* Add Extra/Dynamic files
*
* @return void
* @since 3.2.0
*/
private function loadExtraFiles()
{
if ($this->component->isArray('files') ||
$this->config->get('google_chart', false))
{
$this->addGoogleChartFiles();
}
}
/**
* Add Google Chart Files
*
* @return void
* @since 3.2.0
*/
private function addGoogleChartFiles()
{
if ($this->config->get('google_chart', false))
{
// move the google chart files
$this->component->appendArray('files', [
'file' => 'google.jsapi.js',
'path' => 'media/js',
'rename' => 0
]);
$this->component->appendArray('files', [
'file' => 'chartbuilder.php',
'path' => 'admin/helpers',
'rename' => 0
]);
}
}
/**
* Add Folders
*
* @param object $versionData
*
* @return void
* @since 3.2.0
*/
private function addFolders(object &$versionData)
{
if (!$this->component->isArray('folders'))
{
return;
}
// pointer tracker
$pointer_tracker = 'h';
foreach ($this->component->get('folders') as $custom)
{
// check type of target type
$_target_type = 'c0mp0n3nt';
if (isset($custom['target_type']))
{
$_target_type = $custom['target_type'];
}
// for good practice
$this->pathfix->set(
$custom, ['path', 'folder', 'folderpath']
);
// fix custom path
if (isset($custom['path'])
&& StringHelper::check($custom['path']))
{
$custom['path'] = trim((string) $custom['path'], '/');
}
// by default custom path is true
$customPath = 'custom';
// set full path if this is a full path folder
if (!isset($custom['folder']) && isset($custom['folderpath']))
{
// update the dynamic path
$custom['folderpath'] = $this->dynamicpath->update(
$custom['folderpath']
);
// set the folder path with / if does not have a drive/windows full path
$custom['folder'] = (preg_match(
'/^[a-z]:/i', $custom['folderpath']
)) ? trim($custom['folderpath'], '/')
: '/' . trim($custom['folderpath'], '/');
// remove the file path
unset($custom['folderpath']);
// triget fullpath
$customPath = 'full';
}
// make sure we use the correct name
$pathArray = (array) explode('/', (string) $custom['path']);
$lastFolder = end($pathArray);
// only rename folder if last has folder name
if (isset($custom['rename']) && $custom['rename'] == 1)
{
$custom['path'] = str_replace(
'/' . $lastFolder, '', (string) $custom['path']
);
$rename = 'new';
$newname = $lastFolder;
}
elseif ('full' === $customPath)
{
// make sure we use the correct name
$folderArray = (array) explode('/', (string) $custom['folder']);
$lastFolder = end($folderArray);
$rename = 'new';
$newname = $lastFolder;
}
else
{
$rename = false;
$newname = '';
}
// insure we have no duplicates
$key_pointer = StringHelper::safe(
$custom['folder']
) . '_f' . $pointer_tracker;
$pointer_tracker++;
// fix custom path
$custom['path'] = ltrim((string) $custom['path'], '/');
// set new folder to object
$versionData->move->static->{$key_pointer} = new \stdClass();
$versionData->move->static->{$key_pointer}->naam = str_replace('//', '/', (string) $custom['folder']);
$versionData->move->static->{$key_pointer}->path = $_target_type . '/' . $custom['path'];
$versionData->move->static->{$key_pointer}->rename = $rename;
$versionData->move->static->{$key_pointer}->newName = $newname;
$versionData->move->static->{$key_pointer}->type = 'folder';
$versionData->move->static->{$key_pointer}->custom = $customPath;
// set the target if type and id is found
if (isset($custom['target_id']) && isset($custom['target_type']))
{
$versionData->move->static->{$key_pointer}->_target = [
'key' => $custom['target_id'] . '_' . $custom['target_type'],
'type' => $custom['target_type']
];
}
}
$this->component->remove('folders');
}
/**
* Add Files
*
* @param object $versionData
*
* @return void
* @since 3.2.0
*/
private function addFiles(object &$versionData)
{
if (!$this->component->isArray('files')) {
return;
}
// pointer tracker
$pointer_tracker = 'h';
foreach ($this->component->get('files') as $custom)
{
// check type of target type
$_target_type = 'c0mp0n3nt';
if (isset($custom['target_type']))
{
$_target_type = $custom['target_type'];
}
// for good practice
$this->pathfix->set(
$custom, ['path', 'file', 'filepath']
);
// by default custom path is true
$customPath = 'custom';
// set full path if this is a full path file
if (!isset($custom['file']) && isset($custom['filepath']))
{
// update the dynamic path
$custom['filepath'] = $this->dynamicpath->update(
$custom['filepath']
);
// set the file path with / if does not have a drive/windows full path
$custom['file'] = (preg_match('/^[a-z]:/i', $custom['filepath']))
? trim($custom['filepath'], '/') : '/' . trim($custom['filepath'], '/');
// remove the file path
unset($custom['filepath']);
// triget fullpath
$customPath = 'full';
}
// make sure we have not duplicates
$key_pointer = StringHelper::safe(
$custom['file']
) . '_g' . $pointer_tracker;
$pointer_tracker++;
// set new file to object
$versionData->move->static->{$key_pointer} = new \stdClass();
$versionData->move->static->{$key_pointer}->naam = str_replace('//', '/', (string) $custom['file']);
// update the dynamic component name placholders in file names
$custom['path'] = $this->placeholder->update_(
$custom['path']
);
// get the path info
$pathInfo = pathinfo((string) $custom['path']);
if (isset($pathInfo['extension']) && $pathInfo['extension'])
{
$pathInfo['dirname'] = trim($pathInfo['dirname'], '/');
// set the info
$versionData->move->static->{$key_pointer}->path = $_target_type . '/' . $pathInfo['dirname'];
$versionData->move->static->{$key_pointer}->rename = 'new';
$versionData->move->static->{$key_pointer}->newName = $pathInfo['basename'];
}
elseif ('full' === $customPath)
{
// fix custom path
$custom['path'] = ltrim((string) $custom['path'], '/');
// get file array
$fileArray = (array) explode('/', (string) $custom['file']);
// set the info
$versionData->move->static->{$key_pointer}->path = $_target_type . '/' . $custom['path'];
$versionData->move->static->{$key_pointer}->rename = 'new';
$versionData->move->static->{$key_pointer}->newName = end($fileArray);
}
else
{
// fix custom path
$custom['path'] = ltrim((string) $custom['path'], '/');
// set the info
$versionData->move->static->{$key_pointer}->path = $_target_type . '/' . $custom['path'];
$versionData->move->static->{$key_pointer}->rename = false;
}
$versionData->move->static->{$key_pointer}->type = 'file';
$versionData->move->static->{$key_pointer}->custom = $customPath;
// set the target if type and id is found
if (isset($custom['target_id'])
&& isset($custom['target_type']))
{
$versionData->move->static->{$key_pointer}->_target = [
'key' => $custom['target_id'] . '_' . $custom['target_type'],
'type' => $custom['target_type']
];
}
// check if file should be updated
if (!isset($custom['notnew']) || $custom['notnew'] == 0
|| $custom['notnew'] != 1)
{
$this->registry->appendArray('files.not.new', $key_pointer);
}
else
{
// update the file content
$this->registry->set('update.file.content.' . $key_pointer, true);
}
}
$this->component->remove('files');
}

View File

@ -0,0 +1,582 @@
/**
* The new name
*
* @var string
* @since 3.2.0
*/
protected string $newName;
/**
* Current Full Path
*
* @var string
* @since 3.2.0
*/
protected string $currentFullPath;
/**
* Package Full Path
*
* @var string
* @since 3.2.0
*/
protected string $packageFullPath;
/**
* ZIP Full Path
*
* @var string
* @since 3.2.0
*/
protected string $zipFullPath;
/**
* Compiler Config
*
* @var Config
* @since 3.2.0
*/
protected Config $config;
/**
* The compiler registry
*
* @var Registry
* @since 3.2.0
*/
protected Registry $registry;
/**
* Compiler Component Joomla Version Settings
*
* @var Settings
* @since 3.2.0
*/
protected Settings $settings;
/**
* Compiler Component
*
* @var Component
* @since 3.2.0
**/
protected Component $component;
/**
* Compiler Content
*
* @var Content
* @since 3.2.0
**/
protected Content $content;
/**
* Compiler Counter
*
* @var Counter
* @since 3.2.0
*/
protected Counter $counter;
/**
* Compiler Paths
*
* @var Paths
* @since 3.2.0
*/
protected Paths $paths;
/**
* Compiler Utilities Files
*
* @var Files
* @since 3.2.0
*/
protected Files $files;
/**
* Application object.
*
* @var CMSApplication
* @since 3.2.0
**/
protected CMSApplication $app;
/**
* Constructor
*
* @param Config|null $config The compiler config object.
* @param Registry|null $registry The compiler registry object.
* @param Settings|null $settings The compiler component Joomla version settings object.
* @param Component|null $component The component class.
* @param Content|null $content The compiler content object.
* @param Counter|null $counter The compiler counter object.
* @param Paths|null $paths The compiler paths object.
* @param Files|null $files The compiler files object.
* @param CMSApplication|null $app The CMS Application object.
*
* @throws \Exception
* @since 3.2.0
*/
public function __construct(?Config $config = null, ?Registry $registry = null,
?Settings $settings = null, ?Component $component = null,
?Content $content = null, ?Counter $counter = null, ?Paths $paths = null,
?Files $files = null, ?CMSApplication $app = null)
{
$this->config = $config ?: Compiler::_('Config');
$this->registry = $registry ?: Compiler::_('Registry');
$this->settings = $settings ?: Compiler::_('Component.Settings');
$this->component = $component ?: Compiler::_('Component');
$this->content = $content ?: Compiler::_('Content');
$this->counter = $counter ?: Compiler::_('Utilities.Counter');
$this->paths = $paths ?: Compiler::_('Utilities.Paths');
$this->files = $files ?: Compiler::_('Utilities.Files');
$this->app = $app ?: Factory::getApplication();
}
/**
* Build the Single Files & Folders
*
* @return bool
* @since 3.2.0
*/
public function build(): bool
{
if ($this->settings->exists())
{
// TODO needs more looking at this must be dynamic actually
$this->registry->appendArray('files.not.new', 'LICENSE.txt');
// do license check
$LICENSE = $this->doLicenseCheck();
// do README check
$README = $this->doReadmeCheck();
// do CHANGELOG check
$CHANGELOG = $this->doChangelogCheck();
// start moving
foreach ($this->settings->single() as $target => $details)
{
// if not gnu/gpl license dont add the LICENSE.txt file
if ($details->naam === 'LICENSE.txt' && !$LICENSE)
{
continue;
}
// if not needed do not add
if (($details->naam === 'README.md' || $details->naam === 'README.txt')
&& !$README)
{
continue;
}
// if not needed do not add
if ($details->naam === 'CHANGELOG.md' && !$CHANGELOG)
{
continue;
}
// set new name
$this->setNewName($details);
// set all paths
$this->setPaths($details);
// check if the path exists
if ($this->pathExist($details))
{
// set the target
$this->setTarget($target, $details);
}
// set dynamic target as needed
$this->setDynamicTarget($details);
}
return true;
}
return false;
}
/**
* Check if license must be added
*
* @return bool
* @since 3.2.0
*/
private function doLicenseCheck(): bool
{
$licenseChecker = strtolower((string) $this->component->get('license', ''));
if (strpos($licenseChecker, 'gnu') !== false
&& strpos(
$licenseChecker, '2'
) !== false
&& (strpos($licenseChecker, 'gpl') !== false
|| strpos(
$licenseChecker, 'General public license'
) !== false))
{
return true;
}
return false;
}
/**
* Check if readme must be added
*
* @return bool
* @since 3.2.0
*/
private function doReadmeCheck(): bool
{
return (bool) $this->component->get('addreadme', false);
}
/**
* Check if changelog must be added
*
* @return bool
* @since 3.2.0
*/
private function doChangelogCheck(): bool
{
return (bool) $this->component->get('changelog', false);
}
/**
* Set the new name
*
* @param object $details
*
* @return void
* @since 3.2.0
*/
private function setNewName(object $details)
{
// do the file renaming
if (isset($details->rename) && $details->rename)
{
if ($details->rename === 'new')
{
$this->newName = $details->newName;
}
else
{
$this->newName = str_replace(
$details->rename,
$this->config->component_code_name,
(string) $details->naam
);
}
}
else
{
$this->newName = $details->naam;
}
}
/**
* Set all needed paths
*
* @param object $details
*
* @return void
* @since 3.2.0
*/
private function setPaths(object $details)
{
// check if we have a target value
if (isset($details->_target))
{
// set destination path
$zipPath = str_replace(
$details->_target['type'] . '/', '', (string) $details->path
);
$path = str_replace(
$details->_target['type'] . '/',
$this->registry->get('dynamic_paths.' . $details->_target['key'], '') . '/',
(string) $details->path
);
}
else
{
// set destination path
$zipPath = str_replace('c0mp0n3nt/', '', (string) $details->path);
$path = str_replace(
'c0mp0n3nt/', $this->paths->component_path . '/', (string) $details->path
);
}
// set the template folder path
$templatePath = (isset($details->custom) && $details->custom)
? (($details->custom !== 'full') ? $this->paths->template_path_custom
. '/' : '') : $this->paths->template_path . '/';
// set the final paths
$currentFullPath = (preg_match('/^[a-z]:/i', (string) $details->naam)) ? $details->naam
: $templatePath . '/' . $details->naam;
$this->currentFullPath = str_replace('//', '/', (string) $currentFullPath);
$this->packageFullPath = str_replace('//', '/', $path . '/' . $this->newName);
$this->zipFullPath = str_replace(
'//', '/', $zipPath . '/' . $this->newName
);
}
/**
* Check if path exists
*
* @param object $details
*
* @return bool
* @since 3.2.0
*/
private function pathExist(object $details): bool
{
// check if this has a type
if (!isset($details->type))
{
return false;
}
// take action based on type
elseif ($details->type === 'file' && !File::exists($this->currentFullPath))
{
$this->app->enqueueMessage(
Text::_('<hr /><h3>File Path Error</h3>'), 'Error'
);
$this->app->enqueueMessage(
Text::sprintf('The file path: <b>%s</b> does not exist, and was not added!',
$this->currentFullPath
), 'Error'
);
return false;
}
elseif ($details->type === 'folder' && !Folder::exists($this->currentFullPath))
{
$this->app->enqueueMessage(
Text::_('<hr /><h3>Folder Path Error</h3>'),
'Error'
);
$this->app->enqueueMessage(
Text::sprintf('The folder path: <b>%s</b> does not exist, and was not added!',
$this->currentFullPath
), 'Error'
);
return false;
}
return true;
}
/**
* Set the target based on target type
*
* @param string $target
* @param object $details
*
* @return void
* @since 3.2.0
*/
private function setTarget(string $target, object $details)
{
// take action based on type
if ($details->type === 'file')
{
// move the file
$this->moveFile();
// register the file
$this->registerFile($target, $details);
}
elseif ($details->type === 'folder')
{
// move the folder to its place
Folder::copy(
$this->currentFullPath, $this->packageFullPath, '', true
);
// count the folder created
$this->counter->folder++;
}
}
/**
* Move/Copy the file into place
*
* @return void
* @since 3.2.0
*/
private function moveFile()
{
// get base name && get the path only
$packageFullPath0nly = str_replace(
basename($this->packageFullPath), '', $this->packageFullPath
);
// check if path exist, if not creat it
if (!Folder::exists($packageFullPath0nly))
{
Folder::create($packageFullPath0nly);
}
// move the file to its place
File::copy($this->currentFullPath, $this->packageFullPath);
// count the file created
$this->counter->file++;
}
/**
* Register the file
*
* @param string $target
* @param object $details
*
* @return void
* @since 3.2.0
*/
private function registerFile(string $target, object $details)
{
// store the new files
if (!in_array($target, $this->registry->get('files.not.new', [])))
{
if (isset($details->_target))
{
$this->files->appendArray($details->_target['key'],
[
'path' => $this->packageFullPath,
'name' => $this->newName,
'zip' => $this->zipFullPath
]
);
}
else
{
$this->files->appendArray('static',
[
'path' => $this->packageFullPath,
'name' => $this->newName,
'zip' => $this->zipFullPath
]
);
}
}
// ensure we update this file if needed
if ($this->registry->exists('update.file.content.' . $target))
{
// remove the pointer
$this->registry->remove('update.file.content.' . $target);
// set the full path
$this->registry->set('update.file.content.' . $this->packageFullPath, $this->packageFullPath);
}
}
/**
* Set Dynamic Target
*
* @param object $details
*
* @return void
* @since 3.2.0
*/
private function setDynamicTarget(object $details)
{
// only add if no target found since those belong to plugins and modules
if (!isset($details->_target))
{
// check if we should add the dynamic folder moving script to the installer script
$checker = array_values((array) explode('/', $this->zipFullPath));
// TODO <-- this may not be the best way, will keep an eye on this.
// We basicly only want to check if a folder is added that is not in the stdFolders array
if (isset($checker[0])
&& StringHelper::check($checker[0])
&& !$this->settings->standardFolder($checker[0]))
{
// activate dynamic folders
$this->setDynamicFolders();
}
elseif (count((array) $checker) == 2
&& StringHelper::check($checker[0]))
{
$add_to_extra = false;
// set the target
$eNAME = 'FILES';
$ename = 'filename';
// this should not happen and must have been caught by the above if statment
if ($details->type === 'folder')
{
// only folders outside the standard folder are added
$eNAME = 'FOLDERS';
$ename = 'folder';
$add_to_extra = true;
}
// if this is a file, it can only be added to the admin/site/media folders
// all other folders are moved as a whole so their files do not need to be declared
elseif ($this->settings->standardFolder($checker[0])
&& !$this->settings->standardRootFile($checker[1]))
{
$add_to_extra = true;
}
// add if valid folder/file
if ($add_to_extra)
{
// set the tab
$eTab = Indent::_(2);
if ('admin' === $checker[0])
{
$eTab = Indent::_(3);
}
// set the xml file
$key_ = 'EXSTRA_'
. StringHelper::safe(
$checker[0], 'U'
) . '_' . $eNAME;
$this->content->add($key_,
PHP_EOL . $eTab . "<" . $ename . ">"
. $checker[1] . "</" . $ename . ">");
}
}
}
}
/**
* Add the dynamic folders
*
* @return void
* @since 3.2.0
*/
private function setDynamicFolders()
{
// 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
$this->registry->set('set_move_folders_install_script', true);
// set message that this was done (will still add a tutorial link later)
$this->app->enqueueMessage(
Text::_('<hr /><h3>Dynamic folder(s) were detected.</h3>'),
'Notice'
);
$this->app->enqueueMessage(
Text::sprintf('A method (setDynamicF0ld3rs) was added to the install <b>script.php</b> of this package to insure that the folder(s) are copied into the correct place when this component is installed!'),
'Notice'
);
}
}

View File

@ -0,0 +1,138 @@
```
██████╗ ██████╗ ██╗ ██╗███████╗██████╗
██╔══██╗██╔═══██╗██║ ██║██╔════╝██╔══██╗
██████╔╝██║ ██║██║ █╗ ██║█████╗ ██████╔╝
██╔═══╝ ██║ ██║██║███╗██║██╔══╝ ██╔══██╗
██║ ╚██████╔╝╚███╔███╔╝███████╗██║ ██║
╚═╝ ╚═════╝ ╚══╝╚══╝ ╚══════╝╚═╝ ╚═╝
```
# final class Grep (Details)
> namespace: **VDM\Joomla\Componentbuilder\Power**
```uml
@startuml
class Grep << (F,LightGreen) >> #Green {
+ string $path
+ ?array $paths
# Contents $contents
# CMSApplication $app
+ __construct(string $path, array $paths, ...)
+ get(string $guid, array $order = ['Local', 'Remote']) : ?object
- searchLocal(string $guid) : ?object
- searchRemote(string $guid) : ?object
- getLocal(object $path, string $guid) : ?object
- getRemote(object $path, string $guid) : ?object
- init() : void
- localIndex(object $path) : void
- remoteIndex(object $path) : void
- loadRemoteFile(string $owner, string $repo, ...) : mixed
- getCode(string $code) : ?string
- getLicense(string $code) : ?string
}
note right of Grep::__construct
Constructor.
since: 3.2.0
arguments:
string $path
array $paths
Contents $contents
?CMSApplication $app = null
end note
note left of Grep::get
Get a power
since: 3.2.0
return: ?object
end note
note right of Grep::searchLocal
Search for a local power
since: 3.2.0
return: ?object
end note
note left of Grep::searchRemote
Search for a remote power
since: 3.2.0
return: ?object
end note
note right of Grep::getLocal
Get a local power
since: 3.2.0
return: ?object
end note
note left of Grep::getRemote
Get a remote power
since: 3.2.0
return: ?object
end note
note right of Grep::init
Set path details
since: 3.2.0
return: void
end note
note left of Grep::localIndex
Load the local repository index of powers
since: 3.2.0
return: void
end note
note right of Grep::remoteIndex
Load the remote repository index of powers
since: 3.2.0
return: void
end note
note left of Grep::loadRemoteFile
Load the remote file
since: 3.2.0
return: mixed
arguments:
string $owner
string $repo
string $path
?string $branch
end note
note right of Grep::getCode
Get the class body
return: ?string
end note
note left of Grep::getLicense
Get the class license
return: ?string
end note
@enduml
```
---
```
██╗ ██████╗██████╗
██║██╔════╝██╔══██╗
██║██║ ██████╔╝
██ ██║██║ ██╔══██╗
╚█████╔╝╚██████╗██████╔╝
╚════╝ ╚═════╝╚═════╝
```
> Build with [Joomla Component Builder](https://git.vdm.dev/joomla/Component-Builder)

View File

@ -0,0 +1,454 @@
<?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;
/**
* Power Grep
* 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 array
* @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 the local path
* @param array $paths The 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, $order = ['Local', 'Remote']): ?object
{
// we can only search if we have paths
if (is_array($this->paths) && $this->paths !== [])
{
foreach ($order as $target)
{
if (($power = $this->{'search' . $target}($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($this->full_path . '/' . $path->local->{$guid}->settings, null)) !== null &&
JsonHelper::check($settings))
{
$power = json_decode($settings);
// get the code
if (($code = FileHelper::getContent($this->full_path . '/' . $path->local->{$guid}->code, null)) !== null)
{
$power->main_class_code = $this->getCode($code);
$power->licensing_template = $this->getLicense($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}->code, $path->branch)) !== null)
{
$power->main_class_code = $this->getCode($code);
$power->licensing_template = $this->getLicense($code);
return $power;
}
}
return null;
}
/**
* Set path details
*
* @return void
* @since 3.2.0
*/
private function init()
{
if (!Folder::exists($this->path))
{
$this->path = null;
}
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))
{
$this->full_path = $this->path . '/' . $path->path;
}
}
else
{
unset($this->paths[$n]);
}
}
// if we still have paths
if ($this->paths !== [])
{
return;
}
}
$this->paths = null;
}
/**
* 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($this->full_path))
{
return;
}
if (($content = FileHelper::getContent($this->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 the class body
*
* @param string $code The class
*
* @return string|null The class body, or null if not found
**/
private function getCode($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
*
* @return string|null The class license, or null if not found
**/
private function getLicense($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;
}
}

View File

@ -0,0 +1,417 @@
/**
* The local path
*
* @var array
* @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 the local path
* @param array $paths The 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, $order = ['Local', 'Remote']): ?object
{
// we can only search if we have paths
if (is_array($this->paths) && $this->paths !== [])
{
foreach ($order as $target)
{
if (($power = $this->{'search' . $target}($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($this->full_path . '/' . $path->local->{$guid}->settings, null)) !== null &&
JsonHelper::check($settings))
{
$power = json_decode($settings);
// get the code
if (($code = FileHelper::getContent($this->full_path . '/' . $path->local->{$guid}->code, null)) !== null)
{
$power->main_class_code = $this->getCode($code);
$power->licensing_template = $this->getLicense($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}->code, $path->branch)) !== null)
{
$power->main_class_code = $this->getCode($code);
$power->licensing_template = $this->getLicense($code);
return $power;
}
}
return null;
}
/**
* Set path details
*
* @return void
* @since 3.2.0
*/
private function init()
{
if (!Folder::exists($this->path))
{
$this->path = null;
}
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))
{
$this->full_path = $this->path . '/' . $path->path;
}
}
else
{
unset($this->paths[$n]);
}
}
// if we still have paths
if ($this->paths !== [])
{
return;
}
}
$this->paths = null;
}
/**
* 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($this->full_path))
{
return;
}
if (($content = FileHelper::getContent($this->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('<p>Super Power</b> repository at <b>git.vdm.dev/%s</b> gave the following error!<br />%s</p>', $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('<p>File at <b>gitea.remote/%s</b> gave the following error!<br />%s</p>', $path, $e->getMessage()),
'Error'
);
return null;
}
return $data;
}
/**
* Get the class body
*
* @param string $code The class
*
* @return string|null The class body, or null if not found
**/
private function getCode($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
*
* @return string|null The class license, or null if not found
**/
private function getLicense($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;
}

View File

@ -0,0 +1,30 @@
{
"add_head": "1",
"extends": "0",
"extends_custom": "",
"guid": "6784dd52-0909-451a-a872-9a942a023c68",
"implements": null,
"implements_custom": "",
"load_selection": null,
"name": "Grep",
"power_version": "1.0.0",
"system_name": "JCB.Power.Grep",
"type": "final class",
"use_selection": {
"use_selection0": {
"use": "8d1baef6-fcad-49a9-848f-428009cdb989",
"as": "default"
},
"use_selection1": {
"use": "a223b31e-ea1d-4cdf-92ae-5f9becffaff0",
"as": "default"
},
"use_selection2": {
"use": "4b225c51-d293-48e4-b3f6-5136cf5c3f18",
"as": "default"
}
},
"namespace": "VDM\\Joomla\\Componentbuilder.Power.Grep",
"description": "Power Grep\r\n The Grep feature will try to find your power in the repositories listed in the global\r\n Options of JCB in the super powers tab, and if it can't be found there will try the global core\r\n Super powers of JCB. All searches are performed according the the [algorithm:cascading]\r\n See documentation for more details: https:\/\/git.vdm.dev\/joomla\/super-powers\/wiki\r\n\r\n@since 3.2.0",
"head": "use Joomla\\CMS\\Factory;\r\nuse Joomla\\CMS\\Filesystem\\Folder;\r\nuse Joomla\\CMS\\Application\\CMSApplication;\r\nuse Joomla\\CMS\\Language\\Text;"
}

View File

@ -0,0 +1,144 @@
/**
* Compiler Counter
*
* @var Counter
* @since 3.2.0
*/
protected Counter $counter;
/**
* Compiler Utilities File
*
* @var File
* @since 3.2.0
*/
protected File $file;
/**
* Constructor
*
* @param Counter|null $counter The compiler counter object.
* @param File|null $file The compiler file object.
*
* @since 3.2.0
*/
public function __construct(?Counter $counter = null, ?File $file = null)
{
$this->counter = $counter ?: Compiler::_('Utilities.Counter');
$this->file = $file ?: Compiler::_('Utilities.File');
}
/**
* Create Path if not exist
*
* @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, bool $addHtml = true)
{
// check if the path exist
if (!JoomlaFolder::exists($path))
{
// create the path
JoomlaFolder::create(
$path
);
// count the folder created
$this->counter->folder++;
if ($addHtml)
{
// add index.html (boring I know)
$this->file->html(
$path, ''
);
}
}
}
/**
* Remove folders with files
*
* @param string $path The path to folder to remove
* @param array|null $ignore The folders and files to ignore and not remove
*
* @return boolean True if all are removed
* @since 3.2.0
*/
public function remove(string $path, ?array $ignore = null): bool
{
if (JoomlaFolder::exists($path))
{
$it = new \RecursiveDirectoryIterator($path);
$it = new \RecursiveIteratorIterator($it, \RecursiveIteratorIterator::CHILD_FIRST);
// remove ending /
$path = rtrim($path, '/');
// now loop the files & folders
foreach ($it as $file)
{
if ('.' === $file->getBasename() || '..' === $file->getBasename()) continue;
// set file dir
$file_dir = $file->getPathname();
// check if this is a dir or a file
if ($file->isDir())
{
$keeper = false;
if (ArrayHelper::check($ignore))
{
foreach ($ignore as $keep)
{
if (strpos((string) $file_dir, $path . '/' . $keep) !== false)
{
$keeper = true;
}
}
}
if ($keeper)
{
continue;
}
JoomlaFolder::delete($file_dir);
}
else
{
$keeper = false;
if (ArrayHelper::check($ignore))
{
foreach ($ignore as $keep)
{
if (strpos((string) $file_dir, $path . '/'. $keep) !== false)
{
$keeper = true;
}
}
}
if ($keeper)
{
continue;
}
JoomlaFile::delete($file_dir);
}
}
// delete the root folder if ignore not set
if (!ArrayHelper::check($ignore))
{
return JoomlaFolder::delete($path);
}
return true;
}
return false;
}

View File

@ -0,0 +1,87 @@
/**
* Compiler Component Joomla Version Settings
*
* @var Settings
* @since 3.2.0
*/
protected Settings $settings;
/**
* Compiler Paths
*
* @var Paths
* @since 3.2.0
*/
protected Paths $paths;
/**
* Compiler Utilities Folder
*
* @var Folder
* @since 3.2.0
*/
protected Folder $folder;
/**
* Constructor
*
* @param Settings|null $settings The compiler component joomla version settings object.
* @param Paths|null $paths The compiler paths object.
* @param Folder|null $folder The compiler folder object.
*
* @since 3.2.0
*/
public function __construct(?Settings $settings = null, ?Paths $paths = null, ?Folder $folder = null)
{
$this->settings = $settings ?: Compiler::_('Component.Settings');
$this->paths = $paths ?: Compiler::_('Utilities.Paths');
$this->folder = $folder ?: Compiler::_('Utilities.Folder');
}
/**
* Build the Component Structure
*
* @return bool
* @since 3.2.0
*/
public function build(): bool
{
if ($this->settings->exists())
{
// setup the main component path
$this->folder->create($this->paths->component_path);
// build the version structure
$this->folders(
$this->settings->structure(),
$this->paths->component_path
);
return true;
}
return false;
}
/**
* Create the folder and subfolders
*
* @param object $folders The object[] of folders
* @param string $path The path
*
* @return void
* @since 3.2.0
*/
protected function folders(object $folders, string $path)
{
foreach ($folders as $folder => $sub_folders)
{
$new_path = $path . '/' . $folder;
$this->folder->create($new_path);
if (ObjectHelper::check($sub_folders))
{
$this->folders($sub_folders, $new_path);
}
}
}

View File

@ -0,0 +1,7 @@
/**
* get the custom code from the local files
*
* @return void
* @since 3.2.0
*/
public function run();

View File

@ -0,0 +1,95 @@
/**
* The compiler Config
*
* @var Config
* @since 3.2.0
*/
protected Config $config;
/**
* The compiler history
*
* @var HistoryInterface
* @since 3.2.0
*/
protected HistoryInterface $history;
/**
* The compiler update sql
*
* @var Updatesql
* @since 3.2.0
*/
protected Updatesql $updatesql;
/**
* Constructor
*
* @param Config|null $config The compiler config object.
* @param HistoryInterface|null $history The compiler history object.
* @param Updatesql|null $updatesql The compiler updatesql object.
*
* @since 3.2.0
*/
public function __construct(?Config $config = null, ?HistoryInterface $history = null,
?Updatesql $updatesql = null)
{
$this->config = $config ?: Compiler::_('Config');
$this->history = $history ?: Compiler::_('History');
$this->updatesql = $updatesql ?: Compiler::_('Model.Updatesql');
}
/**
* check if an update SQL is needed
*
* @param object $item The item data
*
* @return void
* @since 3.2.0
*/
public function set(object &$item)
{
if (($old = $this->history->get('admin_view', $item->id)) !== null)
{
// check if the view name changed
if (StringHelper::check($old->name_single))
{
$this->updatesql->set(
StringHelper::safe(
$old->name_single
), $item->name_single_code, 'table_name',
$item->name_single_code
);
}
// loop the mysql table settings
foreach ($this->config->mysql_table_keys as $mysql_table_key => $mysql_table_val)
{
// check if the table engine changed
if (isset($old->{'mysql_table_' . $mysql_table_key})
&& isset($item->{'mysql_table_' . $mysql_table_key}))
{
$this->updatesql->set(
$old->{'mysql_table_' . $mysql_table_key},
$item->{'mysql_table_' . $mysql_table_key},
'table_' . $mysql_table_key, $item->name_single_code
);
}
// check if there is no history on table engine, and it changed from the default/global
elseif (isset($item->{'mysql_table_' . $mysql_table_key})
&& StringHelper::check(
$item->{'mysql_table_' . $mysql_table_key}
)
&& !is_numeric(
$item->{'mysql_table_' . $mysql_table_key}
))
{
$this->updatesql->set(
$mysql_table_val['default'],
$item->{'mysql_table_' . $mysql_table_key},
'table_' . $mysql_table_key, $item->name_single_code
);
}
}
}
}

View File

@ -0,0 +1,381 @@
/**
* Power Objects
*
* @var Power
* @since 3.2.0
**/
protected Power $power;
/**
* Compiler Config
*
* @var Config
* @since 3.2.0
**/
protected Config $config;
/**
* Compiler Content
*
* @var Content
* @since 3.2.0
**/
protected Content $content;
/**
* Helper Class Autoloader
*
* @var string
* @since 3.2.0
**/
protected string $helper = '';
/**
* Constructor.
*
* @param Power|null $power The power object.
* @param Config|null $config The compiler config object.
* @param Content|null $content The compiler content object.
*
* @since 3.2.0
*/
public function __construct(?Power $power = null, ?Config $config = null, ?Content $content = null)
{
$this->power = $power ?: Compiler::_('Power');
$this->config = $config ?: Compiler::_('Config');
$this->content = $content ?: Compiler::_('Content');
// reset all autoloaders power placeholders
$this->content->set('ADMIN_POWER_HELPER', '');
$this->content->set('SITE_POWER_HELPER', '');
$this->content->set('CUSTOM_POWER_AUTOLOADER', '');
}
/**
* Set the autoloader into the active content array
*
* @return void
* @since 3.2.0
*/
public function set()
{
if (ArrayHelper::check($this->power->namespace))
{
/************************* IMPORTANT SORT NOTICE ***********************************************
* make sure the name space values are sorted from the longest string to the shortest
* so that the search do not mistakenly match a shorter namespace before a longer one
* that has the same short namespace for example:
* NameSpace\SubName\Sub <- will always match first
* NameSpace\SubName\SubSubName
* Should the shorter namespace be listed [first] it will match both of these:
* NameSpace\SubName\Sub\ClassName
* ^^^^^^^^^^^^^^^^^^^^^^
* NameSpace\SubName\SubSubName\ClassName
* ^^^^^^^^^^^^^^^^^^^^^^
***********************************************************************************************/
uksort($this->power->namespace, fn($a, $b) => strlen((string) $b) - strlen((string) $a));
// check if we are using a plugin
if ($this->loadPluginAutoloader())
{
$this->content->set('PLUGIN_POWER_AUTOLOADER', $this->getPluginAutoloader());
}
// load to the helper class
if ($this->loadHelperAutoloader())
{
// load to admin helper class
$this->content->add('ADMIN_POWER_HELPER', $this->getHelperAutoloader());
// load to site helper class if needed
if ($this->loadSiteAutoloader())
{
$this->content->add('SITE_POWER_HELPER', $this->getHelperAutoloader());
}
}
// to add to custom files
$this->content->add('CUSTOM_POWER_AUTOLOADER', $this->getHelperAutoloader());
}
}
/**
* Should we load the plugin autoloader
*
* @return bool
* @since 3.2.0
*/
private function loadPluginAutoloader(): bool
{
return $this->content->exist('PLUGIN_POWER_AUTOLOADER');
}
/**
* Should we load the helper class autoloader
*
* @return bool
* @since 3.2.0
*/
private function loadHelperAutoloader(): bool
{
// for now we load it if the plugin is not loaded
// but we may want to add a switch that
// controls this behaviour.
return !$this->loadPluginAutoloader();
}
/**
* Should we load the autoloader in site area
*
* @return bool
* @since 3.2.0
*/
private function loadSiteAutoloader(): bool
{
return (!$this->config->remove_site_folder || !$this->config->remove_site_edit_folder);
}
/**
* Get helper autoloader code
*
* @return string
* @since 3.2.0
*/
private function getPluginAutoloader(): string
{
// load the code
$code = [];
// if we should not load in the site are
if (($script = $this->getBLockSiteLoading()) !== null)
{
$code[] = $script;
}
// add the composer stuff here
if (($script = $this->getComposer(2)) !== null)
{
$code[] = $script;
}
// get the helper autoloader
if (($script = $this->getAutoloader(2)) !== null)
{
$code[] = $script;
}
// if we have any
if (!empty($code))
{
return PHP_EOL . PHP_EOL . implode(PHP_EOL . PHP_EOL, $code);
}
return '';
}
/**
* Get helper autoloader code
*
* @return string
* @since 3.2.0
*/
private function getHelperAutoloader(): string
{
// check if it was already build
if (!empty($this->helper))
{
return $this->helper;
}
// load the code
$code = [];
// add the composer stuff here
if (($script = $this->getComposer(0)) !== null)
{
$code[] = $script;
}
// get the helper autoloader
if (($script = $this->getAutoloader(0)) !== null)
{
$code[] = $script;
}
// if we have any
if (!empty($code))
{
$this->helper = PHP_EOL . PHP_EOL . implode(PHP_EOL . PHP_EOL, $code);
}
return $this->helper;
}
/**
* Get code that will block the plugin from loading
* the autoloader in the site area
*
* @return string|null
* @since 3.2.0
*/
private function getBLockSiteLoading(): ?string
{
// if we should not load in the site are
if (!$this->loadSiteAutoloader())
{
// we add code to prevent this plugin from triggering on the site area
$not_site = [];
$not_site[] = Indent::_(2) . '//'
. Line::_(__Line__, __Class__) . ' do not run the autoloader in the site area';
$not_site[] = Indent::_(2) . 'if ($this->app->isClient(\'site\'))';
$not_site[] = Indent::_(2) . '{';
$not_site[] = Indent::_(3) . 'return;';
$not_site[] = Indent::_(2) . '}';
return implode(PHP_EOL, $not_site);
}
return null;
}
/**
* Get autoloader code
*
* @param int $tabSpace The dynamic tab spacer
*
* @return string|null
* @since 3.2.0
*/
private function getAutoloader(int $tabSpace): ?string
{
if (($size = ArrayHelper::check($this->power->namespace)) > 0)
{
// we start building the spl_autoload_register function call
$autoload_method = [];
$autoload_method[] = Indent::_($tabSpace) . '//'
. Line::_(__Line__, __Class__) . ' register this component namespace';
$autoload_method[] = Indent::_($tabSpace) . 'spl_autoload_register(function ($class) {';
$autoload_method[] = Indent::_($tabSpace) . Indent::_(1) . '//'
. Line::_(__Line__, __Class__) . ' project-specific base directories and namespace prefix';
$autoload_method[] = Indent::_($tabSpace) . Indent::_(1) . '$search = [';
// counter to manage the comma in the actual array
$counter = 1;
foreach ($this->power->namespace as $base_dir => $prefix)
{
// don't add the ending comma on last value
if ($size == $counter)
{
$autoload_method[] = Indent::_($tabSpace) . Indent::_(2) . "'" . $this->config->get('jcb_powers_path', 'libraries/jcb_powers') . "/$base_dir' => '" . implode('\\\\', $prefix) . "'";
}
else
{
$autoload_method[] = Indent::_($tabSpace) . Indent::_(2) . "'" . $this->config->get('jcb_powers_path', 'libraries/jcb_powers') . "/$base_dir' => '" . implode('\\\\', $prefix) . "',";
}
$counter++;
}
$autoload_method[] = Indent::_($tabSpace) . Indent::_(1) . '];';
$autoload_method[] = Indent::_($tabSpace) . Indent::_(1) . '// Start the search and load if found';
$autoload_method[] = Indent::_($tabSpace) . Indent::_(1) . '$found = false;';
$autoload_method[] = Indent::_($tabSpace) . Indent::_(1) . '$found_base_dir = "";';
$autoload_method[] = Indent::_($tabSpace) . Indent::_(1) . '$found_len = 0;';
$autoload_method[] = Indent::_($tabSpace) . Indent::_(1) . 'foreach ($search as $base_dir => $prefix)';
$autoload_method[] = Indent::_($tabSpace) . Indent::_(1) . '{';
$autoload_method[] = Indent::_($tabSpace) . Indent::_(2) . '//'
. Line::_(__Line__, __Class__) . ' does the class use the namespace prefix?';
$autoload_method[] = Indent::_($tabSpace) . Indent::_(2) . '$len = strlen($prefix);';
$autoload_method[] = Indent::_($tabSpace) . Indent::_(2) . 'if (strncmp($prefix, $class, $len) === 0)';
$autoload_method[] = Indent::_($tabSpace) . Indent::_(2) . '{';
$autoload_method[] = Indent::_($tabSpace) . Indent::_(3) . '//'
. Line::_(__Line__, __Class__) . ' we have a match so load the values';
$autoload_method[] = Indent::_($tabSpace) . Indent::_(3) . '$found = true;';
$autoload_method[] = Indent::_($tabSpace) . Indent::_(3) . '$found_base_dir = $base_dir;';
$autoload_method[] = Indent::_($tabSpace) . Indent::_(3) . '$found_len = $len;';
$autoload_method[] = Indent::_($tabSpace) . Indent::_(3) . '//'
. Line::_(__Line__, __Class__) . ' done here';
$autoload_method[] = Indent::_($tabSpace) . Indent::_(3) . 'break;';
$autoload_method[] = Indent::_($tabSpace) . Indent::_(2) . '}';
$autoload_method[] = Indent::_($tabSpace) . Indent::_(1) . '}';
$autoload_method[] = Indent::_($tabSpace) . Indent::_(1) . '//'
. Line::_(__Line__, __Class__) . ' check if we found a match';
$autoload_method[] = Indent::_($tabSpace) . Indent::_(1) . 'if (!$found)';
$autoload_method[] = Indent::_($tabSpace) . Indent::_(1) . '{';
$autoload_method[] = Indent::_($tabSpace) . Indent::_(2) . '//'
. Line::_(__Line__, __Class__) . ' not found so move to the next registered autoloader';
$autoload_method[] = Indent::_($tabSpace) . Indent::_(2) . 'return;';
$autoload_method[] = Indent::_($tabSpace) . Indent::_(1) . '}';
$autoload_method[] = Indent::_($tabSpace) . Indent::_(1) . '//'
. Line::_(__Line__, __Class__) . ' get the relative class name';
$autoload_method[] = Indent::_($tabSpace) . Indent::_(1) . '$relative_class = substr($class, $found_len);';
$autoload_method[] = Indent::_($tabSpace) . Indent::_(1) . '//'
. Line::_(__Line__, __Class__) . ' replace the namespace prefix with the base directory, replace namespace';
$autoload_method[] = Indent::_($tabSpace) . Indent::_(1) . '// separators with directory separators in the relative class name, append';
$autoload_method[] = Indent::_($tabSpace) . Indent::_(1) . '// with .php';
$autoload_method[] = Indent::_($tabSpace) . Indent::_(1) . "\$file = JPATH_ROOT . '/' . \$found_base_dir . '/src' . str_replace('\\\\', '/', \$relative_class) . '.php';";
$autoload_method[] = Indent::_($tabSpace) . Indent::_(1) . '//'
. Line::_(__Line__, __Class__) . ' if the file exists, require it';
$autoload_method[] = Indent::_($tabSpace) . Indent::_(1) . 'if (file_exists($file))';
$autoload_method[] = Indent::_($tabSpace) . Indent::_(1) . '{';
$autoload_method[] = Indent::_($tabSpace) . Indent::_(2) . 'require $file;';
$autoload_method[] = Indent::_($tabSpace) . Indent::_(1) . '}';
$autoload_method[] = Indent::_($tabSpace) . '});';
return implode(PHP_EOL, $autoload_method);
}
return null;
}
/**
* Get the composer autoloader routine
*
* @param int $tabSpace The dynamic tab spacer
*
* @return string|null
* @since 3.2.0
*/
private function getComposer(int $tabSpace): ?string
{
if (ArrayHelper::check($this->power->composer))
{
// load the composer routine
$composer_routine = [];
// counter to manage the comma in the actual array
$add_once = [];
foreach ($this->power->composer as $access_point)
{
// don't add the ending comma on last value
if (empty($add_once[$access_point]))
{
$composer_routine[] = Indent::_($tabSpace) . "\$composer_autoloader = JPATH_LIBRARIES . '/$access_point';";
$composer_routine[] = Indent::_($tabSpace) . 'if (file_exists($composer_autoloader))';
$composer_routine[] = Indent::_($tabSpace) . "{";
$composer_routine[] = Indent::_($tabSpace) . Indent::_(1) . 'require_once $composer_autoloader;';
$composer_routine[] = Indent::_($tabSpace) . "}";
$add_once[$access_point] = true;
}
}
// this is just about the [autoloader or autoloaders] in the comment ;)
if (count($add_once) == 1)
{
array_unshift($composer_routine, Indent::_($tabSpace) . '//'
. Line::_(__Line__, __Class__) . ' add the autoloader for the composer classes');
}
else
{
array_unshift($composer_routine, Indent::_($tabSpace) . '//'
. Line::_(__Line__, __Class__) . ' add the autoloaders for the composer classes');
}
return implode(PHP_EOL, $composer_routine);
}
return null;
}

View File

@ -0,0 +1,173 @@
/**
* Compiler Config
*
* @var Config
* @since 3.2.0
**/
protected Config $config;
/**
* Compiler Component
*
* @var Component
* @since 3.2.0
**/
protected Component $component;
/**
* Constructor
*
* @param Config|null $config The compiler config object.
* @param Component|null $component The component class.
*
* @since 3.2.0
*/
public function __construct(?Config $config = null, ?Component $component = null)
{
$this->config = $config ?: Compiler::_('Config');
$this->component = $component ?: Compiler::_('Component');
// set the template path
$this->setTemplatePath();
// set component sales name
$this->setComponentSalesName();
// set component backup name
$this->setComponentBackupName();
// set component folder name
$this->setComponentFolderName();
// set component path
$this->setComponentPath();
// set the template path for custom
$this->setTemplatePathCustom();
}
/**
* getting any valid paths
*
* @param string $key The value's key/path name
*
* @return string The path found as a string
* @since 3.2.0
* @throws \InvalidArgumentException If $key is not a valid function name.
*/
public function __get(string $key): string
{
// check if it has been set
if ($this->exist($key))
{
return $this->get($key);
}
throw new \InvalidArgumentException(sprintf('Path %s could not be found in the Paths Class.', $key));
}
/**
* Model the key
*
* @param string $key The key to model
*
* @return string
* @since 3.2.0
*/
protected function key(string $key): string
{
return $key;
}
/**
* Set the template path
*
* @return void
*
* @since 3.2.0
*/
private function setTemplatePath(): void
{
$this->set('template_path',
$this->config->get('compiler_path', JPATH_COMPONENT_ADMINISTRATOR . '/compiler') . '/joomla_'
. $this->config->joomla_versions[$this->config->joomla_version]['folder_key']
);
}
/**
* Set component sales name
*
* @return void
*
* @since 3.2.0
*/
private function setComponentSalesName(): void
{
$this->set('component_sales_name',
'com_' . $this->component->get('sales_name') . '__J'
. $this->config->joomla_version
);
}
/**
* Set component backup name
*
* @return void
*
* @since 3.2.0
*/
private function setComponentBackupName(): void
{
$this->set('component_backup_name',
'com_' . $this->component->get('sales_name') . '_v' . str_replace(
'.', '_', (string) $this->component->get('component_version')
) . '__J' . $this->config->joomla_version
);
}
/**
* Set component folder name
*
* @return void
*
* @since 3.2.0
*/
private function setComponentFolderName(): void
{
$this->set('component_folder_name',
'com_' . $this->component->get('name_code') . '_v' . str_replace(
'.', '_', (string) $this->component->get('component_version')
) . '__J' . $this->config->joomla_version
);
}
/**
* Set component path
*
* @return void
*
* @since 3.2.0
*/
private function setComponentPath(): void
{
$this->set('component_path',
$this->config->get('compiler_path', JPATH_COMPONENT_ADMINISTRATOR . '/compiler') . '/'
. $this->get('component_folder_name')
);
}
/**
* set the template path for custom TODO: just use custom_folder_path in config
*
* @return void
*
* @since 3.2.0
*/
private function setTemplatePathCustom(): void
{
$this->set('template_path_custom',
$this->config->get(
'custom_folder_path', JPATH_COMPONENT_ADMINISTRATOR . '/custom'
)
);
}

View File

@ -0,0 +1,319 @@
/**
* Compiler Config
*
* @var Config
* @since 3.2.0
*/
protected Config $config;
/**
* The compiler registry
*
* @var Registry
* @since 3.2.0
*/
protected Registry $registry;
/**
* 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 Field Data
*
* @var FieldData
* @since 3.2.0
*/
protected FieldData $field;
/**
* Compiler Files Folders
*
* @var Filesfolders
* @since 3.2.0
*/
protected Filesfolders $filesFolders;
/**
* Database object to query local DB
*
* @var \JDatabaseDriver
* @since 3.2.0
**/
protected \JDatabaseDriver $db;
/**
* Constructor
*
* @param Config|null $config The compiler config object.
* @param Registry|null $registry The compiler registry object.
* @param Customcode|null $customcode The compiler customcode object.
* @param Gui|null $gui The compiler customcode gui.
* @param FieldData|null $field The compiler field data object.
* @param Filesfolders|null $filesFolders The compiler files folders object.
* @param \JDatabaseDriver|null $db The database object.
*
* @since 3.2.0
*/
public function __construct(?Config $config = null, ?Registry $registry = null,
?Customcode $customcode = null, ?Gui $gui = null,
?FieldData $field = null, ?Filesfolders $filesFolders = null,
?\JDatabaseDriver $db = null)
{
$this->config = $config ?: Compiler::_('Config');
$this->registry = $registry ?: Compiler::_('Registry');
$this->customcode = $customcode ?: Compiler::_('Customcode');
$this->gui = $gui ?: Compiler::_('Customcode.Gui');
$this->field = $field ?: Compiler::_('Field.Data');
$this->filesFolders = $filesFolders ?: Compiler::_('Model.Filesfolders');
$this->db = $db ?: Factory::getDbo();
}
/**
* Get Media Library Data and store globally in registry
*
* @param int $id the library id
*
* @return object|bool object on success
* @since 3.2.0
*/
public function get(int $id)
{
// check if the lib has already been set
if (!$this->registry->exists("builder.libraries.$id"))
{
// get some switches
$uikit = $this->config->get('uikit', 0);
$footable_version = $this->config->get('footable_version', 0);
// make sure we should continue and that the lib is not already being loaded
switch ($id)
{
case 1: // No Library
return false;
break;
case 3: // Uikit v3
if (2 == $uikit || 3 == $uikit)
{
// already being loaded
$this->registry->set("builder.libraries.$id", false);
}
break;
case 4: // Uikit v2
if (2 == $uikit || 1 == $uikit)
{
// already being loaded
$this->registry->set("builder.libraries.$id", false);
}
break;
case 5: // FooTable v2
if (2 == $footable_version)
{
// already being loaded
$this->registry->set("builder.libraries.$id", false);
}
break;
case 6: // FooTable v3
if (3 == $footable_version)
{
// already being loaded
$this->registry->set("builder.libraries.$id", false);
}
break;
}
}
// check if the lib has already been set
if (!$this->registry->exists("builder.libraries.$id"))
{
$query = $this->db->getQuery(true);
$query->select('a.*');
$query->select(
$this->db->quoteName(
array(
'a.id',
'a.name',
'a.how',
'a.type',
'a.addconditions',
'b.addconfig',
'c.addfiles',
'c.addfolders',
'c.addfilesfullpath',
'c.addfoldersfullpath',
'c.addurls',
'a.php_setdocument'
), array(
'id',
'name',
'how',
'type',
'addconditions',
'addconfig',
'addfiles',
'addfolders',
'addfilesfullpath',
'addfoldersfullpath',
'addurls',
'php_setdocument'
)
)
);
// from these tables
$query->from('#__componentbuilder_library AS a');
$query->join(
'LEFT',
$this->db->quoteName('#__componentbuilder_library_config', 'b')
. ' ON (' . $this->db->quoteName('a.id') . ' = '
. $this->db->quoteName('b.library') . ')'
);
$query->join(
'LEFT', $this->db->quoteName(
'#__componentbuilder_library_files_folders_urls', 'c'
) . ' ON (' . $this->db->quoteName('a.id') . ' = '
. $this->db->quoteName('c.library') . ')'
);
$query->where($this->db->quoteName('a.id') . ' = ' . (int) $id);
$query->where($this->db->quoteName('a.target') . ' = 1');
// Reset the query using our newly populated query object.
$this->db->setQuery($query);
// Load the results as a list of stdClass objects
$library = $this->db->loadObject();
// check if this lib uses build-in behaviour
if ($library->how == 4)
{
// fall back on build-in features
$buildin = [
3 => ['uikit' => 3],
4 => ['uikit' => 1],
5 => ['footable_version' => 2, 'footable' => true],
6 => ['footable_version' => 3, 'footable' => true]
];
if (isset($buildin[$library->id])
&& ArrayHelper::check(
$buildin[$library->id]
))
{
// set the lib switch
foreach ($buildin[$library->id] as $lib => $val)
{
// ---- we are targeting these ----
// $this->config->uikit
// $this->config->footable_version
// $this->config->footable
$this->config->set($lib, $val);
}
// since we are falling back on build-in feature
$library->how = 0;
}
else
{
// since we did not find build in behaviour we must load always.
$library->how = 1;
}
}
// check if this lib has dynamic behaviour
if ($library->how > 0)
{
// set files and folders
$this->filesFolders->set($library);
// add config fields only if needed
if ($library->how > 1)
{
// set the config data
$library->addconfig = (isset($library->addconfig)
&& JsonHelper::check(
$library->addconfig
)) ? json_decode((string) $library->addconfig, true) : null;
if (ArrayHelper::check($library->addconfig))
{
$library->config = array_map(
function ($array) {
$array['alias'] = 0;
$array['title'] = 0;
$array['settings'] = $this->field->get(
$array['field']
);
return $array;
}, array_values($library->addconfig)
);
}
}
// if this lib is controlled by custom script
if (3 == $library->how)
{
// set Needed PHP
if (isset($library->php_setdocument)
&& StringHelper::check(
$library->php_setdocument
))
{
$library->document = $this->gui->set(
$this->customcode->update(
base64_decode((string) $library->php_setdocument)
),
array(
'table' => 'library',
'field' => 'php_setdocument',
'id' => (int) $id,
'type' => 'php')
);
}
}
// if this lib is controlled by conditions
elseif (2 == $library->how)
{
// set the addconditions data
$library->addconditions = (isset($library->addconditions)
&& JsonHelper::check(
$library->addconditions
)) ? json_decode((string) $library->addconditions, true) : null;
if (ArrayHelper::check(
$library->addconditions
))
{
$library->conditions = array_values(
$library->addconditions
);
}
}
unset($library->php_setdocument);
unset($library->addconditions);
unset($library->addconfig);
// load to global lib
$this->registry->set("builder.libraries.$id", $library);
}
else
{
$this->registry->set("builder.libraries.$id", false);
}
}
// if set return
return $this->registry->get("builder.libraries.$id", false);
}

View File

@ -0,0 +1,838 @@
/**
* Compiler Joomla Plugins Data
*
* @var array
* @since 3.2.0
*/
protected array $data = [];
/**
* Compiler Config
*
* @var Config
* @since 3.2.0
*/
protected Config $config;
/**
* 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 Placeholder
*
* @var Placeholder
* @since 3.2.0
**/
protected Placeholder $placeholder;
/**
* Compiler Language
*
* @var Language
* @since 3.2.0
**/
protected Language $language;
/**
* Compiler Field
*
* @var Field
* @since 3.2.0
*/
protected Field $field;
/**
* Compiler field name
*
* @var FieldName
* @since 3.2.0
*/
protected FieldName $fieldName;
/**
* Compiler Files Folders
*
* @var Filesfolders
* @since 3.2.0
*/
protected Filesfolders $filesFolders;
/**
* Database object to query local DB
*
* @var \JDatabaseDriver
* @since 3.2.0
**/
protected \JDatabaseDriver $db;
/**
* Constructor
*
* @param Config|null $config The compiler config object.
* @param Customcode|null $customcode The compiler customcode object.
* @param Gui|null $gui The compiler customcode gui.
* @param Placeholder|null $placeholder The compiler placeholder object.
* @param Language|null $language The compiler Language object.
* @param Field|null $field The compiler field data object.
* @param FieldName|null $fieldName The compiler field name object.
* @param Filesfolders|null $filesFolders The compiler files folders object.
* @param \JDatabaseDriver|null $db The database object.
*
* @since 3.2.0
*/
public function __construct(?Config $config = null, ?Customcode $customcode = null,
?Gui $gui = null, ?Placeholder $placeholder = null,
?Language $language = null, ?Field $field = null, ?FieldName $fieldName = null,
?Filesfolders $filesFolders = null, ?\JDatabaseDriver $db = null)
{
$this->config = $config ?: Compiler::_('Config');
$this->customcode = $customcode ?: Compiler::_('Customcode');
$this->gui = $gui ?: Compiler::_('Customcode.Gui');
$this->placeholder = $placeholder ?: Compiler::_('Placeholder');
$this->language = $language ?: Compiler::_('Language');
$this->field = $field ?: Compiler::_('Field');
$this->fieldName = $fieldName ?: Compiler::_('Field.Name');
$this->filesFolders = $filesFolders ?: Compiler::_('Model.Filesfolders');
$this->db = $db ?: Factory::getDbo();
}
/**
* Get the Joomla Plugin/s
*
* @param int|null $id the plugin id
*
* @return object|array|null if ID found it returns object, if no ID given it returns all set
* @since 3.2.0
*/
public function get(int $id = null)
{
if (is_null($id) && $this->exists())
{
return $this->data;
}
elseif ($this->exists($id))
{
return $this->data[$id];
}
return null;
}
/**
* Check if the Joomla Plugin/s exists
*
* @param int|null $id the plugin id
*
* @return bool if ID found it returns true, if no ID given it returns true if any are set
* @since 3.2.0
*/
public function exists(int $id = null): bool
{
if (is_null($id))
{
return ArrayHelper::check($this->data);
}
elseif (isset($this->data[$id]))
{
return true;
}
return $this->set($id);
}
/**
* Set the Joomla Plugin
*
* @param int $id the plugin id
*
* @return bool true on success
* @since 3.2.0
*/
public function set(int $id): bool
{
if (isset($this->data[$id]))
{
return true;
}
else
{
// Create a new query object.
$query = $this->db->getQuery(true);
$query->select('a.*');
$query->select(
$this->db->quoteName(
array(
'g.name',
'e.name',
'e.head',
'e.comment',
'e.id',
'f.addfiles',
'f.addfolders',
'f.addfilesfullpath',
'f.addfoldersfullpath',
'f.addurls',
'u.version_update',
'u.id'
), array(
'group',
'extends',
'class_head',
'comment',
'class_id',
'addfiles',
'addfolders',
'addfilesfullpath',
'addfoldersfullpath',
'addurls',
'version_update',
'version_update_id'
)
)
);
// 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->join(
'LEFT',
$this->db->quoteName('#__componentbuilder_class_extends', 'e')
. ' ON (' . $this->db->quoteName('a.class_extends') . ' = '
. $this->db->quoteName('e.id') . ')'
);
$query->join(
'LEFT', $this->db->quoteName(
'#__componentbuilder_joomla_plugin_updates', 'u'
) . ' ON (' . $this->db->quoteName('a.id') . ' = '
. $this->db->quoteName('u.joomla_plugin') . ')'
);
$query->join(
'LEFT', $this->db->quoteName(
'#__componentbuilder_joomla_plugin_files_folders_urls', 'f'
) . ' ON (' . $this->db->quoteName('a.id') . ' = '
. $this->db->quoteName('f.joomla_plugin') . ')'
);
$query->where($this->db->quoteName('a.id') . ' = ' . (int) $id);
$query->where($this->db->quoteName('a.published') . ' >= 1');
$this->db->setQuery($query);
$this->db->execute();
if ($this->db->getNumRows())
{
// get the plugin data
$plugin = $this->db->loadObject();
// tweak system to set stuff to the plugin domain
$_backup_target = $this->config->build_target;
$_backup_lang = $this->config->lang_target;
$_backup_langPrefix = $this->config->lang_prefix;
// set some keys
$plugin->target_type = 'P|uG!n';
$plugin->key = $plugin->id . '_' . $plugin->target_type;
// update to point to plugin
$this->config->build_target = $plugin->key;
$this->config->lang_target = $plugin->key;
// set version if not set
if (empty($plugin->plugin_version))
{
$plugin->plugin_version = '1.0.0';
}
// set GUI mapper
$guiMapper = array('table' => 'joomla_plugin',
'id' => (int) $id, 'type' => 'php');
// update the name if it has dynamic values
$plugin->name = $this->placeholder->update_(
$this->customcode->update($plugin->name)
);
// update the name if it has dynamic values
$plugin->code_name
= ClassfunctionHelper::safe(
$plugin->name
);
// set official name
$plugin->official_name = ucwords(
$plugin->group . ' - ' . $plugin->name
);
// set lang prefix
$plugin->lang_prefix = PluginHelper::safeLangPrefix(
$plugin->code_name,
$plugin->group
);
// set langPrefix
$this->config->lang_prefix = $plugin->lang_prefix;
// set plugin class name
$plugin->class_name
= PluginHelper::safeClassName(
$plugin->code_name,
$plugin->group
);
// set plugin install class name
$plugin->installer_class_name
= PluginHelper::safeInstallClassName(
$plugin->code_name,
$plugin->group
);
// set plugin folder name
$plugin->folder_name
= PluginHelper::safeFolderName(
$plugin->code_name,
$plugin->group
);
// set the zip name
$plugin->zip_name = $plugin->folder_name . '_v' . str_replace(
'.', '_', (string) $plugin->plugin_version
) . '__J' . $this->config->joomla_version;
// set plugin file name
$plugin->file_name = strtolower((string) $plugin->code_name);
// set plugin context
$plugin->context = $plugin->folder_name . '.' . $plugin->id;
// set official_name lang strings
$this->language->set(
$plugin->key, $this->config->lang_prefix, $plugin->official_name
);
// set some placeholder for this plugin
$this->placeholder->set('Plugin_name', $plugin->official_name);
$this->placeholder->set('PLUGIN_NAME', $plugin->official_name);
$this->placeholder->set('Plugin', ucfirst((string) $plugin->code_name));
$this->placeholder->set('plugin', strtolower((string) $plugin->code_name));
$this->placeholder->set('Plugin_group', ucfirst((string) $plugin->group));
$this->placeholder->set('plugin_group', strtolower((string) $plugin->group));
$this->placeholder->set('plugin.version', $plugin->plugin_version);
$this->placeholder->set('VERSION', $plugin->plugin_version);
$this->placeholder->set('plugin_version', str_replace(
'.', '_', (string) $plugin->plugin_version
));
// set description
$this->placeholder->set('DESCRIPTION', '');
if (!isset($plugin->description)
|| !StringHelper::check(
$plugin->description
))
{
$plugin->description = '';
}
else
{
$plugin->description = $this->placeholder->update_(
$this->customcode->update($plugin->description)
);
$this->language->set(
$plugin->key, $plugin->lang_prefix . '_DESCRIPTION',
$plugin->description
);
// set description
$this->placeholder->set('DESCRIPTION', $plugin->description);
$plugin->description = '<p>' . $plugin->description . '</p>';
}
// get author name
$project_author = $this->config->project_author;
// we can only set these if the component was passed
$plugin->xml_description = "<h1>" . $plugin->official_name
. " (v." . $plugin->plugin_version
. ")</h1> <div style='clear: both;'></div>"
. $plugin->description . "<p>Created by <a href='" . trim(
(string) $this->config->project_website
) . "' target='_blank'>" . trim(
(string) OutputFilter::cleanText($project_author)
) . "</a><br /><small>Development started "
. Factory::getDate($plugin->created)->format("jS F, Y")
. "</small></p>";
// set xml discription
$this->language->set(
$plugin->key, $plugin->lang_prefix . '_XML_DESCRIPTION',
$plugin->xml_description
);
// update the readme if set
if ($plugin->addreadme == 1 && !empty($plugin->readme))
{
$plugin->readme = $this->placeholder->update_(
$this->customcode->update(base64_decode((string) $plugin->readme))
);
}
else
{
$plugin->addreadme = 0;
unset($plugin->readme);
}
// open some base64 strings
if (!empty($plugin->main_class_code))
{
// set GUI mapper field
$guiMapper['field'] = 'main_class_code';
// base64 Decode main_class_code.
$plugin->main_class_code = $this->gui->set(
$this->placeholder->update_(
$this->customcode->update(
base64_decode((string) $plugin->main_class_code)
)
),
$guiMapper
);
}
// set the head :)
if ($plugin->add_head == 1 && !empty($plugin->head))
{
// set GUI mapper field
$guiMapper['field'] = 'head';
// base64 Decode head.
$plugin->head = $this->gui->set(
$this->placeholder->update_(
$this->customcode->update(
base64_decode((string) $plugin->head)
)
),
$guiMapper
);
}
elseif (!empty($plugin->class_head))
{
// base64 Decode head.
$plugin->head = $this->gui->set(
$this->placeholder->update_(
$this->customcode->update(
base64_decode((string) $plugin->class_head)
)
),
array(
'table' => 'class_extends',
'field' => 'head',
'id' => (int) $plugin->class_id,
'type' => 'php')
);
}
unset($plugin->class_head);
// set the comment
if (!empty($plugin->comment))
{
// base64 Decode comment.
$plugin->comment = $this->gui->set(
$this->placeholder->update_(
$this->customcode->update(
base64_decode((string) $plugin->comment)
)
),
array(
'table' => 'class_extends',
'field' => 'comment',
'id' => (int) $plugin->class_id,
'type' => 'php')
);
}
// start the config array
$plugin->config_fields = [];
// create the form arrays
$plugin->form_files = [];
$plugin->fieldsets_label = [];
$plugin->fieldsets_paths = [];
$plugin->add_rule_path = [];
$plugin->add_field_path = [];
// set global fields rule to default component path
$plugin->fields_rules_paths = 1;
// set the fields data
$plugin->fields = (isset($plugin->fields)
&& JsonHelper::check($plugin->fields))
? json_decode((string) $plugin->fields, true) : null;
if (ArrayHelper::check($plugin->fields))
{
// ket global key
$key = $plugin->key;
$dynamic_fields = array('fieldset' => 'basic',
'fields_name' => 'params',
'file' => 'config');
foreach ($plugin->fields as $n => &$form)
{
if (isset($form['fields'])
&& ArrayHelper::check(
$form['fields']
))
{
// make sure the dynamic_field is set to dynamic_value by default
foreach (
$dynamic_fields as $dynamic_field =>
$dynamic_value
)
{
if (!isset($form[$dynamic_field])
|| !StringHelper::check(
$form[$dynamic_field]
))
{
$form[$dynamic_field] = $dynamic_value;
}
else
{
if ('fields_name' === $dynamic_field
&& strpos((string) $form[$dynamic_field], '.')
!== false)
{
$form[$dynamic_field]
= $form[$dynamic_field];
}
else
{
$form[$dynamic_field]
= StringHelper::safe(
$form[$dynamic_field]
);
}
}
}
// check if field is external form file
if (!isset($form['plugin']) || $form['plugin'] != 1)
{
// now build the form key
$unique = $form['file'] . $form['fields_name']
. $form['fieldset'];
}
else
{
// now build the form key
$unique = $form['fields_name']
. $form['fieldset'];
}
// set global fields rule path switchs
if ($plugin->fields_rules_paths == 1
&& isset($form['fields_rules_paths'])
&& $form['fields_rules_paths'] == 2)
{
$plugin->fields_rules_paths = 2;
}
// set where to path is pointing
$plugin->fieldsets_paths[$unique]
= $form['fields_rules_paths'];
// add the label if set to lang
if (isset($form['label'])
&& StringHelper::check(
$form['label']
))
{
$plugin->fieldsets_label[$unique]
= $this->language->key($form['label']);
}
// check for extra rule paths
if (isset($form['addrulepath'])
&& ArrayHelper::check($form['addrulepath']))
{
foreach ($form['addrulepath'] as $add_rule_path)
{
if (StringHelper::check($add_rule_path['path']))
{
$plugin->add_rule_path[$unique] = $add_rule_path['path'];
}
}
}
// check for extra field paths
if (isset($form['addfieldpath'])
&& ArrayHelper::check($form['addfieldpath']))
{
foreach ($form['addfieldpath'] as $add_field_path)
{
if (StringHelper::check($add_field_path['path']))
{
$plugin->add_field_path[$unique] = $add_field_path['path'];
}
}
}
// build the fields
$form['fields'] = array_map(
function ($field) use ($key, $unique) {
// make sure the alias and title is 0
$field['alias'] = 0;
$field['title'] = 0;
// set the field details
$this->field->set(
$field, $key, $key, $unique
);
// update the default if set
if (StringHelper::check(
$field['custom_value']
)
&& isset($field['settings']))
{
if (($old_default
= GetHelper::between(
$field['settings']->xml,
'default="', '"', false
)) !== false)
{
// replace old default
$field['settings']->xml
= str_replace(
'default="' . $old_default
. '"', 'default="'
. $field['custom_value'] . '"',
(string) $field['settings']->xml
);
}
else
{
// add the default (hmmm not ideal but okay it should work)
$field['settings']->xml
= 'default="'
. $field['custom_value'] . '" '
. $field['settings']->xml;
}
}
unset($field['custom_value']);
// return field
return $field;
}, array_values($form['fields'])
);
// check if field is external form file
if (!isset($form['plugin']) || $form['plugin'] != 1)
{
// load the form file
if (!isset($plugin->form_files[$form['file']]))
{
$plugin->form_files[$form['file']]
= [];
}
if (!isset($plugin->form_files[$form['file']][$form['fields_name']]))
{
$plugin->form_files[$form['file']][$form['fields_name']]
= [];
}
if (!isset($plugin->form_files[$form['file']][$form['fields_name']][$form['fieldset']]))
{
$plugin->form_files[$form['file']][$form['fields_name']][$form['fieldset']]
= [];
}
// do some house cleaning (for fields)
foreach ($form['fields'] as $field)
{
// so first we lock the field name in
$this->fieldName->get(
$field, $plugin->key, $unique
);
// add the fields to the global form file builder
$plugin->form_files[$form['file']][$form['fields_name']][$form['fieldset']][]
= $field;
}
// remove form
unset($plugin->fields[$n]);
}
else
{
// load the config form
if (!isset($plugin->config_fields[$form['fields_name']]))
{
$plugin->config_fields[$form['fields_name']]
= [];
}
if (!isset($plugin->config_fields[$form['fields_name']][$form['fieldset']]))
{
$plugin->config_fields[$form['fields_name']][$form['fieldset']]
= [];
}
// do some house cleaning (for fields)
foreach ($form['fields'] as $field)
{
// so first we lock the field name in
$this->fieldName->get(
$field, $plugin->key, $unique
);
// add the fields to the config builder
$plugin->config_fields[$form['fields_name']][$form['fieldset']][]
= $field;
}
// remove form
unset($plugin->fields[$n]);
}
}
else
{
unset($plugin->fields[$n]);
}
}
}
unset($plugin->fields);
// set files and folders
$this->filesFolders->set($plugin);
// add PHP in plugin install
$plugin->add_install_script = true;
$addScriptMethods = [
'php_preflight',
'php_postflight',
'php_method'
];
$addScriptTypes = [
'install',
'update',
'uninstall'
];
foreach ($addScriptMethods as $scriptMethod)
{
foreach ($addScriptTypes as $scriptType)
{
if (isset( $plugin->{'add_' . $scriptMethod . '_' . $scriptType})
&& $plugin->{'add_' . $scriptMethod . '_' . $scriptType} == 1
&& StringHelper::check(
$plugin->{$scriptMethod . '_' . $scriptType}
))
{
// set GUI mapper field
$guiMapper['field'] = $scriptMethod . '_' . $scriptType;
$plugin->{$scriptMethod . '_' . $scriptType} = $this->gui->set(
$this->placeholder->update_(
$this->customcode->update(
base64_decode(
(string) $plugin->{$scriptMethod . '_' . $scriptType}
)
)
),
$guiMapper
);
}
else
{
unset($plugin->{$scriptMethod . '_' . $scriptType});
$plugin->{'add_' . $scriptMethod . '_' . $scriptType} = 0;
}
}
}
// add_sql
if ($plugin->add_sql == 1
&& StringHelper::check($plugin->sql))
{
$plugin->sql = $this->placeholder->update_(
$this->customcode->update(base64_decode((string) $plugin->sql))
);
}
else
{
unset($plugin->sql);
$plugin->add_sql = 0;
}
// add_sql_uninstall
if ($plugin->add_sql_uninstall == 1
&& StringHelper::check(
$plugin->sql_uninstall
))
{
$plugin->sql_uninstall = $this->placeholder->update_(
$this->customcode->update(
base64_decode((string) $plugin->sql_uninstall)
)
);
}
else
{
unset($plugin->sql_uninstall);
$plugin->add_sql_uninstall = 0;
}
// update the URL of the update_server if set
if ($plugin->add_update_server == 1
&& StringHelper::check(
$plugin->update_server_url
))
{
$plugin->update_server_url = $this->placeholder->update_(
$this->customcode->update($plugin->update_server_url)
);
}
// add the update/sales server FTP details if that is the expected protocol
$serverArray = array('update_server', 'sales_server');
foreach ($serverArray as $server)
{
if ($plugin->{'add_' . $server} == 1
&& is_numeric(
$plugin->{$server}
)
&& $plugin->{$server} > 0)
{
// get the server protocol
$plugin->{$server . '_protocol'}
= GetHelper::var(
'server', (int) $plugin->{$server}, 'id', 'protocol'
);
}
else
{
$plugin->{$server} = 0;
// only change this for sales server (update server can be added locally to the zip file)
if ('sales_server' === $server)
{
$plugin->{'add_' . $server} = 0;
}
$plugin->{$server . '_protocol'} = 0;
}
}
// set the update server stuff (TODO)
// update_server_xml_path
// update_server_xml_file_name
// rest globals
$this->config->build_target = $_backup_target;
$this->config->lang_target = $_backup_lang;
$this->config->set('lang_prefix', $_backup_langPrefix);
$this->placeholder->remove('Plugin_name');
$this->placeholder->remove('Plugin');
$this->placeholder->remove('plugin');
$this->placeholder->remove('Plugin_group');
$this->placeholder->remove('plugin_group');
$this->placeholder->remove('plugin.version');
$this->placeholder->remove('plugin_version');
$this->placeholder->remove('VERSION');
$this->placeholder->remove('DESCRIPTION');
$this->placeholder->remove('PLUGIN_NAME');
$this->data[$id] = $plugin;
return true;
}
}
return false;
}

View File

@ -0,0 +1,60 @@
/**
* 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
*
* @param string $key The main string key
* @param mixed $value The values to set
*
* @return void
* @since 3.2.0
*/
public function set(string $key, $value);
/**
* Get content
*
* @param string $key The main string key
* @param mixed $value The values to set
*
* @return mixed
* @since 3.2.0
*/
public function get(string $key);
/**
* Does key exist
*
* @param string $key The main string key
*
* @return bool
* @since 3.2.0
*/
public function exist(string $key): bool;
/**
* Add content
*
* @param string $key The main string key
* @param mixed $value The values to set
*
* @return void
* @since 3.2.0
*/
public function add(string $key, $value);
/**
* Remove content
*
* @param string $key The main string key
*
* @return void
* @since 3.2.0
*/
public function remove(string $key);

View File

@ -0,0 +1,546 @@
/**
* The joint types
*
* @var array
* @since 3.2.0
*/
protected array $jointer = [
1 => 'LEFT',
2 => 'LEFT OUTER',
3 => 'INNER',
4 => 'RIGHT',
5 => 'RIGHT OUTER'
];
/**
* The operator types
*
* @var array
* @since 3.2.0
*/
protected array $operator = [
1 => '=',
2 => '!=',
3 => '<>',
4 => '>',
5 => '<',
6 => '>=',
7 => '<=',
8 => '!<',
9 => '!>',
10 => 'IN',
11 => 'NOT IN'
];
/**
* The gui mapper array
*
* @var array
* @since 3.2.0
*/
protected array $guiMapper = [
'table' => 'dynamic_get',
'id' => null,
'field' => null,
'type' => 'php'
];
/**
* Compiler Config
*
* @var Config
* @since 3.2.0
*/
protected Config $config;
/**
* The compiler registry
*
* @var Registry
* @since 3.2.0
*/
protected Registry $registry;
/**
* 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 Placeholder
*
* @var Placeholder
* @since 3.2.0
**/
protected Placeholder $placeholder;
/**
* Compiler Dynamic Get Selection
*
* @var Selection
* @since 3.2.0
**/
protected Selection $selection;
/**
* Constructor
*
* @param Config|null $config The compiler config.
* @param Registry|null $registry The compiler registry.
* @param Customcode|null $customcode The compiler customcode object.
* @param Gui|null $gui The compiler customcode gui.
* @param Placeholder|null $placeholder The compiler placeholder object.
* @param Selection|null $selection The compiler dynamic get selection object.
*
* @since 3.2.0
*/
public function __construct(?Config $config = null, ?Registry $registry = null, ?Customcode $customcode = null,
?Gui $gui = null, ?Placeholder $placeholder = null, ?Selection $selection = null)
{
$this->config = $config ?: Compiler::_('Config');
$this->registry = $registry ?: Compiler::_('Registry');
$this->customcode = $customcode ?: Compiler::_('Customcode');
$this->gui = $gui ?: Compiler::_('Customcode.Gui');
$this->placeholder = $placeholder ?: Compiler::_('Placeholder');
$this->selection = $selection ?: Compiler::_('Dynamicget.Selection');
}
/**
* Set Dynamic Get
*
* @param object $item The item data
* @param string $view_code The view code name
* @param string $context The context for events
*
* @return void
* @since 3.2.0
*/
public function set(object &$item, string $view_code, string $context)
{
// reset buckets
$item->main_get = [];
$item->custom_get = [];
// should joined and other tweaks be added
$add_tweaks_joints = true;
// set source data
switch ($item->main_source)
{
case 1:
// check if auto sync is set
if ($item->select_all == 1)
{
$item->view_selection = '*';
}
// set the view data
$item->main_get[0]['selection'] = $this->selection->get(
$item->key, $view_code,
$item->view_selection,
$item->view_table_main, 'a', 'view'
);
$item->main_get[0]['as'] = 'a';
$item->main_get[0]['key'] = $item->key;
$item->main_get[0]['context'] = $context;
unset($item->view_selection);
break;
case 2:
// check if auto sync is set
if ($item->select_all == 1)
{
$item->db_selection = '*';
}
// set the database data
$item->main_get[0]['selection'] = $this->selection->get(
$item->key, $view_code,
$item->db_selection,
$item->db_table_main, 'a', 'db'
);
$item->main_get[0]['as'] = 'a';
$item->main_get[0]['key'] = $item->key;
$item->main_get[0]['context'] = $context;
unset($item->db_selection);
break;
case 3:
// set GUI mapper field
$this->guiMapper['field'] = 'php_custom_get';
// get the custom query
$customQueryString
= $this->gui->set(
$this->customcode->update(
base64_decode((string) $item->php_custom_get)
),
$this->guiMapper
);
// get the table name
$_searchQuery
= GetHelper::between(
$customQueryString, '$query->from(', ')'
);
if (StringHelper::check(
$_searchQuery
)
&& strpos((string) $_searchQuery, '#__') !== false)
{
$_queryName = GetHelper::between(
$_searchQuery, '#__', "'"
);
if (!StringHelper::check(
$_queryName
))
{
$_queryName = GetHelper::between(
$_searchQuery, '#__', '"'
);
}
}
// set to blank if not found
if (!isset($_queryName)
|| !StringHelper::check(
$_queryName
))
{
$_queryName = '';
}
// set custom script
$item->main_get[0]['selection'] = [
'select' => $customQueryString,
'from' => '', 'table' => '', 'type' => '',
'name' => $_queryName];
$item->main_get[0]['as'] = 'a';
$item->main_get[0]['key'] = $item->key;
$item->main_get[0]['context'] = $context;
// do not add
$add_tweaks_joints = false;
break;
}
// only add if main source is not custom
if ($add_tweaks_joints)
{
// set join_view_table details
$item->join_view_table = json_decode(
(string) $item->join_view_table, true
);
if (ArrayHelper::check(
$item->join_view_table
))
{
// start the part of a table bucket
$_part_of_a = [];
// build relationship
$_relationship = array_map(
function ($op) use (&$_part_of_a) {
$bucket = [];
// array(on_field_as, on_field)
$bucket['on_field'] = array_map(
'trim',
explode('.', (string) $op['on_field'])
);
// array(join_field_as, join_field)
$bucket['join_field'] = array_map(
'trim',
explode('.', (string) $op['join_field'])
);
// triget filed that has table a relationship
if ($op['row_type'] == 1
&& ($bucket['on_field'][0] === 'a'
|| isset($_part_of_a[$bucket['on_field'][0]])
|| isset($_part_of_a[$bucket['join_field'][0]])))
{
$_part_of_a[$op['as']] = $op['as'];
}
return $bucket;
}, $item->join_view_table
);
// loop joints
foreach (
$item->join_view_table as $nr => &$option
)
{
if (StringHelper::check(
$option['selection']
))
{
// convert the type
$option['type']
= $this->jointer[$option['type']];
// convert the operator
$option['operator']
= $this->operator[$option['operator']];
// get the on field values
$on_field
= $_relationship[$nr]['on_field'];
// get the join field values
$join_field
= $_relationship[$nr]['join_field'];
// set selection
$option['selection']
= $this->selection->get(
$item->key,
$view_code,
$option['selection'],
$option['view_table'],
$option['as'],
'view',
$option['row_type']
);
$option['key'] = $item->key;
$option['context'] = $context;
// load to the getters
if ($option['row_type'] == 1)
{
$item->main_get[] = $option;
if ($on_field[0] === 'a'
|| isset($_part_of_a[$join_field[0]])
|| isset($_part_of_a[$on_field[0]]))
{
$this->registry->
set('builder.site_main_get.' . $this->config->build_target .
'.' . $view_code . '.' . $option['as'], $option['as']);
}
else
{
$this->registry->
set('builder.site_dynamic_get.' . $this->config->build_target .
'.' . $view_code . '.' . $option['as'] . '.' . $join_field[1], $on_field[0]);
}
}
elseif ($option['row_type'] == 2)
{
$item->custom_get[] = $option;
if ($on_field[0] != 'a')
{
$this->registry->
set('builder.site_dynamic_get.' . $this->config->build_target .
'.' . $view_code . '.' . $option['as'] . '.' . $join_field[1], $on_field[0]);
}
}
}
unset($item->join_view_table[$nr]);
}
}
unset($item->join_view_table);
// set join_db_table details
$item->join_db_table = json_decode(
(string) $item->join_db_table, true
);
if (ArrayHelper::check(
$item->join_db_table
))
{
// start the part of a table bucket
$_part_of_a = [];
// build relationship
$_relationship = array_map(
function ($op) use (&$_part_of_a) {
$bucket = [];
// array(on_field_as, on_field)
$bucket['on_field'] = array_map(
'trim',
explode('.', (string) $op['on_field'])
);
// array(join_field_as, join_field)
$bucket['join_field'] = array_map(
'trim',
explode('.', (string) $op['join_field'])
);
// triget filed that has table a relationship
if ($op['row_type'] == 1
&& ($bucket['on_field'][0] === 'a'
|| isset($_part_of_a[$bucket['on_field'][0]])
|| isset($_part_of_a[$bucket['join_field'][0]])))
{
$_part_of_a[$op['as']] = $op['as'];
}
return $bucket;
}, $item->join_db_table
);
// loop joints
foreach (
$item->join_db_table as $nr => &$option1
)
{
if (StringHelper::check(
$option1['selection']
))
{
// convert the type
$option1['type']
= $this->jointer[$option1['type']];
// convert the operator
$option1['operator']
= $this->operator[$option1['operator']];
// get the on field values
$on_field
= $_relationship[$nr]['on_field'];
// get the join field values
$join_field
= $_relationship[$nr]['join_field'];
// set selection
$option1['selection']
= $this->selection->get(
$item->key,
$view_code,
$option1['selection'],
$option1['db_table'],
$option1['as'],
'db',
$option1['row_type']
);
$option1['key'] = $item->key;
$option1['context'] = $context;
// load to the getters
if ($option1['row_type'] == 1)
{
$item->main_get[] = $option1;
if ($on_field[0] === 'a'
|| isset($_part_of_a[$join_field[0]])
|| isset($_part_of_a[$on_field[0]]))
{
$this->registry->
set('builder.site_main_get.' . $this->config->build_target .
'.' . $view_code . '.' . $option1['as'], $option1['as']);
}
else
{
$this->registry->
set('builder.site_dynamic_get.' . $this->config->build_target .
'.' . $view_code . '.' . $option1['as'] . '.' . $join_field[1], $on_field[0]);
}
}
elseif ($option1['row_type'] == 2)
{
$item->custom_get[] = $option1;
if ($on_field[0] != 'a')
{
$this->registry->
set('builder.site_dynamic_get.' . $this->config->build_target .
'.' . $view_code . '.' . $option1['as'] . '.' . $join_field[1], $on_field[0]);
}
}
}
unset($item->join_db_table[$nr]);
}
}
unset($item->join_db_table);
// set filter details
$item->filter = json_decode(
(string) $item->filter, true
);
if (ArrayHelper::check(
$item->filter
))
{
foreach ($item->filter as $nr => &$option2)
{
if (isset($option2['operator']))
{
$option2['operator'] = $this->operator[$option2['operator']];
$option2['state_key'] = $this->placeholder->update_(
$this->customcode->update(
$option2['state_key']
)
);
$option2['key'] = $item->key;
}
else
{
unset($item->filter[$nr]);
}
}
}
// set where details
$item->where = json_decode((string) $item->where, true);
if (ArrayHelper::check(
$item->where
))
{
foreach ($item->where as $nr => &$option3)
{
if (isset($option3['operator']))
{
$option3['operator']
= $this->operator[$option3['operator']];
}
else
{
unset($item->where[$nr]);
}
}
}
else
{
unset($item->where);
}
// set order details
$item->order = json_decode((string) $item->order, true);
if (!ArrayHelper::check(
$item->order
))
{
unset($item->order);
}
// set grouping
$item->group = json_decode((string) $item->group, true);
if (!ArrayHelper::check(
$item->group
))
{
unset($item->group);
}
// set global details
$item->global = json_decode(
(string) $item->global, true
);
if (!ArrayHelper::check(
$item->global
))
{
unset($item->global);
}
}
else
{
// when we have a custom query script we do not add the dynamic options
unset($item->join_view_table);
unset($item->join_db_table);
unset($item->filter);
unset($item->where);
unset($item->order);
unset($item->group);
unset($item->global);
}
}

View File

@ -0,0 +1,80 @@
/**
* 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 exist
if ($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;
}

View File

@ -0,0 +1,59 @@
/**
* Field Grouping https://docs.joomla.org/Form_field
**/
protected static $fields = [
'default' => [
'accesslevel', 'cachehandler', 'calendar', 'captcha', 'category', 'checkbox', 'checkboxes', 'chromestyle',
'color', 'combo', 'componentlayout', 'contentlanguage', 'contenttype', 'databaseconnection', 'components',
'editor', 'editors', 'email', 'file', 'file', 'filelist', 'folderlist', 'groupedlist', 'headertag', 'helpsite', 'hidden', 'imagelist',
'integer', 'language', 'list', 'media', 'menu', 'modal_menu', 'menuitem', 'meter', 'modulelayout', 'moduleorder', 'moduleposition',
'moduletag', 'note', 'number', 'password', 'plugins', 'predefinedlist', 'radio', 'range', 'repeatable', 'rules',
'sessionhandler', 'spacer', 'sql', 'subform', 'tag', 'tel', 'templatestyle', 'text', 'textarea', 'timezone', 'url', 'user', 'usergroup'
],
'plain' => [
'cachehandler', 'calendar', 'checkbox', 'chromestyle', 'color', 'componentlayout', 'contenttype', 'editor', 'editors', 'captcha',
'email', 'file', 'headertag', 'helpsite', 'hidden', 'integer', 'language', 'media', 'menu', 'modal_menu', 'menuitem', 'meter', 'modulelayout', 'templatestyle',
'moduleorder', 'moduletag', 'number', 'password', 'range', 'rules', 'tag', 'tel', 'text', 'textarea', 'timezone', 'url', 'user', 'usergroup'
],
'option' => [
'accesslevel', 'category', 'checkboxes', 'combo', 'contentlanguage', 'databaseconnection', 'components',
'filelist', 'folderlist', 'imagelist', 'list', 'plugins', 'predefinedlist', 'radio', 'sessionhandler', 'sql', 'groupedlist'
],
'text' => [
'calendar', 'color', 'editor', 'email', 'number', 'password', 'range', 'tel', 'text', 'textarea', 'url'
],
'list' => [
'checkbox', 'checkboxes', 'list', 'radio', 'groupedlist', 'combo'
],
'dynamic' => [
'category', 'file', 'filelist', 'folderlist', 'headertag', 'imagelist', 'integer', 'media', 'meter', 'rules', 'tag', 'timezone', 'user'
],
'spacer' => [
'note', 'spacer'
],
'special' => [
'contentlanguage', 'moduleposition', 'plugin', 'repeatable', 'subform'
],
'search' => [
'editor', 'email', 'tel', 'text', 'textarea', 'url', 'subform'
]
];
/**
* Field Checker
*
* @param string $type The field type
* @param string $option The field grouping
*
* @return bool if the field was found
*/
public static function check(string $type, string $option = 'default'): bool
{
// now check
if (isset(self::$fields[$option]) &&
in_array($type, self::$fields[$option]))
{
return true;
}
return false;
}

View File

@ -0,0 +1,55 @@
/**
* 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;
}

View File

@ -0,0 +1,21 @@
/**
* Encrypt a string as needed
*
* @param string $string The string to encrypt
* @param string $key The encryption key
*
* @return string
* @since 3.2.0
**/
public function encrypt(string $string, string $key): string;
/**
* Decrypt a string as needed
*
* @param string $string The string to decrypt
* @param string $key The decryption key
*
* @return string
* @since 3.2.0
**/
public function decrypt(string $string, string $key): string;

View File

@ -0,0 +1,20 @@
/**
* set the server details
*
* @param object $details The server details
*
* @return self
* @since 3.2.0
**/
public function set(object $details);
/**
* move a file to server with the FTP client
*
* @param string $localPath The full local path to the file
* @param string $fileName The file name
*
* @return bool
* @since 3.2.0
**/
public function move(string $localPath, string $fileName): bool;

View File

@ -0,0 +1,200 @@
/**
* History Item Object
*
* @var object|null
* @since 3.2.0
*/
protected ?object $tmp;
/**
* Compiler Config
*
* @var Config
* @since 3.2.0
*/
protected Config $config;
/**
* Database object to query local DB
*
* @var \JDatabaseDriver
* @since 3.2.0
*/
protected \JDatabaseDriver $db;
/**
* Constructor
*
* @param Config|null $config The compiler config object.
* @param \JDatabaseDriver|null $db The Database Driver object.
*
* @since 3.2.0
*/
public function __construct(?Config $config = null, ?\JDatabaseDriver $db = null)
{
$this->config = $config ?: Compiler::_('Config');
$this->db = $db ?: Factory::getDbo();
}
/**
* Get Item History object
*
* @param string $type The type of item
* @param int $id The item ID
*
* @return ?object The history
* @since 3.2.0
*/
public function get(string $type, int $id): ?object
{
// quick class object to store old history object
$this->tmp = null;
// Create a new query object.
$query = $this->db->getQuery(true);
$query->select('h.*');
$query->from('#__ucm_history AS h');
$query->where(
$this->db->quoteName('h.ucm_item_id') . ' = ' . (int) $id
);
// Join over the content type for the type id
$query->join(
'LEFT', '#__content_types AS ct ON ct.type_id = h.ucm_type_id'
);
$query->where(
'ct.type_alias = ' . $this->db->quote(
'com_componentbuilder.' . $type
)
);
$query->order('h.save_date DESC');
$this->db->setQuery($query, 0, 1);
$this->db->execute();
if ($this->db->getNumRows())
{
// new version of this item found
// so we need to mark it as the last compiled version
$newActive = $this->db->loadObject();
// set the new version watch
$this->set($newActive, 1);
}
// Get last compiled verion
$query = $this->db->getQuery(true);
$query->select('h.*');
$query->from('#__ucm_history AS h');
$query->where(
$this->db->quoteName('h.ucm_item_id') . ' = ' . (int) $id
);
$query->where('h.keep_forever = 1');
$query->where('h.version_note LIKE ' . $this->db->quote('%component%'));
// make sure it does not return the active version
if (isset($newActive) && isset($newActive->version_id))
{
$query->where('h.version_id != ' . (int) $newActive->version_id);
}
// Join over the content type for the type id
$query->join(
'LEFT', '#__content_types AS ct ON ct.type_id = h.ucm_type_id'
);
$query->where(
'ct.type_alias = ' . $this->db->quote(
'com_componentbuilder.' . $type
)
);
$query->order('h.save_date DESC');
$this->db->setQuery($query);
$this->db->execute();
if ($this->db->getNumRows())
{
// the old active version was found
// so we may need to do an SQL update
// and unmark the old compiled version
$oldActives = $this->db->loadObjectList();
foreach ($oldActives as $oldActive)
{
// remove old version watch
$this->set($oldActive, 0);
}
}
// return the last used history record or null.
return $this->tmp;
}
/**
* Set Item History Watch
*
* @param Object $object The history object
* @param int $action The action to take
* 0 = remove watch
* 1 = add watch
*
* @return bool
* @since 3.2.0
*/
protected function set(object $object, int $action): bool
{
// check the note
if (JsonHelper::check($object->version_note))
{
$version_note = json_decode((string) $object->version_note, true);
}
else
{
$version_note = array('component' => []);
}
// set watch
switch ($action)
{
case 0:
// remove watch
if (isset($version_note['component'])
&& ($key = array_search(
$this->config->component_id, $version_note['component']
)) !== false)
{
// last version that was used to build/compile
$this->tmp = json_decode((string) $object->version_data);
// remove it from this component
unset($version_note['component'][$key]);
}
else
{
// since it was not found, no need to update anything
return true;
}
break;
case 1:
// add watch
if (!in_array($this->config->component_id, $version_note['component']))
{
$version_note['component'][] = $this->config->component_id;
}
else
{
// since it is there already, no need to update anything
return true;
}
break;
}
// check if we need to still keep this locked
if (isset($version_note['component'])
&& ArrayHelper::check($version_note['component']))
{
// insure component ids are only added once per item
$version_note['component'] = array_unique(
$version_note['component']
);
// we may change this, little risky (but since JCB does not have history notes it should be okay for now)
$object->version_note = json_encode($version_note);
$object->keep_forever = '1';
}
else
{
$object->version_note = '';
$object->keep_forever = '0';
}
// run the update
return $this->db->updateObject('#__ucm_history', $object, 'version_id');
}

View File

@ -0,0 +1,83 @@
/**
* 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(CustomviewData::class, 'Customview.Data')
->share('Customview.Data', [$this, 'getCustomviewData'], true);
$container->alias(DynamicgetData::class, 'Dynamicget.Data')
->share('Dynamicget.Data', [$this, 'getDynamicgetData'], true);
$container->alias(DynamicgetSelection::class, 'Dynamicget.Selection')
->share('Dynamicget.Selection', [$this, 'getDynamicgetSelection'], true);
}
/**
* Get the Compiler Customview Data
*
* @param Container $container The DI container.
*
* @return CustomviewData
* @since 3.2.0
*/
public function getCustomviewData(Container $container): CustomviewData
{
return new CustomviewData(
$container->get('Config'),
$container->get('Event'),
$container->get('Customcode'),
$container->get('Customcode.Gui'),
$container->get('Model.Libraries'),
$container->get('Templatelayout.Data'),
$container->get('Dynamicget.Data'),
$container->get('Model.Loader'),
$container->get('Model.Javascriptcustomview'),
$container->get('Model.Csscustomview'),
$container->get('Model.Phpcustomview'),
$container->get('Model.Ajaxcustomview'),
$container->get('Model.Custombuttons')
);
}
/**
* Get the Compiler Dynamicget Data
*
* @param Container $container The DI container.
*
* @return DynamicgetData
* @since 3.2.0
*/
public function getDynamicgetData(Container $container): DynamicgetData
{
return new DynamicgetData(
$container->get('Config'),
$container->get('Registry'),
$container->get('Event'),
$container->get('Customcode'),
$container->get('Customcode.Dispenser'),
$container->get('Customcode.Gui'),
$container->get('Model.Dynamicget')
);
}
/**
* Get the Compiler Dynamicget Selection
*
* @param Container $container The DI container.
*
* @return DynamicgetSelection
* @since 3.2.0
*/
public function getDynamicgetSelection(Container $container): DynamicgetSelection
{
return new DynamicgetSelection(
$container->get('Config'),
$container->get('Registry')
);
}

View File

@ -0,0 +1,196 @@
/**
* 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(CompilerComponent::class, 'Component')
->share('Component', [$this, 'getComponent'], true);
$container->alias(Settings::class, 'Component.Settings')
->share('Component.Settings', [$this, 'getSettings'], true);
$container->alias(Dashboard::class, 'Component.Dashboard')
->share('Component.Dashboard', [$this, 'getDashboard'], true);
$container->alias(Placeholder::class, 'Component.Placeholder')
->share('Component.Placeholder', [$this, 'getPlaceholder'], true);
$container->alias(Data::class, 'Component.Data')
->share('Component.Data', [$this, 'getData'], true);
$container->alias(Structure::class, 'Component.Structure')
->share('Component.Structure', [$this, 'getStructure'], true);
$container->alias(Structuresingle::class, 'Component.Structure.Single')
->share('Component.Structure.Single', [$this, 'getStructuresingle'], true);
$container->alias(Structuremultiple::class, 'Component.Structure.Multiple')
->share('Component.Structure.Multiple', [$this, 'getStructuremultiple'], true);
}
/**
* Get the Component
*
* @param Container $container The DI container.
*
* @return CompilerComponent
* @since 3.2.0
*/
public function getComponent(Container $container): CompilerComponent
{
return new CompilerComponent(
$container->get('Component.Data')
);
}
/**
* Get the Compiler Component (version) Settings
*
* @param Container $container The DI container.
*
* @return Settings
* @since 3.2.0
*/
public function getSettings(Container $container): Settings
{
return new Settings(
$container->get('Config'),
$container->get('Registry'),
$container->get('Event'),
$container->get('Placeholder'),
$container->get('Component'),
$container->get('Utilities.Paths'),
$container->get('Utilities.Dynamicpath'),
$container->get('Utilities.Pathfix')
);
}
/**
* Get the Compiler Component Dynamic Dashboard
*
* @param Container $container The DI container.
*
* @return Dashboard
* @since 3.2.0
*/
public function getDashboard(Container $container): Dashboard
{
return new Dashboard(
$container->get('Registry'),
$container->get('Component')
);
}
/**
* Get the Component Placeholders
*
* @param Container $container The DI container.
*
* @return Placeholder
* @since 3.2.0
*/
public function getPlaceholder(Container $container): Placeholder
{
return new Placeholder(
$container->get('Config')
);
}
/**
* Get the Component Data
*
* @param Container $container The DI container.
*
* @return Data
* @since 3.2.0
*/
public function getData(Container $container): Data
{
return new Data(
$container->get('Config'),
$container->get('Event'),
$container->get('Placeholder'),
$container->get('Component.Placeholder'),
$container->get('Customcode.Dispenser'),
$container->get('Customcode'),
$container->get('Customcode.Gui'),
$container->get('Field'),
$container->get('Field.Name'),
$container->get('Field.Unique.Name'),
$container->get('Model.Filesfolders'),
$container->get('Model.Historycomponent'),
$container->get('Model.Whmcs'),
$container->get('Model.Sqltweaking'),
$container->get('Model.Adminviews'),
$container->get('Model.Siteviews'),
$container->get('Model.Customadminviews'),
$container->get('Model.Updateserver'),
$container->get('Model.Joomlamodules'),
$container->get('Model.Joomlaplugins')
);
}
/**
* Get the Compiler Structure
*
* @param Container $container The DI container.
*
* @return Structure
* @since 3.2.0
*/
public function getStructure(Container $container): Structure
{
return new Structure(
$container->get('Component.Settings'),
$container->get('Utilities.Paths'),
$container->get('Utilities.Folder')
);
}
/**
* Get the Compiler Structure Single
*
* @param Container $container The DI container.
*
* @return Structuresingle
* @since 3.2.0
*/
public function getStructuresingle(Container $container): Structuresingle
{
return new Structuresingle(
$container->get('Config'),
$container->get('Registry'),
$container->get('Component.Settings'),
$container->get('Component'),
$container->get('Content'),
$container->get('Utilities.Counter'),
$container->get('Utilities.Paths'),
$container->get('Utilities.Files')
);
}
/**
* Get the Compiler Structure Multiple
*
* @param Container $container The DI container.
*
* @return Structuremultiple
* @since 3.2.0
*/
public function getStructuremultiple(Container $container): Structuremultiple
{
return new Structuremultiple(
$container->get('Config'),
$container->get('Registry'),
$container->get('Component.Settings'),
$container->get('Component'),
$container->get('Model.Createdate'),
$container->get('Model.Modifieddate'),
$container->get('Utilities.Structure')
);
}

View File

@ -0,0 +1,83 @@
/**
* The compiler registry
*
* @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');
}
/**
* Count how many times the same field is used per view
*
* @param string $name The name of the field
* @param string $view The name of the view
*
* @return void
* @since 3.2.0
*/
public function set(string $name, string $view)
{
if (($number = $this->registry->get("unique.names.${view}.counter.${name}")) === null)
{
$this->registry->set("unique.names.${view}.counter.${name}", 1);
return;
}
// count how many times the field is used
$this->registry->set("unique.names.${view}.counter.${name}", ++$number);
return;
}
/**
* Naming each field with an unique name
*
* @param string $name The name of the field
* @param string $view The name of the view
*
* @return string the name
* @since 3.2.0
*/
public function get(string $name, string $view): string
{
// only increment if the field name is used multiple times
if ($this->registry->get("unique.names.${view}.counter.${name}") > 1)
{
$counter = 1;
// set the unique name
$unique_name = FieldHelper::safe(
$name . '_' . $counter
);
while ($this->registry->get("unique.names.${view}.names.${unique_name}") !== null)
{
// increment the number
$counter++;
// try again
$unique_name = FieldHelper::safe(
$name . '_' . $counter
);
}
// set the new name number
$this->registry->set("unique.names.${view}.names.${unique_name}", $counter);
// return the unique name
return $unique_name;
}
return $name;
}

View File

@ -0,0 +1,171 @@
/**
* The language content
*
* @var array
* @since 3.2.0
**/
protected array $content = [];
/**
* Compiler Config
*
* @var Config
* @since 3.2.0
**/
protected Config $config;
/**
* Constructor.
*
* @param Config|null $config The compiler config object.
*
* @since 3.2.0
*/
public function __construct(?Config $config = null)
{
$this->config = $config ?: Compiler::_('Config');
}
/**
* Get the language string key
*
* @param string $string The plan text string (English)
*
* @return string The key language string (all uppercase)
* @since 3.2.0
*/
public function key($string): string
{
// this is there to insure we don't break already added Language strings
if (StringHelper::safe($string, 'U', '_', false, false)
=== $string)
{
return false;
}
// build language key
$key_lang = $this->config->lang_prefix . '_' . StringHelper::safe(
$string, 'U'
);
// set the language string
$this->set($this->config->lang_target, $key_lang, $string);
return $key_lang;
}
/**
* check if the language string exist
*
* @param string $target The target area for the language string
* @param string|null $language The language key string
*
* @return bool
* @since 3.2.0
*/
public function exist(string $target, ?string $language = null): bool
{
if ($language)
{
return isset($this->content[$target][$language]);
}
return isset($this->content[$target]);
}
/**
* get the language string
*
* @param string $target The target area for the language string
* @param string|null $language The language key string
*
* @return Mixed The language string found or empty string if none is found
* @since 3.2.0
*/
public function get(string $target, string $language): string
{
if (isset($this->content[$target][$language]))
{
return $this->content[$target][$language];
}
return '';
}
/**
* get target array
*
* @param string $target The target area for the language string
*
* @return array The target array or empty array if none is found
* @since 3.2.0
*/
public function getTarget(string $target): array
{
if (isset($this->content[$target]) && ArrayHelper::check($this->content[$target]))
{
return $this->content[$target];
}
return [];
}
/**
* set target array
*
* @param string $target The target area for the language string
* @param array|null $content The language content string
*
* @return void
* @since 3.2.0
*/
public function setTarget(string $target, ?array $content)
{
$this->content[$target] = $content;
}
/**
* set the language content values to language content array
*
* @param string $target The target area for the language string
* @param string $language The language key string
* @param string $string The language string
* @param bool $addPrefix The switch to add langPrefix
*
* @return void
* @since 3.2.0
*/
public function set(string $target, string $language, string $string, bool $addPrefix = false)
{
if ($addPrefix && empty(
$this->content[$target][$this->config->lang_prefix . '_' . $language]
))
{
$this->content[$target][$this->config->lang_prefix . '_' . $language]
= $this->fix($string);
}
elseif (empty($this->content[$target][$language]))
{
$this->content[$target][$language] = $this->fix(
$string
);
}
}
/**
* We need to remove all text breaks from all language strings
*
* @param string $string The language string
*
* @return string
* @since 3.2.0
*/
protected function fix(string $string): string
{
if ($this->config->remove_line_breaks)
{
return trim(str_replace(array(PHP_EOL, "\r", "\n"), '', $string));
}
return trim($string);
}

View File

@ -0,0 +1,125 @@
/**
* The array of last modified dates
*
* @var array
* @since 3.2.0
*/
protected array $last = [];
/**
* Get the last modified date of an item
*
* @param array $item The item data
*
* @return string The modified date
* @since 3.2.0
*/
public function get(array $item): string
{
$key = $this->getKey($item);
if (!isset($this->last[$key]))
{
$date = max($this->getDate($item), $this->getModified($item));
$this->last[$key] = Factory::getDate($date)->format(
'jS F, Y'
);
}
return $this->last[$key];
}
/**
* Get the last modified date of an item
*
* @param array $item The item data
*
* @return int The modified date as int
* @since 3.2.0
*/
protected function getDate(array $item): int
{
if (isset($item['settings']) && isset($item['settings']->modified)
&& StringHelper::check($item['settings']->modified)
&& '0000-00-00 00:00:00' !== $item['settings']->modified)
{
return strtotime((string) $item['settings']->modified);
}
return strtotime("now");
}
/**
* Get the last modified date of an item's sub items
*
* @param array $item The item data
*
* @return int The modified date as int
* @since 3.2.0
*/
protected function getModified(array $item): int
{
$date = 0;
// if not settings is found
if (!isset($item['settings']) || !ObjectHelper::check($item['settings']))
{
return $date;
}
// check if we have fields
if (isset($item['settings']->fields) && ArrayHelper::check($item['settings']->fields))
{
foreach ($item['settings']->fields as $field)
{
if (isset($field['settings'])
&& ObjectHelper::check($field['settings'])
&& isset($field['settings']->modified)
&& StringHelper::check($field['settings']->modified)
&& '0000-00-00 00:00:00' !== $field['settings']->modified)
{
$modified = strtotime((string) $field['settings']->modified);
$date = max($date, $modified);
}
}
}
// check if we have a main dynamic get
elseif (isset($item['settings']->main_get)
&& ObjectHelper::check($item['settings']->main_get)
&& isset($item['settings']->main_get->modified)
&& StringHelper::check($item['settings']->main_get->modified)
&& '0000-00-00 00:00:00' !== $item['settings']->main_get->modified)
{
$modified = strtotime((string) $item['settings']->main_get->modified);
$date = max($date, $modified);
}
return $date;
}
/**
* Get the key for an item
*
* @param array $item The item data
*
* @return string The key
* @since 3.2.0
*/
protected function getKey(array $item): string
{
if (isset($item['adminview']))
{
return $item['adminview'] . 'admin';
}
elseif (isset($item['siteview']))
{
return $item['siteview'] . 'site';
}
elseif (isset($item['customadminview']))
{
return $item['customadminview'] . 'customadmin';
}
return 'error';
}

View File

@ -0,0 +1,199 @@
/**
* The compiler registry
*
* @var Registry
* @since 3.2.0
*/
protected Registry $registry;
/**
* Unique Field Names
*
* @var array
* @since 3.2.0
*/
protected array $unique;
/**
* Compiler Placeholder
*
* @var Placeholder
* @since 3.2.0
*/
protected Placeholder $placeholder;
/**
* Compiler Field Unique Name
*
* @var UniqueName
* @since 3.2.0
*/
protected UniqueName $uniqueName;
/**
* Constructor
*
* @param Placeholder|null $placeholder The compiler component placeholder object.
* @param UniqueName|null $uniqueName The compiler field unique name object.
* @param Registry|null $registry The compiler registry object.
*
* @since 3.2.0
*/
public function __construct(?Placeholder $placeholder = null, ?UniqueName $uniqueName = null, ?Registry $registry = null)
{
$this->placeholder = $placeholder ?: Compiler::_('Placeholder');
$this->uniqueName = $uniqueName ?: Compiler::_('Field.Unique.Name');
$this->registry = $registry ?: Compiler::_('Registry');
}
/**
* Get the field's actual name
*
* @param array $field The field array
* @param string|null $listViewName The list view name
* @param string $amicably The peaceful resolve (for fields in subforms in same view :)
*
* @return string Success returns field name
* @since 3.2.0
*/
public function get(array &$field, ?string $listViewName = null, string $amicably = ''): string
{
// return the unique name if already set
if ($listViewName && StringHelper::check($listViewName)
&& isset($field['hash'])
&& isset(
$this->unique[$listViewName . $amicably . $field['hash']]
))
{
return $this->unique[$listViewName . $amicably . $field['hash']];
}
// always make sure we have a field name and type
if (!isset($field['settings']) || !isset($field['settings']->type_name)
|| !isset($field['settings']->name))
{
return 'error';
}
// set the type name
$type_name = TypeHelper::safe(
$field['settings']->type_name
);
// set the name of the field
$name = FieldHelper::safe($field['settings']->name);
// check that we have the properties
if (ArrayHelper::check($field['settings']->properties))
{
foreach ($field['settings']->properties as $property)
{
if ($property['name'] === 'name')
{
// if category then name must be catid (only one per view)
if ($type_name === 'category')
{
// quick check if this is a category linked to view page
$requeSt_id = GetHelper::between(
$field['settings']->xml, 'name="', '"'
);
if (strpos($requeSt_id, '_request_id') !== false
|| strpos($requeSt_id, '_request_catid') !== false)
{
// keep it then, don't change
$name = $this->placeholder->update_(
$requeSt_id
);
}
else
{
$name = 'catid';
}
// if list view name is set
if (StringHelper::check($listViewName))
{
// check if we should use another Text Name as this views name
$otherName = $this->placeholder->update_(
GetHelper::between(
$field['settings']->xml, 'othername="', '"'
)
);
$otherViews = $this->placeholder->update_(
GetHelper::between(
$field['settings']->xml, 'views="', '"'
)
);
$otherView = $this->placeholder->update_(
GetHelper::between(
$field['settings']->xml, 'view="', '"'
)
);
// This is to link other view category
if (StringHelper::check($otherName)
&& StringHelper::check(
$otherViews
) && StringHelper::check(
$otherView
))
{
// set other category details
$this->registry->set("category.other.name.${listViewName}", [
'name' => FieldHelper::safe(
$otherName
),
'views' => StringHelper::safe(
$otherViews
),
'view' => StringHelper::safe(
$otherView
)
]);
}
}
}
// if tag is set then enable all tag options for this view (only one per view)
elseif ($type_name === 'tag')
{
$name = 'tags';
}
// if the field is set as alias it must be called alias
elseif (isset($field['alias']) && $field['alias'])
{
$name = 'alias';
}
else
{
// get value from xml
$xml = FieldHelper::safe(
$this->placeholder->update_(
GetHelper::between(
$field['settings']->xml, 'name="', '"'
)
)
);
// check if a value was found
if (StringHelper::check($xml))
{
$name = $xml;
}
}
// exit foreach loop
break;
}
}
}
// return the value unique
if (StringHelper::check($listViewName) && isset($field['hash']))
{
$this->unique[$listViewName . $amicably . $field['hash']]
= $this->uniqueName->get($name, $listViewName . $amicably);
// now return the unique name
return $this->unique[$listViewName . $amicably . $field['hash']];
}
// fall back to global
return $name;
}

View File

@ -0,0 +1,406 @@
/**
* 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)
];
}
/**
* 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;
}

View File

@ -0,0 +1,8 @@
/**
* get all System Placeholders
*
* @return array The global placeholders
*
* @since 3.2.0
*/
public function get(): array;

View File

@ -0,0 +1,73 @@
/**
* The compiler registry
*
* @var Registry
* @since 3.2.0
*/
protected Registry $registry;
/**
* Constructor
*
* @param Registry|null $config The compiler registry object.
*
* @since 3.2.0
*/
public function __construct(?Registry $registry = null)
{
$this->registry = $registry ?: Compiler::_('Registry');
}
/**
* get the field database name and AS prefix
*
* @param string $nameListCode The list view name
* @param int $fieldId The field ID
* @param string $targetArea The area being targeted
*
* @return string|null
* @since 3.2.0
*/
public function get(string $nameListCode, int $fieldId, string $targetArea = 'builder.list'): ?string
{
if (($fields = $this->registry->get("${targetArea}.${nameListCode}")) !== null)
{
if ($fieldId < 0)
{
switch ($fieldId)
{
case -1:
return 'a.id';
case -2:
return 'a.ordering';
case -3:
return 'a.published';
}
}
foreach ($fields as $field)
{
if ($field['id'] == $fieldId)
{
// now check if this is a category
if ($field['type'] === 'category')
{
return 'c.title';
}
// set the custom code
elseif (ArrayHelper::check(
$field['custom']
))
{
return $field['custom']['db'] . "."
. $field['custom']['text'];
}
else
{
return 'a.' . $field['code'];
}
}
}
}
return null;
}

View File

@ -0,0 +1,62 @@
/**
* 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(Data::class, 'Joomlaplugin.Data')
->share('Joomlaplugin.Data', [$this, 'getData'], true);
$container->alias(Structure::class, 'Joomlaplugin.Structure')
->share('Joomlaplugin.Structure', [$this, 'getStructure'], true);
}
/**
* Get the Joomla Plugin Data
*
* @param Container $container The DI container.
*
* @return Data
* @since 3.2.0
*/
public function getData(Container $container): Data
{
return new Data(
$container->get('Config'),
$container->get('Customcode'),
$container->get('Customcode.Gui'),
$container->get('Placeholder'),
$container->get('Language'),
$container->get('Field'),
$container->get('Field.Name'),
$container->get('Model.Filesfolders')
);
}
/**
* Get the Joomla Plugin Structure Builder
*
* @param Container $container The DI container.
*
* @return Structure
* @since 3.2.0
*/
public function getStructure(Container $container): Structure
{
return new Structure(
$container->get('Joomlaplugin.Data'),
$container->get('Component'),
$container->get('Config'),
$container->get('Registry'),
$container->get('Customcode.Dispenser'),
$container->get('Event'),
$container->get('Utilities.Counter'),
$container->get('Utilities.Folder'),
$container->get('Utilities.File'),
$container->get('Utilities.Files')
);
}

View File

@ -0,0 +1,48 @@
/**
* 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(CompilerLanguage::class, 'Language')
->share('Language', [$this, 'getLanguage'], true);
$container->alias(Extractor::class, 'Language.Extractor')
->share('Language.Extractor', [$this, 'getLanguageExtractor'], true);
}
/**
* Get the Compiler Language
*
* @param Container $container The DI container.
*
* @return CompilerLanguage
* @since 3.2.0
*/
public function getLanguage(Container $container): CompilerLanguage
{
return new CompilerLanguage(
$container->get('Config')
);
}
/**
* Get the Compiler Language Extractor
*
* @param Container $container The DI container.
*
* @return Extractor
* @since 3.2.0
*/
public function getLanguageExtractor(Container $container): Extractor
{
return new Extractor(
$container->get('Config'),
$container->get('Language'),
$container->get('Placeholder')
);
}

View File

@ -0,0 +1,203 @@
/**
* Tracking the update of fields per/view
*
* @var array
* @since 3.2.0
*/
protected array $views;
/**
* Compiler Customcode Dispenser
*
* @var Dispenser
* @since 3.2.0
*/
protected Dispenser $dispenser;
/**
* Constructor
*
* @param Dispenser|null $dispenser The compiler customcode dispenser object.
*
* @since 3.2.0
*/
public function __construct(?Dispenser $dispenser = null)
{
$this->dispenser = $dispenser ?: Compiler::_('Customcode.Dispenser');
}
/**
* Update field customcode
*
* @param int $id The field id
* @param object $field The field object
* @param string|null $singleViewName The view edit or single name
* @param string|null $listViewName The view list name
*
* @return void
* @since 3.2.0
*/
public function update(int $id, object &$field, $singleViewName = null, $listViewName = null)
{
// check if we should load scripts for single view
if ($singleViewName && StringHelper::check($singleViewName)
&& !isset($this->views[$singleViewName][$id]))
{
// add_javascript_view_footer
if ($field->add_javascript_view_footer == 1
&& StringHelper::check(
$field->javascript_view_footer
))
{
$convert__ = true;
if (isset($field->javascript_view_footer_decoded)
&& $field->javascript_view_footer_decoded)
{
$convert__ = false;
}
$this->dispenser->set(
$field->javascript_view_footer,
'view_footer',
$singleViewName,
null,
array(
'table' => 'field',
'id' => (int) $id,
'field' => 'javascript_view_footer',
'type' => 'js',
'prefix' => PHP_EOL),
$convert__,
$convert__,
true
);
if (!isset($field->javascript_view_footer_decoded))
{
$field->javascript_view_footer_decoded
= true;
}
if (strpos((string) $field->javascript_view_footer, "token") !== false
|| strpos((string) $field->javascript_view_footer, "task=ajax") !== false)
{
if (!isset($this->dispenser->hub['token']))
{
$this->dispenser->hub['token'] = [];
}
if (!isset($this->dispenser->hub['token'][$singleViewName])
|| !$this->dispenser->hub['token'][$singleViewName])
{
$this->dispenser->hub['token'][$singleViewName]
= true;
}
}
}
// add_css_view
if ($field->add_css_view == 1)
{
$convert__ = true;
if (isset($field->css_view_decoded)
&& $field->css_view_decoded)
{
$convert__ = false;
}
$this->dispenser->set(
$field->css_view,
'css_view',
$singleViewName,
null,
array('prefix' => PHP_EOL),
$convert__,
$convert__,
true
);
if (!isset($field->css_view_decoded))
{
$field->css_view_decoded = true;
}
}
// add this only once to single view.
$this->views[$singleViewName][$id] = true;
}
// check if we should load scripts for list views
if ($listViewName && StringHelper::check($listViewName)
&& !isset($this->views[$listViewName][$id]))
{
// add_javascript_views_footer
if ($field->add_javascript_views_footer == 1
&& StringHelper::check(
$field->javascript_views_footer
))
{
$convert__ = true;
if (isset($field->javascript_views_footer_decoded)
&& $field->javascript_views_footer_decoded)
{
$convert__ = false;
}
$this->dispenser->set(
$field->javascript_views_footer,
'views_footer',
$singleViewName,
null,
array(
'table' => 'field',
'id' => (int) $id,
'field' => 'javascript_views_footer',
'type' => 'js',
'prefix' => PHP_EOL),
$convert__,
$convert__,
true
);
if (!isset($field->javascript_views_footer_decoded))
{
$field->javascript_views_footer_decoded = true;
}
if (strpos((string) $field->javascript_views_footer, "token") !== false
|| strpos((string) $field->javascript_views_footer, "task=ajax") !== false)
{
if (!isset($this->dispenser->hub['token']))
{
$this->dispenser->hub['token'] = [];
}
if (!isset($this->dispenser->hub['token'][$listViewName])
|| !$this->dispenser->hub['token'][$listViewName])
{
$this->dispenser->hub['token'][$listViewName]
= true;
}
}
}
// add_css_views
if ($field->add_css_views == 1)
{
$convert__ = true;
if (isset($field->css_views_decoded)
&& $field->css_views_decoded)
{
$convert__ = false;
}
$this->dispenser->set(
$field->css_views,
'css_views',
$singleViewName,
null,
array('prefix' => PHP_EOL),
$convert__,
$convert__,
true
);
if (!isset($field->css_views_decoded))
{
$field->css_views_decoded = true;
}
}
// add this only once to list view.
$this->views[$listViewName][$id] = true;
}
}

View File

@ -0,0 +1,9 @@
/**
* Set a string as bsae64 (basic)
*
* @param string $script The code string
*
* @return string
* @since 3.2.0
*/
public function set(string $script): string;

Some files were not shown because too many files have changed in this diff Show More