394 lines
8.1 KiB
PHP
394 lines
8.1 KiB
PHP
<?php
|
|
/**
|
|
* @author Tassos Marinos <info@tassos.gr>
|
|
* @link https://www.tassos.gr
|
|
* @copyright Copyright © 2024 Tassos All Rights Reserved
|
|
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
|
|
*/
|
|
|
|
defined('_JEXEC') or die('Restricted access');
|
|
|
|
use Joomla\CMS\Layout\FileLayout;
|
|
use Joomla\Registry\Registry;
|
|
use Joomla\CMS\Language\Text;
|
|
|
|
require_once dirname(__DIR__) . '/helpers/field.php';
|
|
|
|
class JFormFieldNRChainedFields extends NRFormField
|
|
{
|
|
/**
|
|
* All CSV choices.
|
|
*
|
|
* @var array
|
|
*/
|
|
protected $choices = [];
|
|
|
|
/**
|
|
* The separator used in the CSV file.
|
|
*
|
|
* @var string
|
|
*/
|
|
protected $separator = ',';
|
|
|
|
/**
|
|
* The data source contents.
|
|
*
|
|
* @var string
|
|
*/
|
|
protected $dataset = '';
|
|
|
|
/**
|
|
* Method to get the field input markup.
|
|
*
|
|
* @return string The field input markup.
|
|
*/
|
|
protected function getInput()
|
|
{
|
|
$layout = new FileLayout('chainedfields', JPATH_PLUGINS . '/system/nrframework/layouts');
|
|
|
|
$data_source = $this->get('data_source', 'custom');
|
|
|
|
switch ($data_source)
|
|
{
|
|
case 'custom':
|
|
$this->dataset = $this->get('data_source_custom', '');
|
|
break;
|
|
|
|
case 'csv_file':
|
|
$csv_file = $this->get('data_source_csv', '');
|
|
|
|
if (!file_exists($csv_file))
|
|
{
|
|
return;
|
|
}
|
|
|
|
$this->dataset = $csv_file;
|
|
break;
|
|
}
|
|
|
|
$this->separator = $this->get('separator', ',');
|
|
|
|
$data = [
|
|
'csv' => $this->dataset,
|
|
'data_source' => $data_source,
|
|
'value' => $this->getValue(),
|
|
'data' => $this->getData()
|
|
];
|
|
|
|
return $layout->render($data);
|
|
}
|
|
|
|
/**
|
|
* Returns the field value.
|
|
*
|
|
* @return mixed
|
|
*/
|
|
private function getValue()
|
|
{
|
|
if (!$this->value)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
if (!$this->choices = \NRFramework\Helpers\ChainedFields::loadCSV($this->dataset, $this->get('data_source', 'custom'), $this->separator, $this->id . '_', $this->name))
|
|
{
|
|
return null;
|
|
}
|
|
|
|
$choices = $this->choices['inputs'];
|
|
|
|
// Ensure the value is in correct format when used as plain field or in subform
|
|
$this->value = array_values((array) $this->value);
|
|
|
|
foreach ($this->choices['inputs'] as $key => $input)
|
|
{
|
|
$choices[$key]['choices'] = $this->getSelectedChoices($key, $this->value, $input);
|
|
}
|
|
|
|
return $choices;
|
|
}
|
|
|
|
/**
|
|
* Finds the choices of the select.
|
|
*
|
|
* @param string $key
|
|
* @param array $value
|
|
* @param array $input
|
|
*
|
|
* @return mixed
|
|
*/
|
|
private function getSelectedChoices($key, $value, $input)
|
|
{
|
|
$choices = $this->getSelectChoices($value, $input['id']);
|
|
|
|
if (!is_array($choices))
|
|
{
|
|
return null;
|
|
}
|
|
|
|
// set selected options based on value
|
|
foreach ($choices as $_key => &$choice)
|
|
{
|
|
if (!isset($value[$key]) || $choice['value'] !== $value[$key])
|
|
{
|
|
continue;
|
|
}
|
|
|
|
$choice['isSelected'] = true;
|
|
}
|
|
|
|
return $choices;
|
|
}
|
|
|
|
/**
|
|
* Handles the AJAX request.
|
|
*
|
|
* Runs when select a value from a select field.
|
|
*
|
|
* @param array $options
|
|
*
|
|
* @return array
|
|
*/
|
|
public function onAjax($options)
|
|
{
|
|
$options = new Registry($options);
|
|
|
|
if (!$select_id = $options->get('select_id'))
|
|
{
|
|
echo json_encode([
|
|
'error' => true,
|
|
'response' => Text::_('NR_CANNOT_PROCESS_REQUEST')
|
|
]);
|
|
jexit();
|
|
}
|
|
|
|
if (!$value = $options->get('value'))
|
|
{
|
|
echo json_encode([
|
|
'error' => true,
|
|
'response' => Text::_('NR_CANNOT_PROCESS_REQUEST')
|
|
]);
|
|
jexit();
|
|
}
|
|
|
|
if (!$value = json_decode($options->get('value'), true))
|
|
{
|
|
echo json_encode([
|
|
'error' => true,
|
|
'response' => Text::_('NR_CANNOT_PROCESS_REQUEST')
|
|
]);
|
|
jexit();
|
|
}
|
|
|
|
if (!$data_source = $options->get('data_source'))
|
|
{
|
|
echo json_encode([
|
|
'error' => true,
|
|
'response' => Text::_('NR_CANNOT_PROCESS_REQUEST')
|
|
]);
|
|
jexit();
|
|
}
|
|
|
|
if (!$csv = $options->get('csv'))
|
|
{
|
|
echo json_encode([
|
|
'error' => true,
|
|
'response' => Text::_('NR_CANNOT_PROCESS_REQUEST')
|
|
]);
|
|
jexit();
|
|
}
|
|
|
|
$csv = json_decode($csv, true);
|
|
|
|
// get field ID from select ID
|
|
$id = preg_replace('/_[0-9]+$/', '', $select_id);
|
|
|
|
if (!$id || !$select_id || !$value || !$csv)
|
|
{
|
|
echo json_encode([
|
|
'error' => true,
|
|
'response' => Text::_('NR_CANNOT_PROCESS_REQUEST')
|
|
]);
|
|
jexit();
|
|
}
|
|
|
|
$this->id = $id;
|
|
|
|
// get all CSV data
|
|
if (!$this->choices = \NRFramework\Helpers\ChainedFields::loadCSV($csv, $data_source, $this->separator, $this->id . '_', $this->name))
|
|
{
|
|
echo json_encode([
|
|
'error' => true,
|
|
'response' => Text::_('NR_CANNOT_PROCESS_REQUEST')
|
|
]);
|
|
jexit();
|
|
}
|
|
|
|
// find next select options
|
|
$this->findNextOptions($id, $select_id, $value);
|
|
}
|
|
|
|
/**
|
|
* Finds the options of the next select.
|
|
*
|
|
* @param string $id
|
|
* @param string $select_id
|
|
* @param array $value
|
|
*
|
|
* @return void
|
|
*/
|
|
private function findNextOptions($id, $select_id, $value)
|
|
{
|
|
// find next ID
|
|
$next_select_id = $this->getNextSelectID($id, $select_id);
|
|
|
|
// get next choices
|
|
$choices = $next_select_id ? $this->getSelectChoices($value, $next_select_id) : [];
|
|
|
|
echo json_encode([
|
|
'error' => false,
|
|
'response' => $choices
|
|
]);
|
|
jexit();
|
|
}
|
|
|
|
/**
|
|
* Returns the select choices.
|
|
*
|
|
* @param array $field_value
|
|
* @param string $select_id
|
|
* @param integer $depth
|
|
* @param array $choices
|
|
* @param array $full_field_value
|
|
*
|
|
* @return array
|
|
*/
|
|
private function getSelectChoices($field_value = null, $select_id = null, $depth = null, $choices = null, $full_field_value = null)
|
|
{
|
|
$full_field_value = $full_field_value !== null ? $full_field_value : $field_value;
|
|
$value = array_shift($field_value);
|
|
$index = $select_id ? $this->getSelectID($select_id) : 1;
|
|
$depth = $depth ? $depth : 1;
|
|
$choices = $choices === null ? $this->choices['choices'] : (empty($choices) ? [] : $choices);
|
|
$select_choices = [];
|
|
|
|
if ($depth == $index)
|
|
{
|
|
$select_choices = $choices;
|
|
}
|
|
else
|
|
{
|
|
foreach ($choices as $choice)
|
|
{
|
|
if ($choice['value'] !== $value)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
$select_choices = $this->getSelectChoices($field_value, $select_id, $depth + 1, !empty($choice['choices']) ? $choice['choices'] : [], $full_field_value);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (empty($select_choices) && $this->getPreviousSelectValue($select_id, $full_field_value))
|
|
{
|
|
$select_choices = [
|
|
[
|
|
'text' => 'No options',
|
|
'value' => '',
|
|
'isSelected' => true
|
|
]
|
|
];
|
|
}
|
|
|
|
return $select_choices;
|
|
}
|
|
|
|
/**
|
|
* Returns the previous select value
|
|
*
|
|
* @param string $select_id
|
|
* @param string $full_field_value
|
|
*
|
|
* @return string
|
|
*/
|
|
public function getPreviousSelectValue($select_id, $full_field_value)
|
|
{
|
|
$explode = explode('_', $select_id);
|
|
|
|
$input_id = $explode[count($explode) - 1];
|
|
$field_id = rtrim($select_id, '_' . $input_id);
|
|
|
|
$prev_input_id = sprintf('%s.%s', $field_id, $input_id - 1);
|
|
$prev_input_value = isset($full_field_value[$prev_input_id]) ? $full_field_value[$prev_input_id] : null;
|
|
|
|
return $prev_input_value;
|
|
}
|
|
|
|
/**
|
|
* Finds the next select ID
|
|
*
|
|
* @param string $base_id
|
|
* @param string $select_id
|
|
*
|
|
* @return mixed
|
|
*/
|
|
public function getNextSelectID($base_id, $select_id)
|
|
{
|
|
$id = $this->getSelectID($select_id);
|
|
$next_id = $id + 1;
|
|
|
|
if ($next_id % 10 == 0)
|
|
{
|
|
$next_id++;
|
|
}
|
|
|
|
$next_select_id = sprintf('%s_%d', $base_id, $next_id);
|
|
|
|
foreach ($this->choices['inputs'] as $input)
|
|
{
|
|
if ($input['id'] != $next_select_id)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
return $next_select_id;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Gets the ID (index) of the select by its ID.
|
|
*
|
|
* @param string $select_id
|
|
*
|
|
* @return int
|
|
*/
|
|
public function getSelectID($select_id)
|
|
{
|
|
$explode = explode('_', $select_id);
|
|
|
|
return (int) array_pop($explode);
|
|
}
|
|
|
|
/**
|
|
* Fetches all CSV data.
|
|
*
|
|
* @return array
|
|
*/
|
|
private function getData()
|
|
{
|
|
if (!$this->dataset)
|
|
{
|
|
return [];
|
|
}
|
|
|
|
if (!$choices = \NRFramework\Helpers\ChainedFields::loadCSV($this->dataset, $this->get('data_source', 'csv_file'), $this->separator, $this->id . '_', $this->name))
|
|
{
|
|
return [];
|
|
}
|
|
|
|
return $choices;
|
|
}
|
|
} |