Spade

Mini Shell

Directory:~$ /home/lmsyaran/public_html/joomla4/
Upload File

[Home] [System Details] [Kill Me]
Current File:~$ /home/lmsyaran/public_html/joomla4/Data.zip

PK
:�[�7�Ǔ�Data.phpnu�[���<?php

namespace Nextend\Framework\Data;


class Data {

    /**
     * @var array
     */
    public $_data = array();

    public function __construct($data = null, $json = false) {

        if ($data) {
            if (is_array($data)) {
                $this->loadArray($data);
            } else {
                $this->loadJSON($data);
            }
        }
    }

    /**
     * @param $json
     */
    public function loadJSON($json) {
        $array = json_decode($json, true);
        if (is_array($array)) $this->_data =
array_merge($this->_data, $array);
    }

    /**
     * @param $array
     */
    public function loadArray($array) {
        if (!$this->_data) $this->_data = array();
        if (is_array($array)) $this->_data =
array_merge($this->_data, $array);
    }

    /**
     * @return mixed|string
     */
    public function toJSON() {
        return json_encode($this->_data);
    }

    /**
     * @return array
     */
    public function toArray() {
        return (array)$this->_data;
    }

    public function has($key) {

        return isset($this->_data[$key]);
    }

    /**
     * @param string $key
     * @param string $default
     *
     * @return mixed
     */
    public function get($key, $default = '') {
        if (isset($this->_data[$key])) return $this->_data[$key];

        return $default;
    }

    public function getIfEmpty($key, $default = '') {
        if (isset($this->_data[$key]) &&
!empty($this->_data[$key])) return $this->_data[$key];

        return $default;
    }

    /**
     * @param string $key
     * @param mixed  $value
     */
    public function set($key, $value) {
        $this->_data[$key] = $value;
    }

    public function un_set($key) {
        if (isset($this->_data[$key])) {
            unset($this->_data[$key]);
        }
    }

    public function fillDefault($defaults) {
        $this->_data = array_merge($defaults, $this->_data);
    }
}PK�z�[]?�8��Action/Delete.phpnu�[���<?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\Data\Action;


use VDM\Joomla\Interfaces\DeleteInterface as Database;
use VDM\Joomla\Interfaces\Data\DeleteInterface;


/**
 * Data Delete
 * 
 * @since 3.2.2
 */
class Delete implements DeleteInterface
{
	/**
	 * The Delete Class.
	 *
	 * @var   Database
	 * @since 3.2.2
	 */
	protected Database $database;

	/**
	 * Table Name
	 *
	 * @var    string
	 * @since 3.2.2
	 */
	protected string $table;

	/**
	 * Constructor.
	 *
	 * @param Database   $database   The Delete Class.
	 * @param string|null $table       The table name.
	 *
	 * @since 3.2.2
	 */
	public function __construct(Database $database, ?string $table = null)
	{
		$this->database = $database;
		if ($table !== null)
		{
			$this->table = $table;
		}
	}

	/**
	 * Set the current active table
	 *
	 * @param string|null $table The table that should be active
	 *
	 * @return self
	 * @since 3.2.2
	 */
	public function table(?string $table): self
	{
		if ($table !== null)
		{
			$this->table = $table;
		}

		return $this;
	}

	/**
	 * Delete all items in the database that match these conditions
	 *
	 * @param   array    $conditions    Conditions by which to delete the data
in database [array of arrays (key => value)]
	 *
	 * @return  bool
	 * @since   3.2.2
	 **/
	public function items(array $conditions): bool
	{
		return $this->database->items($conditions, $this->getTable());
	}

	/**
	 * Truncate a table
	 *
	 * @return  void
	 * @since   3.2.2
	 **/
	public function truncate(): void
	{
		$this->database->truncate($this->getTable());
	}

	/**
	 * Get the current active table
	 *
	 * @return  string
	 * @since 3.2.2
	 */
	public function getTable(): string
	{
		return $this->table;
	}
}

PK�z�[�#o,,Action/index.htmlnu�[���<html><body
bgcolor="#FFFFFF"></body></html>PK�z�[����Action/Insert.phpnu�[���<?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\Data\Action;


use VDM\Joomla\Interfaces\ModelInterface as Model;
use VDM\Joomla\Interfaces\InsertInterface as Database;
use VDM\Joomla\Interfaces\Data\InsertInterface;


/**
 * Data Insert (GUID)
 * 
 * @since 3.2.2
 */
class Insert implements InsertInterface
{
	/**
	 * Model
	 *
	 * @var    Model
	 * @since 3.2.0
	 */
	protected Model $model;

	/**
	 * Database
	 *
	 * @var    Database
	 * @since 3.2.0
	 */
	protected Database $database;

	/**
	 * Table Name
	 *
	 * @var    string
	 * @since 3.2.1
	 */
	protected string $table;

	/**
	 * Constructor
	 *
	 * @param Model       $model       The set model object.
	 * @param Database    $database    The insert database object.
	 * @param string|null $table       The table name.
	 *
	 * @since 3.2.2
	 */
	public function __construct(Model $model, Database $database, ?string
$table = null)
	{
		$this->model = $model;
		$this->database = $database;
		if ($table !== null)
		{
			$this->table = $table;
		}
	}

	/**
	 * Set the current active table
	 *
	 * @param string|null $table The table that should be active
	 *
	 * @return self
	 * @since 3.2.2
	 */
	public function table(?string $table): self
	{
		if ($table !== null)
		{
			$this->table = $table;
		}

		return $this;
	}

	/**
	 * Insert a value to a given table
	 *          Example: $this->value(Value, 'value_key',
'GUID');
	 *
	 * @param   mixed     $value      The field value
	 * @param   string    $field      The field key
	 * @param   string    $keyValue   The key value
	 * @param   string    $key        The key name
	 *
	 * @return  bool
	 * @since 3.2.0
	 */
	public function value($value, string $field, string $keyValue, string $key
= 'guid'): bool
	{
		// build the array
		$item = [];
		$item[$key] = $keyValue;
		$item[$field] = $value;

		// Insert the column of this table
		return $this->row($item);
	}

	/**
	 * Insert single row with multiple values to a given table
	 *          Example: $this->item(Array);
	 *
	 * @param   array    $item   The item to save
	 *
	 * @return  bool
	 * @since 3.2.0
	 */
	public function row(array $item): bool
	{
		// check if object could be modelled
		if (($item = $this->model->row($item, $this->getTable())) !==
null)
		{
			// Insert the column of this table
			return $this->database->row($item, $this->getTable());
		}
		return false;
	}

	/**
	 * Insert multiple rows to a given table
	 *          Example: $this->items(Array);
	 *
	 * @param   array|null   $items  The items updated in database (array of
arrays)
	 *
	 * @return  bool
	 * @since 3.2.0
	 */
	public function rows(?array $items): bool
	{
		// check if object could be modelled
		if (($items = $this->model->rows($items, $this->getTable())) !==
null)
		{
			// Insert the column of this table
			return $this->database->rows($items, $this->getTable());
		}
		return false;
	}

	/**
	 * Insert single item with multiple values to a given table
	 *          Example: $this->item(Object);
	 *
	 * @param   object    $item   The item to save
	 *
	 * @return  bool
	 * @since 3.2.0
	 */
	public function item(object $item): bool
	{
		// check if object could be modelled
		if (($item = $this->model->item($item, $this->getTable())) !==
null)
		{
			// Insert the column of this table
			return $this->database->item($item, $this->getTable());
		}
		return false;
	}

	/**
	 * Insert multiple items to a given table
	 *          Example: $this->items(Array);
	 *
	 * @param   array|null   $items  The items updated in database (array of
objects)
	 *
	 * @return  bool
	 * @since 3.2.0
	 */
	public function items(?array $items): bool
	{
		// check if object could be modelled
		if (($items = $this->model->items($items, $this->getTable()))
!== null)
		{
			// Update the column of this table using guid as the primary key.
			return $this->database->items($items, $this->getTable());
		}
		return false;
	}

	/**
	 * Get the current active table
	 *
	 * @return  string
	 * @since 3.2.2
	 */
	public function getTable(): string
	{
		return $this->table;
	}
}

PK�z�[�X�99Action/Load.phpnu�[���<?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\Data\Action;


use VDM\Joomla\Interfaces\ModelInterface as Model;
use VDM\Joomla\Interfaces\LoadInterface as Database;
use VDM\Joomla\Interfaces\Data\LoadInterface;


/**
 * Data Load (GUID)
 * 
 * @since 3.2.2
 */
class Load implements LoadInterface
{
	/**
	 * Model Load
	 *
	 * @var    Model
	 * @since 2.0.1
	 */
	protected Model $model;

	/**
	 * Database Load
	 *
	 * @var    Database
	 * @since 2.0.1
	 */
	protected Database $load;

	/**
	 * Table Name
	 *
	 * @var    string
	 * @since 3.2.1
	 */
	protected string $table;

	/**
	 * Constructor
	 *
	 * @param Model       $model     The model object.
	 * @param Database    $load      The database object.
	 * @param string|null $table     The table name.
	 *
	 * @since 2.0.1
	 */
	public function __construct(Model $model, Database $load, ?string $table =
null)
	{
		$this->model = $model;
		$this->load = $load;
		if ($table !== null)
		{
			$this->table = $table;
		}
	}

	/**
	 * Set the current active table
	 *
	 * @param string|null $table The table that should be active
	 *
	 * @return self
	 * @since 3.2.2
	 */
	public function table(?string $table): self
	{
		if ($table !== null)
		{
			$this->table = $table;
		}

		return $this;
	}

	/**
	 * Get a value from a given table
	 *          Example: $this->value(
	 *                        [
	 *                           'guid' =>
'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'
	 *                        ], 'value_key'
	 *                    );
	 *
	 * @param   array      $keys      The item keys
	 * @param   string     $field     The field key
	 *
	 * @return  mixed
	 * @since 2.0.1
	 */
	public function value(array $keys, string $field)
	{
		return $this->model->value(
			$this->load->value(
				["a.{$field}" => $field],
				['a' => $this->getTable()],
				$this->prefix($keys)
			),
			$field,
			$this->getTable()
		);
	}

	/**
	 * Get a value from multiple rows from a given table
	 *          Example: $this->values(
	 *                        [
	 *                           'guid' =>
'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'
	 *                        ], 'value_key'
	 *                    );
	 *
	 * @param   array      $keys      The item keys
	 * @param   string     $field     The field key
	 *
	 * @return  array|null
	 * @since 3.2.2
	 */
	public function values(array $keys, string $field): ?array
	{
		return $this->model->values(
			$this->load->values(
				["a.{$field}" => $field],
				['a' => $this->getTable()],
				$this->prefix($keys)
			),
			$field,
			$this->getTable()
		);
	}

	/**
	 * Get values from a given table
	 *          Example: $this->item(
	 *                        [
	 *                           'guid' =>
'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'
	 *                        ]
	 *                    );
	 *
	 * @param   array    $keys      The item keys
	 *
	 * @return  object|null
	 * @since 2.0.1
	 */
	public function item(array $keys): ?object
	{
		return $this->model->item(
			$this->load->item(
				['all' => 'a.*'],
				['a' => $this->getTable()],
				$this->prefix($keys)
			),
			$this->getTable()
		);
	}
 
	/**
	 * Get values from a given table
	 *          Example: $this->items(
	 *                        [
	 *                           'guid' => [
	 *                              'operator' =>
'IN',
	 *                              'value' =>
[''xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'',
''xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'']
	 *                           ]
	 *                        ]
	 *                    );
	 *          Example: $this->items($ids);
	 *
	 * @param   array    $keys    The item keys
	 *
	 * @return  array|null
	 * @since 2.0.1
	 */
	public function items(array $keys): ?array
	{
		return $this->model->items(
			$this->load->items(
				['all' => 'a.*'], ['a' =>
$this->getTable()], $this->prefix($keys)
			),
			$this->getTable()
		);
	}

	/**
	 * Get the current active table
	 *
	 * @return  string
	 * @since 3.2.2
	 */
	public function getTable(): string
	{
		return $this->table;
	}

	/**
	 * Add prefix to the keys
	 *
	 * @param   array    $keys The query keys
	 *
	 * @return  array
	 * @since 2.0.1
	 */
	private function prefix(array &$keys): array
	{
		// update the key values
		$bucket = [];
		foreach ($keys as $k => $v)
		{
			$bucket['a.' . $k] = $v;
		}
		return $bucket;
	}
}

PK�z�[W�:���Action/Update.phpnu�[���<?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\Data\Action;


use VDM\Joomla\Interfaces\ModelInterface as Model;
use VDM\Joomla\Interfaces\UpdateInterface as Database;
use VDM\Joomla\Interfaces\Data\UpdateInterface;


/**
 * Data Update
 * 
 * @since 3.2.2
 */
class Update implements UpdateInterface
{
	/**
	 * Model
	 *
	 * @var    Model
	 * @since 3.2.0
	 */
	protected Model $model;

	/**
	 * Database
	 *
	 * @var    Database
	 * @since 3.2.0
	 */
	protected Database $database;

	/**
	 * Table Name
	 *
	 * @var    string
	 * @since 3.2.1
	 */
	protected string $table;

	/**
	 * Constructor
	 *
	 * @param Model       $model       The set model object.
	 * @param Database    $database    The update database object.
	 * @param string|null $table       The table name.
	 *
	 * @since 3.2.0
	 */
	public function __construct(Model $model, Database $database, ?string
$table = null)
	{
		$this->model = $model;
		$this->database = $database;
		if ($table !== null)
		{
			$this->table = $table;
		}
	}

	/**
	 * Set the current active table
	 *
	 * @param string|null $table The table that should be active
	 *
	 * @return self
	 * @since 3.2.2
	 */
	public function table(?string $table): self
	{
		if ($table !== null)
		{
			$this->table = $table;
		}

		return $this;
	}

	/**
	 * Update a value to a given table
	 *          Example: $this->value(Value, 'value_key',
'GUID');
	 *
	 * @param   mixed     $value      The field value
	 * @param   string    $field      The field key
	 * @param   string    $keyValue   The key value
	 * @param   string    $key        The key name
	 *
	 * @return  bool
	 * @since 3.2.0
	 */
	public function value($value, string $field, string $keyValue, string $key
= 'guid'): bool
	{
		// build the array
		$item = [];
		$item[$key] = $keyValue;
		$item[$field] = $value;

		// Update the column of this table using $key as the primary key.
		return $this->row($item, $key);
	}

	/**
	 * Update single row with multiple values to a given table
	 *          Example: $this->item(Array);
	 *
	 * @param   array    $item   The item to save
	 * @param   string   $key    The key name
	 *
	 * @return  bool
	 * @since 3.2.0
	 */
	public function row(array $item, string $key = 'guid'): bool
	{
		// check if object could be modelled
		if (($item = $this->model->row($item, $this->getTable())) !==
null)
		{
			// Update the column of this table using $key as the primary key.
			return $this->database->row($item, $key, $this->getTable());
		}
		return false;
	}

	/**
	 * Update multiple rows to a given table
	 *          Example: $this->items(Array);
	 *
	 * @param   array|null   $items  The items updated in database (array of
arrays)
	 * @param   string       $key    The key name
	 *
	 * @return  bool
	 * @since 3.2.0
	 */
	public function rows(?array $items, string $key = 'guid'): bool
	{
		// check if object could be modelled
		if (($items = $this->model->rows($items, $this->getTable())) !==
null)
		{
			// Update the column of this table using $key as the primary key.
			return $this->database->rows($items, $key, $this->getTable());
		}
		return false;
	}

	/**
	 * Update single item with multiple values to a given table
	 *          Example: $this->item(Object);
	 *
	 * @param   object    $item   The item to save
	 * @param   string    $key    The key name
	 *
	 * @return  bool
	 * @since 3.2.0
	 */
	public function item(object $item, string $key = 'guid'): bool
	{
		// check if object could be modelled
		if (($item = $this->model->item($item, $this->getTable())) !==
null)
		{
			// Update the column of this table using $key as the primary key.
			return $this->database->item($item, $key, $this->getTable());
		}
		return false;
	}

	/**
	 * Update multiple items to a given table
	 *          Example: $this->items(Array);
	 *
	 * @param   array|null   $items  The items updated in database (array of
objects)
	 * @param   string       $key    The key name
	 *
	 * @return  bool
	 * @since 3.2.0
	 */
	public function items(?array $items, string $key = 'guid'):
bool
	{
		// check if object could be modelled
		if (($items = $this->model->items($items, $this->getTable()))
!== null)
		{
			// Update the column of this table using $key as the primary key.
			return $this->database->items($items, $key,
$this->getTable());
		}
		return false;
	}

	/**
	 * Get the current active table
	 *
	 * @return  string
	 * @since 3.2.2
	 */
	public function getTable(): string
	{
		return $this->table;
	}
}

PK�z�[�	���Factory.phpnu�[���<?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\Data;


use Joomla\DI\Container;
use VDM\Joomla\Service\Table;
use VDM\Joomla\Service\Database;
use VDM\Joomla\Service\Model;
use VDM\Joomla\Service\Data;
use VDM\Joomla\Interfaces\FactoryInterface;
use VDM\Joomla\Abstraction\Factory as ExtendingFactory;


/**
 * Data Factory
 * 
 * @since 3.2.2
 */
abstract class Factory extends ExtendingFactory implements FactoryInterface
{
	/**
	 * Create a container object
	 *
	 * @return  Container
	 * @since 3.2.2
	 */
	protected static function createContainer(): Container
	{
		return (new Container())
			->registerServiceProvider(new Table())
			->registerServiceProvider(new Database())
			->registerServiceProvider(new Model())
			->registerServiceProvider(new Data());
	}
}

PK�z�[��[�88Guid.phpnu�[���<?php
/**
 * @package    Joomla.Component.Builder
 *
 * @created    4th September, 2020
 * @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\Data;


/**
 * Globally Unique Identifier
 * 
 * @since  5.0.2
 */
trait Guid
{
	/**
	 * Returns a GUIDv4 string.
	 * 
	 * This function uses the best cryptographically secure method
	 * available on the platform with a fallback to an older, less secure
version.
	 *
	 * @param string $key The key to check and modify values.
	 *
	 * @return string A GUIDv4 string.
	 *
	 * @since 5.0.2
	 */
	public function getGuid(string $key): string
	{
		// Windows: Use com_create_guid if available
		if (function_exists('com_create_guid'))
		{
			$guid = trim(\com_create_guid(), '{}');
			return $this->checkGuid($guid, $key);
		}

		// Unix-based systems: Use openssl_random_pseudo_bytes if available
		if (function_exists('random_bytes'))
		{
			try {
				$data = random_bytes(16);
			} catch (Exception $e) {
				// Handle the error appropriately (logging, throwing, etc.)
				return $this->fallbackGuid($key);
			}

			// Set the version to 0100 and the bits 6-7 to 10 as per RFC 4122
			$data[6] = chr(ord($data[6]) & 0x0f | 0x40);
			$data[8] = chr(ord($data[8]) & 0x3f | 0x80);

			$guid = vsprintf('%s%s-%s-%s-%s-%s%s%s',
str_split(bin2hex($data), 4));
			return $this->checkGuid($guid, $key);
		}

		// Fallback to older methods if secure methods are not available
		return $this->fallbackGuid($key);
	}

	/**
	 * Generates a fallback GUIDv4 using less secure methods.
	 *
	 * @param string $key The key to check and modify values.
	 *
	 * @return string A GUIDv4 string.
	 *
	 * @since 5.0.2
	 */
	private function fallbackGuid(string $key): string
	{
		$charid = strtolower(md5(uniqid(random_int(0, PHP_INT_MAX), true)));
		$guidv4 = sprintf(
			'%s-%s-%s-%s-%s',
			substr($charid,  0, 8),
			substr($charid,  8, 4),
			substr($charid, 12, 4),
			substr($charid, 16, 4),
			substr($charid, 20, 12)
		);

		return $this->checkGuid($guidv4, $key);
	}

	/**
	 * Checks if the GUID value is unique and does not already exist.
	 *
	 * @param string $guid The GUID value to check.
	 * @param string $key  The key to check and modify values.
	 *
	 * @return string The unique GUID value.
	 *
	 * @since 5.0.2
	 */
	private function checkGuid(string $guid, string $key): string
	{
		// Check that the GUID does not already exist
		if ($this->items->table($this->getTable())->values([$guid],
$key))
		{
			return $this->getGuid($key);
		}

		return $guid;
	}
}

PK�z�[�#o,,
index.htmlnu�[���<html><body
bgcolor="#FFFFFF"></body></html>PK�z�[3�T��Item.phpnu�[���<?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\Data;


use VDM\Joomla\Interfaces\Data\LoadInterface as Load;
use VDM\Joomla\Interfaces\Data\InsertInterface as Insert;
use VDM\Joomla\Interfaces\Data\UpdateInterface as Update;
use VDM\Joomla\Interfaces\Data\DeleteInterface as Delete;
use VDM\Joomla\Interfaces\LoadInterface as Database;
use VDM\Joomla\Interfaces\Data\ItemInterface;


/**
 * Data Item
 * 
 * @since 3.2.2
 */
final class Item implements ItemInterface
{
	/**
	 * The Load Class.
	 *
	 * @var   Load
	 * @since 3.2.2
	 */
	protected Load $load;

	/**
	 * The Insert Class.
	 *
	 * @var   Insert
	 * @since 3.2.2
	 */
	protected Insert $insert;

	/**
	 * The Update Class.
	 *
	 * @var   Update
	 * @since 3.2.2
	 */
	protected Update $update;

	/**
	 * The Delete Class.
	 *
	 * @var   Delete
	 * @since 3.2.2
	 */
	protected Delete $delete;

	/**
	 * The Load Class.
	 *
	 * @var   Database
	 * @since 3.2.2
	 */
	protected Database $database;

	/**
	 * Table Name
	 *
	 * @var    string
	 * @since 3.2.1
	 */
	protected string $table;

	/**
	 * Constructor.
	 *
	 * @param Load        $load     The LoadInterface Class.
	 * @param Insert      $insert   The InsertInterface Class.
	 * @param Update      $update   The UpdateInterface Class.
	 * @param Delete      $delete   The UpdateInterface Class.
	 * @param Database    $database The Database Load Class.
	 * @param string|null $table    The table name.
	 *
	 * @since 3.2.2
	 */
	public function __construct(Load $load, Insert $insert, Update $update,
		Delete $delete, Database $database, ?string $table = null)
	{
		$this->load = $load;
		$this->insert = $insert;
		$this->update = $update;
		$this->delete = $delete;
		$this->database = $database;
		if ($table !== null)
		{
			$this->table = $table;
		}
	}

	/**
	 * Set the current active table
	 *
	 * @param string  $table The table that should be active
	 *
	 * @return self
	 * @since 3.2.2
	 */
	public function table(string $table): self
	{
		$this->table = $table;

		return $this;
	}

	/**
	 * Get an item
	 *
	 * @param string   $value   The item key value
	 * @param string   $key     The item key
	 *
	 * @return object|null The item object or null
	 * @since 3.2.2
	 */
	public function get(string $value, string $key = 'guid'):
?object
	{
		return $this->load->table($this->getTable())->item([$key
=> $value]);
	}

	/**
	 * Get the value
	 *
	 * @param string   $value   The item key value
	 * @param string   $key     The item key
	 * @param string   $get     The key of the values we want back
	 *
	 * @return mixed
	 * @since 3.2.2
	 */
	public function value(string $value, string $key = 'guid',
string $get = 'id')
	{
		return $this->load->table($this->getTable())->value([$key
=> $value], $get);
	}

	/**
	 * Set an item
	 *
	 * @param object       $item    The item
	 * @param string       $key     The item key
	 * @param string|null  $action  The action to load power
	 *
	 * @return bool
	 * @since 3.2.2
	 */
	public function set(object $item, string $key = 'guid', ?string
$action = null): bool
	{
		if ($action !== null || (isset($item->{$key}) && ($action =
$this->action($item->{$key}, $key)) !== null))
		{
			return method_exists($this, $action) ? $this->{$action}($item, $key)
: false;
		}

		return false;
	}

	/**
	 * Delete an item
	 *
	 * @param string   $value   The item key value
	 * @param string   $key     The item key
	 *
	 * @return bool
	 * @since 3.2.2
	 */
	public function delete(string $value, string $key = 'guid'):
bool
	{
		return $this->delete->table($this->getTable())->items([$key
=> $value]);
	}

	/**
	 * Get the current active table
	 *
	 * @return  string
	 * @since 3.2.2
	 */
	public function getTable(): string
	{
		return $this->table;
	}

	/**
	 * Insert a item
	 *
	 * @param object   $item  The item
	 *
	 * @return bool
	 * @since 3.2.2
	 */
	private function insert(object $item): bool
	{
		return $this->insert->table($this->getTable())->item($item);
	}

	/**
	 * Update a item
	 *
	 * @param object   $item  The item
	 * @param string   $key   The item key
	 *
	 * @return bool
	 * @since 3.2.2
	 */
	private function update(object $item, string $key): bool
	{
		return $this->update->table($this->getTable())->item($item,
$key);
	}

	/**
	 * Get loading action
	 *
	 * @param string  $value The key value the item
	 * @param string  $key   The item key
	 *
	 * @return string
	 * @since 3.2.2
	 */
	private function action(string $value, string $key): string
	{
		$id = $this->database->value(
			["a.id" => 'id'],
			["a" => $this->getTable()],
			["a.$key" => $value]
		);

		if ($id !== null && $id > 0)
		{
			return 'update';
		}

		return 'insert';
	}
}

PK�z�[�0�R��	Items.phpnu�[���<?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\Data;


use VDM\Joomla\Interfaces\Data\LoadInterface as Load;
use VDM\Joomla\Interfaces\Data\InsertInterface as Insert;
use VDM\Joomla\Interfaces\Data\UpdateInterface as Update;
use VDM\Joomla\Interfaces\Data\DeleteInterface as Delete;
use VDM\Joomla\Interfaces\LoadInterface as Database;
use VDM\Joomla\Interfaces\Data\ItemsInterface;


/**
 * Data Items
 * 
 * @since 3.2.2
 */
final class Items implements ItemsInterface
{
	/**
	 * The LoadInterface Class.
	 *
	 * @var   Load
	 * @since 3.2.2
	 */
	protected Load $load;

	/**
	 * The InsertInterface Class.
	 *
	 * @var   Insert
	 * @since 3.2.2
	 */
	protected Insert $insert;

	/**
	 * The UpdateInterface Class.
	 *
	 * @var   Update
	 * @since 3.2.2
	 */
	protected Update $update;

	/**
	 * The DeleteInterface Class.
	 *
	 * @var   Delete
	 * @since 3.2.2
	 */
	protected Delete $delete;

	/**
	 * The Load Class.
	 *
	 * @var   Database
	 * @since 3.2.2
	 */
	protected Database $database;

	/**
	 * Table Name
	 *
	 * @var    string
	 * @since 3.2.1
	 */
	protected string $table;

	/**
	 * Constructor.
	 *
	 * @param Load        $load       The LoadInterface Class.
	 * @param Insert      $insert     The InsertInterface Class.
	 * @param Update      $update     The UpdateInterface Class.
	 * @param Delete      $delete     The DeleteInterface Class.
	 * @param Database    $database   The Database Load Class.
	 * @param string|null $table      The table name.
	 *
	 * @since 3.2.2
	 */
	public function __construct(Load $load, Insert $insert, Update $update,
Delete $delete,
		Database $database, ?string $table = null)
	{
		$this->load = $load;
		$this->insert = $insert;
		$this->update = $update;
		$this->delete = $delete;
		$this->database = $database;
		if ($table !== null)
		{
			$this->table = $table;
		}
	}

	/**
	 * Set the current active table
	 *
	 * @param string $table The table that should be active
	 *
	 * @return self
	 * @since 3.2.2
	 */
	public function table(string $table): self
	{
		$this->table = $table;

		return $this;
	}

	/**
	 * Get list of items
	 *
	 * @param array     $values    The ids of the items
	 * @param string    $key       The key of the values
	 *
	 * @return array|null The item object or null
	 * @since 3.2.2
	 */
	public function get(array $values, string $key = 'guid'):
?array
	{
		return $this->load->table($this->getTable())->items([
			$key => [
				'operator' => 'IN',
				'value' => array_values($values)
			]
		]);
	}

	/**
	 * Get the values
	 *
	 * @param array   $values    The list of values (to search by).
	 * @param string  $key       The key on which the values being searched.
	 * @param string  $get       The key of the values we want back
	 *
	 * @return array|null   The array of found values.
	 * @since 3.2.2
	 */
	public function values(array $values, string $key = 'guid',
string $get = 'id'): ?array
	{
		// Perform the database query
		return $this->load->table($this->getTable())->values([
			$key => [
				'operator' => 'IN',
				'value' => array_values($values)
			]
		], $get);
	}

	/**
	 * Set items
	 *
	 * @param array     $items  The list of items
	 * @param string    $key    The key on which the items should be set
	 *
	 * @return bool
	 * @since 3.2.2
	 */
	public function set(array $items, string $key = 'guid'): bool
	{
		if (($sets = $this->sort($items, $key)) !== null)
		{
			foreach ($sets as $action => $items)
			{
				$this->{$action}($items, $key);
			}
			return true;
		}

		return false;
	}

	/**
	 * Delete items
	 *
	 * @param array    $values  The item key value
	 * @param string   $key     The item key
	 *
	 * @return bool
	 * @since 3.2.2
	 */
	public function delete(array $values, string $key = 'guid'):
bool
	{
		return $this->delete->table($this->getTable())->items([$key
=> ['operator' => 'IN', 'value' =>
$values]]);
	}

	/**
	 * Get the current active table
	 *
	 * @return  string
	 * @since 3.2.2
	 */
	public function getTable(): string
	{
		return $this->table;
	}

	/**
	 * Insert a item
	 *
	 * @param array   $items  The item
	 *
	 * @return bool
	 * @since 3.2.2
	 */
	private function insert(array $items): bool
	{
		return
$this->insert->table($this->getTable())->rows($items);
	}

	/**
	 * Update a item
	 *
	 * @param object   $item  The item
	 * @param string   $key   The item key
	 *
	 * @return bool
	 * @since 3.2.2
	 */
	private function update(array $items, string $key): bool
	{
		return $this->update->table($this->getTable())->rows($items,
$key);
	}

	/**
	 * Sort items between insert and update.
	 *
	 * @param array  $items The list of items.
	 * @param string $key   The key on which the items should be sorted.
	 *
	 * @return array|null The sorted sets.
	 * @since 3.2.2
	 */
	private function sort(array $items, string $key): ?array
	{
		// Extract relevant items based on the key.
		$values = $this->extractValues($items, $key);
		if ($values === null)
		{
			return null;
		}

		$sets = [
			'insert' => [],
			'update' => []
		];

		// Check for existing items.
		$existingItems = $this->database->values(
			["a.$key" => $key],
			["a" => $this->getTable()],
			["a.$key" => ['operator' => 'IN',
'value' => $values]]
		);

		if ($existingItems !== null)
		{
			$sets['update'] = $this->extractSet($items, $existingItems,
$key) ?? [];
			$sets['insert'] = $this->extractSet($items, $existingItems,
$key, true) ?? [];
		}
		else
		{
			$sets['insert'] = $items;
		}

		// If either set is empty, remove it from the result.
		$sets = array_filter($sets);

		return !empty($sets) ? $sets : null;
	}

	/**
	 * Extracts values for a given key from an array of items.
	 * Items can be either arrays or objects.
	 *
	 * @param array $items Array of items (arrays or objects)
	 * @param string $key The key to extract values for
	 *
	 * @return array|null Extracted values
	 * @since 3.2.2
	 */
	private function extractValues(array $items, string $key): ?array
	{
		$result = [];

		foreach ($items as $item)
		{
			if (is_array($item) && !empty($item[$key]))
			{
				$result[] = $item[$key];
			}
			elseif (is_object($item) && !empty($item->{$key}))
			{
				$result[] = $item->{$key};
			}
		}

		return ($result === []) ? null : $result;
	}

	/**
	 * Extracts items from an array of items based on a set.
	 * Items can be either arrays or objects.
	 *
	 * @param array  $items   Array of items (arrays or objects)
	 * @param array  $set	 The set to match values against
	 * @param string $key	 The key of the set values
	 * @param bool   $inverse Whether to extract items not in the set
	 *
	 * @return array|null Extracted values
	 * @since 3.2.2
	 */
	private function extractSet(array $items, array $set, string $key, bool
$inverse = false): ?array
	{
		$result = [];

		foreach ($items as $item)
		{
			$value = is_array($item) ? ($item[$key] ?? null) : ($item->{$key} ??
null);

			if ($value !== null)
			{
				$inSet = in_array($value, $set);
				if (($inSet && !$inverse) || (!$inSet && $inverse))
				{
					$result[] = is_array($item) ? $item : (array) $item; // convert all to
arrays
				}
			}
		}

		return empty($result) ? null : $result;
	}
}

PK�z�[w���7�7MultiSubform.phpnu�[���<?php
/**
 * @package    Joomla.Component.Builder
 *
 * @created    3rd September, 2020
 * @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\Data;


use VDM\Joomla\Interfaces\Data\SubformInterface as Subform;
use VDM\Joomla\Interfaces\Data\MultiSubformInterface;


/**
 * CRUD the data of multi subform to another views (tables)
 * 
 * @since  3.2.2
 */
final class MultiSubform implements MultiSubformInterface
{
	/**
	 * The Subform Class.
	 *
	 * @var   Subform
	 * @since 3.2.2
	 */
	protected Subform $subform;

	/**
	 * Constructor.
	 *
	 * @param Subform     $subform   The Subform Class.
	 *
	 * @since 3.2.2
	 */
	public function __construct(Subform $subform)
	{
		$this->subform = $subform;
	}

	/**
	 * Get a subform items
	 *
	 * @param array   $getMap  The map to get the subfrom data
	 *
	 *     Example:
	 *        $getMap = [
	 *        	'_core' => [
	 *        		'table' =>'data',
	 *        		'linkValue' => $item->guid ?? '',
	 *        		'linkKey' => 'look',
	 *        		'field' => 'data',
	 *        		'get' =>
['guid','email','image','mobile_phone','website','dateofbirth']
	 *        	],
	 *        	'countries' => [
	 *        		'table' =>'data_country',
	 *        		'linkValue' => 'data:guid', //
coretable:fieldname
	 *        		'linkKey' => 'data',
	 *        		'get' =>
['guid','country','currency']
	 *        	]
	 *        ];
	 *
	 * @return array|null   The subform
	 * @since 3.2.2
	 */
	public function get(array $getMap): ?array
	{
		// Validate the core map presence and structure
		if (!isset($getMap['_core']) ||
!is_array($getMap['_core']) ||
!$this->validGetMap($getMap['_core']))
		{
			return null;
		}

		// Initialize the core data
		$coreData = $this->getSubformData($getMap['_core']);

		// Return null if fetching core data fails
		if (null === $coreData)
		{
			return null;
		}
		$table = $getMap['_core']['table'];
		unset($getMap['_core']);

		// Recursively get data for all nested subforms
		return $this->getNestedSubforms($getMap, $coreData, $table);
	}

	/**
	 * Set a subform items
	 *
	 * @param mixed   $items    The list of items from the subform to set
	 * @param array   $setMap   The map to set the subfrom data
	 *
	 *     Example:
	 *        $items,
	 *        $setMap = [
	 *        	'_core' => [
	 *        		'table' =>'data',
	 *        		'indexKey' => 'guid',
	 *        		'linkKey' => 'look',
	 *        		'linkValue' => $data['guid'] ??
''
	 *        	],
	 *        	'countries' => [
	 *        		'table' =>'data_country',
	 *        		'indexKey' => 'guid',
	 *        		'linkKey' => 'data',
	 *        		'linkValue' => 'data:guid' //
coretable:fieldname
	 *        	]
	 *        ];
	 *
	 * @return bool
	 * @since 3.2.2
	 */
	public function set(mixed $items, array $setMap): bool
	{
		// Validate the core map presence and structure
		if (!isset($setMap['_core']) ||
!is_array($setMap['_core']) ||
!$this->validSetMap($setMap['_core']))
		{
			return false;
		}

		// catch an empty set
		if (!is_array($items))
		{
			$items = []; // will delete all existing linked items :( not ideal, but
real
		}

		// Save the core data
		if (!$this->setSubformData($items, $setMap['_core']))
		{
			return false;
		}
		$table = $setMap['_core']['table'];
		unset($setMap['_core']);

		// Recursively set data for all nested subforms
		return $this->setNestedSubforms($setMap, $items, $table);
	}

	/**
	 * Fetch data based on provided map configuration.
	 *
	 * @param array       $map       Map configuration
	 * @param array|null  $coreData  The core data to be appended with subform
data
	 *
	 * @return array|null Fetched data or null on failure
	 * @since 3.2.2
	 */
	private function getSubformData(array $map, ?array $coreData = null):
?array
	{
		$map['linkValue'] =
$this->setLinkValue($map['linkValue'], $coreData);

		if (empty($map['linkValue']) ||
strpos($map['linkValue'], ':') !== false)
		{
			return null;
		}

		return $this->subform->table($map['table'])->get(
			$map['linkValue'],
			$map['linkKey'],
			$map['field'],
			$map['get']
		);
	}

	/**
	 * Set data based on provided map configuration.
	 *
	 * @param array       $items     The list of items from the subform to
set
	 * @param array       $map       The map to set the subfrom data
	 * @param array|null  $coreData  The core data to be appended with subform
data
	 *
	 * @return bool
	 * @since 3.2.2
	 */
	private function setSubformData(array $items, array $map, ?array $coreData
= null): bool
	{
		$map['linkValue'] =
$this->setLinkValue($map['linkValue'], $coreData);

		if (empty($map['linkValue']) ||
strpos($map['linkValue'], ':') !== false)
		{
			return false;
		}

		return $this->subform->table($map['table'])->set(
			$items,
			$map['indexKey'],
			$map['linkKey'],
			$map['linkValue']
		);
	}

	/**
	 * Set the linked value if needed, and posible.
	 *
	 * @param string      $linkValue   The current linkValue
	 * @param array|null  $data        The already found data as table =>
dataSet[field] => value
	 *
	 * @return string|null The actual linkValue
	 * @since 3.2.2
	 */
	private function setLinkValue(string $linkValue, ?array $data = null):
?string
	{
		if ($data !== null && strpos($linkValue, ':') !==
false)
		{
			[$table, $field] = explode(':', $linkValue);
			$linkValue = $data[$table][$field] ?? null;
		}

		return $linkValue;
	}

	/**
	 * Recursively process additional subform data.
	 *
	 * @param array  $getMap       The nested map of data to process
	 * @param array  $subformData  The core subform data
	 * @param string $table        The core table
	 *
	 * @return array The core data with nested subforms included
	 * @since 3.2.2
	 */
	private function getNestedSubforms(array $getMap, array $subformData,
string $table): array
	{
		foreach ($subformData as &$subform)
		{
			$subform = $this->processGetSubform($getMap, $subform, $table);
		}

		return $subformData;
	}

	/**
	 * Recursively process additional subform data.
	 *
	 * @param array  $setMap       The nested map of data to process
	 * @param array  $subformData  The core subform data
	 * @param string $table        The core table
	 *
	 * @return bool
	 * @since 3.2.2
	 */
	private function setNestedSubforms(array $setMap, array $subformData,
string $table): bool
	{
		$status = true;
		foreach ($subformData as $subform)
		{
			if (!$this->processSetSubform($setMap, $subform, $table))
			{
				$status = false;
			}
		}

		return $status;
	}

	/**
	 * Process each subform entry based on the map.
	 *
	 * @param array  $getMap    Mapping data for processing subforms
	 * @param array  $subform   A single subform entry
	 * @param string $table     The table name used for linking values
	 * 
	 * @return array Updated subform
	 * @since 3.2.2
	 */
	private function processGetSubform(array $getMap, array $subform, string
$table): array
	{
		foreach ($getMap as $key => $map)
		{
			if (!is_array($map) || isset($subform[$key]))
			{
				continue;
			}

			$this->processGetMap($subform, $map, $key, $table);
		}

		return $subform;
	}

	/**
	 * Process each subform entry based on the map.
	 *
	 * @param array  $setMap    Mapping data for processing subforms
	 * @param array  $subform   A single subform entry
	 * @param string $table     The table name used for linking values
	 * 
	 * @return bool
	 * @since 3.2.2
	 */
	private function processSetSubform(array $setMap, array $subform, string
$table): bool
	{
		$status = true;
		foreach ($setMap as $key => $map)
		{
			if (!is_array($map) || !isset($subform[$key]))
			{
				continue;
			}

			if (!$this->processSetMap($subform, $map, $key, $table))
			{
				$status = false;
			}
		}

		return $status;
	}

	/**
	 * Process a given map by either fetching nested subforms or handling them
directly.
	 *
	 * @param array  &$subform Reference to subform data
	 * @param array  $map      Map configuration for subform processing
	 * @param string $key      Key associated with the map
	 * @param string $table    Core table name for linking values
	 *
	 * @return void
	 * @since 3.2.2
	 */
	private function processGetMap(array &$subform, array $map, string
$key, string $table): void
	{
		if (isset($map['_core']))
		{
			$this->handleCoreGetMap($subform, $map, $key, $table);
		}
		else
		{
			$this->handleRegularGetMap($subform, $map, $key, $table);
		}
	}

	/**
	 * Process a given map by either setting nested subforms or handling them
directly.
	 *
	 * @param array  $subform  Subform data
	 * @param array  $map      Map configuration for subform processing
	 * @param string $key      Key associated with the map
	 * @param string $table    Core table name for linking values
	 *
	 * @return bool
	 * @since 3.2.2
	 */
	private function processSetMap(array $subform, array $map, string $key,
string $table): bool
	{
		if (isset($map['_core']))
		{
			return $this->handleCoreSetMap($subform, $map, $key, $table);
		}

		return $this->handleRegularSetMap($subform, $map, $key, $table);
	}

	/**
	 * Handle the processing of '_core' maps in a subform.
	 *
	 * @param array  &$subform Reference to subform data
	 * @param array  $map      Map configuration for core subform processing
	 * @param string $key      Key associated with the map
	 * @param string $table    Core table name for linking values
	 *
	 * @return void
	 * @since 3.2.2
	 */
	private function handleCoreGetMap(array &$subform, array $map, string
$key, string $table): void
	{
		if (is_array($map['_core']) &&
$this->validGetMap($map['_core']))
		{
			$map['_core']['linkValue'] =
$this->setLinkValue($map['_core']['linkValue'],
[$table => $subform]);

			$subCoreData = $this->get($map);
			if ($subCoreData !== null)
			{
				$subform[$key] = $subCoreData;
			}
		}
	}

	/**
	 * Handle the processing of '_core' maps in a subform.
	 *
	 * @param array  $subform  Subform data
	 * @param array  $map      Map configuration for core subform processing
	 * @param string $key      Key associated with the map
	 * @param string $table    Core table name for linking values
	 *
	 * @return bool
	 * @since 3.2.2
	 */
	private function handleCoreSetMap(array $subform, array $map, string $key,
string $table): bool
	{
		if (is_array($map['_core']) &&
$this->validGetMap($map['_core']))
		{
			$map['_core']['linkValue'] =
$this->setLinkValue($map['_core']['linkValue'],
[$table => $subform]);

			return $this->set($subform[$key], $map);
		}

		return false;
	}

	/**
	 * Handle the processing of regular maps in a subform.
	 *
	 * @param array   &$subform Reference to subform data
	 * @param array   $map      Map configuration for regular subform
processing
	 * @param string  $key      Key associated with the map
	 * @param string  $table    Core table name for linking values
	 *
	 * @return void
	 * @since 3.2.2
	 */
	private function handleRegularGetMap(array &$subform, array $map,
string $key, string $table): void
	{
		$map['field'] = $key;
		if ($this->validGetMap($map))
		{
			$subformData = $this->getSubformData($map, [$table => $subform]);
			if ($subformData !== null)
			{
				$subform[$key] = $subformData;
			}
		}
	}

	/**
	 * Handle the processing of regular maps in a subform.
	 *
	 * @param array   $subform  Subform data
	 * @param array   $map      Map configuration for regular subform
processing
	 * @param string  $key      Key associated with the map
	 * @param string  $table    Core table name for linking values
	 *
	 * @return bool
	 * @since 3.2.2
	 */
	private function handleRegularSetMap(array $subform, array $map, string
$key, string $table): bool
	{
		if ($this->validSetMap($map))
		{
			// will delete all existing linked items [IF EMPTY] :( not ideal, but
real
			$data = (empty($subform[$key]) || !is_array($subform[$key])) ? [] :
$subform[$key];

			return $this->setSubformData($data, $map, [$table => $subform]);
		}

		return false;
	}

	/**
	 * Validate the get map configuration for fetching subform data.
	 * Ensures all required keys are present and have valid values.
	 *
	 * @param array  $map  The map configuration to validate.
	 *
	 * @return bool  Returns true if the map is valid, false otherwise.
	 * @since 3.2.2
	 */
	private function validGetMap(array $map): bool
	{
		// List of required keys with their expected types or validation
functions
		$requiredKeys = [
			'table' => 'is_string',
			'linkValue' => 'is_string',
			'linkKey' => 'is_string',
			'field' => 'is_string',
			'get' => 'is_array'
		];

		// Iterate through each required key and validate
		foreach ($requiredKeys as $key => $validator)
		{
			if (empty($map[$key]) || !$validator($map[$key]))
			{
				return false; // Key missing or validation failed
			}
		}

		return true; // All checks passed
	}

	/**
	 * Validate the set map configuration for fetching subform data.
	 * Ensures all required keys are present and have valid values.
	 *
	 * @param array  $map  The map configuration to validate.
	 *
	 * @return bool  Returns true if the map is valid, false otherwise.
	 * @since 3.2.2
	 */
	private function validSetMap(array $map): bool
	{
		// List of required keys with their expected types or validation
functions
		$requiredKeys = [
			'table' => 'is_string',
			'indexKey' => 'is_string',
			'linkKey' => 'is_string',
			'linkValue' => 'is_string'
		];

		// Iterate through each required key and validate
		foreach ($requiredKeys as $key => $validator)
		{
			if (empty($map[$key]) || !$validator($map[$key]))
			{
				return false; // Key missing or validation failed
			}
		}

		return true; // All checks passed
	}
}

PK�z�[�;h� � Subform.phpnu�[���<?php
/**
 * @package    Joomla.Component.Builder
 *
 * @created    3rd September, 2020
 * @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\Data;


use VDM\Joomla\Interfaces\Data\ItemsInterface as Items;
use VDM\Joomla\Data\Guid;
use VDM\Joomla\Interfaces\Data\GuidInterface;
use VDM\Joomla\Interfaces\Data\SubformInterface;


/**
 * CRUD the data of any sub-form to another view (table)
 * 
 * @since  3.2.2
 */
final class Subform implements GuidInterface, SubformInterface
{
	/**
	 * The Globally Unique Identifier.
	 *
	 * @since 5.0.2
	 */
	use Guid;

	/**
	 * The Items Class.
	 *
	 * @var   Items
	 * @since 3.2.2
	 */
	protected Items $items;

	/**
	 * Table Name
	 *
	 * @var    string
	 * @since 3.2.1
	 */
	protected string $table;

	/**
	 * Constructor.
	 *
	 * @param Items       $items   The Items Class.
	 * @param string|null $table   The table name.
	 *
	 * @since 3.2.2
	 */
	public function __construct(Items $items, ?string $table = null)
	{
		$this->items = $items;
		if ($table !== null)
		{
			$this->table = $table;
		}
	}

	/**
	 * Set the current active table
	 *
	 * @param string $table The table that should be active
	 *
	 * @return self
	 * @since 3.2.2
	 */
	public function table(string $table): self
	{
		$this->table = $table;

		return $this;
	}

	/**
	 * Get a subform items
	 *
	 * @param string   $linkValue  The value of the link key in child table.
	 * @param string   $linkKey    The link key on which the items where
linked in the child table.
	 * @param string   $field      The parent field name of the subform in the
parent view.
	 * @param array    $get        The array SET of the keys of each row in
the subform.
	 * @param bool     $multi      The switch to return a multiple set.
	 *
	 * @return array|null   The subform
	 * @since 3.2.2
	 */
	public function get(string $linkValue, string $linkKey, string $field,
array $get, bool $multi = true): ?array
	{
		if (($items =
$this->items->table($this->getTable())->get([$linkValue],
$linkKey)) !== null)
		{
			return $this->converter($items, $get, $field, $multi);
		}
		return null;
	}

	/**
	 * Set a subform items
	 *
	 * @param mixed    $items      The list of items from the subform to set
	 * @param string   $indexKey   The index key on which the items should be
observed as it relates to insert/update/delete.
	 * @param string   $linkKey    The link key on which the items where
linked in the child table.
	 * @param string   $linkValue  The value of the link key in child table.
	 *
	 * @return bool
	 * @since 3.2.2
	 */
	public function set(mixed $items, string $indexKey, string $linkKey,
string $linkValue): bool
	{
		$items = $this->process($items, $indexKey, $linkKey, $linkValue);

		$this->purge($items, $indexKey, $linkKey, $linkValue);

		if (empty($items))
		{
			return true; // nothing to set (already purged)
		}

		return $this->items->table($this->getTable())->set(
			$items, $indexKey
		);
	}

	/**
	 * Get the current active table
	 *
	 * @return  string
	 * @since 3.2.2
	 */
	public function getTable(): string
	{
		return $this->table;
	}

	/**
	 * Purge all items no longer in subform
	 *
	 * @param array    $items      The list of items to set.
	 * @param string   $indexKey   The index key on which the items should be
observed as it relates to insert/update/delete
	 * @param string   $linkKey    The link key on which the items where
linked in the child table.
	 * @param string   $linkValue  The value of the link key in child table.
	 *
	 * @return void
	 * @since 3.2.2
	 */
	private function purge(array $items, string $indexKey, string $linkKey,
string $linkValue): void
	{
		// Get the current index values from the database
		$currentIndexValues =
$this->items->table($this->getTable())->values([$linkValue],
$linkKey, $indexKey);

		if ($currentIndexValues !== null)
		{
			// Check if the items array is empty
			if (empty($items))
			{
				// Set activeIndexValues to an empty array if items is empty
				$activeIndexValues = [];
			}
			else
			{
				// Extract the index values from the items array
				$activeIndexValues = array_values(array_map(function($item) use
($indexKey) {
					return $item[$indexKey] ?? null;
				}, $items));
			}

			// Find the index values that are no longer in the items array
			$inactiveIndexValues = array_diff($currentIndexValues,
$activeIndexValues);

			// Delete the inactive index values
			if (!empty($inactiveIndexValues))
			{
				$this->items->table($this->getTable())->delete($inactiveIndexValues,
$indexKey);
			}
		}
	}

	/**
	 * Filters the specified keys from an array of objects or arrays, converts
them to arrays,
	 * and sets them by association with a specified key and an incrementing
integer.
	 *
	 * @param array  $items  Array of objects or arrays to be filtered.
	 * @param array  $keySet Array of keys to retain in each item.
	 * @param string $field  The field prefix for the resulting associative
array.
	 * @param bool   $multi  The switch to return a multiple set.
	 *
	 * @return array Array of filtered arrays set by association.
	 * @since 3.2.2
	 */
	private function converter(array $items, array $keySet, string $field,
bool $multi): array
	{
		/**
		 * Filters keys for a single item and converts it to an array.
		 *
		 * @param object|array $item   The item to filter.
		 * @param array        $keySet The keys to retain.
		 *
		 * @return array The filtered array.
		 * @since 3.2.2
		 */
		$filterKeys = function ($item, array $keySet) {
			$filteredArray = [];
			foreach ($keySet as $key) {
				if (is_object($item) && property_exists($item, $key)) {
					$filteredArray[$key] = $item->{$key};
				} elseif (is_array($item) && array_key_exists($key, $item)) {
					$filteredArray[$key] = $item[$key];
				}
			}
			return $filteredArray;
		};

		$result = [];
		foreach ($items as $index => $item)
		{
			if (!$multi)
			{
				return $filterKeys($item, $keySet);
			}
			$filteredArray = $filterKeys($item, $keySet);
			$result[$field . $index] = $filteredArray;
		}

		return $result;
	}

	/**
	 * Processes an array of arrays based on the specified key.
	 *
	 * @param mixed    $items      Array of arrays to be processed.
	 * @param string   $indexKey   The index key on which the items should be
observed as it relates to insert/update/delete
	 * @param string   $linkKey    The link key on which the items where
linked in the child table.
	 * @param string   $linkValue  The value of the link key in child table.
	 *
	 * @return array  The processed array of arrays.
	 * @since 3.2.2
	 */
	private function process($items, string $indexKey, string $linkKey, string
$linkValue): array
	{
		$items = is_array($items) ? $items : [];
		if ($items !== [] && !$this->isMultipleSets($items))
		{
			$items = [$items];
		}

		foreach ($items as &$item)
		{
			$value = $item[$indexKey] ?? '';
			switch ($indexKey) {
				case 'guid':
					if (empty($value))
					{
						// set INDEX
						$item[$indexKey] = $this->getGuid($indexKey);
					}
					break;
				case 'id':
					if (empty($value))
					{
						$item[$indexKey] = 0;
					}
					break;
				default:
					// No action for other keys if empty
					break;
			}
			// set LINK
			$item[$linkKey] = $linkValue;
		}

		return array_values($items);
	}

	/**
	 * Function to determine if the array consists of multiple data sets
(arrays of arrays).
	 * 
	 * @param array $array The input array to be checked.
	 * 
	 * @return bool True if the array contains only arrays (multiple data
sets), false otherwise.
	 * @since  5.0.2
	 */
	private function isMultipleSets(array $array): bool
	{
		foreach ($array as $element)
		{
			// As soon as we find a non-array element, return false
			if (!is_array($element))
			{
				return false;
			}
		}

		// If all elements are arrays, return true
		return true;
	}
}

PK�z�[��%H=?=?UsersSubform.phpnu�[���<?php
/**
 * @package    Joomla.Component.Builder
 *
 * @created    4th September, 2020
 * @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\Data;


use Joomla\CMS\Factory;
use Joomla\CMS\User\User;
use VDM\Joomla\Interfaces\Data\ItemsInterface as Items;
use VDM\Joomla\Data\Guid;
use VDM\Joomla\Componentbuilder\Utilities\UserHelper;
use VDM\Joomla\Componentbuilder\Utilities\Exception\NoUserIdFoundException;
use VDM\Joomla\Utilities\Component\Helper as Component;
use VDM\Joomla\Interfaces\Data\GuidInterface;
use VDM\Joomla\Interfaces\Data\SubformInterface;


/**
 * CRUD the user data of any sub-form to another view (table)
 * 
 * @since  5.0.2
 */
final class UsersSubform implements GuidInterface, SubformInterface
{
	/**
	 * The Globally Unique Identifier.
	 *
	 * @since 5.0.2
	 */
	use Guid;

	/**
	 * The Items Class.
	 *
	 * @var   Items
	 * @since 3.2.2
	 */
	protected Items $items;

	/**
	 * Table Name
	 *
	 * @var    string
	 * @since 3.2.1
	 */
	protected string $table;

	/**
	 * The user properties
	 *
	 * @var    array
	 * @since 5.0.2
	 */
	protected array $user;

	/**
	 * The current active user
	 *
	 * @var    User
	 * @since 5.0.2
	 */
	protected User $identity;

	/**
	 * The active users
	 *
	 * @var    array
	 * @since 5.0.2
	 */
	protected array $activeUsers = [];

	/**
	 * Constructor.
	 *
	 * @param Items       $items   The items Class.
	 * @param string|null $table   The table name.
	 *
	 * @since 3.2.2
	 */
	public function __construct(Items $items, ?string $table = null)
	{
		$this->items = $items;
		if ($table !== null)
		{
			$this->table = $table;
		}

		$this->identity = Factory::getApplication()->getIdentity();

		// Retrieve the user properties
		$this->initializeUserProperties();
	}

	/**
	 * Set the current active table
	 *
	 * @param string $table The table that should be active
	 *
	 * @return self
	 * @since  3.2.2
	 */
	public function table(string $table): self
	{
		$this->table = $table;

		return $this;
	}

	/**
	 * Get a subform items
	 *
	 * @param string   $linkValue  The value of the link key in child table.
	 * @param string   $linkKey    The link key on which the items where
linked in the child table.
	 * @param string   $field      The parent field name of the subform in the
parent view.
	 * @param array    $get        The array get:set of the keys of each row
in the subform.
	 * @param bool     $multi      The switch to return a multiple set.
	 *
	 * @return array|null   The subform
	 * @since  3.2.2
	 */
	public function get(string $linkValue, string $linkKey, string $field,
array $get, bool $multi = true): ?array
	{
		if (($items =
$this->items->table($this->getTable())->get([$linkValue],
$linkKey)) !== null)
		{
			return $this->converter(
				$this->getUsersDetails($items),
				$get,
				$field,
				$multi
			);
		}

		return null;
	}

	/**
	 * Set a subform items
	 *
	 * @param mixed    $items      The list of items from the subform to set
	 * @param string   $indexKey   The index key on which the items should be
observed as it relates to insert/update/delete.
	 * @param string   $linkKey    The link key on which the items where
linked in the child table.
	 * @param string   $linkValue  The value of the link key in child table.
	 *
	 * @return bool
	 * @since  3.2.2
	 */
	public function set(mixed $items, string $indexKey, string $linkKey,
string $linkValue): bool
	{
		$items = $this->process($items, $indexKey, $linkKey, $linkValue);

		$this->purge($items, $indexKey, $linkKey, $linkValue);

		if (empty($items))
		{
			return true; // nothing to set (already purged)
		}

		return $this->items->table($this->getTable())->set(
			$items, $indexKey
		);
	}

	/**
	 * Get the current active table
	 *
	 * @return  string
	 * @since   3.2.2
	 */
	public function getTable(): string
	{
		return $this->table;
	}

	/**
	 * Initializes the user properties.
	 *
	 * @return void
	 * @since  5.0.2
	 */
	private function initializeUserProperties(): void
	{
		$user = UserHelper::getUserById(0);

		// Populate user properties array excluding the 'id'
		foreach (get_object_vars($user) as $property => $value)
		{
			if ($property !== 'id')
			{
				$this->user[$property] = $property;
			}
		}
		$this->user['password2'] = 'password2';
	}

	/**
	 * Purge all items no longer in subform
	 *
	 * @param array    $items      The list of items to set.
	 * @param string   $indexKey   The index key on which the items should be
observed as it relates to insert/update/delete
	 * @param string   $linkKey    The link key on which the items where
linked in the child table.
	 * @param string   $linkValue  The value of the link key in child table.
	 *
	 * @return void
	 * @since  3.2.2
	 */
	private function purge(array $items, string $indexKey, string $linkKey,
string $linkValue): void
	{
		// Get the current index values from the database
		$currentIndexValues =
$this->items->table($this->getTable())->values([$linkValue],
$linkKey, $indexKey);

		if ($currentIndexValues !== null)
		{
			// Check if the items array is empty
			if (empty($items))
			{
				// Set activeIndexValues to an empty array if items is empty
				$activeIndexValues = [];
			}
			else
			{
				// Extract the index values from the items array
				$activeIndexValues = array_values(array_map(function($item) use
($indexKey) {
					return $item[$indexKey] ?? null;
				}, $items));
			}

			// Find the index values that are no longer in the items array
			$inactiveIndexValues = array_diff($currentIndexValues,
$activeIndexValues);

			// Delete the inactive index values
			if (!empty($inactiveIndexValues))
			{
				$this->items->table($this->getTable())->delete($inactiveIndexValues,
$indexKey);

				// $this->deleteUsers($inactiveIndexValues); (soon)
			}
		}
	}

	/**
	 * Get the users details found in the user table.
	 *
	 * @param array  $items  Array of objects or arrays to be filtered.
	 *
	 * @return array
	 * @since  5.0.2
	 */
	private function getUsersDetails(array $items): array
	{
		foreach ($items as $index => &$item)
		{
			$item = (array) $item;
			$this->getUserDetails($item);
		}

		return $items;
	}

	/**
	 * Get the user details found in the user table.
	 *
	 * @param array  $item  The user map array
	 *
	 * @return void
	 * @since  5.0.2
	 */
	private function getUserDetails(array &$item): void
	{
		// Validate the user_id and ensure it is numeric and greater than 0
		if (empty($item['user_id']) ||
!is_numeric($item['user_id']) || $item['user_id'] <=
0)
		{
			return;
		}

		// Retrieve the user by ID
		$user = UserHelper::getUserById((int)$item['user_id']);

		// Verify if the user exists and the ID matches
		if ($user && $user->id === (int) $item['user_id'])
		{
			// Iterate over public properties of the user object
			foreach (get_object_vars($user) as $property => $value)
			{
				// Avoid overwriting the id in the item
				if ($property !== 'id')
				{
					$item[$property] = $value;
				}
			}
		}
	}

	/**
	 * Filters the specified keys from an array of objects or arrays, converts
them to arrays,
	 * and sets them by association with a specified key and an incrementing
integer.
	 *
	 * @param array  $items  Array of objects or arrays to be filtered.
	 * @param array  $keySet Array of keys to retain in each item.
	 * @param string $field  The field prefix for the resulting associative
array.
	 * @param bool   $multi  The switch to return a multiple set.
	 *
	 * @return array Array of filtered arrays set by association.
	 * @since  3.2.2
	 */
	private function converter(array $items, array $keySet, string $field,
bool $multi): array
	{
		/**
		 * Filters keys for a single item and converts it to an array.
		 *
		 * @param object|array $item   The item to filter.
		 * @param array        $keySet The keys to retain.
		 *
		 * @return array The filtered array.
		 * @since 3.2.2
		 */
		$filterKeys = function ($item, array $keySet) {
			$filteredArray = [];
			foreach ($keySet as $key) {
				if (is_object($item) && property_exists($item, $key)) {
					$filteredArray[$key] = $item->{$key};
				} elseif (is_array($item) && array_key_exists($key, $item)) {
					$filteredArray[$key] = $item[$key];
				}
			}
			return $filteredArray;
		};

		$result = [];
		foreach ($items as $index => $item)
		{
			if (!$multi)
			{
				return $filterKeys($item, $keySet);
			}
			$filteredArray = $filterKeys($item, $keySet);
			$result[$field . $index] = $filteredArray;
		}

		return $result;
	}

	/**
	 * Processes an array of arrays based on the specified key.
	 *
	 * @param mixed    $items      Array of arrays to be processed.
	 * @param string   $indexKey   The index key on which the items should be
observed as it relates to insert/update/delete
	 * @param string   $linkKey    The link key on which the items where
linked in the child table.
	 * @param string   $linkValue  The value of the link key in child table.
	 *
	 * @return array  The processed array of arrays.
	 * @since  3.2.2
	 */
	private function process($items, string $indexKey, string $linkKey, string
$linkValue): array
	{
		$items = is_array($items) ? $items : [];
		if ($items !== [] && !$this->isMultipleSets($items))
		{
			$items = [$items];
		}

		foreach ($items as $n => &$item)
		{
			$value = $item[$indexKey] ?? '';
			switch ($indexKey) {
				case 'guid':
					if (empty($value))
					{
						// set INDEX
						$item[$indexKey] = $this->getGuid($indexKey);
					}
					break;
				case 'id':
					if (empty($value))
					{
						$item[$indexKey] = 0;
					}
					break;
				default:
					// No action for other keys if empty
					break;
			}

			// set LINK
			$item[$linkKey] = $linkValue;

			// create/update user
			$item['user_id'] = $this->setUserDetails(
				$item,
				$this->getActiveUsers(
					$linkKey,
					$linkValue
				)
			);

			// remove empty row (means no user linked)
			if ($item['user_id'] == 0)
			{
				unset($items[$n]);
			}
		}

		return array_values($items);
	}

	/**
	 * Get current active Users Linked to this entity
	 *
	 * @param string   $linkKey    The link key on which the items where
linked in the child table.
	 * @param string   $linkValue  The value of the link key in child table.
	 *
	 * @return array   The IDs of all active users.
	 * @since  5.0.2
	 */
	private function getActiveUsers(string $linkKey, string $linkValue):
array
	{
		if (isset($this->activeUsers[$linkKey . $linkValue]))
		{
			return $this->activeUsers[$linkKey . $linkValue];
		}

		if (($users =
$this->items->table($this->getTable())->values([$linkValue],
$linkKey, 'user_id')) !== null)
		{
			$this->activeUsers[$linkKey . $linkValue] = $users;
			return $users;
		}

		return [];
	}

	/**
	 * Handles setting user details and saving them.
	 *
	 * This function retrieves the user by ID, sets the user details, 
	 * and adds appropriate user groups before saving the user.
	 *
	 * @param array $item        The user details passed by reference.
	 * @param array $activeUsers The current active user linked to this
entity.
	 *
	 * @return int The ID of the saved user, or 0 on failure.
	 * @since  5.0.2
	 */
	private function setUserDetails(array &$item, array $activeUsers):
int
	{
		$user = $this->loadUser($item, $activeUsers);
		$details = $this->extractUserDetails($item, $user);

		if ($this->identity->id != $user->id)
		{
			$this->assignUserGroups($details, $user, $item);
		}

		return $this->saveUserDetails($details, $details['id'] ??
0);
	}

	/**
	 * Load the user based on the user ID from the item array.
	 *
	 * @param array $item         The array containing user details.
	 * @param array $activeUsers  The current active user linked to this
entity.
	 * 
	 * @return User|null The user object if found, null otherwise.
	 * @since  5.0.2
	 */
	private function loadUser(array $item, array $activeUsers): ?User
	{
		if (!isset($item['user_id']) ||
!is_numeric($item['user_id']) || $item['user_id'] <=
0)
		{
			return null;
		}

		// only allow update to linked users
		if (!in_array($item['user_id'], $activeUsers))
		{
			return null;
		}

		$user = UserHelper::getUserById((int) $item['user_id']);

		if ($user && $user->id == $item['user_id'])
		{
			return $user;
		}

		return null;
	}

	/**
	 * Extract user details from the item array and prepare them for saving.
	 *
	 * @param array     $item The array containing user details.
	 * @param User|null $user The user object if found, null otherwise.
	 * 
	 * @return array The prepared user details array.
	 * @since  5.0.2
	 */
	private function extractUserDetails(array &$item, ?User $user): array
	{
		$details = [];

		if ($user !== null)
		{
			$details['id'] = (int) $item['user_id'];
		}

		foreach ($this->user as $property)
		{
			if (isset($item[$property]))
			{
				$details[$property] = $item[$property];
				unset($item[$property]);
			}
		}

		return $details;
	}

	/**
	 * Assigns user groups based on existing groups and entity type.
	 *
	 * @param array     &$details The array to store user details
including groups.
	 * @param User|null $user     The user object if found, null otherwise.
	 * @param array     $item     The array containing additional user
details.
	 *
	 * @return void
	 * @since 5.0.2
	 */
	private function assignUserGroups(array &$details, ?User $user, array
$item): void
	{
		$groups = $user !== null ? (array) $user->groups : [];

		if (!empty($item['entity_type']))
		{
			$global_entity_groups =
Component::getParams()->get($item['entity_type'] .
'_groups', []);
			foreach ($global_entity_groups as $group)
			{
				if (!in_array($group, $groups))
				{
					$groups[] = $group;
				}
			}
		}

		// Ensure $details['groups'] is an array if it exists, else
default to an empty array
		$detailsGroups = isset($details['groups']) ? (array)
$details['groups'] : [];

		// Merge the arrays and remove duplicates
		$mergedGroups = array_unique(array_merge($detailsGroups, $groups));

		// Only set $details['groups'] if the merged array is not
empty
		if (!empty($mergedGroups))
		{
			$details['groups'] = $mergedGroups;
		}
		else
		{
			unset($details['groups']);
		}
	}

	/**
	 * Save the user details using UserHelper and handle exceptions.
	 *
	 * @param array $details The prepared user details array.
	 * @param int   $userId  The ID of the user being processed.
	 * 
	 * @return int The ID of the saved user, or 0 on failure.
	 * @since 5.0.2
	 */
	private function saveUserDetails(array $details, int $userId): int
	{
		try {
			return UserHelper::save($details, 0, ['useractivation' =>
0, 'sendpassword' => 1, 'allowUserRegistration'
=> 1]);
		} catch (NoUserIdFoundException $e) {
			Factory::getApplication()->enqueueMessage($e->getMessage(),
'error');
		} catch (\Exception $e) {
			Factory::getApplication()->enqueueMessage($e->getMessage(),
'warning');
			return $userId;
		}

		return 0;
	}

	/**
	 * Function to determine if the array consists of multiple data sets
(arrays of arrays).
	 * 
	 * @param array $array The input array to be checked.
	 * 
	 * @return bool True if the array contains only arrays (multiple data
sets), false otherwise.
	 * @since  5.0.2
	 */
	private function isMultipleSets(array $array): bool
	{
		foreach ($array as $element)
		{
			// As soon as we find a non-array element, return false
			if (!is_array($element))
			{
				return false;
			}
		}

		// If all elements are arrays, return true
		return true;
	}
}

PK
:�[�7�Ǔ�Data.phpnu�[���PK�z�[]?�8���Action/Delete.phpnu�[���PK�z�[�#o,,�Action/index.htmlnu�[���PK�z�[����Action/Insert.phpnu�[���PK�z�[�X�99D#Action/Load.phpnu�[���PK�z�[W�:����6Action/Update.phpnu�[���PK�z�[�	����JFactory.phpnu�[���PK�z�[��[�88kOGuid.phpnu�[���PK�z�[�#o,,
�Zindex.htmlnu�[���PK�z�[3�T��A[Item.phpnu�[���PK�z�[�0�R��	�oItems.phpnu�[���PK�z�[w���7�7��MultiSubform.phpnu�[���PK�z�[�;h�
�
��Subform.phpnu�[���PK�z�[��%H=?=?u�UsersSubform.phpnu�[���PK4�&