* @git 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\Search\Agent; use VDM\Joomla\Utilities\ArrayHelper; use VDM\Joomla\Utilities\StringHelper; use VDM\Joomla\Componentbuilder\Search\Factory; use VDM\Joomla\Componentbuilder\Search\Interfaces\SearchTypeInterface as SearchEngine; /** * Search Agent Update * * @since 3.2.0 */ class Update { /** * Search Engine * * @var SearchEngine * @since 3.2.0 */ protected SearchEngine $search; /** * Constructor * * @param SearchEngine|null $search The search engine object. * * @since 3.2.0 */ public function __construct(?SearchEngine $search = null) { $this->search = $search ?: Factory::_('Search'); } /** * Update the value * * @param mixed $value The field value * @param mixed $line The line to update (0 = all) * * @return mixed * @since 3.2.0 */ public function value($value, $line = 0) { // update the value $update = $this->updateValue($value, $line); // was anything updated if ($value === $update) { return null; } return $update; } /** * Update all search-replace instances inside a value * * @param mixed $value The field value * @param mixed $line The line to update (0 = all) * * @return mixed * @since 3.2.0 */ protected function updateValue($value, $line = 0) { // I know this is a little crazy... TODO refactor into recursion functions // the possibility of updating sub-forms in sub-forms if (ArrayHelper::check($value)) { if (strpos((string) $line, '.') !== false) { $line = explode('.', (string) $line); } // first layer foreach ($value as $keys => &$rows) { if (ArrayHelper::check($rows)) { // second layer foreach ($rows as $key => &$row) { if (ArrayHelper::check($row)) { // third layer foreach ($row as $ke => &$ro) { if (ArrayHelper::check($ro)) { // forth layer foreach ($ro as $k => &$r) { if (StringHelper::check($r) && $this->validateUpdateKey($line, $keys, $key, $ke, $k)) { $_line = (isset($line[4])) ? $line[4] : 0; $r = $this->string($r, $_line); } } } elseif (StringHelper::check($ro) && $this->validateUpdateKey($line, $keys, $key, $ke)) { $_line = (isset($line[3])) ? $line[3] : 0; $ro = $this->string($ro, $_line); } } } elseif (StringHelper::check($row) && $this->validateUpdateKey($line, $keys, $key)) { $_line = (isset($line[2])) ? $line[2] : 0; $row = $this->string($row, $_line); } } } elseif (StringHelper::check($rows) && $this->validateUpdateKey($line, $keys)) { $_line = (isset($line[1])) ? $line[1] : 0; $rows = $this->string($rows, $_line); } } } elseif (StringHelper::check($value)) { $value = $this->string($value, $line); } return $value; } /** * Check if the keys are valid for search when working with arrays * * @param int $line The lines array * @param mixed $keys The line keys * @param mixed $key The line key * @param mixed $k The line ke * @param mixed $k The line k * * @return bool * @since 3.2.0 */ protected function validateUpdateKey($line, $keys = null, $key = null, $ke = null, $k = null): bool { if (ArrayHelper::check($line)) { $_keys = (isset($line[0])) ? $line[0] : null; $_key = (isset($line[1])) ? $line[1] : null; $_ke = (isset($line[2])) ? $line[2] : null; $_k = (isset($line[3])) ? $line[3] : null; if ($keys && $_keys && $_keys !== $keys) { return false; } if ($key && $_key && $_key !== $key) { return false; } if ($ke && $_ke && $_ke !== $ke) { return false; } if ($k && $_k && $_k !== $k) { return false; } } return true; } /** * Update all search-replace instances inside a string * * @param string $value The field value * @param int $line The line to update (0 = all) * * @return string * @since 3.2.0 */ protected function string(string $value, int $line = 0): string { // check if string has a new line if (\preg_match('/\R/', $value) && $line > 0) { // line counter $line_number = 1; $search_array = \preg_split('/\R/', $value); // loop over the lines foreach ($search_array as $nr => $line_value) { if ($line_number == $line) { $search_array[$nr] = $this->search->replace($line_value); // since we are targeting on line (and possibly one number) // this can only happen once, and so we return at this point return implode(PHP_EOL, $search_array); } // next line $line_number++; } // no update took place so we just return the original value return $value; } return $this->search->replace($value); } }