protected function _attributeUnsigned(array &$attributes, array &$field)
	{
		if (empty($attributes['UNSIGNED']) || $attributes['UNSIGNED'] !== true)
		{
			return;
		}

		// Reset the attribute in order to avoid issues if we do type conversion
		$attributes['UNSIGNED'] = false;

		if (is_array($this->unsigned))
		{
			foreach (array_keys($this->unsigned) as $key)
			{
				if (is_int($key) && strcasecmp($attributes['TYPE'], $this->unsigned[$key]) === 0)
				{
					$field['unsigned'] = ' UNSIGNED';

					return;
				}
				elseif (is_string($key) && strcasecmp($attributes['TYPE'], $key) === 0)
				{
					$field['type'] = $key;

					return;
				}
			}

			return;
		}

		$field['unsigned'] = ($this->unsigned === true) ? ' UNSIGNED' : '';
	}

Field attribute UNSIGNED

Depending on the unsigned property value:

- TRUE will always set $field['unsigned'] to 'UNSIGNED'
- FALSE will always set $field['unsigned'] to ''
- array(TYPE) will set $field['unsigned'] to 'UNSIGNED',
if $attributes['TYPE'] is found in the array
- array(TYPE => UTYPE) will change $field['type'],
from TYPE to UTYPE in case of a match

@param array &$attributes
@param array &$field

@return null|void


protected function _attributeDefault(array &$attributes, array &$field)
	{
		if ($this->default === false)
		{
			return;
		}

		if (array_key_exists('DEFAULT', $attributes))
		{
			if ($attributes['DEFAULT'] === null)
			{
				$field['default'] = empty($this->null) ? '' : $this->default . $this->null;

				// Override the NULL attribute if that's our default
				$attributes['NULL'] = true;
				$field['null']      = empty($this->null) ? '' : ' ' . $this->null;
			}
			else
			{
				$field['default'] = $this->default . $this->db->escape($attributes['DEFAULT']);
			}
		}
	}

Field attribute DEFAULT

@param array &$attributes
@param array &$field

@return null|void


protected function _processPrimaryKeys(string $table): string
	{
		$sql = '';

		for ($i = 0, $c = count($this->primaryKeys); $i < $c; $i++)
		{
			if (! isset($this->fields[$this->primaryKeys[$i]]))
			{
				unset($this->primaryKeys[$i]);
			}
		}

		if (count($this->primaryKeys) > 0)
		{
			$sql .= ",\n\tCONSTRAINT " . $this->db->escapeIdentifiers('pk_' . $table)
					. ' PRIMARY KEY(' . implode(', ', $this->db->escapeIdentifiers($this->primaryKeys)) . ')';
		}

		return $sql;
	}

protected
function
_processPrimaryKeys
(
string
$
table
)
:
string
{
$
sql
=
''
;
for
(
$
i
=
0
,
$
c
=
count
(
$
this
->
primaryKeys
)
;
$
i
<
$
c
;
$
i
++
)
{
if
(
!
isset
(
$
this
->
fields
[
$
this
->
primaryKeys
[
$
i
]
]
)
)
{
unset
(
$
this
->
primaryKeys
[
$
i
]
)
;
}
}
if
(
count
(
$
this
->
primaryKeys
)
>
0
)
{
$
sql
.=
",\n\tCONSTRAINT "
.
$
this
->
db
->
escapeIdentifiers
(
'pk_'
.
$
table
)
.
' PRIMARY KEY('
.
implode
(
', '
,
$
this
->
db
->
escapeIdentifiers
(
$
this
->
primaryKeys
)
)
.
')'
;
}
return
$
sql
;
}

Process primary keys

@param string $table Table name

@return string


protected function _processForeignKeys(string $table): string
	{
		$sql = '';

		$allowActions = [
			'CASCADE',
			'SET NULL',
			'NO ACTION',
			'RESTRICT',
			'SET DEFAULT',
		];

		if (count($this->foreignKeys) > 0)
		{
			foreach ($this->foreignKeys as $field => $fkey)
			{
				$name_index = $table . '_' . $field . '_foreign';

				$sql .= ",\n\tCONSTRAINT " . $this->db->escapeIdentifiers($name_index)
					. ' FOREIGN KEY(' . $this->db->escapeIdentifiers($field) . ') REFERENCES ' . $this->db->escapeIdentifiers($this->db->DBPrefix . $fkey['table']) . ' (' . $this->db->escapeIdentifiers($fkey['field']) . ')';

				if ($fkey['onDelete'] !== false && in_array($fkey['onDelete'], $allowActions))
				{
					$sql .= ' ON DELETE ' . $fkey['onDelete'];
				}

				if ($fkey['onUpdate'] !== false && in_array($fkey['onUpdate'], $allowActions))
				{
					$sql .= ' ON UPDATE ' . $fkey['onUpdate'];
				}
			}
		}

		return $sql;
	}

protected
function
_processForeignKeys
(
string
$
table
)
:
string
{
$
sql
=
''
;
$
allowActions
=
[
'CASCADE'
,
'SET NULL'
,
'NO ACTION'
,
'RESTRICT'
,
'SET DEFAULT'
,
]
;
if
(
count
(
$
this
->
foreignKeys
)
>
0
)
{
foreach
(
$
this
->
foreignKeys
as
$
field
=>
$
fkey
)
{
$
name_index
=
$
table
.
'_'
.
$
field
.
'_foreign'
;
$
sql
.=
",\n\tCONSTRAINT "
.
$
this
->
db
->
escapeIdentifiers
(
$
name_index
)
.
' FOREIGN KEY('
.
$
this
->
db
->
escapeIdentifiers
(
$
field
)
.
') REFERENCES '
.
$
this
->
db
->
escapeIdentifiers
(
$
this
->
db
->
DBPrefix
.
$
fkey
[
'table'
]
)
.
' ('
.
$
this
->
db
->
escapeIdentifiers
(
$
fkey
[
'field'
]
)
.
')'
;
if
(
$
fkey
[
'onDelete'
]
!==
false
&&
in_array
(
$
fkey
[
'onDelete'
]
,
$
allowActions
)
)
{
$
sql
.=
' ON DELETE '
.
$
fkey
[
'onDelete'
]
;
}
if
(
$
fkey
[
'onUpdate'
]
!==
false
&&
in_array
(
$
fkey
[
'onUpdate'
]
,
$
allowActions
)
)
{
$
sql
.=
' ON UPDATE '
.
$
fkey
[
'onUpdate'
]
;
}
}
}
return
$
sql
;
}

Process foreign keys

@param string $table Table name

@return string


public function setLocale(string $locale = null)
	{
		if (! is_null($locale))
		{
			$this->locale = $locale;
		}

		return $this;
	}

public function setLocale ( string $ locale = null ) { if ( ! is_null ( $ locale ) ) { $ this -> locale = $ locale ; } return $ this ; }

Sets the current locale to use when performing string lookups.

@param string $locale

@return $this

Sets the current locale to use when performing string lookups .


public function getLine(string $line, array $args = [])
	{
		// ignore requests with no file specified
		if (! strpos($line, '.'))
		{
			return $line;
		}

		// Parse out the file name and the actual alias.
		// Will load the language file and strings.
		[
			$file,
			$parsedLine,
		] = $this->parseLine($line, $this->locale);

		$output = $this->language[$this->locale][$file][$parsedLine] ?? null;

		if ($output === null && strpos($this->locale, '-'))
		{
			[$locale] = explode('-', $this->locale, 2);

			[
				$file,
				$parsedLine,
			] = $this->parseLine($line, $locale);

			$output = $this->language[$locale][$file][$parsedLine] ?? null;
		}

		// if still not found, try English
		if (empty($output))
		{
			$this->parseLine($line, 'en');
			$output = $this->language['en'][$file][$parsedLine] ?? null;
		}

		$output = $output ?? $line;

		if (! empty($args))
		{
			$output = $this->formatMessage($output, $args);
		}

		return $output;
	}

Parses the language string for a file, loads the file, if necessary,
getting the line.

@param string $line Line.
@param array  $args Arguments.

@return string|string[] Returns line.

Parses the language string for a file loads the file if necessary getting the line .


protected function formatMessage($message, array $args = [])
	{
		if (! $this->intlSupport || ! $args)
		{
			return $message;
		}

		if (is_array($message))
		{
			foreach ($message as $index => $value)
			{
				$message[$index] = $this->formatMessage($value, $args);
			}
			return $message;
		}

		return \MessageFormatter::formatMessage($this->locale, $message, $args);
	}

protected function formatMessage ( $ message , array $ args = [ ] ) { if ( ! $ this -> intlSupport || ! $ args ) { return $ message ; } if ( is_array ( $ message ) ) { foreach ( $ message as $ index => $ value ) { $ message [ $ index ] = $ this -> formatMessage ( $ value , $ args ) ; } return $ message ; } return \ MessageFormatter :: formatMessage ( $ this -> locale , $ message , $ args ) ; }

Advanced message formatting.

@param string|array $message Message.
@param array	       $args    Arguments.

@return string|array Returns formatted message.


protected function requireFile(string $path): array
	{
		$files   = Services::locator()->search($path);
		$strings = [];

		foreach ($files as $file)
		{
			// On some OS's we were seeing failures
			// on this command returning boolean instead
			// of array during testing, so we've removed
			// the require_once for now.
			if (is_file($file))
			{
				$strings[] = require $file;
			}
		}

		if (isset($strings[1]))
		{
			$strings = array_replace_recursive(...$strings);
		}
		elseif (isset($strings[0]))
		{
			$strings = $strings[0];
		}

		return $strings;
	}

A simple method for including files that can be
overridden during testing.

@param string $path

@return array

A simple method for including files that can be overridden during testing .


public function addBaseURI($uri, ?bool $explicitReporting = null)
	{
		$this->addOption($uri, 'baseURI', $explicitReporting ?? $this->reportOnly);

		return $this;
	}

public function addBaseURI ( $ uri , ? bool $ explicitReporting = null ) { $ this -> addOption ( $ uri , 'baseURI' , $ explicitReporting ?? $ this -> reportOnly ) ; return $ this ; }

Adds a new base_uri value. Can be either a URI class or a simple string.

base_uri restricts the URLs that can appear in a page’s <base> element.

@see http://www.w3.org/TR/CSP/#directive-base-uri

@param string|array $uri
@param boolean|null $explicitReporting

@return $this

Adds a new base_uri value . Can be either a URI class or a simple string .


public function addImageSrc($uri, ?bool $explicitReporting = null)
	{
		$this->addOption($uri, 'imageSrc', $explicitReporting ?? $this->reportOnly);

		return $this;
	}

public function addImageSrc ( $ uri , ? bool $ explicitReporting = null ) { $ this -> addOption ( $ uri , 'imageSrc' , $ explicitReporting ?? $ this -> reportOnly ) ; return $ this ; }

Adds a new valid endpoint for valid image sources. Can be either
a URI class or a simple string.

@see http://www.w3.org/TR/CSP/#directive-img-src

@param string|array $uri
@param boolean|null $explicitReporting

@return $this

Adds a new valid endpoint for valid image sources . Can be either a URI class or a simple string .


public function addMediaSrc($uri, ?bool $explicitReporting = null)
	{
		$this->addOption($uri, 'mediaSrc', $explicitReporting ?? $this->reportOnly);

		return $this;
	}

public function addMediaSrc ( $ uri , ? bool $ explicitReporting = null ) { $ this -> addOption ( $ uri , 'mediaSrc' , $ explicitReporting ?? $ this -> reportOnly ) ; return $ this ; }

Adds a new valid endpoint for valid video and audio. Can be either
a URI class or a simple string.

@see http://www.w3.org/TR/CSP/#directive-media-src

@param string|array $uri
@param boolean|null $explicitReporting

@return $this

Adds a new valid endpoint for valid video and audio . Can be either a URI class or a simple string .


public function addManifestSrc($uri, ?bool $explicitReporting = null)
	{
		$this->addOption($uri, 'manifestSrc', $explicitReporting ?? $this->reportOnly);

		return $this;
	}

public function addManifestSrc ( $ uri , ? bool $ explicitReporting = null ) { $ this -> addOption ( $ uri , 'manifestSrc' , $ explicitReporting ?? $ this -> reportOnly ) ; return $ this ; }

Adds a new valid endpoint for manifest sources. Can be either
a URI class or simple string.

@see https://www.w3.org/TR/CSP/#directive-manifest-src

@param string|array $uri
@param boolean|null $explicitReporting

@return $this

Adds a new valid endpoint for manifest sources . Can be either a URI class or simple string .


public function addObjectSrc($uri, ?bool $explicitReporting = null)
	{
		$this->addOption($uri, 'objectSrc', $explicitReporting ?? $this->reportOnly);

		return $this;
	}

public function addObjectSrc ( $ uri , ? bool $ explicitReporting = null ) { $ this -> addOption ( $ uri , 'objectSrc' , $ explicitReporting ?? $ this -> reportOnly ) ; return $ this ; }

