auto fixes + some impl.

This commit is contained in:
Dennis Eichhorn 2024-01-26 22:54:00 +00:00
parent 560f8a2796
commit f1a64bdc64
433 changed files with 4473 additions and 1662 deletions

View File

@ -15,7 +15,6 @@ declare(strict_types=1);
namespace phpOMS\Account;
use phpOMS\Localization\Localization;
use phpOMS\Stdlib\Base\Exception\InvalidEnumValue;
use phpOMS\Validation\Network\Email;
/**
@ -164,12 +163,12 @@ class Account implements \JsonSerializable
*/
public function hasPermission(
int $permission,
int $unit = null,
int $app = null,
string $module = null,
int $category = null,
int $element = null,
int $component = null
?int $unit = null,
?int $app = null,
?string $module = null,
?int $category = null,
?int $element = null,
?int $component = null
) : bool
{
foreach ($this->groups as $group) {
@ -317,70 +316,6 @@ class Account implements \JsonSerializable
$this->email = \mb_strtolower($email);
}
/**
* Get status.
*
* @return int Returns the status (AccountStatus)
*
* @since 1.0.0
*/
public function getStatus() : int
{
return $this->status;
}
/**
* Get status.
*
* @param int $status Status
*
* @return void
*
* @throws InvalidEnumValue This exception is thrown if a invalid status is used
*
* @since 1.0.0
*/
public function setStatus(int $status) : void
{
if (!AccountStatus::isValidValue($status)) {
throw new InvalidEnumValue($status);
}
$this->status = $status;
}
/**
* Get type.
*
* @return int Returns the type (AccountType)
*
* @since 1.0.0
*/
public function getType() : int
{
return $this->type;
}
/**
* Get type.
*
* @param int $type Type
*
* @return void
*
* @throws InvalidEnumValue This exception is thrown if an invalid type is used
*
* @since 1.0.0
*/
public function setType(int $type) : void
{
if (!AccountType::isValidValue($type)) {
throw new InvalidEnumValue($type);
}
$this->type = $type;
}
/**
* Get last activity.
*

View File

@ -71,8 +71,8 @@ final class AccountManager implements \Countable
if ($id === 0) {
$account = new Account(Auth::authenticate($this->session));
if (!isset($this->accounts[$account->getId()])) {
$this->accounts[$account->getId()] = $account;
if (!isset($this->accounts[$account->id])) {
$this->accounts[$account->id] = $account;
}
return $account;
@ -92,8 +92,8 @@ final class AccountManager implements \Countable
*/
public function add(Account $account) : bool
{
if (!isset($this->accounts[$account->getId()])) {
$this->accounts[$account->getId()] = $account;
if (!isset($this->accounts[$account->id])) {
$this->accounts[$account->id] = $account;
return true;
}

View File

@ -14,8 +14,6 @@ declare(strict_types=1);
namespace phpOMS\Account;
use phpOMS\Stdlib\Base\Exception\InvalidEnumValue;
/**
* Account group class.
*
@ -88,38 +86,6 @@ class Group implements \JsonSerializable
return $this->id;
}
/**
* Get group status.
*
* @return int Group status
*
* @since 1.0.0
*/
public function getStatus() : int
{
return $this->status;
}
/**
* Set group status.
*
* @param int $status Group status
*
* @return void
*
* @throws InvalidEnumValue This exception is thrown if an invalid status is used
*
* @since 1.0.0
*/
public function setStatus(int $status) : void
{
if (!GroupStatus::isValidValue($status)) {
throw new InvalidEnumValue($status);
}
$this->status = $status;
}
/**
* Get string representation.
*

View File

@ -24,6 +24,18 @@ namespace phpOMS\Account;
*/
final class NullAccount extends Account
{
/**
* Constructor
*
* @param int $id Model id
*
* @since 1.0.0
*/
public function __construct(int $id = 0)
{
$this->id = $id;
}
/**
* {@inheritdoc}
*/

View File

@ -169,13 +169,13 @@ class PermissionAbstract implements \JsonSerializable
* @since 1.0.0
*/
public function __construct(
int $unit = null,
int $app = null,
string $module = null,
string $from = null,
int $category = null,
int $element = null,
int $component = null,
?int $unit = null,
?int $app = null,
?string $module = null,
?string $from = null,
?int $category = null,
?int $element = null,
?int $component = null,
int $permission = PermissionType::NONE
) {
$this->unit = $unit;
@ -308,12 +308,12 @@ class PermissionAbstract implements \JsonSerializable
*/
public function hasPermission(
int $permission,
int $unit = null,
int $app = null,
string $module = null,
int $category = null,
int $element = null,
int $component = null
?int $unit = null,
?int $app = null,
?string $module = null,
?int $category = null,
?int $element = null,
?int $component = null
) : bool
{
return $permission === PermissionType::NONE ||

View File

@ -135,12 +135,12 @@ trait PermissionHandlingTrait
*/
public function hasPermission(
int $permission,
int $unit = null,
int $app = null,
string $module = null,
int $category = null,
int $element = null,
int $component = null
?int $unit = null,
?int $app = null,
?string $module = null,
?int $category = null,
?int $element = null,
?int $component = null
) : bool
{
foreach ($this->permissions as $p) {

View File

@ -148,7 +148,7 @@ final class AffinityPropagation implements ClusteringInterface
$sum += \max(0.0, $this->responsibilityMatrix[$j][$k]);
}
for ($j += 1; $j < $n; ++$j) {
for (++$j; $j < $n; ++$j) {
$sum += \max(0.0, $this->responsibilityMatrix[$j][$k]);
}

View File

@ -59,7 +59,7 @@ final class AgglomerativeClustering implements ClusteringInterface
*
* @since 1.0.0
*/
public function __construct(\Closure $metric = null, \Closure $linkage = null)
public function __construct(?\Closure $metric = null, ?\Closure $linkage = null)
{
$this->metric = $metric ?? function (PointInterface $a, PointInterface $b) {
$aCoordinates = $a->coordinates;

View File

@ -116,7 +116,7 @@ final class DBSCAN implements ClusteringInterface
*
* @since 1.0.0
*/
public function __construct(\Closure $metric = null)
public function __construct(?\Closure $metric = null)
{
$this->metric = $metric ?? function (PointInterface $a, PointInterface $b) {
$aCoordinates = $a->coordinates;

View File

@ -74,7 +74,7 @@ final class Kmeans implements ClusteringInterface
*
* @since 1.0.0
*/
public function __construct(\Closure $metric = null)
public function __construct(?\Closure $metric = null)
{
$this->metric = $metric ?? function (PointInterface $a, PointInterface $b) {
$aCoordinates = $a->coordinates;

View File

@ -102,7 +102,7 @@ final class MeanShift implements ClusteringInterface
*
* @since 1.0.0
*/
public function __construct(\Closure $metric = null, \Closure $kernel = null)
public function __construct(?\Closure $metric = null, ?\Closure $kernel = null)
{
$this->metric = $metric ?? function (PointInterface $a, PointInterface $b) {
$aCoordinates = $a->coordinates;

View File

@ -28,7 +28,7 @@ class Point implements PointInterface
* Coordinates of the point
*
* @var array<int, int|float>
* @sicne 1.0.0
* @since 1.0.0
*/
public array $coordinates = [];

View File

@ -17,7 +17,7 @@ namespace phpOMS\Algorithm\Frequency;
/**
* Apriori algorithm.
*
* The algorithm cheks how often a set exists in a given set of sets.
* The algorithm checks how often a set exists in a given set of sets.
*
* @package phpOMS\Algorithm\Frequency
* @license OMS License 2.0
@ -39,7 +39,7 @@ final class Apriori
/**
* Generate all possible subsets
*
* @param array $arr Array of eleements
* @param array $arr Array of elements
*
* @return array<array>
*

View File

@ -117,7 +117,7 @@ final class MarkovChain
*
* @since 1.0.0
*/
public function generate(int $length, array $start = null) : array
public function generate(int $length, ?array $start = null) : array
{
$orderKeys = \array_keys($this->data);
$orderValues = \array_keys(\reset($this->data));

View File

@ -62,7 +62,7 @@ final class Weighted
}
/**
* Search for a none-conflicting job that comes befor a defined job
* Search for a none-conflicting job that comes before a defined job
*
* @param JobInterface[] $jobs List of jobs
* @param int $pivot Job to find the previous job to

View File

@ -80,9 +80,9 @@ class GeneticOptimization
*
* @example See unit test for example use case
*
* @param array<array> $population List of all elements with ther parameters (i.e. list of "objects" as arrays).
* @param array<array> $population List of all elements with their parameters (i.e. list of "objects" as arrays).
* The constraints are defined as array values.
* @param \Closure $fitness Fitness function calculates score/feasability of solution
* @param \Closure $fitness Fitness function calculates score/feasibility of solution
* @param \Closure $mutate Mutation function to change the parameters of an "object"
* @param \Closure $crossover Crossover function to exchange parameter values between "objects".
* Sometimes single parameters can be exchanged but sometimes interdependencies exist between parameters which is why this function is required.

View File

@ -40,7 +40,7 @@ class SimulatedAnnealing
return $x;
}
// can be many things, e.g. swapping parameters, increasing/decrising, random generation
// can be many things, e.g. swapping parameters, increasing/decreasing, random generation
public static function neighbor(array $generation, $parameterCount)
{
$newGeneration = $generation;
@ -57,17 +57,17 @@ class SimulatedAnnealing
*/
// Simulated Annealing algorithm
// @todo allow to create a solution space (currently all soluctions need to be in space)
// @todo allow to create a solution space (currently all solutions need to be in space)
// @todo currently only replacing generations, not altering them
/**
* Perform optimization
*
* @example See unit test for example use case
*
* @param array $space List of all elements with ther parameters (i.e. list of "objects" as arrays).
* @param array $space List of all elements with their parameters (i.e. list of "objects" as arrays).
* The constraints are defined as array values.
* @param int $initialTemperature Starting temperature
* @param \Closure $costFunction Fitness function calculates score/feasability of solution
* @param \Closure $costFunction Fitness function calculates score/feasibility of solution
* @param \Closure $neighbor Neighbor function to find a new solution/neighbor
* @param float $coolingRate Rate at which cooling takes place
* @param int $iterations Number of iterations

View File

@ -152,7 +152,7 @@ class Path
}
/**
* Find nodes in bettween two nodes.
* Find nodes in between two nodes.
*
* The path may only contain the jump points or pivot points.
* In order to get every node it needs to be expanded.

View File

@ -50,11 +50,11 @@ class TrueSkill
private float $drawProbability = 0.0;
public function __construct(
float $mu = null,
float $sigma = null,
float $beta = null,
float $tau = null,
float $drawProbability = null)
?float $mu = null,
?float $sigma = null,
?float $beta = null,
?float $tau = null,
?float $drawProbability = null)
{
$this->mu = $mu ?? self::DEFAULT_MU;
$this->sigma = $sigma ?? self::DEFAULT_SIGMA;

View File

@ -179,8 +179,8 @@ final class DHLInternationalShipping implements ShippingInterface
*/
public function authLogin(
string $login, string $password,
string $client = null,
string $payload = null
?string $client = null,
?string $payload = null
) : int
{
$this->client = $client ?? $this->client;
@ -230,7 +230,7 @@ final class DHLInternationalShipping implements ShippingInterface
*/
public function authRedirectLogin(
string $client,
string $redirect = null,
?string $redirect = null,
array $payload = []
) : HttpRequest
{

View File

@ -175,8 +175,8 @@ final class DHLParcelDEShipping implements ShippingInterface
*/
public function authLogin(
string $login, string $password,
string $client = null,
string $payload = null
?string $client = null,
?string $payload = null
) : int
{
$this->apiKey = $client ?? $this->client;
@ -221,7 +221,7 @@ final class DHLParcelDEShipping implements ShippingInterface
*/
public function authRedirectLogin(
string $client,
string $redirect = null,
?string $redirect = null,
array $payload = []
) : HttpRequest
{
@ -595,7 +595,7 @@ final class DHLParcelDEShipping implements ShippingInterface
*
* @since 1.0.0
*/
public function getManifest(\DateTime $date = null) : array
public function getManifest(?\DateTime $date = null) : array
{
$base = self::$ENV === 'live' ? self::LIVE_URL : self::SANDBOX_URL;
$uri = $base . '/parcel/de/shipping/' . self::API_VERSION .'/manifest';

View File

@ -44,7 +44,7 @@ use phpOMS\Message\Http\HttpRequest;
interface ShippingInterface
{
/**
* Create request for authentication using login and passowrd
* Create request for authentication using login and password
*
* @param string $login Login name/email
* @param string $password Password
@ -57,8 +57,8 @@ interface ShippingInterface
*/
public function authLogin(
string $login, string $password,
string $client = null,
string $payload = null
?string $client = null,
?string $payload = null
) : int;
/**
@ -71,7 +71,7 @@ interface ShippingInterface
* Use tokenFromRedirect() to parse the token from the redirect after successful login.
*
* @param string $client Client information (e.g. client id)
* @param null|string $redirect Redirect page after successfull login
* @param null|string $redirect Redirect page after successful login
* @param array $payload Other payload data
*
* @return HttpRequest Request which should be used to create the redirect (e.g. header("Location: $request->uri"))
@ -83,7 +83,7 @@ interface ShippingInterface
*/
public function authRedirectLogin(
string $client,
string $redirect = null,
?string $redirect = null,
array $payload = []
) : HttpRequest;

View File

@ -164,8 +164,8 @@ final class UPSShipping implements ShippingInterface
*/
public function authLogin(
string $login, string $password,
string $client = null,
string $payload = null
?string $client = null,
?string $payload = null
) : int
{
$this->client = $client ?? $this->client;
@ -215,7 +215,7 @@ final class UPSShipping implements ShippingInterface
*/
public function authRedirectLogin(
string $client,
string $redirect = null,
?string $redirect = null,
array $payload = []
) : HttpRequest
{

View File

@ -63,7 +63,7 @@ abstract class StatusAbstract
*
* @since 1.0.0
*/
public static function activateRoutes(ApplicationInfo $appInfo = null) : void
public static function activateRoutes(?ApplicationInfo $appInfo = null) : void
{
self::installRoutesHooks(static::PATH . '/../Routes.php', static::PATH . '/../Admin/Install/Application/Routes.php');
}
@ -77,7 +77,7 @@ abstract class StatusAbstract
*
* @since 1.0.0
*/
public static function activateHooks(ApplicationInfo $appInfo = null) : void
public static function activateHooks(?ApplicationInfo $appInfo = null) : void
{
self::installRoutesHooks(static::PATH . '/../Hooks.php', static::PATH . '/../Admin/Install/Application/Hooks.php');
}

View File

@ -28,7 +28,7 @@ use phpOMS\Stdlib\Base\Enum;
*/
abstract class LoginReturnType extends Enum
{
public const OK = 0; /* Everything is ok and the user got authed */
public const OK = 0; /* Everything is ok and the user got authenticated */
public const FAILURE = -1; /* Authentication resulted in a unexpected failure */

View File

@ -35,7 +35,7 @@ final class AutoloadException extends \RuntimeException
*
* @since 1.0.0
*/
public function __construct(string $message, int $code = 0, \Exception $previous = null)
public function __construct(string $message, int $code = 0, ?\Exception $previous = null)
{
parent::__construct('File "' . $message . '" could not get loaded.', $code, $previous);
}

View File

@ -278,7 +278,7 @@ final class FinanceFormulas
*
* @since 1.0.0
*/
public static function getAnnutiyPaymentFactorPV(float $r, int $n) : float
public static function getAnnuityPaymentFactorPV(float $r, int $n) : float
{
return $r / (1 - \pow(1 + $r, -$n));
}
@ -561,7 +561,7 @@ final class FinanceFormulas
*
* @since 1.0.0
*/
public static function getPrincipalOfCompundInterest(float $C, float $r, int $n) : float
public static function getPrincipalOfCompoundInterest(float $C, float $r, int $n) : float
{
return $C / (\pow(1 + $r, $n) - 1);
}
@ -577,7 +577,7 @@ final class FinanceFormulas
*
* @since 1.0.0
*/
public static function getPeriodsOfCompundInterest(float $P, float $C, float $r) : float
public static function getPeriodsOfCompoundInterest(float $P, float $C, float $r) : float
{
return \log($C / $P + 1) / \log(1 + $r);
}

View File

@ -127,7 +127,7 @@ final class NetPromoterScore
/**
* Count promoters
*
* Promotoers are all ratings larger 8
* Promoters are all ratings larger 8
*
* @return int Returns the amount of promoters (>= 0)
*

View File

@ -106,7 +106,7 @@ final class PageRank
*
* @since 1.0.0
*/
public function calculateRanks(int $iterations = 20, array $startRank = null) : array
public function calculateRanks(int $iterations = 20, ?array $startRank = null) : array
{
if ($startRank !== null) {
$this->pageRanks = $startRank;

View File

@ -39,7 +39,7 @@ final class BayesianPersonalizedRanking
// num_factors determines the dimensionality of the latent factor space.
// learning_rate controls the step size for updating the latent factors during optimization.
// regularization prevents overfitting by adding a penalty for large parameter values.
// regularization prevents over-fitting by adding a penalty for large parameter values.
public function __construct(int $numFactors, float $learningRate, float $regularization)
{
$this->numFactors = $numFactors;

View File

@ -1,12 +1,16 @@
# Development
## Development environment
The setup and configuration of the development environment is in the hands of every developer themselves. However, it is recommended to follow the setup instructions in the [Developer-Guide](https://github.com/Karaka-Management/Developer-Guide/blob/develop/general/setup.md).
The setup and configuration of the development environment is in the hands of every developer themselves. However, it is recommended to follow the setup instructions in the [Developer-Guide](https://github.com/Karaka-Management/Developer-Guide/blob/develop/general/setup.md).
## Code of conduct
Every organization member and contributor to the organization must follow the [code of conduct](../Policies & Guidelines/Code of conduct.md).
Every organization member and contributor to the organization must follow the [Code of Conduct](../Policies%20&%20Guidelines/Code%20of%20Conduct.md).
## Becoming a contributor
For public repositories you can immediately start by creating forks and pull requests. For private repositories which are necessary to setup the complete developer environment, feel free to request access. Please not that we may not immediately give you access to private repositories and instead will give you smaller tasks regarding public repositories. Please contact info@jingga.app for more details. (**R1**)
For all contributions our [Contributor License Agreement "CLA"](https://github.com/Karaka-Management/Organization-Guide/blob/master/Processes/HR/Hiring/Individual%20Contributor%20License%20Agreement.md) comes into effect. (**R2**)
## Code changes
@ -16,56 +20,104 @@ Generally, the development philosophy is result orientated. This means that anyo
Developers are encouraged to pick open tasks with high priorities according to their own skill level. Senior developers may directly assign tasks to developers based on their importance. New developers may find it easier to start with a task that has a low priority as they often also have a lower difficulty.
Open tasks can be found in the project overview: [PROJECT.md](https://github.com/orgs/Karaka-Management/projects/10)
Open tasks can be found in the project overview: [Todos](https://github.com/orgs/Karaka-Management/projects/10)
Tasks currently in development are prefixed in the priority column with an asterisk `*` and a name tag in the task description of the developer who is working on the task.
The open tasks are reviewed once a month by a senior developer. The senior developer updates the project overview if necessary and requests feedback regarding development status of important tasks under development. During this process important tasks may also get directly assigned to developers. This review is performed on a judgmental bases of the senior basis.
### Code style
### Quality
Code changes must follow the [style guidelines](https://github.com/Karaka-Management/Developer-Guide/tree/develop/standards). Additionally, the automatic code style inspection tools must return no errors, failures or warnings. Developers should test their changes with inspection tools and configurations mentioned in the [inspection documentation](https://github.com/Karaka-Management/Developer-Guide/blob/develop/quality/inspections.md) in advance before submitting them for review.
#### Code style
In rare cases errors, failures or warnings during the automatic inspection are acceptable. Reasons can be changes in the programming language, special cases which cannot, are difficult or must be individually configured in the inspection settings. If this is the case for a code change and if inspection configuration changes are necessary are decided by the senior developer performing the code review.
Code changes must follow the [style guidelines](https://github.com/Karaka-Management/Developer-Guide/tree/develop/standards) (**R3**). Additionally, the automatic code style inspection tools must return no errors, failures or warnings. Developers should test their changes with inspection tools and configurations mentioned in the [inspection documentation](https://github.com/Karaka-Management/Developer-Guide/blob/develop/quality/inspections.md) in advance before submitting them for review. (**R4**)
Automated checks which are run during the review process:
In rare cases errors, failures or warnings during the automatic inspection are acceptable. Reasons can be for example special cases which are difficult automatize or must be individually configured in the inspection settings. If this is the case for a code change and if inspection configuration changes are necessary are decided by the senior developer performing the code review. (**R5**)
Automated checks which are run during the review process (**R4**):
```sh
php ./vendor/bin/phpcs --severity=1 ./ --standard="Build/Config/phpcs.xml"
php ./vendor/bin/phpcs ./ --standard="Build/Config/phpcs.xml"
php ./vendor/bin/php-cs-fixer fix ./ --config=Build/Config/.php-cs-fixer.php --allow-risky=yes
php ./vendor/bin/phpcbf --standard=Build/Config/phpcs.xml ./
php ./vendor/bin/rector process --dry-run --config Build/Config/rector.php ./
npx eslint ./ -c ./Build/Config/.eslintrc.json
```
### Tests
#### Tests
Code changes must follow the inspection guidelines (i.e. code coverage) mentioned in the [inspection documentation](https://github.com/Karaka-Management/Developer-Guide/blob/develop/quality/inspections.md). Developers should check if the code changes comply with the inspection guidelines before submitting them.
Code changes must follow the inspection guidelines (i.e. code coverage) mentioned in the [inspection documentation](https://github.com/Karaka-Management/Developer-Guide/blob/develop/quality/inspections.md) (**R6**). Developers should test their changes with inspection tools and configurations mentioned in the [inspection documentation](https://github.com/Karaka-Management/Developer-Guide/blob/develop/quality/inspections.md) in advance before submitting them for review. (**R7**)
In rare cases it might be not possible to follow the inspection guidelines. In such cases the senior developer performing the code review may decide if the code change still gets accepted.
In rare cases it might be not possible to follow the inspection guidelines. In such cases the senior developer performing the code review may decide if the code change still gets accepted. (**R8**)
Automated tests which are run during the review process:
Automated tests which are run during the review process (**R7**):
```sh
php ./vendor/bin/phpunit -c tests/PHPUnit/phpunit_default.xml
php ./vendor/bin/phpstan analyse --autoload-file=phpOMS/Autoloader.php -l 9 -c Build/Config/phpstan.neon ./
php ./vendor/bin/phpstan analyse --no-progress -l 9 -c Build/Config/phpstan.neon ./
npx jasmine-node ./
./cOMS/tests/test.sh
```
Additional inspections which are run but might be ignored during the review depending on the use case are mentioned in the [inspection documentation](https://github.com/Karaka-Management/Developer-Guide/blob/develop/quality/inspections.md) as other checks.
Additional inspections which are run but might be ignored during the review depending on the use case are mentioned in the [inspection documentation](https://github.com/Karaka-Management/Developer-Guide/blob/develop/quality/inspections.md) as other checks. (**R7**)
### Demo
#### Performance
Some code changes may also require changes or extensions in the demo setup scripts. The demo setup script try to simulate a real world use case by generating and modifying mostly random data. This is also a good way to setup and “manually” test the code changes in a larger picture. The demo setup script can be found in the [demoSetup](https://github.com/Karaka-Management/demoSetup) repository. The demo setup script takes a long time due to the large amount of user input simulated data which is generated. Therefore it is recommended to run this only sporadically.
Developers should occasionaly check performance statistics. At this point no target metrics are defined.
### Code review
Since the primary application is a web based application a similar tool as the Google lighthouse tool can be used to inspect the application for best practicies which can significantly improve the application performance. The sitespeed.io tool shows potential performance improvements and slow pages. With the php trace and profiler enabled in the `php.ini` file the VM automatically generates profiling and trace reports for every web request. These can be found in the webgrind logs directory and inspected in webgrind and dropped into the trace visualizer for a flame chart visualization. With mysqldumpslow you can inspect slow sql queries which may need optimization.
1. Automatic trace and benchmark generation with every web request in `/var/www/html/webgrind/Logs`
2. Webgrind view `http://vm_ip:82`
3. Trace visualization `http://vm_ip:81`
1. Download the latest trace from `http://vm_ip:82/Logs`
2. Drag and drop that downloaded `*.xt` file in the trace visualizer
4. `sitespeed.io ./Build/Helper/Scripts/sitespeedDemoUrls.txt -b chrome --outputFolder /var/www/html/sitespeed`
5. Slow query inspection.
```sh
mysqldumpslow -t 10 /var/log/mysql/mysql-slow.log
mysqldumpslow -t 10 -s l /var/log/mysql/mysql-slow.log
```
#### Code review
In addition to the automatic code review performed by the various inspection tools such as (phpcs, phpstan, phpunit, eslint and custom scripts) a senior developer must check the proposed code change before it is merged with the respective `develop` branch. Only upon the approval by the reviewer a code change requests gets merged as no other developers have permission in the software to make such code merges.
In case a code change request is not approved the reviewer states the reason for the decision, this may include some tips and requests which will allow the contributor to make improvements so that the code change may get approved.
If the code reviewer only finds minor issues with the proposed code change the reviewer may make small changes to the proposed code change and inform the contributor to speed up the implementation process. Code reviewers are encouraged to do this with new contributors to avoid long iteration processes and to not discourage new developers. However, communication is key and severe issues with code change requests or if the contributor already made multiple code change requests in the past the reviewer should not implement the improvements by himself and rather decline the code change requests with his reasoning.
If the code reviewer only finds minor issues with the proposed code change the reviewer may make small changes to the proposed code change and inform the contributor to speed up the implementation process. Code reviewers are encouraged to do this with new contributors to avoid long iteration processes and to not discourage new developers. However, communication is key and severe issues with code change requests or if the contributor already made multiple code change requests in the past the reviewer should not implement the improvements by himself and rather decline the code change requests with his reasoning. (**R5**+**R8**)
#### Demo
Some code changes may also require changes or extensions in the demo setup scripts. The demo setup script try to simulate a real world use case by generating and modifying mostly random data. This is also a good way to setup and “manually” test the code changes in a larger picture. The demo setup script can be found in the [demoSetup](https://github.com/Karaka-Management/demoSetup) repository. The demo setup script takes a long time due to the large amount of user input simulated data which is generated. Therefore it is recommended to run this only sporadically. (**R9**)
```sh
sudo -u www-data php -dxdebug.remote_enable=1 -dxdebug.start_with_request=yes -dxdebug.mode=coverage,develop,debug demoSetup/setup.php
```
#### Documentation
Occasionally new code or code changes also require new documentation or documentation changes. Developers should make sure that the new code is also reflected in the existing documentation ([Developer-Guide](), [User-Guide]() and/or module documentation) or if additional documentation is necessary.
#### Improvements, features, bugs
If a developer (or employee in general) has an idea for an improvement, feature or finds a potential bug it should be reported at https://github.com/Karaka-Management/Karaka/issues. A senior developer has to check these issues and decide how to proceed with them. The decision how to proceed with the issue must be explained by the senior developer as a response in the issue. Possible steps are:
* Accept the issue and put the task into the [Todos](https://github.com/orgs/Karaka-Management/projects/10)
* Dismiss the issue with an explanation
### Release flow
In case SCSS/CSS or JS files got changed they must get re-built locally before comitting the code change:
```sh
npx esbuild Web/Backend/js/backend.js --bundle --outfile=Install/Application/Backend/js/backend.min.js --minify
scss cssOMS/styles.scss > cssOMS/styles.css
```
For JS you may also use the shorthand command `npm run build`.
Code changes must be performed in a new branch. A new branch can be created with:
```sh
@ -75,8 +127,70 @@ git checkout -b new-branch-name
The name of the branch can be chosen freely however it is recommended to follow the following branch naming conventions:
* `feature-*` for feature implementations
* `hotfix-*` for security related fixes/improvements
* `bug-*` for bug fixes
* `security-*` for security related fixes/improvements
* `general-*` for general improvements (i.e. code documentation improvements, code style improvements)
* `general-*` for general improvements (i.e. documentation, code style & performance improvements)
The senior developer who performs the code review merges the change request into the `develop` branch upon approval.
```mermaid
%%{init: { 'gitGraph': {'mainBranchName': 'master'}} }%%
gitGraph
commit
branch hotfix-xxx
commit
checkout master
branch develop
checkout master
merge hotfix-xxx
checkout develop
branch bug-xxx
commit
commit
checkout hotfix-xxx
commit
checkout master
merge hotfix-xxx
checkout develop
merge bug-xxx
commit
checkout develop
branch feature-xxx
commit
commit
commit
checkout develop
merge feature-xxx
checkout master
merge develop
checkout develop
branch general-xxx
commit
checkout develop
merge general-xxx
branch security-xxx
commit
commit
checkout develop
merge security-xxx
checkout master
merge develop
```
The senior developer who performs the code review merges the change request into the `develop` branch after their successful code review. Unsuccessful reviews lead to change requests by the original developer, other developers who can make the requested changes, changes by the senior developer who performed the review, or dismissal of the changed code. (**R10**)
## Approved dependencies
### Customer dependencies
Developers may only rely on the dependencies defined in [Approved Customer Software]() when developing a solution. If new software should be added to this list or a different version is required developers should make a request with their team leader/head of department who forwards this requests if appropriate to the CTO and explain the reasoning for the different dependency needs. The CTO can decide if the dependency will be accepted. (**R11**)
### Developer dependencies
Developers may only rely on the dependencies defined in [IT Equipment & Software](). If new software should be added to this list or a different version is required developers should make a request with their team leader/head of department who forwards this requests if appropriate to the CTO and explain the reasoning for the different dependency needs. The CTO can decide if the dependency will be accepted. Changing the package managers such as `composer.json` or `package.json` is not allowed by anyone else than the CTO. (**R12**)
## Other related documents
* [Confidentiality Policy](../Policies%20&%20Guidelines/Confidentiality%20Policy.md)
* [Organization Activity Policy](../Policies%20&%20Guidelines/Organization%20Activity%20Policy.md)
* [Tutorials](./Development/Tutorials)

View File

@ -45,12 +45,12 @@ interface SettingsInterface extends OptionsInterface
*/
public function get(
mixed $ids = null,
string | array $names = null,
int $unit = null,
int $app = null,
string $module = null,
int $group = null,
int $account = null
string | array|null $names = null,
?int $unit = null,
?int $app = null,
?string $module = null,
?int $group = null,
?int $account = null
) : mixed;
/**

View File

@ -51,7 +51,7 @@ interface StreamInterface
*
* @since 1.0.0
*/
public function getMetaData(string $key = null);
public function getMetaData(?string $key = null);
/**
* Get the stream resource
@ -72,7 +72,7 @@ interface StreamInterface
*
* @since 1.0.0
*/
public function setStream($stream, int $size = null) : self;
public function setStream($stream, ?int $size = null) : self;
/**
* Detach the current stream resource
@ -264,7 +264,7 @@ interface StreamInterface
*
* @since 1.0.0
*/
public function readLine(int $maxLength = null) : ?string;
public function readLine(?int $maxLength = null) : ?string;
/**
* Set custom data on the stream

View File

@ -94,7 +94,7 @@ final class FileCache extends ConnectionAbstract
*
* @since 1.0.0
*/
public function connect(array $data = null) : void
public function connect(?array $data = null) : void
{
$this->dbdata = $data;

View File

@ -74,7 +74,7 @@ final class MemCached extends ConnectionAbstract
*
* @since 1.0.0
*/
public function connect(array $data = null) : void
public function connect(?array $data = null) : void
{
$this->dbdata = isset($data) ? $data : $this->dbdata;

View File

@ -27,7 +27,7 @@ final class NullCache extends ConnectionAbstract
/**
* {@inheritdoc}
*/
public function connect(array $data = null) : void
public function connect(?array $data = null) : void
{
}

View File

@ -66,7 +66,7 @@ final class RedisCache extends ConnectionAbstract
*
* @since 1.0.0
*/
public function connect(array $data = null) : void
public function connect(?array $data = null) : void
{
$this->dbdata = isset($data) ? $data : $this->dbdata;

View File

@ -33,7 +33,7 @@ final class InvalidConnectionConfigException extends \InvalidArgumentException
*
* @since 1.0.0
*/
public function __construct(string $message = '', int $code = 0, \Exception $previous = null)
public function __construct(string $message = '', int $code = 0, ?\Exception $previous = null)
{
parent::__construct('Invalid/missing config value for "' . $message . '".', $code, $previous);
}

View File

@ -99,7 +99,7 @@ final class CookieJar
mixed $value,
int $expire = 86400,
string $path = '/',
string $domain = null,
?string $domain = null,
bool $secure = false,
bool $httpOnly = true,
bool $overwrite = true

View File

@ -35,7 +35,7 @@ interface DataStorageConnectionInterface
*
* @since 1.0.0
*/
public function connect(array $data = null) : void;
public function connect(?array $data = null) : void;
/**
* Get the datastorage type.

View File

@ -161,7 +161,7 @@ abstract class ConnectionAbstract implements ConnectionInterface
*
* @since 1.0.0
*/
abstract public function connect(array $dbdata = null) : void;
abstract public function connect(?array $dbdata = null) : void;
/**
* Object destructor.

View File

@ -58,7 +58,7 @@ final class MysqlConnection extends ConnectionAbstract
/**
* {@inheritdoc}
*/
public function connect(array $dbdata = null) : void
public function connect(?array $dbdata = null) : void
{
if ($this->status === DatabaseStatus::OK) {
return;

View File

@ -27,7 +27,7 @@ final class NullConnection extends ConnectionAbstract
/**
* {@inheritdoc}
*/
public function connect(array $dbdata = null) : void
public function connect(?array $dbdata = null) : void
{
}

View File

@ -58,7 +58,7 @@ final class PostgresConnection extends ConnectionAbstract
/**
* {@inheritdoc}
*/
public function connect(array $dbdata = null) : void
public function connect(?array $dbdata = null) : void
{
if ($this->status === DatabaseStatus::OK) {
return;

View File

@ -66,7 +66,7 @@ final class SQLiteConnection extends ConnectionAbstract
*
* @since 1.0.0
*/
public function connect(array $dbdata = null) : void
public function connect(?array $dbdata = null) : void
{
if ($this->status === DatabaseStatus::OK) {
return;

View File

@ -58,7 +58,7 @@ final class SqlServerConnection extends ConnectionAbstract
/**
* {@inheritdoc}
*/
public function connect(array $dbdata = null) : void
public function connect(?array $dbdata = null) : void
{
if ($this->status === DatabaseStatus::OK) {
return;

View File

@ -33,7 +33,7 @@ final class InvalidConnectionConfigException extends \InvalidArgumentException
*
* @since 1.0.0
*/
public function __construct(string $message = '', int $code = 0, \Exception $previous = null)
public function __construct(string $message = '', int $code = 0, ?\Exception $previous = null)
{
parent::__construct('Missing config value for "' . $message . '".', $code, $previous);
}

View File

@ -33,7 +33,7 @@ final class InvalidDatabaseTypeException extends \InvalidArgumentException
*
* @since 1.0.0
*/
public function __construct(string $message = '', int $code = 0, \Exception $previous = null)
public function __construct(string $message = '', int $code = 0, ?\Exception $previous = null)
{
parent::__construct('Invalid database type "' . $message . '".', $code, $previous);
}

View File

@ -33,7 +33,7 @@ final class InvalidMapperException extends \RuntimeException
*
* @since 1.0.0
*/
public function __construct(string $message = '', int $code = 0, \Exception $previous = null)
public function __construct(string $message = '', int $code = 0, ?\Exception $previous = null)
{
if ($message === '') {
parent::__construct('Empty mapper.', $code, $previous);

View File

@ -152,7 +152,7 @@ abstract class DataMapperAbstract
*
* @since 1.0.0
*/
public function query(Builder $query = null) : self
public function query(?Builder $query = null) : self
{
$this->query = $query;

View File

@ -179,7 +179,7 @@ class DataMapperFactory
*
* @since 1.0.0
*/
public static function reader(ConnectionAbstract $db = null) : ReadMapper
public static function reader(?ConnectionAbstract $db = null) : ReadMapper
{
return new ReadMapper(new static(), $db ?? self::$db);
}
@ -193,7 +193,7 @@ class DataMapperFactory
*
* @since 1.0.0
*/
public static function get(ConnectionAbstract $db = null) : ReadMapper
public static function get(?ConnectionAbstract $db = null) : ReadMapper
{
/** @var ReadMapper<T> $reader */
$reader = new ReadMapper(new static(), $db ?? self::$db);
@ -210,7 +210,7 @@ class DataMapperFactory
*
* @since 1.0.0
*/
public static function yield(ConnectionAbstract $db = null) : ReadMapper
public static function yield(?ConnectionAbstract $db = null) : ReadMapper
{
/** @var ReadMapper<T> $reader */
$reader = new ReadMapper(new static(), $db ?? self::$db);
@ -227,7 +227,7 @@ class DataMapperFactory
*
* @since 1.0.0
*/
public static function getRaw(ConnectionAbstract $db = null) : ReadMapper
public static function getRaw(?ConnectionAbstract $db = null) : ReadMapper
{
/** @var ReadMapper<T> $reader */
$reader = new ReadMapper(new static(), $db ?? self::$db);
@ -244,7 +244,7 @@ class DataMapperFactory
*
* @since 1.0.0
*/
public static function getRandom(ConnectionAbstract $db = null) : ReadMapper
public static function getRandom(?ConnectionAbstract $db = null) : ReadMapper
{
return (new ReadMapper(new static(), $db ?? self::$db))->getRandom();
}
@ -258,7 +258,7 @@ class DataMapperFactory
*
* @since 1.0.0
*/
public static function count(ConnectionAbstract $db = null) : ReadMapper
public static function count(?ConnectionAbstract $db = null) : ReadMapper
{
return (new ReadMapper(new static(), $db ?? self::$db))->count();
}
@ -272,7 +272,7 @@ class DataMapperFactory
*
* @since 1.0.0
*/
public static function sum(ConnectionAbstract $db = null) : ReadMapper
public static function sum(?ConnectionAbstract $db = null) : ReadMapper
{
return (new ReadMapper(new static(), $db ?? self::$db))->sum();
}
@ -286,7 +286,7 @@ class DataMapperFactory
*
* @since 1.0.0
*/
public static function exists(ConnectionAbstract $db = null) : ReadMapper
public static function exists(?ConnectionAbstract $db = null) : ReadMapper
{
return (new ReadMapper(new static(), $db ?? self::$db))->exists();
}
@ -300,7 +300,7 @@ class DataMapperFactory
*
* @since 1.0.0
*/
public static function has(ConnectionAbstract $db = null) : ReadMapper
public static function has(?ConnectionAbstract $db = null) : ReadMapper
{
return (new ReadMapper(new static(), $db ?? self::$db))->has();
}
@ -314,7 +314,7 @@ class DataMapperFactory
*
* @since 1.0.0
*/
public static function getQuery(ConnectionAbstract $db = null) : Builder
public static function getQuery(?ConnectionAbstract $db = null) : Builder
{
return (new ReadMapper(new static(), $db ?? self::$db))->getQuery();
}
@ -328,7 +328,7 @@ class DataMapperFactory
*
* @since 1.0.0
*/
public static function getAll(ConnectionAbstract $db = null) : ReadMapper
public static function getAll(?ConnectionAbstract $db = null) : ReadMapper
{
/** @var ReadMapper<T> $reader */
$reader = new ReadMapper(new static(), $db ?? self::$db);
@ -345,7 +345,7 @@ class DataMapperFactory
*
* @since 1.0.0
*/
public static function writer(ConnectionAbstract $db = null) : WriteMapper
public static function writer(?ConnectionAbstract $db = null) : WriteMapper
{
return new WriteMapper(new static(), $db ?? self::$db);
}
@ -359,7 +359,7 @@ class DataMapperFactory
*
* @since 1.0.0
*/
public static function create(ConnectionAbstract $db = null) : WriteMapper
public static function create(?ConnectionAbstract $db = null) : WriteMapper
{
return (new WriteMapper(new static(), $db ?? self::$db))->create();
}
@ -373,7 +373,7 @@ class DataMapperFactory
*
* @since 1.0.0
*/
public static function updater(ConnectionAbstract $db = null) : UpdateMapper
public static function updater(?ConnectionAbstract $db = null) : UpdateMapper
{
return new UpdateMapper(new static(), $db ?? self::$db);
}
@ -387,7 +387,7 @@ class DataMapperFactory
*
* @since 1.0.0
*/
public static function update(ConnectionAbstract $db = null) : UpdateMapper
public static function update(?ConnectionAbstract $db = null) : UpdateMapper
{
return (new UpdateMapper(new static(), $db ?? self::$db))->update();
}
@ -401,7 +401,7 @@ class DataMapperFactory
*
* @since 1.0.0
*/
public static function remover(ConnectionAbstract $db = null) : DeleteMapper
public static function remover(?ConnectionAbstract $db = null) : DeleteMapper
{
return new DeleteMapper(new static(), $db ?? self::$db);
}
@ -415,7 +415,7 @@ class DataMapperFactory
*
* @since 1.0.0
*/
public static function delete(ConnectionAbstract $db = null) : DeleteMapper
public static function delete(?ConnectionAbstract $db = null) : DeleteMapper
{
return (new DeleteMapper(new static(), $db ?? self::$db))->delete();
}
@ -463,7 +463,7 @@ class DataMapperFactory
*
* @since 1.0.0
*/
public static function createBaseModel(array $data = null) : object
public static function createBaseModel(?array $data = null) : object
{
if (empty(static::FACTORY)) {
$class = empty(static::MODEL) ? \substr(static::class, 0, -6) : static::MODEL;
@ -485,7 +485,7 @@ class DataMapperFactory
*
* @since 1.0.0
*/
public static function getObjectId(object $obj, string $member = null, \ReflectionClass &$refClass = null) : mixed
public static function getObjectId(object $obj, ?string $member = null, ?\ReflectionClass &$refClass = null) : mixed
{
$propertyName = $member ?? static::COLUMNS[static::PRIMARYFIELD]['internal'];
@ -513,7 +513,7 @@ class DataMapperFactory
*
* @since 1.0.0
*/
public static function setObjectId(object $obj, mixed $objId, \ReflectionClass &$refClass = null) : void
public static function setObjectId(object $obj, mixed $objId, ?\ReflectionClass &$refClass = null) : void
{
$propertyName = static::COLUMNS[static::PRIMARYFIELD]['internal'];
\settype($objId, static::COLUMNS[static::PRIMARYFIELD]['type']);
@ -569,13 +569,13 @@ class DataMapperFactory
* @since 1.0.0
*/
public static function find(
string $search = null,
DataMapperAbstract $mapper = null,
?string $search = null,
?DataMapperAbstract $mapper = null,
int $id = 0,
string $secondaryId = '',
string $type = null,
?string $type = null,
int $pageLimit = 25,
string $sortBy = null,
?string $sortBy = null,
string $sortOrder = OrderType::DESC,
array $searchFields = [],
array $filters = []
@ -680,7 +680,7 @@ class DataMapperFactory
--$count;
}
} else {
if (\reset($data)->getId() === $id) {
if (\reset($data)->id === $id) {
\array_shift($data);
$hasNext = true;
--$count;
@ -723,7 +723,7 @@ class DataMapperFactory
];
}
if (\reset($data)->getId() === $id) {
if (\reset($data)->id === $id) {
\array_shift($data);
$hasPrevious = true;
--$count;

View File

@ -119,7 +119,7 @@ final class DeleteMapper extends DataMapperAbstract
*
* @since 1.0.0
*/
private function deleteSingleRelation(object $obj, array $relation, \ReflectionClass &$refClass = null) : void
private function deleteSingleRelation(object $obj, array $relation, ?\ReflectionClass &$refClass = null) : void
{
if (empty($relation)) {
return;
@ -166,7 +166,7 @@ final class DeleteMapper extends DataMapperAbstract
*
* @since 1.0.0
*/
private function deleteHasMany(object $obj, mixed $objId, \ReflectionClass &$refClass = null) : void
private function deleteHasMany(object $obj, mixed $objId, ?\ReflectionClass &$refClass = null) : void
{
if (empty($this->mapper::HAS_MANY)) {
return;
@ -237,7 +237,7 @@ final class DeleteMapper extends DataMapperAbstract
*
* @since 1.0.0
*/
public function deleteRelationTable(string $member, array $objIds = null, mixed $objId) : void
public function deleteRelationTable(string $member, ?array $objIds = null, mixed $objId) : void
{
if ((empty($objIds) && $objIds !== null)
|| $this->mapper::HAS_MANY[$member]['table'] === $this->mapper::TABLE

View File

@ -258,7 +258,7 @@ final class ReadMapper extends DataMapperAbstract
*
* @since 1.0.0
*/
public function executeGet(Builder $query = null) : mixed
public function executeGet(?Builder $query = null) : mixed
{
$primaryKeys = [];
$memberOfPrimaryField = $this->mapper::COLUMNS[$this->mapper::PRIMARYFIELD]['internal'];
@ -293,7 +293,7 @@ final class ReadMapper extends DataMapperAbstract
// it cannot get assigned to the correct parent object.
// Other relation types are easy because either the parent or child object contain the relation info.
// One solution could be to always pass an array
if (!empty($this->with)) {
if (!empty($this->with) && !empty($value)) {
$this->loadHasManyRelations($obj[$value]);
}
}
@ -317,7 +317,7 @@ final class ReadMapper extends DataMapperAbstract
*
* @since 1.0.0
*/
public function executeGetYield(Builder $query = null)
public function executeGetYield(?Builder $query = null)
{
$primaryKeys = [];
$memberOfPrimaryField = $this->mapper::COLUMNS[$this->mapper::PRIMARYFIELD]['internal'];
@ -350,7 +350,7 @@ final class ReadMapper extends DataMapperAbstract
*
* @since 1.0.0
*/
public function executeGetRaw(Builder $query = null) : array
public function executeGetRaw(?Builder $query = null) : array
{
$query ??= $this->getQuery();
$results = false;
@ -385,7 +385,7 @@ final class ReadMapper extends DataMapperAbstract
*
* @since 1.0.0
*/
public function executeGetRawYield(Builder $query = null)
public function executeGetRawYield(?Builder $query = null)
{
$query ??= $this->getQuery();
@ -426,7 +426,7 @@ final class ReadMapper extends DataMapperAbstract
*
* @since 1.0.0
*/
public function executeGetAll(Builder $query = null) : array
public function executeGetAll(?Builder $query = null) : array
{
$result = $this->executeGet($query);
@ -537,7 +537,7 @@ final class ReadMapper extends DataMapperAbstract
*
* @since 1.0.0
*/
public function getQuery(Builder $query = null, array $columns = []) : Builder
public function getQuery(?Builder $query = null, array $columns = []) : Builder
{
$query ??= $this->query ?? new Builder($this->db, true);
@ -1243,7 +1243,7 @@ final class ReadMapper extends DataMapperAbstract
$refClass = null;
// @todo check if there are more cases where the relation is already loaded with joins etc.
// there can be pseudo hasMany elements like localizations. They are has manies but these are already loaded with joins!
// there can be pseudo hasMany elements like localizations. They are hasMany but these are already loaded with joins!
foreach ($this->with as $member => $withData) {
if (isset($this->mapper::HAS_MANY[$member])) {
$many = $this->mapper::HAS_MANY[$member];

View File

@ -102,7 +102,7 @@ final class UpdateMapper extends DataMapperAbstract
*
* @since 1.0.0
*/
private function updateModel(object $obj, mixed $objId, \ReflectionClass &$refClass = null) : void
private function updateModel(object $obj, mixed $objId, ?\ReflectionClass &$refClass = null) : void
{
try {
// Model doesn't have anything to update
@ -193,6 +193,14 @@ final class UpdateMapper extends DataMapperAbstract
/** @var class-string<DataMapperFactory> $mapper */
$mapper = $this->mapper::BELONGS_TO[$propertyName]['mapper'];
if (!isset($this->with[$propertyName])) {
$id = $mapper::getObjectId($obj);
return empty($id) && $mapper::isNullModel($obj)
? null
: $id;
}
/** @var self $relMapper */
$relMapper = $this->createRelationMapper($mapper::update(db: $this->db), $propertyName);
$relMapper->depth = $this->depth + 1;
@ -215,6 +223,14 @@ final class UpdateMapper extends DataMapperAbstract
/** @var class-string<DataMapperFactory> $mapper */
$mapper = $this->mapper::OWNS_ONE[$propertyName]['mapper'];
if (!isset($this->with[$propertyName])) {
$id = $mapper::getObjectId($obj);
return empty($id) && $mapper::isNullModel($obj)
? null
: $id;
}
/** @var self $relMapper */
$relMapper = $this->createRelationMapper($mapper::update(db: $this->db), $propertyName);
$relMapper->depth = $this->depth + 1;
@ -235,7 +251,7 @@ final class UpdateMapper extends DataMapperAbstract
*
* @since 1.0.0
*/
private function updateHasMany(object $obj, mixed $objId, \ReflectionClass &$refClass = null) : void
private function updateHasMany(object $obj, mixed $objId, ?\ReflectionClass &$refClass = null) : void
{
if (empty($this->with) || empty($this->mapper::HAS_MANY)) {
return;

View File

@ -74,20 +74,16 @@ final class WriteMapper extends DataMapperAbstract
*/
public function executeCreate(object $obj) : mixed
{
$refClass = null;
if ($this->mapper::isNullModel($obj)) {
$objId = $this->mapper::getObjectId($obj);
if ((!empty($objId) && $this->mapper::AUTOINCREMENT)
|| $this->mapper::isNullModel($obj)
) {
return $objId === 0 ? null : $objId;
}
if (!empty($id = $this->mapper::getObjectId($obj)) && $this->mapper::AUTOINCREMENT) {
$objId = $id;
} else {
$refClass = null;
$objId = $this->createModel($obj, $refClass);
$this->mapper::setObjectId($obj, $objId, $refClass);
}
$this->createHasMany($obj, $objId, $refClass);
@ -104,7 +100,7 @@ final class WriteMapper extends DataMapperAbstract
*
* @since 1.0.0
*/
private function createModel(object $obj, \ReflectionClass &$refClass = null) : mixed
private function createModel(object $obj, ?\ReflectionClass &$refClass = null) : mixed
{
try {
$query = new Builder($this->db);
@ -246,7 +242,9 @@ final class WriteMapper extends DataMapperAbstract
$primaryKey = $mapper::getObjectId($obj);
// @todo the $mapper::create() might cause a problem if 'by' is set. because we don't want to create this obj but the child obj.
return empty($primaryKey) ? $mapper::create(db: $this->db)->execute($obj) : $primaryKey;
return empty($primaryKey)
? $mapper::create(db: $this->db)->execute($obj)
: $primaryKey;
}
/**
@ -262,7 +260,7 @@ final class WriteMapper extends DataMapperAbstract
*
* @since 1.0.0
*/
private function createHasMany(object $obj, mixed $objId, \ReflectionClass &$refClass = null) : void
private function createHasMany(object $obj, mixed $objId, ?\ReflectionClass &$refClass = null) : void
{
foreach ($this->mapper::HAS_MANY as $propertyName => $rel) {
if (!isset($this->mapper::HAS_MANY[$propertyName]['mapper'])) {

View File

@ -538,7 +538,7 @@ class Builder extends BuilderAbstract
*
* @since 1.0.0
*/
public function where(string | array | self $columns, string | array $operator = null, mixed $values = null, string | array $boolean = 'and') : self
public function where(string | array | self $columns, string | array|null $operator = null, mixed $values = null, string | array $boolean = 'and') : self
{
if (!\is_array($columns)) {
$columns = [$columns];
@ -577,7 +577,7 @@ class Builder extends BuilderAbstract
*
* @since 1.0.0
*/
public function andWhere(string | array | Where $where, string | array $operator = null, mixed $values = null) : self
public function andWhere(string | array | Where $where, string | array|null $operator = null, mixed $values = null) : self
{
return $this->where($where, $operator, $values, 'and');
}
@ -593,7 +593,7 @@ class Builder extends BuilderAbstract
*
* @since 1.0.0
*/
public function orWhere(string | array | self $where, string | array $operator = null, mixed $values = null) : self
public function orWhere(string | array | self $where, string | array|null $operator = null, mixed $values = null) : self
{
return $this->where($where, $operator, $values, 'or');
}
@ -1097,7 +1097,7 @@ class Builder extends BuilderAbstract
*
* @since 1.0.0
*/
public function join(string | self $table, string $type = JoinType::JOIN, string $alias = null) : self
public function join(string | self $table, string $type = JoinType::JOIN, ?string $alias = null) : self
{
$this->joins[$alias ?? $table] = ['type' => $type, 'table' => $table, 'alias' => $alias];
@ -1114,7 +1114,7 @@ class Builder extends BuilderAbstract
*
* @since 1.0.0
*/
public function leftJoin(string | self $table, string $alias = null) : self
public function leftJoin(string | self $table, ?string $alias = null) : self
{
return $this->join($table, JoinType::LEFT_JOIN, $alias);
}
@ -1129,7 +1129,7 @@ class Builder extends BuilderAbstract
*
* @since 1.0.0
*/
public function leftOuterJoin(string | self $table, string $alias = null) : self
public function leftOuterJoin(string | self $table, ?string $alias = null) : self
{
return $this->join($table, JoinType::LEFT_OUTER_JOIN, $alias);
}
@ -1144,7 +1144,7 @@ class Builder extends BuilderAbstract
*
* @since 1.0.0
*/
public function leftInnerJoin(string | self $table, string $alias = null) : self
public function leftInnerJoin(string | self $table, ?string $alias = null) : self
{
return $this->join($table, JoinType::LEFT_INNER_JOIN, $alias);
}
@ -1159,7 +1159,7 @@ class Builder extends BuilderAbstract
*
* @since 1.0.0
*/
public function rightJoin(string | self $table, string $alias = null) : self
public function rightJoin(string | self $table, ?string $alias = null) : self
{
return $this->join($table, JoinType::RIGHT_JOIN, $alias);
}
@ -1174,7 +1174,7 @@ class Builder extends BuilderAbstract
*
* @since 1.0.0
*/
public function rightOuterJoin(string | self $table, string $alias = null) : self
public function rightOuterJoin(string | self $table, ?string $alias = null) : self
{
return $this->join($table, JoinType::RIGHT_OUTER_JOIN, $alias);
}
@ -1189,7 +1189,7 @@ class Builder extends BuilderAbstract
*
* @since 1.0.0
*/
public function rightInnerJoin(string | self $table, string $alias = null) : self
public function rightInnerJoin(string | self $table, ?string $alias = null) : self
{
return $this->join($table, JoinType::RIGHT_INNER_JOIN, $alias);
}
@ -1204,7 +1204,7 @@ class Builder extends BuilderAbstract
*
* @since 1.0.0
*/
public function outerJoin(string | self $table, string $alias = null) : self
public function outerJoin(string | self $table, ?string $alias = null) : self
{
return $this->join($table, JoinType::OUTER_JOIN, $alias);
}
@ -1219,7 +1219,7 @@ class Builder extends BuilderAbstract
*
* @since 1.0.0
*/
public function innerJoin(string | self $table, string $alias = null) : self
public function innerJoin(string | self $table, ?string $alias = null) : self
{
return $this->join($table, JoinType::INNER_JOIN, $alias);
}
@ -1234,7 +1234,7 @@ class Builder extends BuilderAbstract
*
* @since 1.0.0
*/
public function crossJoin(string | self $table, string $alias = null) : self
public function crossJoin(string | self $table, ?string $alias = null) : self
{
return $this->join($table, JoinType::CROSS_JOIN, $alias);
}
@ -1249,7 +1249,7 @@ class Builder extends BuilderAbstract
*
* @since 1.0.0
*/
public function fullJoin(string | self $table, string $alias = null) : self
public function fullJoin(string | self $table, ?string $alias = null) : self
{
return $this->join($table, JoinType::FULL_JOIN, $alias);
}
@ -1264,7 +1264,7 @@ class Builder extends BuilderAbstract
*
* @since 1.0.0
*/
public function fullOuterJoin(string | self $table, string $alias = null) : self
public function fullOuterJoin(string | self $table, ?string $alias = null) : self
{
return $this->join($table, JoinType::FULL_OUTER_JOIN, $alias);
}
@ -1296,7 +1296,7 @@ class Builder extends BuilderAbstract
*
* @since 1.0.0
*/
public function on(string | array $columns, string | array $operator = null, mixed $values = null, string | array $boolean = 'and', string $table = null) : self
public function on(string | array $columns, string | array|null $operator = null, mixed $values = null, string | array $boolean = 'and', ?string $table = null) : self
{
if (!\is_array($columns)) {
$columns = [$columns];
@ -1338,7 +1338,7 @@ class Builder extends BuilderAbstract
*
* @since 1.0.0
*/
public function orOn(string | array $columns, string | array $operator = null, string | array $values = null) : self
public function orOn(string | array $columns, string | array|null $operator = null, string | array|null $values = null) : self
{
return $this->on($columns, $operator, $values, 'or');
}
@ -1354,7 +1354,7 @@ class Builder extends BuilderAbstract
*
* @since 1.0.0
*/
public function andOn(string | array $columns, string | array $operator = null, string | array $values = null) : self
public function andOn(string | array $columns, string | array|null $operator = null, string | array|null $values = null) : self
{
return $this->on($columns, $operator, $values, 'and');
}

View File

@ -245,7 +245,7 @@ class Grammar extends GrammarAbstract
*
* @param Builder $query Builder
* @param array $wheres Where elmenets
* @param bool $first Is first element (usefull for nesting)
* @param bool $first Is first element (useful for nesting)
*
* @return string
*
@ -430,7 +430,7 @@ class Grammar extends GrammarAbstract
*
* @param array $element Element data
* @param Builder $query Query builder
* @param bool $first Is first element (usefull for nesting)
* @param bool $first Is first element (useful for nesting)
*
* @return string
*

View File

@ -272,7 +272,7 @@ class Builder extends BuilderAbstract
public function field(
string $name, string $type, $default = null,
bool $isNullable = true, bool $isPrimary = false, bool $isUnique = false, bool $autoincrement = false,
string $foreignTable = null, string $foreignKey = null, array $meta = []
?string $foreignTable = null, ?string $foreignKey = null, array $meta = []
) : self {
$this->createFields[$name] = [
'name' => $name,
@ -318,7 +318,7 @@ class Builder extends BuilderAbstract
*
* @since 1.0.0
*/
public function addConstraint(string $key, string $foreignTable, string $foreignKey, string $constraint = null) : self
public function addConstraint(string $key, string $foreignTable, string $foreignKey, ?string $constraint = null) : self
{
$this->alterAdd['type'] = 'CONSTRAINT';
$this->alterAdd['key'] = $key;

View File

@ -36,7 +36,7 @@ final class LockException extends \RuntimeException
*
* @since 1.0.0
*/
public function __construct(string $message, int $code = 0, \Exception $previous = null)
public function __construct(string $message, int $code = 0, ?\Exception $previous = null)
{
parent::__construct('Interaction with "' . $message . '" already locked.', $code, $previous);
}

View File

@ -66,13 +66,13 @@ final class HttpSession implements SessionInterface
/**
* Constructor.
*
* @param int $liftetime Session life time
* @param int $lifetime Session life time
* @param string $sid Session id
* @param int $inactivityInterval Interval for session activity
*
* @since 1.0.0
*/
public function __construct(int $liftetime = 3600, string $sid = '', int $inactivityInterval = 0)
public function __construct(int $lifetime = 3600, string $sid = '', int $inactivityInterval = 0)
{
if (\session_id()) {
\session_write_close(); // @codeCoverageIgnore
@ -86,8 +86,17 @@ final class HttpSession implements SessionInterface
if (\session_status() !== \PHP_SESSION_ACTIVE && !\headers_sent()) {
// @codeCoverageIgnoreStart
// samesite: Strict results in losing sessions in some situations when working with iframe
// This can happen when the iframe content uses relative links
// -> loads iframe page
// -> iframe page references relative resources (css, js, ...)
// -> client browser tries to load resources
// -> client browser loads current app based on relative link but without session cookie
// -> creates new session cookie for page (not authenticated yet)
// -> loses authentication on iframe parent
// samesite: None would solve that but is way too dangerous.
\session_set_cookie_params([
'lifetime' => $liftetime,
'lifetime' => $lifetime,
'path' => '/',
'domain' => '',
'secure' => false,
@ -97,8 +106,7 @@ final class HttpSession implements SessionInterface
\session_start();
// @codeCoverageIgnoreEnd
} else {
$logger = FileLogger::getInstance();
$logger->error(
FileLogger::getInstance()->error(
FileLogger::MSG_FULL, [
'message' => 'Bad application flow.',
'line' => __LINE__,

View File

@ -53,7 +53,7 @@ final class Dispatcher implements DispatcherInterface
*
* @since 1.0.0
*/
public function __construct(ApplicationAbstract $app = null)
public function __construct(?ApplicationAbstract $app = null)
{
$this->app = $app;
}
@ -112,7 +112,7 @@ final class Dispatcher implements DispatcherInterface
*
* @since 1.0.0
*/
private function dispatchString(string $controller, array $data = null) : array
private function dispatchString(string $controller, ?array $data = null) : array
{
$views = [];
$dispatch = \explode(':', $controller);
@ -152,7 +152,7 @@ final class Dispatcher implements DispatcherInterface
*
* @since 1.0.0
*/
private function dispatchArray(array $controller, array $data = null) : array
private function dispatchArray(array $controller, ?array $data = null) : array
{
$views = [];
foreach ($controller as $controllerSingle) {
@ -172,7 +172,7 @@ final class Dispatcher implements DispatcherInterface
*
* @since 1.0.0
*/
private function dispatchClosure(callable $controller, array $data = null) : mixed
private function dispatchClosure(callable $controller, ?array $data = null) : mixed
{
return $data === null ? $controller($this->app) : $controller($this->app, ...$data);
}

View File

@ -21,7 +21,7 @@ use phpOMS\Dispatcher\DispatcherInterface;
* EventManager class.
*
* The event manager allows to define events which can be triggered/executed in an application.
* This implementation allows to create sub-conditions which need to be met (triggered in advance) bevore the actual
* This implementation allows to create sub-conditions which need to be met (triggered in advance) before the actual
* callback is getting executed.
*
* What happens after triggering an event (removing the callback, resetting the sub-conditions etc.) depends on the setup.
@ -64,7 +64,7 @@ final class EventManager implements \Countable
*
* @since 1.0.0
*/
public function __construct(Dispatcher $dispatcher = null)
public function __construct(?Dispatcher $dispatcher = null)
{
$this->dispatcher = $dispatcher ?? new class() implements DispatcherInterface {
/**
@ -90,7 +90,7 @@ final class EventManager implements \Countable
* return [
* '{EVENT_ID}' => [
* 'callback' => [
* '{DESTINATION_NAMESPACE:method}', // can also be static by using :: between namespace and functio name
* '{DESTINATION_NAMESPACE:method}', // can also be static by using :: between namespace and function name
* // more callbacks here
* ],
* ],
@ -159,7 +159,7 @@ final class EventManager implements \Countable
/**
* Trigger event based on regex for group and/or id.
*
* This tigger function allows the group to be a regex in either this function call or in the definition of the group.
* This trigger function allows the group to be a regex in either this function call or in the definition of the group.
*
* @param string $group Name of the event (can be regex)
* @param string $id Sub-requirement for event (can be regex)

View File

@ -27,7 +27,7 @@ Version 2.0
Subject to the terms and conditions of this License, each Contributor grants to You after purchase a perpetual, worldwide, non-exclusive, irrevocable copyright license to prepare Derivative Works of, publicly display, publicly perform the Work and such Derivative Works in Source or Object form. You are not allowed to sublicense, reproduce, or distribute the Work and such Derivative Works in Source or Object form.
3. Redistribution.
3. Redistribution
You may not reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form.

View File

@ -96,11 +96,11 @@ class BaseStringL11nType implements \JsonSerializable
$this->l11n = $l11n;
} elseif (isset($this->l11n) && $this->l11n instanceof BaseStringL11n) {
$this->l11n->content = $l11n;
$this->l11n->setLanguage($lang);
$this->l11n->language = $lang;
} else {
$this->l11n = new BaseStringL11n();
$this->l11n->content = $l11n;
$this->l11n->setLanguage($lang);
$this->l11n->language = $lang;
}
}

View File

@ -24,4 +24,15 @@ namespace phpOMS\Localization\Defaults;
*/
final class NullCity extends City
{
/**
* Constructor
*
* @param int $id Model id
*
* @since 1.0.0
*/
public function __construct(int $id = 0)
{
$this->id = $id;
}
}

View File

@ -24,4 +24,15 @@ namespace phpOMS\Localization\Defaults;
*/
final class NullCountry extends Country
{
/**
* Constructor
*
* @param int $id Model id
*
* @since 1.0.0
*/
public function __construct(int $id = 0)
{
$this->id = $id;
}
}

View File

@ -24,4 +24,15 @@ namespace phpOMS\Localization\Defaults;
*/
final class NullCurrency extends Currency
{
/**
* Constructor
*
* @param int $id Model id
*
* @since 1.0.0
*/
public function __construct(int $id = 0)
{
$this->id = $id;
}
}

View File

@ -24,4 +24,15 @@ namespace phpOMS\Localization\Defaults;
*/
final class NullIban extends Iban
{
/**
* Constructor
*
* @param int $id Model id
*
* @since 1.0.0
*/
public function __construct(int $id = 0)
{
$this->id = $id;
}
}

View File

@ -24,4 +24,15 @@ namespace phpOMS\Localization\Defaults;
*/
final class NullLanguage extends Language
{
/**
* Constructor
*
* @param int $id Model id
*
* @since 1.0.0
*/
public function __construct(int $id = 0)
{
$this->id = $id;
}
}

View File

@ -135,6 +135,26 @@ trait ISO3166Trait
self::getRegion('west-africa'),
self::getRegion('central-africa')
);
case 'nato':
return [
self::_ALB, self::_BEL, self::_BGR, self::_CAN, self::_HRV,
self::_CZE, self::_DNK, self::_EST, self::_FRA, self::_DEU,
self::_GRC, self::_HUN, self::_ISL, self::_ITA, self::_LVA,
self::_LTU, self::_LUX, self::_MNE, self::_NLD, self::_MKD,
self::_NOR, self::_POL, self::_PRT, self::_ROU, self::_SVK,
self::_SVN, self::_ESP, self::_TUR, self::_GBR, self::_USA,
self::_SWE,
];
case 'oecd':
return [
self::_AUS, self::_NZL, self::_AUT, self::_NOR, self::_BEL,
self::_POL, self::_CAN, self::_PRT, self::_CHL, self::_SVK,
self::_DNK, self::_ESP, self::_EST, self::_SWE, self::_FIN,
self::_CHE, self::_FRA, self::_TUR, self::_DEU, self::_GBR,
self::_GRC, self::_USA, self::_HUN, self::_ISL, self::_IRL,
self::_ISR, self::_ITA, self::_JPN, self::_KOR, self::_LUX,
self::_MEX, self::_NLD, self::_CZE, self::_SVN,
];
case 'eu':
return [
self::_AUT, self::_BEL, self::_BGR, self::_HRV, self::_CYP,
@ -151,6 +171,16 @@ trait ISO3166Trait
self::_ITA, self::_LVA, self::_LTU, self::_LUX, self::_MLT,
self::_NLD, self::_PRT, self::_SVK, self::_SVN, self::_ESP,
];
case 'schengen':
return [
self::_AUT, self::_BEL, self::_HRV,
self::_CZE, self::_DNK, self::_EST, self::_FIN, self::_FRA,
self::_DEU, self::_GRC, self::_HUN, self::_ITA,
self::_LVA, self::_LTU, self::_LUX, self::_MLT, self::_NLD,
self::_POL, self::_PRT, self::_SVK, self::_SVN,
self::_ESP, self::_SWE,
self::_ISL, self::_NOR, self::_CHE, self::_LIE,
];
case 'north-europe':
return [
self::_ALA, self::_DNK, self::_EST, self::_FRO, self::_FIN,
@ -285,6 +315,19 @@ trait ISO3166Trait
return [
self::_ATA, self::_ATF,
];
case 'dach':
return [
self::_DEU, self::_AUT, self::_CHE,
];
case 'g8':
return [
self::_USA, self::_GBR, self::_FRA, self::_DEU, self::_ITA,
self::_CAN, self::_RUS, self::_JAP,
];
case 'p5':
return [
self::_USA, self::_GBR, self::_FRA, self::_RUS, self::_CHN,
];
default:
return [];
}

View File

@ -135,7 +135,7 @@ final class L11nManager
*
* @since 1.0.0
*/
public function getModuleLanguage(string $language, string $module = null) : array
public function getModuleLanguage(string $language, ?string $module = null) : array
{
if ($module === null && isset($this->language[$language])) {
return $this->language[$language];
@ -213,7 +213,7 @@ final class L11nManager
*
* @since 1.0.0
*/
public function getNumeric(Localization $l11n, int | float | FloatInt $numeric, string $format = null) : string
public function getNumeric(Localization $l11n, int | float | FloatInt $numeric, ?string $format = null) : string
{
if (!($numeric instanceof FloatInt)) {
return \number_format(
@ -243,7 +243,7 @@ final class L11nManager
*
* @since 1.0.0
*/
public function getPercentage(Localization $l11n, float $percentage, string $format = null) : string
public function getPercentage(Localization $l11n, float $percentage, ?string $format = null) : string
{
return \number_format(
$percentage, $l11n->getPrecision()[$format ?? 'medium'],
@ -268,13 +268,13 @@ final class L11nManager
public function getCurrency(
Localization $l11n,
int | float | Money | FloatInt $currency,
string $symbol = null,
string $format = null,
?string $symbol = null,
?string $format = null,
int $divide = 1
) : string
{
$language = $l11n->language;
$symbol ??= $l11n->getCurrency();
$symbol ??= $l11n->currency;
if (\is_float($currency)) {
$currency = (int) ($currency * \pow(10, Money::MAX_DECIMALS));
@ -320,7 +320,7 @@ final class L11nManager
*
* @since 1.0.0
*/
public function getDateTime(Localization $l11n, \DateTimeInterface $datetime = null, string $format = null) : string
public function getDateTime(Localization $l11n, ?\DateTimeInterface $datetime = null, ?string $format = null) : string
{
return $datetime === null
? ''

View File

@ -36,7 +36,7 @@ class LanguageResult implements \ArrayAccess, \IteratorAggregate, \JsonSerializa
* Match values per language
*
* @var array<int|float, int|float>
* @sicne 1.0.0
* @since 1.0.0
*/
private array $result = [];
@ -188,7 +188,7 @@ class LanguageResult implements \ArrayAccess, \IteratorAggregate, \JsonSerializa
*
* @since 1.0.0
*/
public function limit(int $offset, int $length = null) : self
public function limit(int $offset, ?int $length = null) : self
{
return new self(\array_slice($this->result, $offset, $length));
}

View File

@ -1,8 +1,7 @@
<?php declare(strict_types=1);
return [
'ab' =>
[
'ab' => [
0 => 'а',
1 => 'и',
2 => 'р',

View File

@ -1,8 +1,7 @@
<?php declare(strict_types=1);
return [
'af' =>
[
'af' => [
0 => 'e',
1 => 'n',
2 => 'i',

View File

@ -1,8 +1,7 @@
<?php declare(strict_types=1);
return [
'am' =>
[
'am' => [
0 => 'ን',
1 => 'ት',
2 => 'ት_',

View File

@ -1,8 +1,7 @@
<?php declare(strict_types=1);
return [
'ar' =>
[
'ar' => [
0 => 'ا',
1 => 'ل',
2 => 'ال',

View File

@ -1,8 +1,7 @@
<?php declare(strict_types=1);
return [
'ay' =>
[
'ay' => [
0 => 'a',
1 => 'i',
2 => 'k',

View File

@ -1,8 +1,7 @@
<?php declare(strict_types=1);
return [
'az-Cyrl' =>
[
'az-Cyrl' => [
0 => 'ә',
1 => 'а',
2 => 'и',

View File

@ -1,8 +1,7 @@
<?php declare(strict_types=1);
return [
'az-Latn' =>
[
'az-Latn' => [
0 => 'ə',
1 => 'a',
2 => 'i',

View File

@ -1,8 +1,7 @@
<?php declare(strict_types=1);
return [
'be' =>
[
'be' => [
0 => 'а',
1 => 'н',
2 => 'ы',

View File

@ -1,8 +1,7 @@
<?php declare(strict_types=1);
return [
'bg' =>
[
'bg' => [
0 => 'а',
1 => 'о',
2 => 'и',

View File

@ -1,8 +1,7 @@
<?php declare(strict_types=1);
return [
'bi' =>
[
'bi' => [
0 => 'o',
1 => 'e',
2 => 'a',

View File

@ -1,8 +1,7 @@
<?php declare(strict_types=1);
return [
'bn' =>
[
'bn' => [
0 => '_র_',
1 => '_র',
2 => 'র_',

View File

@ -1,8 +1,7 @@
<?php declare(strict_types=1);
return [
'bo' =>
[
'bo' => [
0 => 'ས_',
1 => '_ས_',
2 => 'ས',

View File

@ -1,8 +1,7 @@
<?php declare(strict_types=1);
return [
'br' =>
[
'br' => [
0 => 'e',
1 => 'a',
2 => 'n',

View File

@ -1,8 +1,7 @@
<?php declare(strict_types=1);
return [
'bs-Cyrl' =>
[
'bs-Cyrl' => [
0 => 'а',
1 => 'и',
2 => 'о',

View File

@ -1,8 +1,7 @@
<?php declare(strict_types=1);
return [
'bs-Latn' =>
[
'bs-Latn' => [
0 => 'a',
1 => 'i',
2 => 'o',

View File

@ -1,8 +1,7 @@
<?php declare(strict_types=1);
return [
'ca' =>
[
'ca' => [
0 => 'e',
1 => 'a',
2 => 'i',

View File

@ -1,8 +1,7 @@
<?php declare(strict_types=1);
return [
'ch' =>
[
'ch' => [
0 => 'a',
1 => 'i',
2 => 'n',

View File

@ -1,8 +1,7 @@
<?php declare(strict_types=1);
return [
'co' =>
[
'co' => [
0 => 'i',
1 => 'a',
2 => 'u',

View File

@ -1,8 +1,7 @@
<?php declare(strict_types=1);
return [
'cr' =>
[
'cr' => [
0 => 'ᓂ',
1 => 'ᑕ',
2 => '',

View File

@ -1,8 +1,7 @@
<?php declare(strict_types=1);
return [
'cs' =>
[
'cs' => [
0 => 'o',
1 => 'n',
2 => 'e',

View File

@ -1,8 +1,7 @@
<?php declare(strict_types=1);
return [
'cy' =>
[
'cy' => [
0 => 'a',
1 => 'd',
2 => 'y',

View File

@ -1,8 +1,7 @@
<?php declare(strict_types=1);
return [
'da' =>
[
'da' => [
0 => 'e',
1 => 'r',
2 => 'n',

View File

@ -1,8 +1,7 @@
<?php declare(strict_types=1);
return [
'de' =>
[
'de' => [
0 => 'e',
1 => 'n',
2 => 'r',

View File

@ -1,8 +1,7 @@
<?php declare(strict_types=1);
return [
'dz' =>
[
'dz' => [
0 => 'ས_',
1 => '_ད',
2 => '_ག',

View File

@ -1,8 +1,7 @@
<?php declare(strict_types=1);
return [
'el-monoton' =>
[
'el-monoton' => [
0 => 'α',
1 => 'ι',
2 => 'ε',

View File

@ -1,8 +1,7 @@
<?php declare(strict_types=1);
return [
'el-polyton' =>
[
'el-polyton' => [
0 => 'α',
1 => 'τ',
2 => 'ι',

View File

@ -1,8 +1,7 @@
<?php declare(strict_types=1);
return [
'en' =>
[
'en' => [
0 => 'e',
1 => 't',
2 => 'n',

View File

@ -1,8 +1,7 @@
<?php declare(strict_types=1);
return [
'eo' =>
[
'eo' => [
0 => 'a',
1 => 'e',
2 => 'o',

Some files were not shown because too many files have changed in this diff Show More