* @link https://www.tassos.gr * @copyright Copyright © 2024 Tassos All Rights Reserved * @license GNU GPLv3 or later */ namespace NRFramework\Conditions; defined('_JEXEC') or die; use Joomla\CMS\Layout\LayoutHelper; use NRFramework\Conditions\ConditionsHelper; use NRFramework\Extension; use Joomla\CMS\Language\Text; use Joomla\CMS\Uri\Uri; use Joomla\CMS\HTML\HTMLHelper; use Joomla\CMS\Form\Form; class ConditionBuilder { public static function pass($rules) { $rules = self::prepareRules($rules); if (empty($rules)) { return true; } return ConditionsHelper::getInstance()->passSets($rules); } /** * Prepare rules object to run checks * * @return void */ public static function prepareRules($rules = []) { if (!is_array($rules)) { return []; } $rules_ = []; foreach ($rules as $key => $group) { if (isset($group['enabled']) AND !(bool) $group['enabled']) { continue; } // A group without rules, doesn't make sense. if (!isset($group['rules']) OR (isset($group['rules']) AND empty($group['rules']))) { continue; } $validRules = []; foreach ($group['rules'] as $rule) { // Make sure rule has a name. if (!isset($rule['name']) OR (isset($rule['name']) AND empty($rule['name']))) { continue; } // Rule is invalid if both value and params properties are empty if (!isset($rule['value']) && !isset($rule['params'])) { continue; } // Skip disabled rules if (isset($rule['enabled']) && !(bool) $rule['enabled']) { continue; } // We don't need this property. unset($rule['enabled']); // Prepare rule value if necessary if (isset($rule['value'])) { $rule['value'] = self::prepareTFRepeaterValue($rule['value']); } // Verify operator if (!isset($rule['operator']) OR (isset($rule['operator']) && empty($rule['operator']))) { $rule['operator'] = isset($rule['params']['operator']) ? $rule['params']['operator'] : ''; } $validRules[] = $rule; } if (count($validRules) > 0) { $group['rules'] = $validRules; if (!isset($group['matching_method']) OR (isset($group['matching_method']) AND empty($group['matching_method']))) { $group['matching_method'] = 'all'; } unset($group['enabled']); $rules_[] = $group; } } return $rules_; } /** * Parse the value of the TF Repeater Input field. * * @param array $selection * * @return mixed */ public static function prepareTFRepeaterValue($selection) { // Only proceed when we have an array of arrays selection. if (!is_array($selection)) { return $selection; } $first = array_values($selection)[0]; if (!is_array($first)) { return $selection; } if (!isset($first['value'])) { return $selection; } $new_selection = []; foreach ($selection as $value) { /** * We expect a `value` key for TFInputRepeater fields or a key,value pair * for plain arrays. */ if (!isset($value['value'])) { /** * If no value exists, it means that the passed $assignment->selection is a key,value pair array so we use the value * as our returned selection. * * This happens when we pass a key,value pair array as $assignment->selection when we expect a TFInputRepeater value * so we need to take this into consideration. */ $new_selection[] = $value; continue; } // value must not be empty if (is_scalar($value['value']) && empty(trim($value['value']))) { continue; } $new_selection[] = count($value) === 1 ? $value['value'] : $value; } return $new_selection; } /** * Returns the TGeoIP plugin modal. * * @return string */ public static function getGeoModal() { // Do not proceed if the database is up-to-date if (!\NRFramework\Extension::geoPluginNeedsUpdate()) { return; } HTMLHelper::_('bootstrap.modal'); $modalName = 'tf-geodbchecker-modal'; // The TGeoIP Plugin URL $url = Uri::base(true) . '/index.php?option=com_plugins&view=plugin&tmpl=component&layout=modal&extension_id=' . \NRFramework\Functions::getExtensionID('tgeoip', 'system'); $options = [ 'title' => Text::_('NR_EDIT'), 'url' => $url, 'height' => '400px', 'backdrop' => 'static', 'bodyHeight' => '70', 'modalWidth' => '70', 'footer' => ' ', ]; return HTMLHelper::_('bootstrap.renderModal', $modalName, $options); } /** * Prepares the given rules list. * * @param array $list * * @return array */ public static function prepareXmlRulesList($list) { if (is_array($list)) { $list = implode(',', array_map('trim', $list)); } else if (is_string($list)) { $list = str_replace(' ', '', $list); } return $list; } /** * Adds a new condition item or group. * * @param string $controlGroup The name of the input used to store the data. * @param string $groupKey The group index ID. * @param string $conditionKey The added condition item index ID. * @param array $condition The condition name we are adding. * @param string $include_rules The list of included conditions that override the available conditions. * @param string $exclude_rules The list of excluded conditions that override the available conditions. * @param bool $exclude_rules_pro Whether the excluded rules should appear as Pro missing features. * * @return string */ public static function add($controlGroup, $groupKey, $conditionKey, $condition = null, $include_rules = [], $exclude_rules = [], $exclude_rules_pro = false) { $controlGroup_ = $controlGroup . "[$groupKey][rules][$conditionKey]"; // @Todo - rename input namespace to 'conditions' $form = self::getForm('conditionbuilder/base.xml', $controlGroup_, $condition); $form->setFieldAttribute('name', 'include_rules', is_array($include_rules) ? implode(',', $include_rules) : $include_rules); $form->setFieldAttribute('name', 'exclude_rules', is_array($exclude_rules) ? implode(',', $exclude_rules) : $exclude_rules); $form->setFieldAttribute('name', 'exclude_rules_pro', $exclude_rules_pro); $options = [ 'name' => $controlGroup_, 'enabled' => !isset($condition['enabled']) ? true : (string) $condition['enabled'] == '1', 'toolbar' => $form, 'groupKey' => $groupKey, 'conditionKey' => $conditionKey, 'options' => '' ]; if (isset($condition['name'])) { $optionsHTML = self::renderOptions($condition['name'], $controlGroup_, $condition); $options['condition_name'] = $condition['name']; $options['options'] = $optionsHTML; } return self::getLayout('conditionbuilder_row', $options); } /** * Render condition item settings. * * @param string $name The name of the condition item. * @param string $controlGroup The name of the input used to store the data. * @param object $formData The data that will be bound to the form. * * @return string */ public static function renderOptions($name, $controlGroup = null, $formData = null) { if (!$form = self::getForm('conditions/' . strtolower(str_replace('\\', '/', $name)) . '.xml', $controlGroup, $formData)) { return; } $form->setFieldAttribute('note', 'ruleName', $name); return $form->renderFieldset('general'); } /** * Handles loading condition builder given a payload. * * @param array $payload * * @return string */ public static function initLoad($payload = []) { if (!$payload) { return; } if (!isset($payload['data']) && !isset($payload['name'])) { return; } if (!$data = json_decode($payload['data'])) { return; } // transform object to assosiative array $data = json_decode(json_encode($data), true); // html of condition builder $html = ''; $include_rules = isset($payload['include_rules']) ? $payload['include_rules'] : []; $exclude_rules = isset($payload['exclude_rules']) ? $payload['exclude_rules'] : []; $exclude_rules_pro = isset($payload['exclude_rules_pro']) ? $payload['exclude_rules_pro'] : false; foreach ($data as $groupKey => $groupConditions) { $payload = [ 'name' => $payload['name'], 'groupKey' => $groupKey, 'groupConditions' => $groupConditions, 'include_rules' => $include_rules, 'exclude_rules' => $exclude_rules, 'exclude_rules_pro' => $exclude_rules_pro ]; $html .= self::getLayout('conditionbuilder_group', $payload); } return $html; } /** * Render a layout given its name and payload. * * @param string $name * @param array $payload * * @return string */ public static function getLayout($name, $payload) { return LayoutHelper::render($name, $payload, JPATH_PLUGINS . '/system/nrframework/layouts'); } /** * Returns the form by binding given data. * * @param string $name * @param string $controlGroup * @param array $data * * @return object */ private static function getForm($name, $controlGroup, $data = null) { if (!file_exists(JPATH_PLUGINS . '/system/nrframework/xml/' . $name)) { return; } $form = new Form('cb', ['control' => $controlGroup]); $form->addFieldPath(JPATH_PLUGINS . '/system/nrframework/fields'); $form->loadFile(JPATH_PLUGINS . '/system/nrframework/xml/' . $name); if (!is_null($data)) { $form->bind($data); } return $form; } }