Adds a new valid endpoint for Flash and other plugin sources. Can be either
a URI class or a simple string.

@see http://www.w3.org/TR/CSP/#directive-object-src

@param string|array $uri
@param boolean|null $explicitReporting

@return $this

Adds a new valid endpoint for Flash and other plugin sources . Can be either a URI class or a simple string .


public function addPluginType($mime, ?bool $explicitReporting = null)
	{
		$this->addOption($mime, 'pluginTypes', $explicitReporting ?? $this->reportOnly);

		return $this;
	}

public function addPluginType ( $ mime , ? bool $ explicitReporting = null ) { $ this -> addOption ( $ mime , 'pluginTypes' , $ explicitReporting ?? $ this -> reportOnly ) ; return $ this ; }

Limits the types of plugins that can be used. Can be either
a URI class or a simple string.

@see http://www.w3.org/TR/CSP/#directive-plugin-types

@param string|array $mime              One or more plugin mime types, separate by spaces
@param boolean|null $explicitReporting

@return $this

Limits the types of plugins that can be used . Can be either a URI class or a simple string .


public function addSandbox($flags, ?bool $explicitReporting = null)
	{
		$this->addOption($flags, 'sandbox', $explicitReporting ?? $this->reportOnly);
		return $this;
	}

public function addSandbox ( $ flags , ? bool $ explicitReporting = null ) { $ this -> addOption ( $ flags , 'sandbox' , $ explicitReporting ?? $ this -> reportOnly ) ; return $ this ; }

specifies an HTML sandbox policy that the user agent applies to
the protected resource.

@see http://www.w3.org/TR/CSP/#directive-sandbox

@param string|array $flags             An array of sandbox flags that can be added to the directive.
@param boolean|null $explicitReporting

@return $this

specifies an HTML sandbox policy that the user agent applies to the protected resource .


public function addScriptSrc($uri, ?bool $explicitReporting = null)
	{
		$this->addOption($uri, 'scriptSrc', $explicitReporting ?? $this->reportOnly);

		return $this;
	}

public function addScriptSrc ( $ uri , ? bool $ explicitReporting = null ) { $ this -> addOption ( $ uri , 'scriptSrc' , $ explicitReporting ?? $ this -> reportOnly ) ; return $ this ; }

Adds a new valid endpoint for javascript file sources. Can be either
a URI class or a simple string.

@see http://www.w3.org/TR/CSP/#directive-connect-src

@param string|array $uri
@param boolean|null $explicitReporting

@return $this

Adds a new valid endpoint for javascript file sources . Can be either a URI class or a simple string .


public function addStyleSrc($uri, ?bool $explicitReporting = null)
	{
		$this->addOption($uri, 'styleSrc', $explicitReporting ?? $this->reportOnly);

		return $this;
	}

public function addStyleSrc ( $ uri , ? bool $ explicitReporting = null ) { $ this -> addOption ( $ uri , 'styleSrc' , $ explicitReporting ?? $ this -> reportOnly ) ; return $ this ; }

Adds a new valid endpoint for CSS file sources. Can be either
a URI class or a simple string.

@see http://www.w3.org/TR/CSP/#directive-connect-src

@param string|array $uri
@param boolean|null $explicitReporting

@return $this

Adds a new valid endpoint for CSS file sources . Can be either a URI class or a simple string .


protected function addOption($options, string $target, ?bool $explicitReporting = null)
	{
		// Ensure we have an array to work with...
		if (is_string($this->{$target}))
		{
			$this->{$target} = [$this->{$target}];
		}

		if (is_array($options))
		{
			foreach ($options as $opt)
			{
				$this->{$target}[$opt] = $explicitReporting ?? $this->reportOnly;
			}
		}
		else
		{
			$this->{$target}[$options] = $explicitReporting ?? $this->reportOnly;
		}
	}

DRY method to add an string or array to a class property.

@param string|array $options
@param string       $target
@param boolean|null $explicitReporting

DRY method to add an string or array to a class property .


protected function generateNonces(ResponseInterface &$response)
	{
		$body = $response->getBody();

		if (empty($body))
		{
			return;
		}

		if (! is_array($this->styleSrc))
		{
			$this->styleSrc = [$this->styleSrc];
		}
		if (! is_array($this->scriptSrc))
		{
			$this->scriptSrc = [$this->scriptSrc];
		}

		// Replace style placeholders with nonces
		$body = preg_replace_callback(
				'/{csp-style-nonce}/', function ($matches) {
					$nonce = bin2hex(random_bytes(12));

					$this->styleSrc[] = 'nonce-' . $nonce;

					return "nonce=\"{$nonce}\"";
				}, $body
		);

		// Replace script placeholders with nonces
		$body = preg_replace_callback(
				'/{csp-script-nonce}/', function ($matches) {
					$nonce = bin2hex(random_bytes(12));

					$this->scriptSrc[] = 'nonce-' . $nonce;

					return "nonce=\"{$nonce}\"";
				}, $body
		);

		$response->setBody($body);
	}

Scans the body of the request message and replaces any nonce
placeholders with actual nonces, that we'll then add to our
headers.

@param ResponseInterface|\CodeIgniter\HTTP\Response $response

Scans the body of the request message and replaces any nonce placeholders with actual nonces that we ll then add to our headers .


protected function buildHeaders(ResponseInterface &$response)
	{
		// Ensure both headers are available and arrays...
		$response->setHeader('Content-Security-Policy', []);
		$response->setHeader('Content-Security-Policy-Report-Only', []);

		$directives = [
			'base-uri'        => 'baseURI',
			'child-src'       => 'childSrc',
			'connect-src'     => 'connectSrc',
			'default-src'     => 'defaultSrc',
			'font-src'        => 'fontSrc',
			'form-action'     => 'formAction',
			'frame-ancestors' => 'frameAncestors',
			'img-src'         => 'imageSrc',
			'media-src'       => 'mediaSrc',
			'object-src'      => 'objectSrc',
			'plugin-types'    => 'pluginTypes',
			'script-src'      => 'scriptSrc',
			'style-src'       => 'styleSrc',
			'manifest-src'    => 'manifestSrc',
			'sandbox'         => 'sandbox',
			'report-uri'      => 'reportURI',
		];

		// inject default base & default URIs if needed
		if (empty($this->baseURI))
		{
			$this->baseURI = 'self';
		}
		if (empty($this->defaultSrc))
		{
			$this->defaultSrc = 'self';
		}

		foreach ($directives as $name => $property)
		{
			// base_uri
			if (! empty($this->{$property}))
			{
				$this->addToHeader($name, $this->{$property});
			}
		}

		// Compile our own header strings here since if we just
		// append it to the response, it will be joined with
		// commas, not semi-colons as we need.
		if (! empty($this->tempHeaders))
		{
			$header = '';
			foreach ($this->tempHeaders as $name => $value)
			{
				$header .= " {$name} {$value};";
			}
			// add token only if needed
			if ($this->upgradeInsecureRequests)
			{
				$header .= ' upgrade-insecure-requests;';
			}

			$response->appendHeader('Content-Security-Policy', $header);
		}

		if (! empty($this->reportOnlyHeaders))
		{
			$header = '';
			foreach ($this->reportOnlyHeaders as $name => $value)
			{
				$header .= " {$name} {$value};";
			}
			$response->appendHeader('Content-Security-Policy-Report-Only', $header);
		}

		$this->tempHeaders       = [];
		$this->reportOnlyHeaders = [];
	}

Based on the current state of the elements, will add the appropriate
Content-Security-Policy and Content-Security-Policy-Report-Only headers
with their values to the response object.

@param ResponseInterface|\CodeIgniter\HTTP\Response $response

Based on the current state of the elements will add the appropriate Content - Security - Policy and Content - Security - Policy - Report - Only headers with their values to the response object .


public function getTitle(bool $safe = false): string
	{
		if ($safe)
		{
			return str_replace(' ', '-', strtolower($this->title));
		}

		return $this->title;
	}

public
function
getTitle
(
bool
$
safe
=
false
)
:
string
{
if
(
$
safe
)
{
return
str_replace
(
' '
,
'-'
,
strtolower
(
$
this
->
title
)
)
;
}
return
$
this
->
title
;
}

Gets the Collector's title.

@param  boolean $safe
@return string


protected function collectLogs()
	{
		if (! is_null($this->data))
		{
			return $this->data;
		}

		return $this->data = Services::logger(true)->logCache ?? [];
	}

protected function collectLogs ( ) { if ( ! is_null ( $ this -> data ) ) { return $ this -> data ; } return $ this -> data = Services :: logger ( true ) -> logCache ?? [ ] ; }


public function prepareParams($params)
	{
		if (empty($params) || ( ! is_string($params) && ! is_array($params)))
		{
			return [];
		}

		if (is_string($params))
		{
			$new_params = [];
			$separator  = ' ';

			if (strpos($params, ',') !== false)
			{
				$separator = ',';
			}

			$params = explode($separator, $params);
			unset($separator);

			foreach ($params as $p)
			{
				if (! empty($p))
				{
					list($key, $val)        = explode('=', $p);
					$new_params[trim($key)] = trim($val, ', ');
				}
			}

			$params = $new_params;

			unset($new_params);
		}

		if (is_array($params) && empty($params))
		{
			return [];
		}

		return $params;
	}

public
function
prepareParams
(
$
params
)
{
if
(
empty
(
$
params
)
||
(
!
is_string
(
$
params
)
&&
!
is_array
(
$
params
)
)
)
{
return
[
]
;
}
if
(
is_string
(
$
params
)
)
{
$
new_params
=
[
]
;
$
separator
=
' '
;
if
(
strpos
(
$
params
,
','
)
!==
false
)
{
$
separator
=
','
;
}
$
params
=
explode
(
$
separator
,
$
params
)
;
unset
(
$
separator
)
;
foreach
(
$
params
as
$
p
)
{
if
(
!
empty
(
$
p
)
)
{
list
(
$
key
,
$
val
)
=
explode
(
'='
,
$
p
)
;
$
new_params
[
trim
(
$
key
)
]
=
trim
(
$
val
,
', '
)
;
}
}
$
params
=
$
new_params
;
unset
(
$
new_params
)
;
}
if
(
is_array
(
$
params
)
&&
empty
(
$
params
)
)
{
return
[
]
;
}
return
$
params
;
}

Parses the params attribute. If an array, returns untouched.
If a string, it should be in the format "key1=value key2=value".
It will be split and returned as an array.

@param $params

@return array|null

Parses the params attribute . If an array returns untouched . If a string it should be in the format key1 = value key2 = value . It will be split and returned as an array .


protected function determineClass(string $library): array
	{
		// We don't want to actually call static methods
		// by default, so convert any double colons.
		$library = str_replace('::', ':', $library);

		list($class, $method) = explode(':', $library);

		if (empty($class))
		{
			throw ViewException::forNoCellClass();
		}

		if (! class_exists($class, true))
		{
			throw ViewException::forInvalidCellClass($class);
		}

		if (empty($method))
		{
			$method = 'index';
		}

		return [
			$class,
			$method,
		];
	}

Given the library string, attempts to determine the class and method
to call.

@param string $library

@return array

Given the library string attempts to determine the class and method to call .


public function getResult(string $type = 'object'): array
	{
		if ($type === 'array')
		{
			return $this->getResultArray();
		}
		elseif ($type === 'object')
		{
			return $this->getResultObject();
		}

		return $this->getCustomResultObject($type);
	}

public function getResult ( string $ type = 'object' ) : array { if ( $ type === 'array' ) { return $ this -> getResultArray ( ) ; } elseif ( $ type === 'object' ) { return $ this -> getResultObject ( ) ; } return $ this -> getCustomResultObject ( $ type ) ; }

Retrieve the results of the query. Typically an array of
individual data rows, which can be either an 'array', an
'object', or a custom class name.

@param string $type The row type. Either 'array', 'object', or a class name to use

@return array

Retrieve the results of the query . Typically an array of individual data rows which can be either an array an object or a custom class name .


public function getCustomResultObject(string $className)
	{
		if (isset($this->customResultObject[$className]))
		{
			return $this->customResultObject[$className];
		}

		if (is_bool($this->resultID) || ! $this->resultID || $this->numRows === 0)
		{
			return [];
		}

		// Don't fetch the result set again if we already have it
		$_data = null;
		if (($c = count($this->resultArray)) > 0)
		{
			$_data = 'result_array';
		}
		elseif (($c = count($this->resultObject)) > 0)
		{
			$_data = 'result_object';
		}

		if ($_data !== null)
		{
			for ($i = 0; $i < $c; $i ++)
			{
				$this->customResultObject[$className][$i] = new $className();

				foreach ($this->{$_data}[$i] as $key => $value)
				{
					$this->customResultObject[$className][$i]->$key = $value;
				}
			}

			return $this->customResultObject[$className];
		}

		is_null($this->rowData) || $this->dataSeek(0);
		$this->customResultObject[$className] = [];

		while ($row = $this->fetchObject($className))
		{
			$this->customResultObject[$className][] = $row;
		}

		return $this->customResultObject[$className];
	}

