jcb-compiler/src/1bd48df2-4f7e-4581-9fe9-4b5.../code.php

262 lines
7.5 KiB
PHP

<?php
/**
* @package Joomla.Component.Builder
*
* @created 4th September, 2022
* @author Llewellyn van der Merwe <https://dev.vdm.io>
* @git Joomla Component Builder <https://git.vdm.dev/joomla/Component-Builder>
* @copyright Copyright (C) 2015 Vast Development Method. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace VDM\Joomla\Componentbuilder\Compiler\Customcode;
use Joomla\CMS\Factory;
use Joomla\CMS\Application\CMSApplication;
use Joomla\CMS\Language\Text;
use VDM\Joomla\Utilities\ArrayHelper;
use VDM\Joomla\Utilities\StringHelper;
use VDM\Joomla\Utilities\GetHelper;
use VDM\Joomla\Utilities\FileHelper;
use VDM\Joomla\Utilities\String\FieldHelper;
use VDM\Joomla\Componentbuilder\Compiler\Factory as Compiler;
use VDM\Joomla\Componentbuilder\Compiler\Config;
use VDM\Joomla\Componentbuilder\Compiler\Placeholder\Reverse;
use VDM\Joomla\Componentbuilder\Compiler\Power\Parser;
use VDM\Joomla\Componentbuilder\Compiler\Interfaces\Customcode\GuiInterface;
/**
* Compiler Gui Custom Code
*
* @since 3.2.0
*/
class Gui implements GuiInterface
{
/**
* Compiler Config
*
* @var Config
* @since 3.2.0
**/
protected Config $config;
/**
* Compiler Placeholder Reverse
*
* @var Reverse
* @since 3.2.0
**/
protected Reverse $reverse;
/**
* Compiler Powers Parser
*
* @var Parser
* @since 3.2.0
**/
protected Parser $parser;
/**
* Database object to query local DB
*
* @since 3.2.0
**/
protected $db;
/**
* Database object to query local DB
*
* @since 3.2.0
**/
protected $app;
/**
* Constructor.
*
* @param Config|null $config The compiler config object.
* @param Reverse|null $reverse The compiler placeholder reverse object.
* @param Parser|null $parser The powers parser object.
*
* @throws \Exception
* @since 3.2.0
*/
public function __construct(?Config $config = null, ?Reverse $reverse = null, ?Parser $parser = null)
{
$this->config = $config ?: Compiler::_('Config');
$this->reverse = $reverse ?: Compiler::_('Placeholder.Reverse');
$this->parser = $parser ?: Compiler::_('Power.Parser');
$this->db = Factory::getDbo();
$this->app = Factory::getApplication();
}
/**
* Set the JCB GUI code placeholder
*
* @param string $string The code string
* @param array $config The placeholder config values
*
* @return string
* @since 3.2.0
*/
public function set(string $string, array $config): string
{
if (StringHelper::check($string))
{
if ($this->config->get('add_placeholders', false)
&& $this->check($string) && ArrayHelper::check($config)
&& isset($config['table']) && StringHelper::check($config['table'])
&& isset($config['field']) && StringHelper::check($config['field'])
&& isset($config['type']) && StringHelper::check($config['type'])
&& isset($config['id']) && is_numeric($config['id']))
{
// if we have a key we must get the ID
if (isset($config['key']) && StringHelper::check($config['key']) && $config['key'] !== 'id')
{
if (($id = GetHelper::var($config['table'], $config['id'], $config['key'], 'id')) !== false && is_numeric($id))
{
$config['id'] = $id;
}
else
{
// we must give a error message to inform the user of this issue. (should never happen)
$this->app->enqueueMessage(
Text::sprintf('COM_COMPONENTBUILDER_ID_MISMATCH_WAS_DETECTED_WITH_THE_SSSS_GUI_CODE_FIELD_SO_THE_PLACEHOLDER_WAS_NOT_SET',
$config['table'], $config['field'],
$config['key'], $config['id']
), 'Error'
);
// check some config
if (!isset($config['prefix']))
{
$config['prefix'] = '';
}
return $config['prefix'] . $string;
}
}
// check some config
if (!isset($config['prefix']))
{
$config['prefix'] = PHP_EOL;
}
// add placeholder based on type of code
switch (strtolower((string) $config['type']))
{
// adding with html commenting
case 'html':
$front = $config['prefix'] . '<!--' . '[JCBGUI.';
$sufix = '$$$$]-->' . PHP_EOL;
$back = '<!--[/JCBGUI' . $sufix;
break;
// adding with php commenting
default:
$front = $config['prefix'] . '/***' . '[JCBGUI.';
$sufix = '$$$$]***/' . PHP_EOL;
$back = '/***[/JCBGUI' . $sufix;
break;
}
return $front . $config['table'] . '.' . $config['field'] . '.'
. $config['id'] . '.' . $sufix . $string . $back;
}
// check some config
if (!isset($config['prefix']))
{
$config['prefix'] = '';
}
return $config['prefix'] . $string;
}
return $string;
}
/**
* search a file for gui code blocks that were updated in the IDE
*
* @param string $file The file path to search
* @param array $placeholders The values to replace in the code being stored
* @param string $today The date for today
* @param string $target The target path type
*
* @return void
* @since 3.2.0
*/
public function search(string &$file, array &$placeholders, string &$today, string &$target)
{
// get file content
$file_content = FileHelper::getContent($file);
// get the USE statements (to reverse engineer super power keys)
$use_statements = $this->parser->getUseStatements($file_content);
$guiCode = [];
// we add a new search for the GUI CODE Blocks
$guiCode[] = GetHelper::allBetween(
$file_content, '/***[JCB' . 'GUI<>', '/***[/JCBGUI' . '$$$$]***/'
);
$guiCode[] = GetHelper::allBetween(
$file_content, '<!--[JCB' . 'GUI<>', '<!--[/JCBGUI' . '$$$$]-->'
);
if (($guiCode = ArrayHelper::merge($guiCode)) !== false
&& ArrayHelper::check($guiCode, true))
{
foreach ($guiCode as $code)
{
$first_line = strtok($code, PHP_EOL);
// get the GUI target details
$query = explode('.', trim($first_line, '.'));
// only continue if we have 3 values in the query
if (is_array($query) && count($query) >= 3)
{
// cleanup the newlines around the code
$code = trim(str_replace($first_line, '', (string) $code), PHP_EOL)
. PHP_EOL;
// set the ID
$id = (int) $query[2];
// make the field name save
$field = FieldHelper::safe($query[1]);
// make the table name save
$table = StringHelper::safe($query[0]);
// reverse placeholder as much as we can
$code = $this->reverse->engine(
$code, $placeholders, $target, $id, $field, $table, $use_statements
);
// update the GUI/Tables/Database
$object = new \stdClass();
$object->id = $id;
$object->{$field} = base64_encode(
(string) $code
); // (TODO) this may not always work...
// update the value in GUI
$this->db->updateObject(
'#__componentbuilder_' . (string) $table, $object, 'id'
);
}
}
}
}
/**
* search a code to see if there is already any custom
* code or other reasons not to add the GUI code placeholders
*
* @param string $code The code to check
*
* @return bool true if GUI code placeholders can be added
* @since 3.2.0
*/
protected function check(string &$code): bool
{
// check for customcode placeholders
// we do not add GUI wrapper placeholder to code
// that already has any customcode placeholders
return strpos($code, '$$$$') === false;
}
}