Returns the results as an array of custom objects.

@param string $className The name of the class to use.

@return mixed

Returns the results as an array of custom objects .


public function getResultArray(): array
	{
		if (! empty($this->resultArray))
		{
			return $this->resultArray;
		}

		// In the event that query caching is on, the result_id variable
		// will not be a valid resource so we'll simply return an empty
		// array.
		if (is_bool($this->resultID) || ! $this->resultID || $this->numRows === 0)
		{
			return [];
		}

		if ($this->resultObject)
		{
			foreach ($this->resultObject as $row)
			{
				$this->resultArray[] = (array) $row;
			}

			return $this->resultArray;
		}

		is_null($this->rowData) || $this->dataSeek(0);
		while ($row = $this->fetchAssoc())
		{
			$this->resultArray[] = $row;
		}

		return $this->resultArray;
	}

Returns the results as an array of arrays.

If no results, an empty array is returned.

@return array

Returns the results as an array of arrays .


public function getResultObject(): array
	{
		if (! empty($this->resultObject))
		{
			return $this->resultObject;
		}

		// In the event that query caching is on, the result_id variable
		// will not be a valid resource so we'll simply return an empty
		// array.
		if (is_bool($this->resultID) || ! $this->resultID || $this->numRows === 0)
		{
			return [];
		}

		if ($this->resultArray)
		{
			foreach ($this->resultArray as $row)
			{
				$this->resultObject[] = (object) $row;
			}

			return $this->resultObject;
		}

		is_null($this->rowData) || $this->dataSeek(0);
		while ($row = $this->fetchObject())
		{
			$this->resultObject[] = $row;
		}

		return $this->resultObject;
	}

Returns the results as an array of objects.

If no results, an empty array is returned.

@return array

Returns the results as an array of objects .


public function getRow($n = 0, string $type = 'object')
	{
		if (! is_numeric($n))
		{
			// We cache the row data for subsequent uses
			is_array($this->rowData) || $this->rowData = $this->getRowArray(0);

			// array_key_exists() instead of isset() to allow for NULL values
			if (empty($this->rowData) || ! array_key_exists($n, $this->rowData))
			{
				return null;
			}

			return $this->rowData[$n];
		}

		if ($type === 'object')
		{
			return $this->getRowObject($n);
		}
		elseif ($type === 'array')
		{
			return $this->getRowArray($n);
		}

		return $this->getCustomRowObject($n, $type);
	}

Wrapper object to return a row as either an array, an object, or
a custom class.

If row doesn't exist, returns null.

@param mixed   $n    The index of the results to return
@param string  $type The type of result object. 'array', 'object' or class name.

@return mixed

Wrapper object to return a row as either an array an object or a custom class .


public function getCustomRowObject(int $n, string $className)
	{
		isset($this->customResultObject[$className]) || $this->getCustomResultObject($className);

		if (empty($this->customResultObject[$className]))
		{
			return null;
		}

		if ($n !== $this->currentRow && isset($this->customResultObject[$className][$n]))
		{
			$this->currentRow = $n;
		}

		return $this->customResultObject[$className][$this->currentRow];
	}

public function getCustomRowObject ( int $ n , string $ className ) { isset ( $ this -> customResultObject [ $ className ] ) || $ this -> getCustomResultObject ( $ className ) ; if ( empty ( $ this -> customResultObject [ $ className ] ) ) { return null ; } if ( $ n !== $ this -> currentRow && isset ( $ this -> customResultObject [ $ className ] [ $ n ] ) ) { $ this -> currentRow = $ n ; } return $ this -> customResultObject [ $ className ] [ $ this -> currentRow ] ; }

Returns a row as a custom class instance.

If row doesn't exists, returns null.

@param integer $n
@param string  $className

@return mixed

Returns a row as a custom class instance .


public function getRowArray(int $n = 0)
	{
		$result = $this->getResultArray();
		if (empty($result))
		{
			return null;
		}

		if ($n !== $this->currentRow && isset($result[$n]))
		{
			$this->currentRow = $n;
		}

		return $result[$this->currentRow];
	}

public function getRowArray ( int $ n = 0 ) { $ result = $ this -> getResultArray ( ) ; if ( empty ( $ result ) ) { return null ; } if ( $ n !== $ this -> currentRow && isset ( $ result [ $ n ] ) ) { $ this -> currentRow = $ n ; } return $ result [ $ this -> currentRow ] ; }

Returns a single row from the results as an array.

If row doesn't exist, returns null.

@param integer $n

@return mixed

Returns a single row from the results as an array .


public function getRowObject(int $n = 0)
	{
		$result = $this->getResultObject();
		if (empty($result))
		{
			return null;
		}

		if ($n !== $this->customResultObject && isset($result[$n]))
		{
			$this->currentRow = $n;
		}

		return $result[$this->currentRow];
	}

public function getRowObject ( int $ n = 0 ) { $ result = $ this -> getResultObject ( ) ; if ( empty ( $ result ) ) { return null ; } if ( $ n !== $ this -> customResultObject && isset ( $ result [ $ n ] ) ) { $ this -> currentRow = $ n ; } return $ result [ $ this -> currentRow ] ; }

Returns a single row from the results as an object.

If row doesn't exist, returns null.

@param integer $n

@return mixed

Returns a single row from the results as an object .


public function setRow($key, $value = null)
	{
		// We cache the row data for subsequent uses
		if (! is_array($this->rowData))
		{
			$this->rowData = $this->getRowArray(0);
		}

		if (is_array($key))
		{
			foreach ($key as $k => $v)
			{
				$this->rowData[$k] = $v;
			}

			return;
		}

		if ($key !== '' && $value !== null)
		{
			$this->rowData[$key] = $value;
		}
	}

Assigns an item into a particular column slot.

@param mixed $key
@param mixed $value

@return mixed

Assigns an item into a particular column slot .


public function getFirstRow(string $type = 'object')
	{
		$result = $this->getResult($type);

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

public function getFirstRow ( string $ type = 'object' ) { $ result = $ this -> getResult ( $ type ) ; return ( empty ( $ result ) ) ? null : $ result [ 0 ] ; }

Returns the "first" row of the current results.

@param string $type

@return mixed

Returns the first row of the current results .


public function getLastRow(string $type = 'object')
	{
		$result = $this->getResult($type);

		return (empty($result)) ? null : $result[count($result) - 1];
	}

public function getLastRow ( string $ type = 'object' ) { $ result = $ this -> getResult ( $ type ) ; return ( empty ( $ result ) ) ? null : $ result [ count ( $ result ) - 1 ] ; }

Returns the "last" row of the current results.

@param string $type

@return mixed

Returns the last row of the current results .


public function getNextRow(string $type = 'object')
	{
		$result = $this->getResult($type);
		if (empty($result))
		{
			return null;
		}

		return isset($result[$this->currentRow + 1]) ? $result[++ $this->currentRow] : null;
	}

public function getNextRow ( string $ type = 'object' ) { $ result = $ this -> getResult ( $ type ) ; if ( empty ( $ result ) ) { return null ; } return isset ( $ result [ $ this -> currentRow + 1 ] ) ? $ result [ ++ $ this -> currentRow ] : null ; }

Returns the "next" row of the current results.

@param string $type

@return mixed

Returns the next row of the current results .


public function getUnbufferedRow(string $type = 'object')
	{
		if ($type === 'array')
		{
			return $this->fetchAssoc();
		}
		elseif ($type === 'object')
		{
			return $this->fetchObject();
		}

		return $this->fetchObject($type);
	}

public function getUnbufferedRow ( string $ type = 'object' ) { if ( $ type === 'array' ) { return $ this -> fetchAssoc ( ) ; } elseif ( $ type === 'object' ) { return $ this -> fetchObject ( ) ; } return $ this -> fetchObject ( $ type ) ; }

Returns an unbuffered row and move the pointer to the next row.

@param string $type

@return mixed

Returns an unbuffered row and move the pointer to the next row .


protected function match(array $acceptable, string $supported, bool $enforceTypes = false): bool
	{
		$supported = $this->parseHeader($supported);
		if (is_array($supported) && count($supported) === 1)
		{
			$supported = $supported[0];
		}

		// Is it an exact match?
		if ($acceptable['value'] === $supported['value'])
		{
			return $this->matchParameters($acceptable, $supported);
		}

		// Do we need to compare types/sub-types? Only used
		// by negotiateMedia().
		if ($enforceTypes)
		{
			return $this->matchTypes($acceptable, $supported);
		}

		return false;
	}

Match-maker

@param  array   $acceptable
@param  string  $supported
@param  boolean $enforceTypes
@return boolean


protected function matchParameters(array $acceptable, array $supported): bool
	{
		if (count($acceptable['params']) !== count($supported['params']))
		{
			return false;
		}

		foreach ($supported['params'] as $label => $value)
		{
			if (! isset($acceptable['params'][$label]) ||
					$acceptable['params'][$label] !== $value)
			{
				return false;
			}
		}

		return true;
	}

protected function matchParameters ( array $ acceptable , array $ supported ) : bool { if ( count ( $ acceptable [ 'params' ] ) !== count ( $ supported [ 'params' ] ) ) { return false ; } foreach ( $ supported [ 'params' ] as $ label => $ value ) { if ( ! isset ( $ acceptable [ 'params' ] [ $ label ] ) || $ acceptable [ 'params' ] [ $ label ] !== $ value ) { return false ; } } return true ; }

Checks two Accept values with matching 'values' to see if their
'params' are the same.

@param array $acceptable
@param array $supported

@return boolean

Checks two Accept values with matching values to see if their params are the same .


public function run(bool $useSafeOutput = false)
	{
		$path = CLI::getURI() ?: 'list';

		// Set the path for the application to route to.
		$this->app->setPath("ci{$path}");

		return $this->app->useSafeOutput($useSafeOutput)->run();
	}

Runs the current command discovered on the CLI.

@param boolean $useSafeOutput

@return \CodeIgniter\HTTP\RequestInterface|\CodeIgniter\HTTP\Response|\CodeIgniter\HTTP\ResponseInterface|mixed
@throws \Exception

Runs the current command discovered on the CLI .


public function showHeader()
	{
		CLI::newLine(1);

		CLI::write(CLI::color('CodeIgniter CLI Tool', 'green')
				. ' - Version ' . CodeIgniter::CI_VERSION
				. ' - Server-Time: ' . date('Y-m-d H:i:sa'));

		CLI::newLine(1);
	}

public
function
showHeader
(
)
{
CLI
::
newLine
(
1
)
;
CLI
::
write
(
CLI
::
color
(
'CodeIgniter CLI Tool'
,
'green'
)
.
' - Version '
.
CodeIgniter
::
CI_VERSION
.
' - Server-Time: '
.
date
(
'Y-m-d H:i:sa'
)
)
;
CLI
::
newLine
(
1
)
;
}

Displays basic information about the Console.

Displays basic information about the Console .


public function links(string $group = 'default', string $template = 'default_full'): string
	{
		$this->ensureGroup($group);

		return $this->displayLinks($group, $template);
	}

public function links ( string $ group = 'default' , string $ template = 'default_full' ) : string { $ this -> ensureGroup ( $ group ) ; return $ this -> displayLinks ( $ group , $ template ) ; }

Handles creating and displaying the

@param string $group
@param string $template The output template alias to render.

@return string


public function makeLinks(int $page, int $perPage, int $total, string $template = 'default_full', int $segment = 0): string
	{
		$name = time();

		$this->store($name, $page, $perPage, $total, $segment);

		return $this->displayLinks($name, $template);
	}

public function makeLinks ( int $ page , int $ perPage , int $ total , string $ template = 'default_full' , int $ segment = 0 ) : string { $ name = time ( ) ; $ this -> store ( $ name , $ page , $ perPage , $ total , $ segment ) ; return $ this -> displayLinks ( $ name , $ template ) ; }

Allows for a simple, manual, form of pagination where all of the data
is provided by the user. The URL is the current URI.

@param integer $page
@param integer $perPage
@param integer $total
@param string  $template The output template alias to render.
@param integer $segment  (if page number is provided by URI segment)

@return string

Allows for a simple manual form of pagination where all of the data is provided by the user . The URL is the current URI .


public function store(string $group, int $page, int $perPage, int $total, int $segment = 0)
	{
		$this->segment[$group] = $segment;

		$this->ensureGroup($group);

		$this->groups[$group]['currentPage'] = $page;
		$this->groups[$group]['perPage']     = $perPage;
		$this->groups[$group]['total']       = $total;
		$this->groups[$group]['pageCount']   = (int)ceil($total / $perPage);

		return $this;
	}

public function store ( string $ group , int $ page , int $ perPage , int $ total , int $ segment = 0 ) { $ this -> segment [ $ group ] = $ segment ; $ this -> ensureGroup ( $ group ) ; $ this -> groups [ $ group ] [ 'currentPage' ] = $ page ; $ this -> groups [ $ group ] [ 'perPage' ] = $ perPage ; $ this -> groups [ $ group ] [ 'total' ] = $ total ; $ this -> groups [ $ group ] [ 'pageCount' ] = ( int ) ceil ( $ total / $ perPage ) ; return $ this ; }

Stores a set of pagination data for later display. Most commonly used
by the model to automate the process.

@param string  $group
@param integer $page
@param integer $perPage
@param integer $total
@param integer $segment

@return $this

Stores a set of pagination data for later display . Most commonly used by the model to automate the process .


public function setPath(string $path, string $group = 'default')
	{
		$this->ensureGroup($group);

		$this->groups[$group]['uri']->setPath($path);

		return $this;
	}

public function setPath ( string $ path , string $ group = 'default' ) { $ this -> ensureGroup ( $ group ) ; $ this -> groups [ $ group ] [ 'uri' ] -> setPath ( $ path ) ; return $ this ; }

Sets the path that an aliased group of links will use.

@param string $group
@param string $path

@return mixed

Sets the path that an aliased group of links will use .


public function getPageCount(string $group = 'default'): int
	{
		$this->ensureGroup($group);

		return $this->groups[$group]['pageCount'];
	}

public function getPageCount ( string $ group = 'default' ) : int { $ this -> ensureGroup ( $ group ) ; return $ this -> groups [ $ group ] [ 'pageCount' ] ; }

Returns the total number of pages.

@param string|null $group

@return integer


public function getCurrentPage(string $group = 'default'): int
	{
		$this->ensureGroup($group);

		return $this->groups[$group]['currentPage'];
	}

public function getCurrentPage ( string $ group = 'default' ) : int { $ this -> ensureGroup ( $ group ) ; return $ this -> groups [ $ group ] [ 'currentPage' ] ; }

Returns the number of the current page of results.

@param string|null $group

@return integer

Returns the number of the current page of results .


public function hasMore(string $group = 'default'): bool
	{
		$this->ensureGroup($group);

		return ($this->groups[$group]['currentPage'] * $this->groups[$group]['perPage']) < $this->groups[$group]['total'];
	}

public function hasMore ( string $ group = 'default' ) : bool { $ this -> ensureGroup ( $ group ) ; return ( $ this -> groups [ $ group ] [ 'currentPage' ] * $ this -> groups [ $ group ] [ 'perPage' ] ) < $ this -> groups [ $ group ] [ 'total' ] ; }

Tells whether this group of results has any more pages of results.

@param string|null $group

@return boolean

Tells whether this group of results has any more pages of results .


public function getLastPage(string $group = 'default')
	{
		$this->ensureGroup($group);

		if (! is_numeric($this->groups[$group]['total']) || ! is_numeric($this->groups[$group]['perPage']))
		{
			return null;
		}

		return (int)ceil($this->groups[$group]['total'] / $this->groups[$group]['perPage']);
	}

public function getLastPage ( string $ group = 'default' ) { $ this -> ensureGroup ( $ group ) ; if ( ! is_numeric ( $ this -> groups [ $ group ] [ 'total' ] ) || ! is_numeric ( $ this -> groups [ $ group ] [ 'perPage' ] ) ) { return null ; } return ( int ) ceil ( $ this -> groups [ $ group ] [ 'total' ] / $ this -> groups [ $ group ] [ 'perPage' ] ) ; }

Returns the last page, if we have a total that we can calculate with.

@param string $group

@return integer|null

Returns the last page if we have a total that we can calculate with .


public function getPageURI(int $page = null, string $group = 'default', bool $returnObject = false)
	{
		$this->ensureGroup($group);

		/**
		 * @var \CodeIgniter\HTTP\URI $uri
		 */
		$uri = $this->groups[$group]['uri'];

		$segment = $this->segment[$group] ?? 0;

		if ($segment)
		{
			$uri->setSegment($segment, $page);
		}
		else
		{
			$uri->addQuery('page', $page);
		}

		if ($this->only)
		{
			$query = array_intersect_key($_GET, array_flip($this->only));

			if (! $segment)
			{
				$query['page'] = $page;
			}

			$uri->setQueryArray($query);
		}

		return $returnObject === true ? $uri : (string) $uri;
	}

Returns the URI for a specific page for the specified group.

@param integer|null $page
@param string       $group
@param boolean      $returnObject

@return string|\CodeIgniter\HTTP\URI

Returns the URI for a specific page for the specified group .


public function getNextPageURI(string $group = 'default', bool $returnObject = false)
	{
		$this->ensureGroup($group);

		$last = $this->getLastPage($group);
		$curr = $this->getCurrentPage($group);
		$page = null;

		if (! empty($last) && ! empty($curr) && $last === $curr)
		{
			return null;
		}

		if ($last > $curr)
		{
			$page = $curr + 1;
		}

		return $this->getPageURI($page, $group, $returnObject);
	}

public function getNextPageURI ( string $ group = 'default' , bool $ returnObject = false ) { $ this -> ensureGroup ( $ group ) ; $ last = $ this -> getLastPage ( $ group ) ; $ curr = $ this -> getCurrentPage ( $ group ) ; $ page = null ; if ( ! empty ( $ last ) && ! empty ( $ curr ) && $ last === $ curr ) { return null ; } if ( $ last > $ curr ) { $ page = $ curr + 1 ; } return $ this -> getPageURI ( $ page , $ group , $ returnObject ) ; }

Returns the full URI to the next page of results, or null.

@param string  $group
@param boolean $returnObject

@return string|null

Returns the full URI to the next page of results or null .


public function getPreviousPageURI(string $group = 'default', bool $returnObject = false)
	{
		$this->ensureGroup($group);

		$first = $this->getFirstPage($group);
		$curr  = $this->getCurrentPage($group);
		$page  = null;

		if (! empty($first) && ! empty($curr) && $first === $curr)
		{
			return null;
		}

		if ($first < $curr)
		{
			$page = $curr - 1;
		}

		return $this->getPageURI($page, $group, $returnObject);
	}

public function getPreviousPageURI ( string $ group = 'default' , bool $ returnObject = false ) { $ this -> ensureGroup ( $ group ) ; $ first = $ this -> getFirstPage ( $ group ) ; $ curr = $ this -> getCurrentPage ( $ group ) ; $ page = null ; if ( ! empty ( $ first ) && ! empty ( $ curr ) && $ first === $ curr ) { return null ; } if ( $ first < $ curr ) { $ page = $ curr - 1 ; } return $ this -> getPageURI ( $ page , $ group , $ returnObject ) ; }

Returns the full URL to the previous page of results, or null.

@param string  $group
@param boolean $returnObject

@return string|null

Returns the full URL to the previous page of results or null .


public function getPerPage(string $group = 'default'): int
	{
		$this->ensureGroup($group);

		return (int) $this->groups[$group]['perPage'];
	}

public function getPerPage ( string $ group = 'default' ) : int { $ this -> ensureGroup ( $ group ) ; return ( int ) $ this -> groups [ $ group ] [ 'perPage' ] ; }

Returns the number of results per page that should be shown.

@param string $group

@return integer

Returns the number of results per page that should be shown .


public function getDetails(string $group = 'default'): array
	{
		if (! array_key_exists($group, $this->groups))
		{
			throw PagerException::forInvalidPaginationGroup($group);
		}

		$newGroup = $this->groups[$group];

		$newGroup['next']     = $this->getNextPageURI($group);
		$newGroup['previous'] = $this->getPreviousPageURI($group);
		$newGroup['segment']  = $this->segment[$group] ?? 0;

		return $newGroup;
	}

public function getDetails ( string $ group = 'default' ) : array { if ( ! array_key_exists ( $ group , $ this -> groups ) ) { throw PagerException :: forInvalidPaginationGroup ( $ group ) ; } $ newGroup = $ this -> groups [ $ group ] ; $ newGroup [ 'next' ] = $ this -> getNextPageURI ( $ group ) ; $ newGroup [ 'previous' ] = $ this -> getPreviousPageURI ( $ group ) ; $ newGroup [ 'segment' ] = $ this -> segment [ $ group ] ?? 0 ; return $ newGroup ; }

Returns an array with details about the results, including
total, per_page, current_page, last_page, next_url, prev_url, from, to.
Does not include the actual data. This data is suitable for adding
a 'data' object to with the result set and converting to JSON.

@param string $group

@return array

Returns an array with details about the results including total per_page current_page last_page next_url prev_url from to . Does not include the actual data . This data is suitable for adding a data object to with the result set and converting to JSON .


protected function ensureGroup(string $group)
	{
		if (array_key_exists($group, $this->groups))
		{
			return;
		}

		$this->groups[$group] = [
			'uri'       => clone Services::request()->uri,
			'hasMore'   => false,
			'total'     => null,
			'perPage'   => $this->config->perPage,
			'pageCount' => 1,
		];

		if (array_key_exists($group, $this->segment))
		{
			try
			{
				$this->groups[$group]['currentPage'] = $this->groups[$group]['uri']->getSegment($this->segment[$group]);
			}
			catch (\CodeIgniter\HTTP\Exceptions\HTTPException $e)
			{
				$this->groups[$group]['currentPage'] = 1;
			}
		}
		else
		{
			$this->groups[$group]['currentPage'] = $_GET['page_' . $group] ?? $_GET['page'] ?? 1;
		}

		if ($_GET)
		{
			$this->groups[$group]['uri'] = $this->groups[$group]['uri']->setQueryArray($_GET);
		}
	}

protected function ensureGroup ( string $ group ) { if ( array_key_exists ( $ group , $ this -> groups ) ) { return ; } $ this -> groups [ $ group ] = [ 'uri' => clone Services :: request ( ) -> uri , 'hasMore' => false , 'total' => null , 'perPage' => $ this -> config -> perPage , 'pageCount' => 1 , ] ; if ( array_key_exists ( $ group , $ this -> segment ) ) { try { $ this -> groups [ $ group ] [ 'currentPage' ] = $ this -> groups [ $ group ] [ 'uri' ] -> getSegment ( $ this -> segment [ $ group ] ) ; } catch ( \ CodeIgniter \ HTTP \ Exceptions \ HTTPException $ e ) { $ this -> groups [ $ group ] [ 'currentPage' ] = 1 ; } } else { $ this -> groups [ $ group ] [ 'currentPage' ] = $ _GET [ 'page_' . $ group ] ?? $ _GET [ 'page' ] ?? 1 ; } if ( $ _GET ) { $ this -> groups [ $ group ] [ 'uri' ] = $ this -> groups [ $ group ] [ 'uri' ] -> setQueryArray ( $ _GET ) ; } }

Ensures that an array exists for the group specified.

@param string $group

Ensures that an array exists for the group specified .


public function getYears(bool $raw = false)
	{
		if ($raw)
		{
			return $this->difference / YEAR;
		}

		$time = clone($this->currentTime);
		return $time->fieldDifference($this->testTime, IntlCalendar::FIELD_YEAR);
	}

public function getYears ( bool $ raw = false ) { if ( $ raw ) { return $ this -> difference / YEAR ; } $ time = clone ( $ this -> currentTime ) ; return $ time -> fieldDifference ( $ this -> testTime , IntlCalendar :: FIELD_YEAR ) ; }

Returns the number of years of difference between the two.

@param boolean $raw

@return float|integer

Returns the number of years of difference between the two .


public function getMonths(bool $raw = false)
	{
		if ($raw)
		{
			return $this->difference / MONTH;
		}

		$time = clone($this->currentTime);
		return $time->fieldDifference($this->testTime, IntlCalendar::FIELD_MONTH);
	}

public function getMonths ( bool $ raw = false ) { if ( $ raw ) { return $ this -> difference / MONTH ; } $ time = clone ( $ this -> currentTime ) ; return $ time -> fieldDifference ( $ this -> testTime , IntlCalendar :: FIELD_MONTH ) ; }

Returns the number of months difference between the two dates.

@param boolean $raw

@return float|integer

Returns the number of months difference between the two dates .


public function getWeeks(bool $raw = false)
	{
		if ($raw)
		{
			return $this->difference / WEEK;
		}

		$time = clone($this->currentTime);
		return (int)($time->fieldDifference($this->testTime, IntlCalendar::FIELD_DAY_OF_YEAR) / 7);
	}

public function getWeeks ( bool $ raw = false ) { if ( $ raw ) { return $ this -> difference / WEEK ; } $ time = clone ( $ this -> currentTime ) ; return ( int ) ( $ time -> fieldDifference ( $ this -> testTime , IntlCalendar :: FIELD_DAY_OF_YEAR ) / 7 ) ; }

Returns the number of weeks difference between the two dates.

@param boolean $raw

@return float|integer

Returns the number of weeks difference between the two dates .


public function getDays(bool $raw = false)
	{
		if ($raw)
		{
			return $this->difference / DAY;
		}

		$time = clone($this->currentTime);
		return $time->fieldDifference($this->testTime, IntlCalendar::FIELD_DAY_OF_YEAR);
	}

public function getDays ( bool $ raw = false ) { if ( $ raw ) { return $ this -> difference / DAY ; } $ time = clone ( $ this -> currentTime ) ; return $ time -> fieldDifference ( $ this -> testTime , IntlCalendar :: FIELD_DAY_OF_YEAR ) ; }

Returns the number of days difference between the two dates.

@param boolean $raw

@return float|integer

Returns the number of days difference between the two dates .


public function getHours(bool $raw = false)
	{
		if ($raw)
		{
			return $this->difference / HOUR;
		}

		$time = clone($this->currentTime);
		return $time->fieldDifference($this->testTime, IntlCalendar::FIELD_HOUR_OF_DAY);
	}

public function getHours ( bool $ raw = false ) { if ( $ raw ) { return $ this -> difference / HOUR ; } $ time = clone ( $ this -> currentTime ) ; return $ time -> fieldDifference ( $ this -> testTime , IntlCalendar :: FIELD_HOUR_OF_DAY ) ; }

Returns the number of hours difference between the two dates.

@param boolean $raw

@return float|integer

Returns the number of hours difference between the two dates .


public function getMinutes(bool $raw = false)
	{
		if ($raw)
		{
			return $this->difference / MINUTE;
		}

		$time = clone($this->currentTime);
		return $time->fieldDifference($this->testTime, IntlCalendar::FIELD_MINUTE);
	}

public function getMinutes ( bool $ raw = false ) { if ( $ raw ) { return $ this -> difference / MINUTE ; } $ time = clone ( $ this -> currentTime ) ; return $ time -> fieldDifference ( $ this -> testTime , IntlCalendar :: FIELD_MINUTE ) ; }

Returns the number of minutes difference between the two dates.

@param boolean $raw

@return float|integer

Returns the number of minutes difference between the two dates .


public function getSeconds(bool $raw = false)
	{
		if ($raw)
		{
			return $this->difference;
		}

		$time = clone($this->currentTime);
		return $time->fieldDifference($this->testTime, IntlCalendar::FIELD_SECOND);
	}

public function getSeconds ( bool $ raw = false ) { if ( $ raw ) { return $ this -> difference ; } $ time = clone ( $ this -> currentTime ) ; return $ time -> fieldDifference ( $ this -> testTime , IntlCalendar :: FIELD_SECOND ) ; }

Returns the number of seconds difference between the two dates.

@param boolean $raw

@return integer

Returns the number of seconds difference between the two dates .


public function humanize(string $locale = null): string
	{
		$current = clone($this->currentTime);

		$years   = $current->fieldDifference($this->testTime, IntlCalendar::FIELD_YEAR);
		$months  = $current->fieldDifference($this->testTime, IntlCalendar::FIELD_MONTH);
		$days    = $current->fieldDifference($this->testTime, IntlCalendar::FIELD_DAY_OF_YEAR);
		$hours   = $current->fieldDifference($this->testTime, IntlCalendar::FIELD_HOUR_OF_DAY);
		$minutes = $current->fieldDifference($this->testTime, IntlCalendar::FIELD_MINUTE);

		$phrase = null;

		if ($years !== 0)
		{
			$phrase = lang('Time.years', [abs($years)], $locale);
			$before = $years < 0;
		}
		else if ($months !== 0)
		{
			$phrase = lang('Time.months', [abs($months)], $locale);
			$before = $months < 0;
		}
		else if ($days !== 0 && (abs($days) >= 7))
		{
			$weeks  = ceil($days / 7);
			$phrase = lang('Time.weeks', [abs($weeks)], $locale);
			$before = $days < 0;
		}
		else if ($days !== 0)
		{
			$phrase = lang('Time.days', [abs($days)], $locale);
			$before = $days < 0;
		}
		else if ($hours !== 0)
		{
			$phrase = lang('Time.hours', [abs($hours)], $locale);
			$before = $hours < 0;
		}
		else if ($minutes !== 0)
		{
			$phrase = lang('Time.minutes', [abs($minutes)], $locale);
			$before = $minutes < 0;
		}
		else
		{
			return lang('Time.now', [], $locale);
		}

		return $before
			? lang('Time.ago', [$phrase], $locale)
			: lang('Time.inFuture', [$phrase], $locale);
	}

public function humanize ( string $ locale = null ) : string { $ current = clone ( $ this -> currentTime ) ; $ years = $ current -> fieldDifference ( $ this -> testTime , IntlCalendar :: FIELD_YEAR ) ; $ months = $ current -> fieldDifference ( $ this -> testTime , IntlCalendar :: FIELD_MONTH ) ; $ days = $ current -> fieldDifference ( $ this -> testTime , IntlCalendar :: FIELD_DAY_OF_YEAR ) ; $ hours = $ current -> fieldDifference ( $ this -> testTime , IntlCalendar :: FIELD_HOUR_OF_DAY ) ; $ minutes = $ current -> fieldDifference ( $ this -> testTime , IntlCalendar :: FIELD_MINUTE ) ; $ phrase = null ; if ( $ years !== 0 ) { $ phrase = lang ( 'Time.years' , [ abs ( $ years ) ] , $ locale ) ; $ before = $ years < 0 ; } else if ( $ months !== 0 ) { $ phrase = lang ( 'Time.months' , [ abs ( $ months ) ] , $ locale ) ; $ before = $ months < 0 ; } else if ( $ days !== 0 && ( abs ( $ days ) >= 7 ) ) { $ weeks = ceil ( $ days / 7 ) ; $ phrase = lang ( 'Time.weeks' , [ abs ( $ weeks ) ] , $ locale ) ; $ before = $ days < 0 ; } else if ( $ days !== 0 ) { $ phrase = lang ( 'Time.days' , [ abs ( $ days ) ] , $ locale ) ; $ before = $ days < 0 ; } else if ( $ hours !== 0 ) { $ phrase = lang ( 'Time.hours' , [ abs ( $ hours ) ] , $ locale ) ; $ before = $ hours < 0 ; } else if ( $ minutes !== 0 ) { $ phrase = lang ( 'Time.minutes' , [ abs ( $ minutes ) ] , $ locale ) ; $ before = $ minutes < 0 ; } else { return lang ( 'Time.now' , [ ] , $ locale ) ; } return $ before ? lang ( 'Time.ago' , [ $ phrase ] , $ locale ) : lang ( 'Time.inFuture' , [ $ phrase ] , $ locale ) ; }

Convert the time to human readable format

@param string|null $locale

@return string


public function load(array $params = [], string $alias)
	{
		// No DB specified? Beat them senseless...
		if (empty($params['DBDriver']))
		{
			throw new \InvalidArgumentException('You have not selected a database type to connect to.');
		}

		$className = strpos($params['DBDriver'], '\\') === false
			? '\CodeIgniter\Database\\' . $params['DBDriver'] . '\\Connection'
			: $params['DBDriver'] . '\\Connection';

		$class = new $className($params);

		// Store the connection
		$this->connections[$alias] = $class;

		return $this->connections[$alias];
	}

Parses the connection binds and returns an instance of
the driver ready to go.

@param array  $params
@param string $alias

@return   mixed
@internal param bool $useBuilder

Parses the connection binds and returns an instance of the driver ready to go .


public function loadForge(ConnectionInterface $db)
	{
		$className = strpos($db->DBDriver, '\\') === false ? '\CodeIgniter\Database\\' . $db->DBDriver . '\\Forge' : $db->DBDriver . '\\Forge';

		// Make sure a connection exists
		if (! $db->connID)
		{
			$db->initialize();
		}

		$class = new $className($db);

		return $class;
	}

public
function
loadForge
(
ConnectionInterface
$
db
)
{
$
className
=
strpos
(
$
db
->
DBDriver
,
'\\'
)
===
false
'\CodeIgniter\Database\\'
.
$
db
->
DBDriver
.
'\\Forge'
:
$
db
->
DBDriver
.
'\\Forge'
;
// Make sure a connection exists
if
(
!
$
db
->
connID
)
{
$
db
->
initialize
(
)
;
}
$
class
=
new
$
className
(
$
db
)
;
return
$
class
;
}

Creates a new Forge instance for the current database type.

@param ConnectionInterface|BaseConnection $db

@return mixed

Creates a new Forge instance for the current database type .


protected function hasPropertyChanged(string $key, $value = null): bool
	{
		return ! (($this->_original[$key] === null && $value === null) || $this->_original[$key] === $value);
	}

protected function hasPropertyChanged ( string $ key , $ value = null ) : bool { return ! ( ( $ this -> _original [ $ key ] === null && $ value === null ) || $ this -> _original [ $ key ] === $ value ) ; }

Checks a property to see if it has changed since the entity was created.

@param string $key
@param null   $value

@return boolean

Checks a property to see if it has changed since the entity was created .


protected function mapProperty(string $key)
	{
		if (empty($this->_options['datamap']))
		{
			return $key;
		}

		if (isset($this->_options['datamap'][$key]) && ! empty($this->_options['datamap'][$key]))
		{
			return $this->_options['datamap'][$key];
		}

		return $key;
	}

protected function mapProperty ( string $ key ) { if ( empty ( $ this -> _options [ 'datamap' ] ) ) { return $ key ; } if ( isset ( $ this -> _options [ 'datamap' ] [ $ key ] ) && ! empty ( $ this -> _options [ 'datamap' ] [ $ key ] ) ) { return $ this -> _options [ 'datamap' ] [ $ key ] ; } return $ key ; }

Checks the datamap to see if this column name is being mapped,
and returns the mapped name, if any, or the original name.

@param string $key

@return mixed|string

Checks the datamap to see if this column name is being mapped and returns the mapped name if any or the original name .


protected function mutateDate($value)
	{
		if ($value instanceof Time)
		{
			return $value;
		}

		if ($value instanceof \DateTime)
		{
			return Time::instance($value);
		}

		if (is_numeric($value))
		{
			return Time::createFromTimestamp($value);
		}

		if (is_string($value))
		{
			return Time::parse($value);
		}

		return $value;
	}

protected function mutateDate ( $ value ) { if ( $ value instanceof Time ) { return $ value ; } if ( $ value instanceof \ DateTime ) { return Time :: instance ( $ value ) ; } if ( is_numeric ( $ value ) ) { return Time :: createFromTimestamp ( $ value ) ; } if ( is_string ( $ value ) ) { return Time :: parse ( $ value ) ; } return $ value ; }

Converts the given string|timestamp|DateTime|Time instance
into a \CodeIgniter\I18n\Time object.

@param $value

@return \CodeIgniter\I18n\Time
@throws \Exception

Converts the given string|timestamp|DateTime|Time instance into a \ CodeIgniter \ I18n \ Time object .


private function castAsJson($value, bool $asArray = false)
	{
		$tmp = ! is_null($value) ? ($asArray ? [] : new \stdClass) : null;
		if (function_exists('json_decode'))
		{
			if ((is_string($value) && (strpos($value, '[') === 0 || strpos($value, '{') === 0 || (strpos($value, '"') === 0 && strrpos($value, '"') === 0 ))) || is_numeric($value))
			{
				$tmp = json_decode($value, $asArray);

				if (json_last_error() !== JSON_ERROR_NONE)
				{
					throw CastException::forInvalidJsonFormatException(json_last_error());
				}
			}
		}
		return $tmp;
	}

private function castAsJson ( $ value , bool $ asArray = false ) { $ tmp = ! is_null ( $ value ) ? ( $ asArray ? [ ] : new \ stdClass ) : null ; if ( function_exists ( 'json_decode' ) ) { if ( ( is_string ( $ value ) && ( strpos ( $ value , '[' ) === 0 || strpos ( $ value , '{' ) === 0 || ( strpos ( $ value , '"' ) === 0 && strrpos ( $ value , '"' ) === 0 ) ) ) || is_numeric ( $ value ) ) { $ tmp = json_decode ( $ value , $ asArray ) ; if ( json_last_error ( ) !== JSON_ERROR_NONE ) { throw CastException :: forInvalidJsonFormatException ( json_last_error ( ) ) ; } } } return $ tmp ; }

Cast as JSON

@param mixed   $value
@param boolean $asArray

@return mixed
@throws \CodeIgniter\Exceptions\CastException


public function shouldDiscover(string $alias)
	{
		if (! $this->enabled)
		{
			return false;
		}

		$alias = strtolower($alias);

		return in_array($alias, $this->activeExplorers);
	}

public function shouldDiscover ( string $ alias ) { if ( ! $ this -> enabled ) { return false ; } $ alias = strtolower ( $ alias ) ; return in_array ( $ alias , $ this -> activeExplorers ) ; }

Should the application auto-discover the requested resources.

Valid values are:
- events
- registrars
- routes
- services

@param string $alias

@return boolean

Should the application auto - discover the requested resources .


public function findAll(int $limit = 0, int $offset = 0)
	{
		$builder = $this->builder();

		if ($this->tempUseSoftDeletes === true)
		{
			$builder->where($this->table . '.' . $this->deletedField, 0);
		}

		$row = $builder->limit($limit, $offset)
				->get();

		$row = $row->getResult($this->tempReturnType);

		$row = $this->trigger('afterFind', ['data' => $row, 'limit' => $limit, 'offset' => $offset]);

		$this->tempReturnType     = $this->returnType;
		$this->tempUseSoftDeletes = $this->useSoftDeletes;

		return $row['data'];
	}

public function findAll ( int $ limit = 0 , int $ offset = 0 ) { $ builder = $ this -> builder ( ) ; if ( $ this -> tempUseSoftDeletes === true ) { $ builder -> where ( $ this -> table . '.' . $ this -> deletedField , 0 ) ; } $ row = $ builder -> limit ( $ limit , $ offset ) -> get ( ) ; $ row = $ row -> getResult ( $ this -> tempReturnType ) ; $ row = $ this -> trigger ( 'afterFind' , [ 'data' => $ row , 'limit' => $ limit , 'offset' => $ offset ] ) ; $ this -> tempReturnType = $ this -> returnType ; $ this -> tempUseSoftDeletes = $ this -> useSoftDeletes ; return $ row [ 'data' ] ; }

Works with the current Query Builder instance to return
all results, while optionally limiting them.

@param integer $limit
@param integer $offset

@return array|null

Works with the current Query Builder instance to return all results while optionally limiting them .


public function first()
	{
		$builder = $this->builder();

		if ($this->tempUseSoftDeletes === true)
		{
			$builder->where($this->table . '.' . $this->deletedField, 0);
		}

		// Some databases, like PostgreSQL, need order
		// information to consistently return correct results.
		if (empty($builder->QBOrderBy) && ! empty($this->primaryKey))
		{
			$builder->orderBy($this->table . '.' . $this->primaryKey, 'asc');
		}

		$row = $builder->limit(1, 0)
				->get();

		$row = $row->getFirstRow($this->tempReturnType);

		$row = $this->trigger('afterFind', ['data' => $row]);

		$this->tempReturnType = $this->returnType;

		return $row['data'];
	}

Returns the first row of the result set. Will take any previous
Query Builder calls into account when determining the result set.

@return array|object|null

Returns the first row of the result set . Will take any previous Query Builder calls into account when determining the result set .


public function save($data): bool
	{
		if (empty($data))
		{
			return true;
		}

		if (is_object($data) && isset($data->{$this->primaryKey}))
		{
			$response = $this->update($data->{$this->primaryKey}, $data);
		}
		elseif (is_array($data) && ! empty($data[$this->primaryKey]))
		{
			$response = $this->update($data[$this->primaryKey], $data);
		}
		else
		{
			$response = $this->insert($data, false);
			// call insert directly if you want the ID or the record object
			if ($response !== false)
			{
				$response = true;
			}
		}

		return $response;
	}

A convenience method that will attempt to determine whether the
data should be inserted or updated. Will work with either
an array or object. When using with custom class objects,
you must ensure that the class will provide access to the class
variables, even if through a magic method.

@param array|object $data

@return boolean
@throws \ReflectionException

A convenience method that will attempt to determine whether the data should be inserted or updated . Will work with either an array or object . When using with custom class objects you must ensure that the class will provide access to the class variables even if through a magic method .


public static function classToArray($data, $primaryKey = null, string $dateFormat = 'datetime', bool $onlyChanged = true): array
	{
		if (method_exists($data, 'toRawArray'))
		{
			$properties = $data->toRawArray($onlyChanged);

			// Always grab the primary key otherwise updates will fail.
			if (! empty($properties) && ! empty($primaryKey) && ! in_array($primaryKey, $properties))
			{
				$properties[$primaryKey] = $data->{$primaryKey};
			}
		}
		else
		{
			$mirror = new ReflectionClass($data);
			$props  = $mirror->getProperties(ReflectionProperty::IS_PUBLIC | ReflectionProperty::IS_PROTECTED);

			$properties = [];

			// Loop over each property,
			// saving the name/value in a new array we can return.
			foreach ($props as $prop)
			{
				// Must make protected values accessible.
				$prop->setAccessible(true);
				$propName              = $prop->getName();
				$properties[$propName] = $prop->getValue($data);
			}
		}

		// Convert any Time instances to appropriate $dateFormat
		if ($properties)
		{
			foreach ($properties as $key => $value)
			{
				if ($value instanceof Time)
				{
					switch ($dateFormat)
					{
						case 'datetime':
							$converted = $value->format('Y-m-d H:i:s');
							break;
						case 'date':
							$converted = $value->format('Y-m-d');
							break;
						case 'int':
							$converted = $value->getTimestamp();
							break;
						default:
							$converted = (string)$value;
					}

					$properties[$key] = $converted;
				}
			}
		}

		return $properties;
	}

Takes a class an returns an array of it's public and protected
properties as an array suitable for use in creates and updates.

@param string|object $data
@param string|null   $primaryKey
@param string        $dateFormat
@param boolean       $onlyChanged

@return array
@throws \ReflectionException

Takes a class an returns an array of it s public and protected properties as an array suitable for use in creates and updates .


public function insert($data = null, bool $returnID = true)
	{
		$escape = null;

		$this->insertID = 0;

		if (empty($data))
		{
			$data           = $this->tempData['data'] ?? null;
			$escape         = $this->tempData['escape'] ?? null;
			$this->tempData = [];
		}

		if (empty($data))
		{
			throw DataException::forEmptyDataset('insert');
		}

		// If $data is using a custom class with public or protected
		// properties representing the table elements, we need to grab
		// them as an array.
		if (is_object($data) && ! $data instanceof stdClass)
		{
			$data = static::classToArray($data, $this->primaryKey, $this->dateFormat, false);
		}

		// If it's still a stdClass, go ahead and convert to
		// an array so doProtectFields and other model methods
		// don't have to do special checks.
		if (is_object($data))
		{
			$data = (array) $data;
		}

		// Validate data before saving.
		if ($this->skipValidation === false)
		{
			if ($this->validate($data) === false)
			{
				return false;
			}
		}

		// Save the original data so it can be passed to
		// any Model Event callbacks and not stripped
		// by doProtectFields
		$originalData = $data;

		// Must be called first so we don't
		// strip out created_at values.
		$data = $this->doProtectFields($data);

		// Set created_at and updated_at with same time
		$date = $this->setDate();

		if ($this->useTimestamps && ! empty($this->createdField) && ! array_key_exists($this->createdField, $data))
		{
			$data[$this->createdField] = $date;
		}

		if ($this->useTimestamps && ! empty($this->updatedField) && ! array_key_exists($this->updatedField, $data))
		{
			$data[$this->updatedField] = $date;
		}

		$data = $this->trigger('beforeInsert', ['data' => $data]);

		// Must use the set() method to ensure objects get converted to arrays
		$result = $this->builder()
				->set($data['data'], '', $escape)
				->insert();

		$this->trigger('afterInsert', ['data' => $originalData, 'result' => $result]);

		// If insertion failed, get our of here
		if (! $result)
		{
			return $result;
		}

		$this->insertID = $this->db->insertID();

		// otherwise return the insertID, if requested.
		return $returnID ? $this->insertID : $result;
	}

Inserts data into the current table. If an object is provided,
it will attempt to convert it to an array.

@param array|object $data
@param boolean      $returnID Whether insert ID should be returned or not.

@return integer|string|boolean
@throws \ReflectionException

Inserts data into the current table . If an object is provided it will attempt to convert it to an array .


public function insertBatch(array $set = null, bool $escape = null, int $batchSize = 100, bool $testing = false)
	{
		if (is_array($set) && $this->skipValidation === false)
		{
			foreach ($set as $row)
			{
				if ($this->validate($row) === false)
				{
					return false;
				}
			}
		}

		return $this->builder()->insertBatch($set, $escape, $batchSize, $testing);
	}

public function insertBatch ( array $ set = null , bool $ escape = null , int $ batchSize = 100 , bool $ testing = false ) { if ( is_array ( $ set ) && $ this -> skipValidation === false ) { foreach ( $ set as $ row ) { if ( $ this -> validate ( $ row ) === false ) { return false ; } } } return $ this -> builder ( ) -> insertBatch ( $ set , $ escape , $ batchSize , $ testing ) ; }

Compiles batch insert strings and runs the queries, validating each row prior.

@param array   $set       An associative array of insert values
@param boolean $escape    Whether to escape values and identifiers

@param integer $batchSize
@param boolean $testing

@return integer|boolean Number of rows inserted or FALSE on failure

Compiles batch insert strings and runs the queries validating each row prior .


protected function builder(string $table = null)
	{
		if ($this->builder instanceof BaseBuilder)
		{
			return $this->builder;
		}

		// We're going to force a primary key to exist
		// so we don't have overly convoluted code,
		// and future features are likely to require them.
		if (empty($this->primaryKey))
		{
			throw ModelException::forNoPrimaryKey(get_class($this));
		}

		$table = empty($table) ? $this->table : $table;

		// Ensure we have a good db connection
		if (! $this->db instanceof BaseConnection)
		{
			$this->db = Database::connect($this->DBGroup);
		}

		$this->builder = $this->db->table($table);

		return $this->builder;
	}

Provides a shared instance of the Query Builder.

@param string $table

@return BaseBuilder

Provides a shared instance of the Query Builder .


protected function doProtectFields(array $data): array
	{
		if ($this->protectFields === false)
		{
			return $data;
		}

		if (empty($this->allowedFields))
		{
			throw DataException::forInvalidAllowedFields(get_class($this));
		}

		if (is_array($data) && count($data))
		{
			foreach ($data as $key => $val)
			{
				if (! in_array($key, $this->allowedFields))
				{
					unset($data[$key]);
				}
			}
		}

		return $data;
	}

protected function doProtectFields ( array $ data ) : array { if ( $ this -> protectFields === false ) { return $ data ; } if ( empty ( $ this -> allowedFields ) ) { throw DataException :: forInvalidAllowedFields ( get_class ( $ this ) ) ; } if ( is_array ( $ data ) && count ( $ data ) ) { foreach ( $ data as $ key => $ val ) { if ( ! in_array ( $ key , $ this -> allowedFields ) ) { unset ( $ data [ $ key ] ) ; } } } return $ data ; }

Ensures that only the fields that are allowed to be updated
are in the data array.

Used by insert() and update() to protect against mass assignment
vulnerabilities.

@param array $data

@return array
@throws \CodeIgniter\Database\Exceptions\DataException

Ensures that only the fields that are allowed to be updated are in the data array .


protected function cleanValidationRules(array $rules, array $data = null): array
	{
		if (empty($data))
		{
			return [];
		}

		foreach ($rules as $field => $rule)
		{
			if (! array_key_exists($field, $data))
			{
				unset($rules[$field]);
			}
		}

		return $rules;
	}

protected function cleanValidationRules ( array $ rules , array $ data = null ) : array { if ( empty ( $ data ) ) { return [ ] ; } foreach ( $ rules as $ field => $ rule ) { if ( ! array_key_exists ( $ field , $ data ) ) { unset ( $ rules [ $ field ] ) ; } } return $ rules ; }

Removes any rules that apply to fields that have not been set
currently so that rules don't block updating when only updating
a partial row.

@param array      $rules

@param array|null $data

@return array

Removes any rules that apply to fields that have not been set currently so that rules don t block updating when only updating a partial row .


public function getValidationRules(array $options = []): array
	{
		$rules = $this->validationRules;

		if (isset($options['except']))
		{
			$rules = array_diff_key($rules, array_flip($options['except']));
		}
		elseif (isset($options['only']))
		{
			$rules = array_intersect_key($rules, array_flip($options['only']));
		}

		return $rules;
	}

public function getValidationRules ( array $ options = [ ] ) : array { $ rules = $ this -> validationRules ; if ( isset ( $ options [ 'except' ] ) ) { $ rules = array_diff_key ( $ rules , array_flip ( $ options [ 'except' ] ) ) ; } elseif ( isset ( $ options [ 'only' ] ) ) { $ rules = array_intersect_key ( $ rules , array_flip ( $ options [ 'only' ] ) ) ; } return $ rules ; }

Returns the model's defined validation rules so that they
can be used elsewhere, if needed.

@param array $options

@return array

Returns the model s defined validation rules so that they can be used elsewhere if needed .


public function countAllResults(bool $reset = true, bool $test = false)
	{
		if ($this->tempUseSoftDeletes === true)
		{
			$this->builder()->where($this->deletedField, 0);
		}

		return $this->builder()->countAllResults($reset, $test);
	}

public function countAllResults ( bool $ reset = true , bool $ test = false ) { if ( $ this -> tempUseSoftDeletes === true ) { $ this -> builder ( ) -> where ( $ this -> deletedField , 0 ) ; } return $ this -> builder ( ) -> countAllResults ( $ reset , $ test ) ; }

Override countAllResults to account for soft deleted accounts.

@param boolean $reset
@param boolean $test

@return mixed

Override countAllResults to account for soft deleted accounts .


public function setAuth(string $username, string $password, string $type = 'basic')
	{
		$this->config['auth'] = [
			$username,
			$password,
			$type,
		];

		return $this;
	}

public function setAuth ( string $ username , string $ password , string $ type = 'basic' ) { $ this -> config [ 'auth' ] = [ $ username , $ password , $ type , ] ; return $ this ; }

Set the HTTP Authentication.

@param string $username
@param string $password
@param string $type     basic or digest

@return $this


public function setForm(array $params, bool $multipart = false)
	{
		if ($multipart)
		{
			$this->config['multipart'] = $params;
		}
		else
		{
			$this->config['form_params'] = $params;
		}

		return $this;
	}

public function setForm ( array $ params , bool $ multipart = false ) { if ( $ multipart ) { $ this -> config [ 'multipart' ] = $ params ; } else { $ this -> config [ 'form_params' ] = $ params ; } return $ this ; }

Set form data to be sent.

@param array   $params
@param boolean $multipart Set TRUE if you are sending CURLFiles

@return $this


protected function parseOptions(array $options)
	{
		if (array_key_exists('baseURI', $options))
		{
			$this->baseURI = $this->baseURI->setURI($options['baseURI']);
			unset($options['baseURI']);
		}

		if (array_key_exists('headers', $options) && is_array($options['headers']))
		{
			foreach ($options['headers'] as $name => $value)
			{
				$this->setHeader($name, $value);
			}

			unset($options['headers']);
		}

		if (array_key_exists('delay', $options))
		{
			// Convert from the milliseconds passed in
			// to the seconds that sleep requires.
			$this->delay = (float) $options['delay'] / 1000;
			unset($options['delay']);
		}

		foreach ($options as $key => $value)
		{
			$this->config[$key] = $value;
		}
	}

Sets the correct settings based on the options array
passed in.

@param array $options

Sets the correct settings based on the options array passed in .


public function getMethod(bool $upper = false): string
	{
		return ($upper) ? strtoupper($this->method) : strtolower($this->method);
	}

public function getMethod ( bool $ upper = false ) : string { return ( $ upper ) ? strtoupper ( $ this -> method ) : strtolower ( $ this -> method ) ; }

Get the request method. Overrides the Request class' method
since users expect a different answer here.

@param boolean|false $upper Whether to return in upper or lower case.

@return string

Get the request method . Overrides the Request class method since users expect a different answer here .


public function send(string $method, string $url)
	{
		// Reset our curl options so we're on a fresh slate.
		$curl_options = [];

		if (! empty($this->config['query']) && is_array($this->config['query']))
		{
			// This is likely too naive a solution.
			// Should look into handling when $url already
			// has query vars on it.
			$url .= '?' . http_build_query($this->config['query']);
			unset($this->config['query']);
		}

		$curl_options[CURLOPT_URL]            = $url;
		$curl_options[CURLOPT_RETURNTRANSFER] = true;
		$curl_options[CURLOPT_HEADER]         = true;
		$curl_options[CURLOPT_FRESH_CONNECT]  = true;
		// Disable @file uploads in post data.
		$curl_options[CURLOPT_SAFE_UPLOAD] = true;

		$curl_options = $this->setCURLOptions($curl_options, $this->config);
		$curl_options = $this->applyMethod($method, $curl_options);
		$curl_options = $this->applyRequestHeaders($curl_options);

		// Do we need to delay this request?
		if ($this->delay > 0)
		{
			sleep($this->delay);
		}

		$output = $this->sendRequest($curl_options);

		$continueStr = "HTTP/1.1 100 Continue\x0d\x0a\x0d\x0a";
		if (strpos($output, $continueStr) === 0)
		{
			$output = substr($output, strlen($continueStr));
		}

		// Split out our headers and body
		$break = strpos($output, "\r\n\r\n");

		if ($break !== false)
		{
			// Our headers
			$headers = explode("\n", substr($output, 0, $break));

			$this->setResponseHeaders($headers);

			// Our body
			$body = substr($output, $break + 4);
			$this->response->setBody($body);
		}
		else
		{
			$this->response->setBody($output);
		}

		return $this->response;
	}

Fires the actual cURL request.

@param string $method
@param string $url

@return \CodeIgniter\HTTP\ResponseInterface


protected function applyRequestHeaders(array $curl_options = []): array
	{
		$headers = $this->getHeaders();

		if (empty($headers))
		{
			return $curl_options;
		}

		$set = [];

		foreach ($headers as $name => $value)
		{
			$set[] = $name . ': ' . $this->getHeaderLine($name);
		}

		$curl_options[CURLOPT_HTTPHEADER] = $set;

		return $curl_options;
	}

protected
function
applyRequestHeaders
(
array
$
curl_options
=
[
]
)
:
array
{
$
headers
=
$
this
->
getHeaders
(
)
;
if
(
empty
(
$
headers
)
)
{
return
$
curl_options
;
}
$
set
=
[
]
;
foreach
(
$
headers
as
$
name
=>
$
value
)
{
$
set
[
]
=
$
name
.
': '
.
$
this
->
getHeaderLine
(
$
name
)
;
}
$
curl_options
[
CURLOPT_HTTPHEADER
]
=
$
set
;
return
$
curl_options
;
}

Takes all headers current part of this request and adds them
to the cURL request.

@param array $curl_options

@return array

Takes all headers current part of this request and adds them to the cURL request .


protected function setResponseHeaders(array $headers = [])
	{
		foreach ($headers as $header)
		{
			if (($pos = strpos($header, ':')) !== false)
			{
				$title = substr($header, 0, $pos);
				$value = substr($header, $pos + 1);

				$this->response->setHeader($title, $value);
			}
			else if (strpos($header, 'HTTP') === 0)
			{
				preg_match('#^HTTP\/([12]\.[01]) ([0-9]+) (.+)#', $header, $matches);

				if (isset($matches[1]))
				{
					$this->response->setProtocolVersion($matches[1]);
				}

				if (isset($matches[2]))
				{
					$this->response->setStatusCode($matches[2], $matches[3] ?? null);
				}
			}
		}
	}

protected
function
setResponseHeaders
(
array
$
headers
=
[
]
)
{
foreach
(
$
headers
as
$
header
)
{
if
(
(
$
pos
=
strpos
(
$
header
,
':'
)
)
!==
false
)
{
$
title
=
substr
(
$
header
,
0
,
$
pos
)
;
$
value
=
substr
(
$
header
,
$
pos
+
1
)
;
$
this
->
response
->
setHeader
(
$
title
,
$
value
)
;
}
else
if
(
strpos
(
$
header
,
'HTTP'
)
===
0
)
{
preg_match
(
'#^HTTP\/([12]\.[01]) ([0-9]+) (.+)#'
,
$
header
,
$
matches
)
;
if
(
isset
(
$
matches
[
1
]
)
)
{
$
this
->
response
->
setProtocolVersion
(
$
matches
[
1
]
)
;
}
if
(
isset
(
$
matches
[
2
]
)
)
{
$
this
->
response
->
setStatusCode
(
$
matches
[
2
]
,
$
matches
[
3
]
??
)
;
}
}
}
}

Parses the header retrieved from the cURL response into
our Response object.

@param array $headers

Parses the header retrieved from the cURL response into our Response object .


protected function sendRequest(array $curl_options = []): string
	{
		$ch = curl_init();

		curl_setopt_array($ch, $curl_options);

		// Send the request and wait for a response.
		$output = curl_exec($ch);

		if ($output === false)
		{
			throw HTTPException::forCurlError(curl_errno($ch), curl_error($ch));
		}

		curl_close($ch);

		return $output;
	}

Does the actual work of initializing cURL, setting the options,
and grabbing the output.

@codeCoverageIgnore

@param array $curl_options

@return string

Does the actual work of initializing cURL setting the options and grabbing the output .


public function version(string $targetVersion, string $namespace = null, string $group = null)
	{
		if (! $this->enabled)
		{
			throw ConfigException::forDisabledMigrations();
		}

		$this->ensureTable();

		// Set Namespace if not null
		if (! is_null($namespace))
		{
			$this->setNamespace($namespace);
		}

		// Set database group if not null
		if (! is_null($group))
		{
			$this->setGroup($group);
		}

		// Sequential versions need adjusting to 3 places so they can be found later.
		if ($this->type === 'sequential')
		{
			$targetVersion = str_pad($targetVersion, 3, '0', STR_PAD_LEFT);
		}

		$migrations = $this->findMigrations();

		if (empty($migrations))
		{
			return true;
		}

		// Get Namespace current version
		// Note: We use strings, so that timestamp versions work on 32-bit systems
		$currentVersion = $this->getVersion();
		if ($targetVersion > $currentVersion)
		{
			// Moving Up
			$method = 'up';
			ksort($migrations);
		}
		else
		{
			// Moving Down, apply in reverse order
			$method = 'down';
			krsort($migrations);
		}

		// Check Migration consistency
		$this->checkMigrations($migrations, $method, $targetVersion);

		// loop migration for each namespace (module)

		$migrationStatus = false;
		foreach ($migrations as $version => $migration)
		{
			// Only include migrations within the scoop
			if (($method === 'up' && $version > $currentVersion && $version <= $targetVersion) || ( $method === 'down' && $version <= $currentVersion && $version > $targetVersion))
			{
				$migrationStatus = false;
				include_once $migration->path;
				// Get namespaced class name
				$class = $this->namespace . '\Database\Migrations\Migration_' . ($migration->name);

				$this->setName($migration->name);

				// Validate the migration file structure
				if (! class_exists($class, false))
				{
					throw new \RuntimeException(sprintf(lang('Migrations.classNotFound'), $class));
				}

				// Forcing migration to selected database group
				$instance = new $class(\Config\Database::forge($this->group));

				if (! is_callable([$instance, $method]))
				{
					throw new \RuntimeException(sprintf(lang('Migrations.missingMethod'), $method));
				}

				$instance->{$method}();
				if ($method === 'up')
				{
					$this->addHistory($migration->version);
				}
				elseif ($method === 'down')
				{
					$this->removeHistory($migration->version);
				}

				$migrationStatus = true;
			}
		}

		return ($migrationStatus) ? $targetVersion : false;
	}

Migrate to a schema version

Calls each migration step required to get to the schema version of
choice

@param string      $targetVersion Target schema version
@param string|null $namespace
@param string|null $group

@return mixed Current version string on success, FALSE on failure or no migrations are found
@throws ConfigException


public function findMigrations(): array
	{
		$migrations = [];

		// If $this->path contains a valid directory use it.
		if (! empty($this->path))
		{
			helper('filesystem');
			$dir   = rtrim($this->path, DIRECTORY_SEPARATOR) . '/';
			$files = get_filenames($dir, true);
		}
		// Otherwise use FileLocator to search files in the subdirectory of the namespace
		else
		{
			$locator = Services::locator(true);
			$files   = $locator->listNamespaceFiles($this->namespace, '/Database/Migrations/');
		}

		// Load all *_*.php files in the migrations path
		// We can't use glob if we want it to be testable....
		foreach ($files as $file)
		{
			if (substr($file, -4) !== '.php')
			{
				continue;
			}

			// Remove the extension
			$name = basename($file, '.php');

			// Filter out non-migration files
			if (preg_match($this->regex, $name))
			{
				// Create migration object using stdClass
				$migration = new \stdClass();

				// Get migration version number
				$migration->version = $this->getMigrationNumber($name);
				$migration->name    = $this->getMigrationName($name);
				$migration->path    = ! empty($this->path) && strpos($file, $this->path) !== 0
					? $this->path . $file
					: $file;

				// Add to migrations[version]
				$migrations[$migration->version] = $migration;
			}
		}

		ksort($migrations);

		return $migrations;
	}

Retrieves list of available migration scripts for one namespace

@return array    list of migrations as $version for one namespace


protected function checkMigrations(array $migrations, string $method, string $targetVersion): bool
	{
		// Check if no migrations found
		if (empty($migrations))
		{
			if ($this->silent)
			{
				return false;
			}
			throw new \RuntimeException(lang('Migrations.empty'));
		}

		// Check if $targetVersion file is found
		if ((int)$targetVersion !== 0 && ! array_key_exists($targetVersion, $migrations))
		{
			if ($this->silent)
			{
				return false;
			}
			throw new \RuntimeException(lang('Migrations.notFound') . $targetVersion);
		}

		ksort($migrations);

		if ($method === 'down')
		{
			$history_migrations = $this->getHistory($this->group);
			$history_size       = count($history_migrations) - 1;
		}
		// Check for sequence gaps
		$loop = 0;
		foreach ($migrations as $migration)
		{
			if ($this->type === 'sequential' && abs($migration->version - $loop) > 1)
			{
				throw new \RuntimeException(lang('Migrations.gap') . ' ' . $migration->version);
			}
			// Check if all old migration files are all available to do downgrading
			if ($method === 'down')
			{
				if ($loop <= $history_size && $history_migrations[$loop]['version'] !== $migration->version)
				{
					throw new \RuntimeException(lang('Migrations.gap') . ' ' . $migration->version);
				}
			}
			$loop ++;
		}

		return true;
	}

checks if the list of available migration scripts list are consistent
if sequential check if no gaps and check if all consistent with migrations table if downgrading
if timestamp check if consistent with migrations table if downgrading

@param array  $migrations
@param string $method
@param string $targetVersion

@return boolean


public function getHistory(string $group = 'default'): array
	{
		$this->ensureTable();

		$query = $this->db->table($this->table)
				->where('group', $group)
				->where('namespace', $this->namespace)
				->orderBy('version', 'ASC')
				->get();

		if (! $query)
		{
			return [];
		}

		return $query->getResultArray();
	}

public function getHistory ( string $ group = 'default' ) : array { $ this -> ensureTable ( ) ; $ query = $ this -> db -> table ( $ this -> table ) -> where ( 'group' , $ group ) -> where ( 'namespace' , $ this -> namespace ) -> orderBy ( 'version' , 'ASC' ) -> get ( ) ; if ( ! $ query ) { return [ ] ; } return $ query -> getResultArray ( ) ; }

Grabs the full migration history from the database.

@param string $group

@return array

Grabs the full migration history from the database .


protected function getMigrationName(string $migration): string
	{
		$parts = explode('_', $migration);
		array_shift($parts);

		return implode('_', $parts);
	}

protected function getMigrationName ( string $ migration ) : string { $ parts = explode ( '_' , $ migration ) ; array_shift ( $ parts ) ; return implode ( '_' , $ parts ) ; }

Extracts the migration class name from a filename

@param string $migration

@return string    text portion of a migration filename


protected function getVersion(): string
	{
		$this->ensureTable();

		$row = $this->db->table($this->table)
				->select('version')
				->where('group', $this->group)
				->where('namespace', $this->namespace)
				->orderBy('version', 'DESC')
				->get();

		return $row && ! is_null($row->getRow()) ? $row->getRow()->version : '0';
	}

protected function getVersion ( ) : string { $ this -> ensureTable ( ) ; $ row = $ this -> db -> table ( $ this -> table ) -> select ( 'version' ) -> where ( 'group' , $ this -> group ) -> where ( 'namespace' , $ this -> namespace ) -> orderBy ( 'version' , 'DESC' ) -> get ( ) ; return $ row && ! is_null ( $ row -> getRow ( ) ) ? $ row -> getRow ( ) -> version : '0' ; }

Retrieves current schema version

@return string    Current migration version


protected function addHistory(string $version)
	{
		$this->db->table($this->table)
				->insert([
					'version'   => $version,
					'name'      => $this->name,
					'group'     => $this->group,
					'namespace' => $this->namespace,
					'time'      => time(),
				]);
		if (is_cli())
		{
			$this->cliMessages[] = "\t" . CLI::color(lang('Migrations.added'), 'yellow') . "($this->namespace) " . $version . '_' . $this->name;
		}
	}

protected
function
addHistory
(
string
$
version
)
{
$
this
->
db
->
table
(
$
this
->
table
)
->
insert
(
[
'version'
=>
$
version
,
'name'
=>
$
this
->
name
,
'group'
=>
$
this
->
group
,
'namespace'
=>
$
this
->
namespace
,
'time'
=>
time
(
)
,
]
)
;
if
(
is_cli
(
)
)
{
$
this
->
cliMessages
[
]
=
"\t"
.
CLI
::
color
(
lang
(
'Migrations.added'
)
,
'yellow'
)
.
"($this->namespace) "
.
$
version
.
'_'
.
$
this
->
name
;
}
}

Stores the current schema version.

@param string $version

@internal param string $migration Migration reached

@return void


protected function removeHistory(string $version)
	{
		$this->db->table($this->table)
				->where('version', $version)
				->where('group', $this->group)
				->where('namespace', $this->namespace)
				->delete();
		if (is_cli())
		{
			$this->cliMessages[] = "\t" . CLI::color(lang('Migrations.removed'), 'yellow') . "($this->namespace) " . $version . '_' . $this->name;
		}
	}

protected
function
removeHistory
(
string
$
version
)
{
$
this
->
db
->
table
(
$
this
->
table
)
->
where
(
'version'
,
$
version
)
->
where
(
'group'
,
$
this
->
group
)
->
where
(
'namespace'
,
$
this
->
namespace
)
->
delete
(
)
;
if
(
is_cli
(
)
)
{
$
this
->
cliMessages
[
]
=
"\t"
.
CLI
::
color
(
lang
(
'Migrations.removed'
)
,
'yellow'
)
.
"($this->namespace) "
.
$
version
.
'_'
.
$
this
->
name
;
}
}

Removes a single history

@param string $version
@return void


public function ensureTable()
	{
		if ($this->tableChecked || $this->db->tableExists($this->table))
		{
			return;
		}

		$forge = \Config\Database::forge($this->db);

		$forge->addField([
			'version'   => [
				'type'       => 'VARCHAR',
				'constraint' => 255,
				'null'       => false,
			],
			'name'      => [
				'type'       => 'VARCHAR',
				'constraint' => 255,
				'null'       => false,
			],
			'group'     => [
				'type'       => 'VARCHAR',
				'constraint' => 255,
				'null'       => false,
			],
			'namespace' => [
				'type'       => 'VARCHAR',
				'constraint' => 255,
				'null'       => false,
			],
			'time'      => [
				'type'       => 'INT',
				'constraint' => 11,
				'null'       => false,
			],
		]);

		$forge->createTable($this->table, true);

		$this->tableChecked = true;
	}

public function ensureTable ( ) { if ( $ this -> tableChecked || $ this -> db -> tableExists ( $ this -> table ) ) { return ; } $ forge = \ Config \ Database :: forge ( $ this -> db ) ; $ forge -> addField ( [ 'version' => [ 'type' => 'VARCHAR' , 'constraint' => 255 , 'null' => false , ] , 'name' => [ 'type' => 'VARCHAR' , 'constraint' => 255 , 'null' => false , ] , 'group' => [ 'type' => 'VARCHAR' , 'constraint' => 255 , 'null' => false , ] , 'namespace' => [ 'type' => 'VARCHAR' , 'constraint' => 255 , 'null' => false , ] , 'time' => [ 'type' => 'INT' , 'constraint' => 11 , 'null' => false , ] , ] ) ; $ forge -> createTable ( $ this -> table , true ) ; $ this -> tableChecked = true ; }

Ensures that we have created our migrations table
in the database.

Ensures that we have created our migrations table in the database .


public function check($value, string $rule, array $errors = []): bool
	{
		$this->reset();
		$this->setRule('check', null, $rule, $errors);

		return $this->run([
			'check' => $value,
		]);
	}

public function check ( $ value , string $ rule , array $ errors = [ ] ) : bool { $ this -> reset ( ) ; $ this -> setRule ( 'check' , null , $ rule , $ errors ) ; return $ this -> run ( [ 'check' => $ value , ] ) ; }

Check; runs the validation process, returning true or false
determining whether validation was successful or not.

@param mixed    $value  Value to validation.
@param string   $rule   Rule.
@param string[] $errors Errors.

@return boolean True if valid, else false.

Check ; runs the validation process returning true or false determining whether validation was successful or not .


public function withRequest(RequestInterface $request): ValidationInterface
	{
		if (in_array($request->getMethod(), ['put', 'patch', 'delete']))
		{
			$this->data = $request->getRawInput();
		}
		else
		{
			$this->data = $request->getVar() ?? [];
		}

		return $this;
	}

public function withRequest ( RequestInterface $ request ) : ValidationInterface { if ( in_array ( $ request -> getMethod ( ) , [ 'put' , 'patch' , 'delete' ] ) ) { $ this -> data = $ request -> getRawInput ( ) ; } else { $ this -> data = $ request -> getVar ( ) ?? [ ] ; } return $ this ; }

Takes a Request object and grabs the input data to use from its
array values.

@param \CodeIgniter\HTTP\RequestInterface|\CodeIgniter\HTTP\IncomingRequest $request

@return \CodeIgniter\Validation\ValidationInterface

Takes a Request object and grabs the input data to use from its array values .


public function setRule(string $field, string $label = null, string $rules, array $errors = [])
	{
		$this->rules[$field] = [
			'label' => $label,
			'rules' => $rules,
		];
		$this->customErrors  = array_merge($this->customErrors, [
			$field => $errors,
		]);

		return $this;
	}

public function setRule ( string $ field , string $ label = null , string $ rules , array $ errors = [ ] ) { $ this -> rules [ $ field ] = [ 'label' => $ label , 'rules' => $ rules , ] ; $ this -> customErrors = array_merge ( $ this -> customErrors , [ $ field => $ errors , ] ) ; return $ this ; }

Sets an individual rule and custom error messages for a single field.

The custom error message should be just the messages that apply to
this field, like so:

[
'rule' => 'message',
'rule' => 'message'
]

@param string      $field
@param string|null $label
@param string      $rules
@param array       $errors

@return $this

Sets an individual rule and custom error messages for a single field .


public function getRuleGroup(string $group): array
	{
		if (! isset($this->config->$group))
		{
			throw ValidationException::forGroupNotFound($group);
		}

		if (! is_array($this->config->$group))
		{
			throw ValidationException::forGroupNotArray($group);
		}

		return $this->config->$group;
	}

public function getRuleGroup ( string $ group ) : array { if ( ! isset ( $ this -> config -> $ group ) ) { throw ValidationException :: forGroupNotFound ( $ group ) ; } if ( ! is_array ( $ this -> config -> $ group ) ) { throw ValidationException :: forGroupNotArray ( $ group ) ; } return $ this -> config -> $ group ; }

Get rule group.

@param string $group Group.

@return string[] Rule group.

@throws \InvalidArgumentException If group not found.


public function setRuleGroup(string $group)
	{
		$rules       = $this->getRuleGroup($group);
		$this->rules = $rules;

		$errorName = $group . '_errors';
		if (isset($this->config->$errorName))
		{
			$this->customErrors = $this->config->$errorName;
		}
	}

public function setRuleGroup ( string $ group ) { $ rules = $ this -> getRuleGroup ( $ group ) ; $ this -> rules = $ rules ; $ errorName = $ group . '_errors' ; if ( isset ( $ this -> config -> $ errorName ) ) { $ this -> customErrors = $ this -> config -> $ errorName ; } }

Set rule group.

@param string $group Group.

@throws \InvalidArgumentException If group not found.


protected function loadRuleSets()
	{
		if (empty($this->ruleSetFiles))
		{
			throw ValidationException::forNoRuleSets();
		}

		foreach ($this->ruleSetFiles as $file)
		{
			$this->ruleSetInstances[] = new $file();
		}
	}

protected function loadRuleSets ( ) { if ( empty ( $ this -> ruleSetFiles ) ) { throw ValidationException :: forNoRuleSets ( ) ; } foreach ( $ this -> ruleSetFiles as $ file ) { $ this -> ruleSetInstances [ ] = new $ file ( ) ; } }

Loads all of the rulesets classes that have been defined in the
Config\Validation and stores them locally so we can use them.

Loads all of the rulesets classes that have been defined in the Config \ Validation and stores them locally so we can use them .


public function setError(string $field, string $error): ValidationInterface
	{
		$this->errors[$field] = $error;

		return $this;
	}

public function setError ( string $ field , string $ error ) : ValidationInterface { $ this -> errors [ $ field ] = $ error ; return $ this ; }

Sets the error for a specific field. Used by custom validation methods.

@param string $field
@param string $error

@return \CodeIgniter\Validation\ValidationInterface

Sets the error for a specific field . Used by custom validation methods .


protected function getErrorMessage(string $rule, string $field, string $label = null, string $param = null): string
	{
		// Check if custom message has been defined by user
		if (isset($this->customErrors[$field][$rule]))
		{
			$message = $this->customErrors[$field][$rule];
		}
		else
		{
			// Try to grab a localized version of the message...
			// lang() will return the rule name back if not found,
			// so there will always be a string being returned.
			$message = lang('Validation.' . $rule);
		}

		$message = str_replace('{field}', $label ?? $field, $message);
		$message = str_replace('{param}', $this->rules[$param]['label'] ?? $param, $message);

		return $message;
	}

Attempts to find the appropriate error message

@param string      $rule
@param string      $field
@param string|null $label
@param string      $param

@return string