initial commit
This commit is contained in:
commit
0db3e92ee6
59 changed files with 3384 additions and 0 deletions
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
*.log
|
||||
vendor/
|
||||
.directory
|
||||
18
composer.json
Executable file
18
composer.json
Executable file
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"name": "verua/assessment",
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"VeruA\\": "src/"
|
||||
}
|
||||
},
|
||||
"authors": [
|
||||
{
|
||||
"name": "norb",
|
||||
"email": "norbert.wagner@verua.ch"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"monolog/monolog": "^3.9"
|
||||
}
|
||||
}
|
||||
172
composer.lock
generated
Normal file
172
composer.lock
generated
Normal file
|
|
@ -0,0 +1,172 @@
|
|||
{
|
||||
"_readme": [
|
||||
"This file locks the dependencies of your project to a known state",
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "06188d9a0d54c92495e101cc6232cee3",
|
||||
"packages": [
|
||||
{
|
||||
"name": "monolog/monolog",
|
||||
"version": "3.9.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Seldaek/monolog.git",
|
||||
"reference": "10d85740180ecba7896c87e06a166e0c95a0e3b6"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/Seldaek/monolog/zipball/10d85740180ecba7896c87e06a166e0c95a0e3b6",
|
||||
"reference": "10d85740180ecba7896c87e06a166e0c95a0e3b6",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.1",
|
||||
"psr/log": "^2.0 || ^3.0"
|
||||
},
|
||||
"provide": {
|
||||
"psr/log-implementation": "3.0.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"aws/aws-sdk-php": "^3.0",
|
||||
"doctrine/couchdb": "~1.0@dev",
|
||||
"elasticsearch/elasticsearch": "^7 || ^8",
|
||||
"ext-json": "*",
|
||||
"graylog2/gelf-php": "^1.4.2 || ^2.0",
|
||||
"guzzlehttp/guzzle": "^7.4.5",
|
||||
"guzzlehttp/psr7": "^2.2",
|
||||
"mongodb/mongodb": "^1.8",
|
||||
"php-amqplib/php-amqplib": "~2.4 || ^3",
|
||||
"php-console/php-console": "^3.1.8",
|
||||
"phpstan/phpstan": "^2",
|
||||
"phpstan/phpstan-deprecation-rules": "^2",
|
||||
"phpstan/phpstan-strict-rules": "^2",
|
||||
"phpunit/phpunit": "^10.5.17 || ^11.0.7",
|
||||
"predis/predis": "^1.1 || ^2",
|
||||
"rollbar/rollbar": "^4.0",
|
||||
"ruflin/elastica": "^7 || ^8",
|
||||
"symfony/mailer": "^5.4 || ^6",
|
||||
"symfony/mime": "^5.4 || ^6"
|
||||
},
|
||||
"suggest": {
|
||||
"aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB",
|
||||
"doctrine/couchdb": "Allow sending log messages to a CouchDB server",
|
||||
"elasticsearch/elasticsearch": "Allow sending log messages to an Elasticsearch server via official client",
|
||||
"ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)",
|
||||
"ext-curl": "Required to send log messages using the IFTTTHandler, the LogglyHandler, the SendGridHandler, the SlackWebhookHandler or the TelegramBotHandler",
|
||||
"ext-mbstring": "Allow to work properly with unicode symbols",
|
||||
"ext-mongodb": "Allow sending log messages to a MongoDB server (via driver)",
|
||||
"ext-openssl": "Required to send log messages using SSL",
|
||||
"ext-sockets": "Allow sending log messages to a Syslog server (via UDP driver)",
|
||||
"graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server",
|
||||
"mongodb/mongodb": "Allow sending log messages to a MongoDB server (via library)",
|
||||
"php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib",
|
||||
"rollbar/rollbar": "Allow sending log messages to Rollbar",
|
||||
"ruflin/elastica": "Allow sending log messages to an Elastic Search server"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "3.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Monolog\\": "src/Monolog"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Jordi Boggiano",
|
||||
"email": "j.boggiano@seld.be",
|
||||
"homepage": "https://seld.be"
|
||||
}
|
||||
],
|
||||
"description": "Sends your logs to files, sockets, inboxes, databases and various web services",
|
||||
"homepage": "https://github.com/Seldaek/monolog",
|
||||
"keywords": [
|
||||
"log",
|
||||
"logging",
|
||||
"psr-3"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/Seldaek/monolog/issues",
|
||||
"source": "https://github.com/Seldaek/monolog/tree/3.9.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/Seldaek",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/monolog/monolog",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-03-24T10:02:05+00:00"
|
||||
},
|
||||
{
|
||||
"name": "psr/log",
|
||||
"version": "3.0.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/php-fig/log.git",
|
||||
"reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/php-fig/log/zipball/f16e1d5863e37f8d8c2a01719f5b34baa2b714d3",
|
||||
"reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.0.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "3.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Psr\\Log\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "PHP-FIG",
|
||||
"homepage": "https://www.php-fig.org/"
|
||||
}
|
||||
],
|
||||
"description": "Common interface for logging libraries",
|
||||
"homepage": "https://github.com/php-fig/log",
|
||||
"keywords": [
|
||||
"log",
|
||||
"psr",
|
||||
"psr-3"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/php-fig/log/tree/3.0.2"
|
||||
},
|
||||
"time": "2024-09-11T13:17:53+00:00"
|
||||
}
|
||||
],
|
||||
"packages-dev": [],
|
||||
"aliases": [],
|
||||
"minimum-stability": "stable",
|
||||
"stability-flags": {},
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": {},
|
||||
"platform-dev": {},
|
||||
"plugin-api-version": "2.6.0"
|
||||
}
|
||||
85
index.php
Normal file
85
index.php
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
<?php
|
||||
|
||||
use \VeruA\DomainObjects\{
|
||||
DomainObject,
|
||||
Owner,
|
||||
Client,
|
||||
Address,
|
||||
ValueObjects\Date,
|
||||
};
|
||||
use \VeruA\DomainObjects\Validation\{
|
||||
OwnerValidator,
|
||||
ClientValidator,
|
||||
ResultCollection,
|
||||
};
|
||||
|
||||
const BASE_PATH = __DIR__;
|
||||
require __DIR__ . '/vendor/autoload.php';
|
||||
|
||||
// owner
|
||||
$owner = new Owner([
|
||||
'id' => 1,
|
||||
'firstname' => 'Arthur',
|
||||
'lastname' => 'Dent',
|
||||
'gln' => 7653298712357,
|
||||
// 'gln' => 7653298712358, // GLN with valid checksum
|
||||
'email' => 'dear@example.com',
|
||||
'username' => 'ardente'
|
||||
]);
|
||||
|
||||
|
||||
// client
|
||||
$client = new Client([
|
||||
'id' => 1,
|
||||
'firstname' => '',
|
||||
// 'firstname' => 'Ford',
|
||||
'lastname' => 'Prefect',
|
||||
'ahv' => 1234,
|
||||
'birthday' => new Date('12.02.1842'),
|
||||
'address' => new Address([
|
||||
'id' => 1,
|
||||
'street' => '58 Orionis',
|
||||
'city' => 'Beteigeuze',
|
||||
'email' => null,
|
||||
]),
|
||||
]);
|
||||
|
||||
printDMO($owner);
|
||||
dumpValidationErrors($owner->validate(OwnerValidator::getInstance()));
|
||||
|
||||
printDMO($client);
|
||||
dumpValidationErrors($client->validate(ClientValidator::getInstance()));
|
||||
|
||||
|
||||
function printDMO(DomainObject $dmo, int $level = 1)
|
||||
{
|
||||
echo "<h$level>".get_class($dmo)."</h$level>\n";
|
||||
echo "<dl style=\"margin-left: {$level}em\">\n";
|
||||
foreach ($dmo as $field => $value)
|
||||
{
|
||||
// display missing if ValueObject->__toString() is empty
|
||||
if ((string)$value === '') $value = '<i>__ missing __</i>';
|
||||
|
||||
// output fieldname and value
|
||||
echo "<dt style=\"float: left\">$field:</dt><dd style=\"margin-left: 10em\">$value</dd>\n";
|
||||
|
||||
// recursive print DMOs .. will obviously not work on self reference ..
|
||||
if ($value instanceOf DomainObject)
|
||||
{
|
||||
$level++;
|
||||
printDMO($value, $level);
|
||||
$level--;
|
||||
}
|
||||
}
|
||||
echo "</dl>\n";
|
||||
}
|
||||
|
||||
function dumpValidationErrors(bool|ResultCollection $validationResult)
|
||||
{
|
||||
if ($validationResult !== true)
|
||||
{
|
||||
echo "<hr><strong>Validation Errors:</strong>\n<pre>";
|
||||
var_dump($validationResult);
|
||||
echo '</pre><hr>';
|
||||
}
|
||||
}
|
||||
27
readme.md
Normal file
27
readme.md
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
# Assessment: VeruA DomainObjects & Validation
|
||||
The following assessment may be solved with the help of additional sources, such as Q&A or LLMs but must be indicated as such.
|
||||
|
||||
## General
|
||||
In the example `index.php` there are three DomainObjects that are instantiated with default values. An [Owner](https://docs.verua.ch/latest/classes/VeruA-DomainObjects-Owner.html)-Object and a [Client](https://docs.verua.ch/latest/classes/VeruA-DomainObjects-Client.html)-Object are build directly. The third, an [Address](https://docs.verua.ch/latest/classes/VeruA-DomainObjects-Address.html)-Object is passed into the address field of the `Client`-Object.
|
||||
|
||||
All three are then validated acording to their respective validators. The Address object is validated through the [ClientValidator](https://code.verua.online/VeruA/Assessment/src/commit/83166a50af0cca2873d74ae0955cad67d20a5d02/src/DomainObjects/Validation/ClientValidator.php#L24).
|
||||
|
||||
## Exercises
|
||||
|
||||
1. Find out where and when the *default validators* of a `ValueObject` are executed.
|
||||
|
||||
1. A *default validator* has to check that an e-mail address is correct on the `email` field of `Owner` and of `Client::Address` if set, but the field can be empty.
|
||||
Implement it in the `ValueObjects/Email` class and use php's [filter_var(FILTER_VALIDATE_EMAIL)](https://www.php.net/manual/en/filter.constants.php#constant.filter-validate-email)
|
||||
|
||||
1. The validation works well, but the requirements changed. Redesign it, to implement the possibility to have multiple validators at once. As an example implement a new `ExportAddressValidator` in addition to the standard `AddressValidator` that requires an e-mail address and a valid AHV-number. The goal is, to check, if a given `DomainObject` is valid against different validators in different circumstances, configured and executed in one run.
|
||||
|
||||
1. `DomainObjects` are often loaded from a database with the *DataMapper Pattern*, where you get entire collections of `DomainObjects` containing more child objects.
|
||||
E.g. you have a collection of `Invoice`-Objects that contains an `Owner`-Object, a `Client`-Object that in turn contains an `Address`-Object.
|
||||
We need a possibility to preconfigure the validators that have to be used to validate the whole collection of `DomainObjects`
|
||||
This excecise is about the design decisions and not the code. Feel free to design with UML, sample code or with whatever you feel the most comfortable.
|
||||
|
||||
## Considerations
|
||||
|
||||
- Rewrite it with the possibility to have different Validators from different packages.
|
||||
|
||||
- Keep in mind, that if a field is not set at all, it is never validated.
|
||||
49
src/DomainObjects/Address.php
Normal file
49
src/DomainObjects/Address.php
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace VeruA\DomainObjects;
|
||||
|
||||
use VeruA\DomainObjects\ValueObjects\IntKey;
|
||||
use VeruA\DomainObjects\ValueObjects\Varchar;
|
||||
use VeruA\DomainObjects\ValueObjects\Email;
|
||||
use VeruA\DomainObjects\ValueObjects\Phone;
|
||||
use VeruA\DomainObjects\ValueObjects\URL;
|
||||
|
||||
/**
|
||||
* An Address
|
||||
*
|
||||
* @property ValueObjects\Integer $id The pk of the client
|
||||
* @property ValueObjects\Varchar $street (str)
|
||||
* @property ValueObjects\Varchar $zip (plz)
|
||||
* @property ValueObjects\Varchar $city (ort)
|
||||
* @property ValueObjects\Varchar $pobox (pfach)
|
||||
* @property ValueObjects\Email $email
|
||||
* @property ValueObjects\Phone $phone (tel)
|
||||
* @property ValueObjects\Phone $cellPhone (natel)
|
||||
* @property ValueObjects\Phone $officePhone (tel_geschaeft
|
||||
* @property ValueObjects\Phone $fax
|
||||
* @property ValueObjects\URL $website (webseite)
|
||||
*/
|
||||
class Address extends DomainObject
|
||||
{
|
||||
|
||||
protected function fields(array ...$superFields): array
|
||||
{
|
||||
return parent::fields([
|
||||
'id' => IntKey::class,
|
||||
'street' => Varchar::class,
|
||||
'zip' => Varchar::class,
|
||||
'city' => Varchar::class,
|
||||
'pobox' => Varchar::class,
|
||||
'email' => Email::class,
|
||||
'phone' => Phone::class,
|
||||
'cellPhone' => Phone::class,
|
||||
'officePhone' => Phone::class,
|
||||
'fax' => Phone::class,
|
||||
'website' => URL::class,
|
||||
], ...$superFields);
|
||||
}
|
||||
|
||||
}
|
||||
/* jEdit buffer local properties {{{
|
||||
* :folding=explicit:collapseFolds=1:
|
||||
}}}*/
|
||||
71
src/DomainObjects/Business.php
Normal file
71
src/DomainObjects/Business.php
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace VeruA\DomainObjects;
|
||||
|
||||
/**
|
||||
* The Business interface represents the common parts of the Owner and Spitex DMO
|
||||
*
|
||||
* Implemented by {@see Owner} and {@see Spitex}
|
||||
*
|
||||
* Please note that it is mandatory to implement all listed properties in the implementing
|
||||
* {@see Business::__get()} method
|
||||
* as documented below:
|
||||
*
|
||||
* * **$name** : {@see ValueObjects\Varchar} <br> *The name of the Spitex or Owner in charge*<br>
|
||||
* * **$gln** : {@see ValueObjects\EAN13} <br> *GLN-Number of the Business*<br>
|
||||
* * **$isSpitex** : {@see ValueObjects\Boolean} <br> *Is it a Spitex Business*<br>
|
||||
* * **$billcare** : {@see ValueObjects\Integer} <br> *Does Business use BillCare* `0 => false, 2 => MF`<br>
|
||||
* * **$logo** : {@see ValueObjects\Varchar} <br> *The logo of the Spitex or Owner in charge*<br>
|
||||
*
|
||||
* @link https://docs.verua.ch/latest/files/public-data-init-db.html
|
||||
*/
|
||||
interface Business
|
||||
{
|
||||
/**
|
||||
* Magic getter, override to implement above mentioned properties
|
||||
*
|
||||
* ``` php
|
||||
* switch ($field)
|
||||
* {
|
||||
* case 'name': return $this->name();
|
||||
* case 'gln': return $this->gln();
|
||||
* ...
|
||||
* }
|
||||
* return parent::__get($field);
|
||||
* ```
|
||||
*/
|
||||
public function __get(string $field);
|
||||
|
||||
/**
|
||||
* Magic setter, override if special handling on write is needed
|
||||
*/
|
||||
public function __set(string $name, $value);
|
||||
|
||||
/**
|
||||
* Returns the complete name of the Business
|
||||
*/
|
||||
public function name();
|
||||
|
||||
/**
|
||||
* Returns true if the Business is a Spitex, false otherwise
|
||||
*/
|
||||
public function isSpitex(): bool;
|
||||
|
||||
/**
|
||||
* Activates / Deactivates Modules
|
||||
* @todo put moduels in a separate table. Do not use the fields directly to change state, to ease
|
||||
* migration
|
||||
* @param $modules 'field' => true|false
|
||||
*/
|
||||
public function modules(Array $modules);
|
||||
|
||||
/**
|
||||
* Returns true if the given Module is active for this Spitex or Owner
|
||||
*/
|
||||
public function isModuleActive(string $module): bool;
|
||||
|
||||
/**
|
||||
* Returns true only if all given modules are active
|
||||
*/
|
||||
public function areModulesActive(array $modules): bool;
|
||||
}
|
||||
32
src/DomainObjects/Canton.php
Normal file
32
src/DomainObjects/Canton.php
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace VeruA\DomainObjects;
|
||||
|
||||
use VeruA\DomainObjects\DomainObject;
|
||||
use VeruA\DomainObjects\Owner;
|
||||
use VeruA\DomainObjects\ValueObjects\{IntKey, Varchar, Boolean, Integer};
|
||||
|
||||
class Canton extends DomainObject {
|
||||
|
||||
protected function fields(array ...$superFields): array
|
||||
{
|
||||
|
||||
return parent::fields([
|
||||
'id' => IntKey::class,
|
||||
'taxwert' => Varchar::class, // decimal on db
|
||||
'kanton' => Varchar::class,
|
||||
'prioritaet' => Integer::class,
|
||||
'del' => Boolean::class,
|
||||
'tarifsystem' => Integer::class,
|
||||
'zsr_nr' => Varchar::class,
|
||||
'kuerzel_kanton' => Varchar::class,
|
||||
'kvg_uvg' => Integer::class,
|
||||
'tariffs_pa' => Boolean::class,
|
||||
'color' => Varchar::class,
|
||||
'user' => Integer::class,
|
||||
'date' => Varchar::class,
|
||||
|
||||
'owner' => Owner::class // @see blameable object in Symfony
|
||||
], ...$superFields);
|
||||
}
|
||||
}
|
||||
64
src/DomainObjects/Client.php
Normal file
64
src/DomainObjects/Client.php
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace VeruA\DomainObjects;
|
||||
|
||||
use VeruA\Log;
|
||||
use VeruA\DomainObjects\ValueObjects\DataType;
|
||||
use VeruA\DomainObjects\ValueObjects\Integer;
|
||||
use VeruA\DomainObjects\ValueObjects\IntKey;
|
||||
use VeruA\DomainObjects\ValueObjects\Varchar;
|
||||
use VeruA\DomainObjects\ValueObjects\Date;
|
||||
use VeruA\DomainObjects\ValueObjects\Boolean;
|
||||
use VeruA\DomainObjects\ValueObjects\EAN13;
|
||||
|
||||
use VeruA\DomainObjects\Organisation;
|
||||
|
||||
/**
|
||||
* A DomainObject representation of Client (Klient)
|
||||
*
|
||||
* Includes the tables <pre>klient, personen, adressen</pre>
|
||||
* @uses ValueObjects\DataType
|
||||
* @uses ValueObjects\AHV
|
||||
*
|
||||
* @property ValueObjects\Intkey $id The pk of the client
|
||||
* @property ValueObjects\EAN13 $ahv Clients AHV-Number (SSN)
|
||||
* @property ValueObjects\Date $birthday The Birthdate
|
||||
* @property ValueObjects\Integer $childCount Number of Children
|
||||
* @property ValueObjects\Varchar $citizenship Citizenship
|
||||
* @property ValueObjects\Varchar $cardId cardId is the unique 20 digits card identifier
|
||||
* @property ValueObjects\Date $expiryDate expiryDate is the expiry date of the card
|
||||
* @property Organisation $insurance Organisation object of Insurance (normally KV)
|
||||
*
|
||||
* @property-read ValueObjects\Varchar $fullName A pointer to Person fullName
|
||||
*/
|
||||
class Client extends Person
|
||||
{
|
||||
use Log;
|
||||
|
||||
protected function fields(array ...$superFields): array
|
||||
{
|
||||
return parent::fields([
|
||||
// klient
|
||||
'id' => IntKey::class,
|
||||
'id_pers' => Integer::class,
|
||||
'insuranceId' => Integer::class,
|
||||
'birthday' => Date::class,
|
||||
'ahv' => EAN13::class,
|
||||
'insuredId' => Varchar::class,
|
||||
'caseId' => Varchar::class,
|
||||
'cardId' => Varchar::class,
|
||||
'expiryDate' => Date::class,
|
||||
'bemerkung' => DataType::class,
|
||||
'plz_a' => DataType::class,
|
||||
'ort_a' => DataType::class,
|
||||
'zivilstand' => DataType::class,
|
||||
'childCount' => Integer::class,
|
||||
'citizenship' => Varchar::class,
|
||||
'insurance' => Organisation::class,
|
||||
], ...$superFields);
|
||||
}
|
||||
}
|
||||
|
||||
/* jEdit buffer local properties {{{
|
||||
* :folding=explicit:collapseFolds=1:
|
||||
}}}*/
|
||||
9
src/DomainObjects/DataProvider.php
Normal file
9
src/DomainObjects/DataProvider.php
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace VeruA\DomainObjects;
|
||||
|
||||
interface DataProvider
|
||||
{
|
||||
|
||||
public function load(DomainObject $dmo): void;
|
||||
}
|
||||
61
src/DomainObjects/DataSource.php
Normal file
61
src/DomainObjects/DataSource.php
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace VeruA\DomainObjects;
|
||||
|
||||
/**
|
||||
* A DataSource Singelton to load a DomainObject without a dependency to the actual DataProvider
|
||||
* A DataProvider only needs to implement the DataProvider Interface. An example of a DataProvider is
|
||||
* the the MapperRegistry
|
||||
* @see \VeruA\DataMapper\MapperRegistry
|
||||
*/
|
||||
class DataSource
|
||||
{
|
||||
/**
|
||||
* The sole instance of the DataSource
|
||||
*/
|
||||
public static DataSource $instance;
|
||||
|
||||
/**
|
||||
* The Dataprovider object which redirects the load call to the apropriate implementation
|
||||
*/
|
||||
public DataProvider $provider;
|
||||
|
||||
/**
|
||||
* The private constructor is called by the init method and sets the provider instance
|
||||
*/
|
||||
private function __construct(DataProvider $provider)
|
||||
{
|
||||
$this->provider = $provider;
|
||||
}
|
||||
|
||||
/**
|
||||
* The static load() method can be called to load the data into the DomainObject
|
||||
*/
|
||||
public static function load(DomainObject $obj): void
|
||||
{
|
||||
self::dataProvider()->load($obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* the init method has to be called before using the load() method
|
||||
*/
|
||||
public static function init(DataProvider $provider): void
|
||||
{
|
||||
self::$instance = new DataSource($provider);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return DataProvider The DataProvider redirects the load call to the apropriate implementation
|
||||
* @throws \Exception if init() has not been called already
|
||||
*/
|
||||
private static function dataProvider(): DataProvider
|
||||
{
|
||||
if (! isset(self::$instance)) throw new \Exception('DataSource needs to be initalized first');
|
||||
|
||||
return self::$instance->provider;
|
||||
}
|
||||
}
|
||||
|
||||
/* jEdit buffer local properties {{{
|
||||
* :folding=explicit:collapseFolds=1:
|
||||
}}}*/
|
||||
44
src/DomainObjects/Doctor.php
Normal file
44
src/DomainObjects/Doctor.php
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace VeruA\DomainObjects;
|
||||
|
||||
use VeruA\Log;
|
||||
use VeruA\DomainObjects\ValueObjects\IntKey;
|
||||
use VeruA\DomainObjects\ValueObjects\Varchar;
|
||||
use VeruA\DomainObjects\ValueObjects\ZSR;
|
||||
use VeruA\DomainObjects\ValueObjects\EAN13;
|
||||
|
||||
/**
|
||||
* A DomainObject representation of Doctor (Arzt) extending Person
|
||||
*
|
||||
* Includes the tables `arzt, personen, adressen, fachr_arzt`
|
||||
*
|
||||
* @property ValueObjects\IntKey $id The pk of the Doctor
|
||||
* @property ValueObjects\IntKey $idPers The pk of the Person
|
||||
* @property ValueObjects\Varchar $field the field (`fachr`) the doctor is specialized in.
|
||||
* Comes from the `fachr_arzt` table and is joined in the Mapper
|
||||
* @property ValueObjects\Varchar $practice The name of the doctor's practice (`praxis`) if any
|
||||
* @property ValueObjects\ZSR $zsr The zsr number (e.g. `A123456`)
|
||||
* @property ValueObjects\EAN13 $gln The gln number of the doctor
|
||||
**/
|
||||
class Doctor extends Person
|
||||
{
|
||||
use Log;
|
||||
|
||||
protected function fields(array ...$superFields): array
|
||||
{
|
||||
return parent::fields([
|
||||
'id' => IntKey::class,
|
||||
'idPers' => IntKey::class,
|
||||
'field' => Varchar::class,
|
||||
'practice' => Varchar::class,
|
||||
'zsr' => ZSR::class,
|
||||
'gln' => EAN13::class,
|
||||
], ...$superFields);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* jEdit buffer local properties {{{
|
||||
* :folding=explicit:collapseFolds=1:
|
||||
}}}*/
|
||||
405
src/DomainObjects/DomainObject.php
Normal file
405
src/DomainObjects/DomainObject.php
Normal file
|
|
@ -0,0 +1,405 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace VeruA\DomainObjects;
|
||||
|
||||
use VeruA\Log;
|
||||
|
||||
use VeruA\DomainObjects\Validation\{Validator, Validatable};
|
||||
use VeruA\DomainObjects\ValueObjects\{Value, Primitive, Complex, DataType, Key};
|
||||
|
||||
/**
|
||||
* A DomainObject reperesents a Basic data entity. e.g. a Client. // {{{
|
||||
*
|
||||
* DomainObjects represent mostly a table or several joined tables but are loaded from the database
|
||||
* through the DataMappers and are independent from the latter
|
||||
*
|
||||
* To create a new DomainObject do the following:
|
||||
* * extend from `DomainObject`
|
||||
* * overwrite the `fields()` method like so
|
||||
* ```php
|
||||
* protected function fields(array ...$superFields): array
|
||||
* {
|
||||
* return parent::fields([
|
||||
* // you need a field calld `id` with a type that implements the `Key` interface
|
||||
* 'id' => IntKey::class,
|
||||
* // any Class that implements the Value interface
|
||||
* 'field1' => Value::class,
|
||||
* // ...
|
||||
* // or any class that descends from DomainObject
|
||||
* 'node1' => DomainObject::class,
|
||||
* // ...
|
||||
* // make sure to pass on the $superFields (remember the dots) to make sure inheritance works
|
||||
* ], ...$superFields);
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @uses ValueObjects\DataType
|
||||
*/
|
||||
//}}}
|
||||
abstract class DomainObject implements Validatable, Value, \Iterator
|
||||
{
|
||||
use Log;
|
||||
|
||||
protected const NEW = 0;
|
||||
protected const DIRTY = 1;
|
||||
protected const GHOST = 2;
|
||||
protected const LOADING = 3;
|
||||
protected const LOADED = 4;
|
||||
|
||||
/**
|
||||
* @var ValueObjects\DataType[] $data Contains the ValueObjects with their respective values
|
||||
*/
|
||||
protected array $data = [];
|
||||
|
||||
/**
|
||||
* Contains all configured fields with their respective Values
|
||||
*
|
||||
* @todo should we replace this entierly by the fields method
|
||||
* @var Value[] gets assigned in the constructor by running the fields() method
|
||||
*/
|
||||
protected array $dataTypes = [];
|
||||
|
||||
/**
|
||||
* @var Validator $validator the Validator in use
|
||||
*/
|
||||
protected Validation\Validator $validator;
|
||||
|
||||
/**
|
||||
* @var int state
|
||||
*/
|
||||
protected int $state = self::DIRTY;
|
||||
|
||||
/**
|
||||
* @var bool[] array that contains every field as key that changed after construction with value true
|
||||
*/
|
||||
protected array $dirty = [];
|
||||
|
||||
protected bool $isDirty = false;
|
||||
|
||||
protected bool $valid = false;
|
||||
protected bool $validated = false;
|
||||
protected ?Violations $violations = null;
|
||||
|
||||
// Constructor {{{
|
||||
/**
|
||||
* Creates a new DomainObject
|
||||
*
|
||||
* The DomainObject can be created in the following ways:
|
||||
* * If an Object of Type ValueObjects\Key is passed, the DomainObjects state is GHOST and will be loaded
|
||||
* according to the DataSource, when a field is accessed
|
||||
* * Without a parameter an empty DomainObject is created in the NEW state
|
||||
* * If $data is an array, it has to be in the form 'field => 'value' as configured in the fields method
|
||||
* @see ValueObjects\IntKey
|
||||
* @param ValueObjects\Key|array $data Sets the values of the DomainObject. Every value is passed to the respective
|
||||
* {@link \VeruA\DomainObjects\ValueObjects} or if a Key is passed a new empty GHOST is created
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($data=null)
|
||||
{
|
||||
$this->dataTypes = $this->fields();
|
||||
|
||||
if ($data instanceof Key)
|
||||
{
|
||||
// var_dump($data);
|
||||
$this->set('id', $data);
|
||||
$this->markGhost();
|
||||
}
|
||||
// var_dump(get_class(), isset($this->id));
|
||||
if (is_array($data)) {
|
||||
foreach ($data as $name => $value) {
|
||||
$this->$name = $value;
|
||||
}
|
||||
}
|
||||
if (!isset($this->id)) $this->markNew();
|
||||
// var_dump($this->state);
|
||||
} // }}}
|
||||
|
||||
// load() {{{
|
||||
/**
|
||||
* Puts all fields of $dmo into this DomainObject.
|
||||
*
|
||||
* @param DomainObject $dmo a DomainObject
|
||||
*/
|
||||
public function load(DomainObject $dmo)
|
||||
{
|
||||
foreach ($dmo as $field => $value)
|
||||
{
|
||||
$this->data[$field] = $value;
|
||||
}
|
||||
} // }}}
|
||||
|
||||
// values() {{{
|
||||
/**
|
||||
* Returns the internal data Array, containing all the DataType Objects
|
||||
*/
|
||||
public function values(): array
|
||||
{
|
||||
return $this->data;
|
||||
} // }}}
|
||||
|
||||
// getValueObjectOf() {{{
|
||||
public function getValueObjectOf(string $field): Value
|
||||
{
|
||||
return $this->get($field);
|
||||
} // }}}
|
||||
|
||||
// dataTypes() {{{
|
||||
/**
|
||||
* Returns the DataType configuration
|
||||
*/
|
||||
public function dataTypes(): array
|
||||
{
|
||||
return $this->dataTypes;
|
||||
}
|
||||
// }}}
|
||||
|
||||
// fields() {{{
|
||||
/**
|
||||
* Configures the DomainObjects Fields
|
||||
*
|
||||
* Overwrite this method to assign the filds with their respective ValueObjects
|
||||
* make sure to call the parent an pass along all of the $superFields arrays like so ...$superFields
|
||||
* The concept is simple. Every SuperClass adds its fields in a separate array, and passes them to
|
||||
* the parent, DomainObject::fields merges them together to have all of the inherited fields available
|
||||
*/
|
||||
protected function fields(array ...$superFields): array
|
||||
{
|
||||
$fields = array_merge($this->dataTypes(), ...$superFields);
|
||||
// var_dump($fields);
|
||||
return $fields;
|
||||
} // }}}
|
||||
|
||||
// state methods {{{
|
||||
|
||||
// isNew() {{{
|
||||
public function isNew(): bool
|
||||
{
|
||||
return ($this->state === self::NEW);
|
||||
}
|
||||
// }}}
|
||||
|
||||
// isGhost() {{{
|
||||
public function isGhost(): bool
|
||||
{
|
||||
return ($this->state === self::GHOST);
|
||||
}
|
||||
// }}}
|
||||
|
||||
// isDirty() {{{
|
||||
public function isDirty(): bool
|
||||
{
|
||||
return $this->isDirty;
|
||||
}
|
||||
// }}}
|
||||
|
||||
public function markGhost() {
|
||||
$this->state = self::GHOST;
|
||||
$this->dirty = [];
|
||||
$this->isDirty = false;
|
||||
}
|
||||
|
||||
public function markNew() {
|
||||
$this->state = self::NEW;
|
||||
$this->dirty = [];
|
||||
$this->isDirty = false;
|
||||
}
|
||||
|
||||
public function markLoaded() {
|
||||
$this->state = self::LOADED;
|
||||
$this->dirty = [];
|
||||
$this->isDirty = false;
|
||||
}
|
||||
|
||||
public function markDirty() {
|
||||
$this->state = self::DIRTY;
|
||||
$this->isDirty = true;
|
||||
foreach ($this as $field => $value) {
|
||||
$this->dirty[$field] = true;
|
||||
}
|
||||
}
|
||||
// }}}
|
||||
|
||||
// __set() {{{
|
||||
/**
|
||||
* Sets a value instatiating a new DataType Object if none is set, or sets the value of the DataType
|
||||
* @throws \OutOfRangeException if the field does not exist
|
||||
* @param string $name The name of the field
|
||||
* @param mixed $value The value
|
||||
*/
|
||||
public function __set(string $name, $value)
|
||||
{
|
||||
$this->dirty[$name] = true;
|
||||
$this->isDirty = true;
|
||||
$this->set($name, $value);
|
||||
} // }}}
|
||||
|
||||
// __get() {{{
|
||||
/**
|
||||
* Returnes the {@link \VeruA\DomainObjects\DataType} of the requested field
|
||||
* @throws \OutOfRangeException if the field does not exist
|
||||
* @param string $name The name of the field
|
||||
* @return \VeruA\DomainObjects\ValueObjects\Value|mixed Returns the DataType of the field
|
||||
*/
|
||||
public function __get(string $field)
|
||||
{
|
||||
$valueObject = $this->get($field);
|
||||
return (! $valueObject instanceof Complex) ? $valueObject->value() : $valueObject;
|
||||
} // }}}
|
||||
|
||||
// __isset() / __unset() {{{
|
||||
public function __isset( $field )
|
||||
{
|
||||
if ($this->isGhost() && $field != 'id') {
|
||||
DataSource::load($this);
|
||||
}
|
||||
return ( isset( $this->data[$field] ) );
|
||||
}
|
||||
|
||||
public function __unset( $name )
|
||||
{
|
||||
unset( $this->data[$name] );
|
||||
}
|
||||
// }}}
|
||||
|
||||
// Value methods {{{
|
||||
public function __toString() {
|
||||
return (string)$this->id;
|
||||
}
|
||||
public function in($dmo) {
|
||||
$this->load($dmo);
|
||||
}
|
||||
public function out() {
|
||||
return $this->__toString();
|
||||
}
|
||||
public function value() {
|
||||
return $this;
|
||||
}
|
||||
// defaultValidators() {{{
|
||||
/**
|
||||
* Overwrite this message if a DataType needs validation methods that are always applied
|
||||
*/
|
||||
public static function defaultValidators(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
// }}}
|
||||
// }}}
|
||||
|
||||
// validation methods {{{
|
||||
/**
|
||||
* Returns if this DMO is valid.
|
||||
* If the DMO is not in a validated state, or because it was not already validated, or because changes
|
||||
* has been made, it is validated.
|
||||
* If a validator is given as argument, the DMO is always validated and the internal state is not altered
|
||||
*/
|
||||
public function isValid(?Validator $validator=null): bool
|
||||
{
|
||||
if (! $this->validated) {
|
||||
$result = $this->validate($validator);
|
||||
}
|
||||
return ($validator) ? (($result === true) ? true : false) : $this->valid;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool|Validation\ResultCollection Returns true if validation passed or a ResultCollection
|
||||
*/
|
||||
public function validate(?Validator $validator=null)
|
||||
{
|
||||
$result = ($validator) ? $validator->validate($this) : $this->validator->validate($this);
|
||||
if ($result === true && $validator) {
|
||||
$this->valid = true;
|
||||
}
|
||||
elseif ($result !== true && !$validator) {
|
||||
$this->violations = $result;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Validation\ResultCollection Returns true if validation passed or a ResultCollection
|
||||
*/
|
||||
public function violations() : ?Validation\ResultCollection
|
||||
{
|
||||
return $this->violations;
|
||||
}
|
||||
// }}}
|
||||
|
||||
// iterator methods {{{
|
||||
public function rewind(): void {
|
||||
reset($this->data);
|
||||
}
|
||||
public function current(): mixed {
|
||||
return current($this->data);
|
||||
}
|
||||
public function key(): mixed {
|
||||
return key($this->data);
|
||||
}
|
||||
public function next(): void {
|
||||
next($this->data);
|
||||
}
|
||||
public function valid(): bool {
|
||||
return key($this->data) !== null;
|
||||
}
|
||||
// }}}
|
||||
|
||||
// set / get methods {{{
|
||||
protected function set(string $field, $value): void
|
||||
{
|
||||
if (! (isset($this->dataTypes[$field]) || array_key_exists($field, $this->dataTypes))) {
|
||||
throw new \OutOfRangeException( 'Can not set unknown index for '.get_class($this).': ' . $field );
|
||||
}
|
||||
|
||||
// Value or DomainObject Instance: store in $data array
|
||||
if ($value instanceof Value || $value instanceof DomainObject)
|
||||
{
|
||||
if (is_a($value, $this->dataTypes[$field])) {
|
||||
$this->data[$field] = $value;
|
||||
}
|
||||
else {
|
||||
$message = "Cannot set $value for $field in ".get_class($this)
|
||||
."\nWrong DataType ".get_class($value)." expected: ".$this->dataTypes[$field];
|
||||
throw new \InvalidArgumentException($message);
|
||||
}
|
||||
}
|
||||
// handle ValueObject
|
||||
elseif (is_a($this->dataTypes[$field], Value::class, true))
|
||||
{
|
||||
if (! isset($this->data[$field])) {
|
||||
// var_dump(get_class($this), $field, $value);
|
||||
$this->data[$field] = new $this->dataTypes[$field]();
|
||||
}
|
||||
|
||||
$this->data[$field]->in( $value );
|
||||
// var_dump($this->data[$field]);
|
||||
}
|
||||
// handle DomainObject
|
||||
elseif ($this->dataTypes[$field] instanceof DomainObject)
|
||||
{
|
||||
$this->data[$field] = new $this->dataTypes[$field]($value);
|
||||
}
|
||||
else {
|
||||
throw new \InvalidArgumentException("Cannot set $value for $field in ".get_class($this) );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected function get(string $field)
|
||||
{
|
||||
if (!isset($this->dataTypes[$field])) {
|
||||
throw new \OutOfRangeException( 'Unknown index in '.get_class($this).': ' . $field );
|
||||
}
|
||||
|
||||
if ($this->isGhost() && $field != 'id') {
|
||||
DataSource::load($this);
|
||||
}
|
||||
// if ($field == 'name') var_dump($this);
|
||||
|
||||
return $this->data[$field];
|
||||
}
|
||||
//}}}
|
||||
|
||||
}
|
||||
|
||||
/* jEdit buffer local properties {{{
|
||||
* :folding=explicit:collapseFolds=1:
|
||||
}}}*/
|
||||
53
src/DomainObjects/Filter/EncodingFilter.php
Normal file
53
src/DomainObjects/Filter/EncodingFilter.php
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
<?php namespace VeruA\DomainObjects\Filter;
|
||||
|
||||
class EncodingFilter
|
||||
{
|
||||
|
||||
private $data;
|
||||
private $dataEnc;
|
||||
private $outEenc;
|
||||
private $inEenc;
|
||||
|
||||
// Constructor {{{
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function __construct( $data, $outEnc=null, $inEnc=null, $dataEnc=null )
|
||||
{
|
||||
$this->data = $data;
|
||||
$this->dataEnc = $dataEnc;
|
||||
$this->outEenc = $outEnc;
|
||||
$this->inEenc = $inEnc;
|
||||
} // }}}
|
||||
|
||||
// Magic getter/setter methods {{{
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function __set( $name, $value )
|
||||
{
|
||||
$filtered = ( isset($this->inEnc) )
|
||||
? mb_convert_encoding($value, $this->inEnc, $this->dataEnc) : $value;
|
||||
|
||||
$this->data->$name = $filtered;
|
||||
}
|
||||
|
||||
public function __get( $name )
|
||||
{
|
||||
$filtered = ( isset($this->outEnc) )
|
||||
? mb_convert_encoding($this->data->$name, $this->outEnc, $this->dataEnc)
|
||||
: $this->data->$name;
|
||||
|
||||
return $filtered;
|
||||
}
|
||||
|
||||
public function __isset( $name )
|
||||
{
|
||||
return isset( $this->data->namme );
|
||||
}
|
||||
// }}}
|
||||
}
|
||||
|
||||
/* jEdit buffer local properties {{{
|
||||
* :folding=explicit:collapseFolds=1:
|
||||
}}}*/
|
||||
40
src/DomainObjects/HealthInsurance.php
Normal file
40
src/DomainObjects/HealthInsurance.php
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace VeruA\DomainObjects;
|
||||
|
||||
use VeruA\Log;
|
||||
use VeruA\DomainObjects\ValueObjects\Boolean;
|
||||
use VeruA\DomainObjects\ValueObjects\DateTime;
|
||||
use VeruA\DomainObjects\ValueObjects\EAN13;
|
||||
use VeruA\DomainObjects\ValueObjects\IntKey;
|
||||
use VeruA\DomainObjects\ValueObjects\Integer;
|
||||
use VeruA\DomainObjects\ValueObjects\Varchar;
|
||||
|
||||
/**
|
||||
*
|
||||
* Health insurance object
|
||||
*/
|
||||
|
||||
class HealthInsurance extends DomainObject {
|
||||
|
||||
protected function fields(array ...$sf): array
|
||||
{
|
||||
return parent::fields([
|
||||
'id' => IntKey::class,
|
||||
'health_insurance_name' => Varchar::class,
|
||||
'insurance_gln' => EAN13::class,
|
||||
'recipient_gln' => EAN13::class,
|
||||
'gln_number' => EAN13::class,
|
||||
'electronic_tp' => Boolean::class,
|
||||
'fk_adressen' => Integer::class,
|
||||
'id_law_code' => Integer::class,
|
||||
'created_at' => DateTime::class,
|
||||
'updated_at' => DateTime::class,
|
||||
'published_at' => DateTime::class,
|
||||
|
||||
'address' => Address::class,
|
||||
'law_code' => LegalCategorisation::class,
|
||||
'mediport_status' => MediportStatus::class,
|
||||
'owner' => Owner::class,
|
||||
}
|
||||
}
|
||||
33
src/DomainObjects/Organisation.php
Normal file
33
src/DomainObjects/Organisation.php
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace VeruA\DomainObjects;
|
||||
|
||||
use VeruA\DomainObjects\ValueObjects\IntKey;
|
||||
use VeruA\DomainObjects\ValueObjects\Integer;
|
||||
use VeruA\DomainObjects\ValueObjects\Varchar;
|
||||
use VeruA\DomainObjects\ValueObjects\EAN13;
|
||||
|
||||
/**
|
||||
* An Organisation
|
||||
*
|
||||
*/
|
||||
class Organisation extends DomainObject
|
||||
{
|
||||
|
||||
protected function fields(array ...$sf): array
|
||||
{
|
||||
return parent::fields([
|
||||
'id' => IntKey::class,
|
||||
'id_adr' => Integer::class,
|
||||
'id_kontakt' => Integer::class,
|
||||
|
||||
'name' => Varchar::class,
|
||||
'zusatz1' => Varchar::class,
|
||||
'zusatz2' => Varchar::class,
|
||||
'gln' => EAN13::class,
|
||||
|
||||
'address' => Address::class,
|
||||
], ...$sf);
|
||||
}
|
||||
|
||||
}
|
||||
196
src/DomainObjects/Owner.php
Normal file
196
src/DomainObjects/Owner.php
Normal file
|
|
@ -0,0 +1,196 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace VeruA\DomainObjects;
|
||||
|
||||
use VeruA\Log;
|
||||
use VeruA\DomainObjects\ValueObjects\{
|
||||
IntKey,
|
||||
Varchar,
|
||||
Boolean,
|
||||
EAN13,
|
||||
Integer,
|
||||
Image,
|
||||
Password
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A User from the Owner table
|
||||
*
|
||||
* @property ValueObjects\Integer $id The pk of the owner
|
||||
* @property ValueObjects\Image $logo The logo of the owner
|
||||
* @property ValueObjects\Varchar $firstname The firstname (vname)
|
||||
* @property ValueObjects\Varchar $lastname The lastname (nname)
|
||||
* @property ValueObjects\EAN13 $gln Users GLN-Number
|
||||
* @property ValueObjects\Boolean $admin @deprecated Has user admin rights? use isAdmin()
|
||||
* @property ValueObjects\Boolean $spitex @deprecated {@see https://rabeweb.planio.de/issues/19089} use isSpitex()
|
||||
* @property ValueObjects\Varchar $username The username to authenticate (benutzer)
|
||||
* @property ValueObjects\Password $password The password to authenticate (passwort)
|
||||
*/
|
||||
class Owner extends DomainObject implements Business
|
||||
{
|
||||
use Log;
|
||||
|
||||
private $clientsInCare = [];
|
||||
|
||||
protected function fields(array ...$superFields): array
|
||||
{
|
||||
return parent::fields([
|
||||
'id' => IntKey::class,
|
||||
'logo' => Image::class,
|
||||
'firstname' => Varchar::class,
|
||||
'lastname' => Varchar::class,
|
||||
'gln' => EAN13::class,
|
||||
'admin' => Boolean::class,
|
||||
'billcare' => Integer::class,
|
||||
'spitex' => Integer::class,
|
||||
|
||||
'email' => Varchar::class,
|
||||
|
||||
'username' => Varchar::class,
|
||||
'password' => Password::class,
|
||||
|
||||
// Modules - todo: normalize in additional table
|
||||
'bcModule' => Integer::class,
|
||||
'xmlModule' => Boolean::class,
|
||||
'ekarusModule' => Boolean::class,
|
||||
'complementaryModule' => Boolean::class,
|
||||
'popModule' => Boolean::class,
|
||||
'qrModule' => Boolean::class,
|
||||
'dpModule' => Boolean::class,
|
||||
'tpModule' => Boolean::class,
|
||||
'dpRights' => Integer::class,
|
||||
'tpRights' => Integer::class,
|
||||
|
||||
// Components - todo: normalize in additional table, same as modules?
|
||||
'componentAccounting' => Boolean::class,
|
||||
'componentBasic' => Boolean::class,
|
||||
'componentStatistics' => Boolean::class,
|
||||
'componentOther' => Boolean::class,
|
||||
], ...$superFields);
|
||||
}
|
||||
|
||||
public function __get(string $field)
|
||||
{
|
||||
switch ($field) {
|
||||
case 'name': return $this->name();
|
||||
case 'isAdmin': return $this->isAdmin();
|
||||
case 'isSpitex': return $this->isSpitex();
|
||||
case 'clientsInCare': return $this->clientsInCare;
|
||||
case 'hasAccessToDP': return $this->hasAccessToModule('dp');
|
||||
case 'hasAccessToTP': return $this->hasAccessToModule('tp');
|
||||
case 'logo': return $this->logo();
|
||||
}
|
||||
return parent::__get($field);
|
||||
}
|
||||
|
||||
public function __set(string $field, $value): void
|
||||
{
|
||||
switch ($field)
|
||||
{
|
||||
case 'clientsInCare':
|
||||
$this->clientsInCare = $value;
|
||||
break;
|
||||
default:
|
||||
parent::__set($field, $value);
|
||||
}
|
||||
}
|
||||
|
||||
public function name()
|
||||
{
|
||||
$name = $this->orga ?? $this->fullName();
|
||||
return $name;
|
||||
}
|
||||
|
||||
public function logo()
|
||||
{
|
||||
$logo = $this->data['logo'];
|
||||
|
||||
if (! $logo->isReadable()) {
|
||||
$logo->in('logo_leer/logo_leer.jpg');
|
||||
}
|
||||
return $logo;
|
||||
}
|
||||
|
||||
// fullName() {{{
|
||||
/**
|
||||
* A commodity function to get the full Clients name composed as `nname, vname`
|
||||
* @return string The full name
|
||||
* @todo add a parameter to customize the formatting/composition
|
||||
*/
|
||||
public function fullName()
|
||||
{
|
||||
return new Varchar($this->lastname .', '. $this->firstname);
|
||||
} // }}}
|
||||
|
||||
public function isSpitex(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function isAdmin(): bool
|
||||
{
|
||||
return $this->admin;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns true if the owner has the permission to access the clients data
|
||||
*/
|
||||
public function hasAccessToClient($clientId): bool
|
||||
{
|
||||
// if false not applicable so access granted
|
||||
return (! $clientId) ? true : $this->inCareOf($clientId);
|
||||
}
|
||||
|
||||
/**
|
||||
* returns true if the owner is in care of the client
|
||||
*/
|
||||
public function inCareOf($clientId): bool
|
||||
{
|
||||
return isset($this->clientsInCare[$clientId]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Activate / Deactivate Modules
|
||||
* @todo put moduels in a separate table. Do not use the fields directly to change state, to ease
|
||||
* migration
|
||||
* @param modules 'field' => true|false
|
||||
*/
|
||||
public function modules(Array $modules)
|
||||
{
|
||||
foreach ($modules as $module => $value) {
|
||||
$this->{$module.'Module'} = $value;
|
||||
}
|
||||
}
|
||||
|
||||
public function isModuleActive(string $module): bool
|
||||
{
|
||||
return $this->{$module.'Module'};
|
||||
}
|
||||
|
||||
public function areModulesActive(array $modules): bool
|
||||
{
|
||||
$areActive = true;
|
||||
foreach ($modules as $module)
|
||||
{
|
||||
if (!$this->{$module.'Module'} === true) {
|
||||
$areActive = false;
|
||||
}
|
||||
}
|
||||
return $areActive;
|
||||
}
|
||||
|
||||
public function hasAccessToModule(string $module): bool
|
||||
{
|
||||
switch ($module)
|
||||
{
|
||||
case 'dp': return ($this->dpRights > 0) ? true : false;
|
||||
case 'tp': return ($this->tpRights > 1) ? true : false;
|
||||
default: return $this->isModuleActive($module);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* jEdit buffer local properties {{{
|
||||
* :folding=explicit:collapseFolds=1:
|
||||
}}}*/
|
||||
64
src/DomainObjects/Person.php
Normal file
64
src/DomainObjects/Person.php
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace VeruA\DomainObjects;
|
||||
|
||||
use VeruA\DomainObjects\ValueObjects\DataType;
|
||||
use VeruA\DomainObjects\ValueObjects\IntKey;
|
||||
use VeruA\DomainObjects\ValueObjects\Integer;
|
||||
use VeruA\DomainObjects\ValueObjects\Varchar;
|
||||
|
||||
/**
|
||||
* A Person
|
||||
*
|
||||
* @property ValueObjects\IntKey $id The pk of the client
|
||||
* @property ValueObjects\Varchar $title (anrede) -> should be replaced by new column gender
|
||||
* @property ValueObjects\Varchar $suffix (titel)
|
||||
* @property ValueObjects\Varchar $firstname (vname)
|
||||
* @property ValueObjects\Varchar $lastname (nname)
|
||||
* @property ValueObjects\Varchar $other (zusatz)
|
||||
* @property ValueObjects\Varchar $remark (bemerkung)
|
||||
* @property Address $address Address object
|
||||
*/
|
||||
class Person extends DomainObject
|
||||
{
|
||||
|
||||
protected function fields(array ...$superFields): array
|
||||
{
|
||||
return parent::fields([
|
||||
'id' => IntKey::class,
|
||||
'title' => Varchar::class, // anrede -> should be replaced by new column gender
|
||||
'suffix' => Varchar::class, // titel
|
||||
'firstname' => Varchar::class,
|
||||
'lastname' => Varchar::class,
|
||||
'other' => Varchar::class, // zusatz
|
||||
'remark' => Varchar::class,
|
||||
|
||||
'address' => Address::class,
|
||||
], ...$superFields);
|
||||
}
|
||||
|
||||
public function __get(string $name)
|
||||
{
|
||||
switch ($name)
|
||||
{
|
||||
case 'fullName':
|
||||
return $this->fullName();
|
||||
}
|
||||
return parent::__get($name);
|
||||
}
|
||||
|
||||
// fullName() {{{
|
||||
/**
|
||||
* A convenience function to get the full Clients name composed as `lastname, firstname`
|
||||
* @return string The full name
|
||||
* @todo add a parameter to customize the formatting/composition
|
||||
*/
|
||||
public function fullName()
|
||||
{
|
||||
return new Varchar($this->lastname .', '. $this->firstname);
|
||||
} // }}}
|
||||
}
|
||||
|
||||
/* jEdit buffer local properties {{{
|
||||
* :folding=explicit:collapseFolds=1:
|
||||
}}}*/
|
||||
113
src/DomainObjects/Spitex.php
Normal file
113
src/DomainObjects/Spitex.php
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace VeruA\DomainObjects;
|
||||
|
||||
use VeruA\Log;
|
||||
use VeruA\DomainObjects\ValueObjects\{
|
||||
IntKey,
|
||||
Varchar,
|
||||
Boolean,
|
||||
EAN13,
|
||||
Integer,
|
||||
Image
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A Spitex Business from the spitex table
|
||||
*
|
||||
* @property ValueObjects\Integer $id The primary key of the spitex table
|
||||
* @property ValueObjects\Image $logo The logo-image of the spitex
|
||||
* @property ValueObjects\Varchar $name The name of the spitex
|
||||
* @property ValueObjects\EAN13 $gln Spitex GLN-Number
|
||||
* @property bool $isSpitex always returns true
|
||||
* @property Address $address adress Object? not implemented in mapper yet
|
||||
*/
|
||||
class Spitex extends DomainObject implements Business
|
||||
{
|
||||
use Log;
|
||||
|
||||
protected function fields(array ...$superFields): array
|
||||
{
|
||||
return parent::fields([
|
||||
'id' => IntKey::class,
|
||||
'logo' => Image::class,
|
||||
'name' => Varchar::class,
|
||||
'gln' => EAN13::class,
|
||||
'billcare' => Integer::class,
|
||||
'address' => Address::class,
|
||||
|
||||
// Modules - todo: normalize in additional table
|
||||
'bcModule' => Integer::class,
|
||||
'xmlModule' => Boolean::class,
|
||||
'ekarusModule' => Boolean::class,
|
||||
'popModule' => Boolean::class,
|
||||
'qrModule' => Boolean::class,
|
||||
'dpModule' => Boolean::class,
|
||||
'tpModule' => Boolean::class,
|
||||
], ...$superFields);
|
||||
}
|
||||
|
||||
public function __get(string $field)
|
||||
{
|
||||
switch ($field) {
|
||||
case 'isSpitex': return $this->isSpitex();
|
||||
case 'logo': return $this->logo();
|
||||
}
|
||||
return parent::__get($field);
|
||||
}
|
||||
|
||||
public function name()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
public function logo()
|
||||
{
|
||||
$logo = $this->data['logo'];
|
||||
|
||||
if (! $logo->isReadable()) {
|
||||
$logo->in('logo_leer/logo_leer.jpg');
|
||||
}
|
||||
return $logo;
|
||||
}
|
||||
|
||||
public function isSpitex(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Activate / Deactivate Modules
|
||||
* @todo put moduels in a separate table. Do not use the fields directly to change state, to ease
|
||||
* migration
|
||||
* @param modules 'field' => true|false
|
||||
*/
|
||||
public function modules(Array $modules)
|
||||
{
|
||||
foreach ($modules as $module => $value) {
|
||||
$this->{$module.'Module'} = $value;
|
||||
}
|
||||
}
|
||||
|
||||
public function isModuleActive(string $module): bool
|
||||
{
|
||||
return $this->{$module.'Module'};
|
||||
}
|
||||
|
||||
public function areModulesActive(array $modules): bool
|
||||
{
|
||||
$areActive = true;
|
||||
foreach ($modules as $module)
|
||||
{
|
||||
if (!$this->{$module.'Module'} === true) {
|
||||
$areActive = false;
|
||||
}
|
||||
}
|
||||
return $areActive;
|
||||
}
|
||||
}
|
||||
|
||||
/* jEdit buffer local properties {{{
|
||||
* :folding=explicit:collapseFolds=1:
|
||||
}}}*/
|
||||
82
src/DomainObjects/Token.php
Normal file
82
src/DomainObjects/Token.php
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace VeruA\DomainObjects;
|
||||
|
||||
use VeruA\DomainObjects\{
|
||||
DomainObject,
|
||||
Owner
|
||||
};
|
||||
use VeruA\DomainObjects\ValueObjects\{
|
||||
Key,
|
||||
IntKey,
|
||||
Varchar,
|
||||
DateTime
|
||||
};
|
||||
|
||||
/**
|
||||
* A Token DomainObject
|
||||
*
|
||||
* @property ValueObjects\Intkey $ownerId The pk of the Owner the token belongs to
|
||||
* @property Owner $owner The Owner of the token
|
||||
* @property ValueObjects\Varchar $string The token string
|
||||
* @property ValueObjects\DateTime $creationTime The script or binary
|
||||
*
|
||||
* @author norb
|
||||
*/
|
||||
class Token extends DomainObject
|
||||
{
|
||||
use \VeruA\Log;
|
||||
|
||||
public function __construct($data=null)
|
||||
{
|
||||
parent::__construct($data);
|
||||
|
||||
if ($data instanceof Key)
|
||||
{
|
||||
$this->set('idOwner', $data);
|
||||
$this->markNew();
|
||||
$this->createToken();
|
||||
}
|
||||
|
||||
$this->log()->debug("Values after instantiation", $this->data);
|
||||
}
|
||||
|
||||
protected function fields(array ...$superFields): array
|
||||
{
|
||||
return parent::fields([
|
||||
'id' => IntKey::class,
|
||||
'idOwner' => IntKey::class,
|
||||
'owner' => Owner::class,
|
||||
'string' => Varchar::class,
|
||||
'creationTime' => DateTime::class,
|
||||
], ...$superFields);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a random generated token consisting of letters and numbers
|
||||
*
|
||||
* @param int $length The character length of the token
|
||||
* @return string The token
|
||||
*/
|
||||
public function createToken(int $length = 64): string
|
||||
{
|
||||
$this->string = bin2hex(random_bytes($length/2));
|
||||
$this->creationTime = new \DateTimeImmutable();
|
||||
return $this->string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the token is still valid
|
||||
*
|
||||
* @return true if creationTime not older than 14 days
|
||||
*/
|
||||
public function good(): bool
|
||||
{
|
||||
return ($this->creationTime->value()->diff(new \DateTimeImmutable())->days < 14);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* jEdit buffer local properties {{{
|
||||
* :folding=explicit:collapseFolds=1:
|
||||
}}}*/
|
||||
181
src/DomainObjects/Validation/AbstractValidator.php
Normal file
181
src/DomainObjects/Validation/AbstractValidator.php
Normal file
|
|
@ -0,0 +1,181 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace VeruA\DomainObjects\Validation;
|
||||
|
||||
use VeruA\Log;
|
||||
use VeruA\DomainObjects\DomainObject;
|
||||
use VeruA\DomainObjects\ValueObjects\Value;
|
||||
use VeruA\DomainObjects\Validation\ResultCollection;
|
||||
|
||||
/**
|
||||
* Validator is a singleton base class for classes validating DomainObjects.
|
||||
*/
|
||||
abstract class AbstractValidator implements Validator
|
||||
{
|
||||
use Log;
|
||||
|
||||
/**
|
||||
* Needs to be declared in every childclass
|
||||
* @var callable[] A list of tests used to validate domainObjects dataTypes, indexed by fieldname
|
||||
*/
|
||||
protected $validators = [];
|
||||
|
||||
/**
|
||||
* Stores the single instance of Validator.
|
||||
* @var Validator
|
||||
* @abstract Needs to be redeclared in every child class
|
||||
*/
|
||||
protected static AbstractValidator $instance;
|
||||
|
||||
private bool $validatorsLoaded = false;
|
||||
|
||||
/**
|
||||
* Implement constructor in childclasses and assign the validator functions to using setValidators()
|
||||
* All sub-classes should have protected constructors.
|
||||
*/
|
||||
protected abstract function __construct();
|
||||
|
||||
// getValidators() {{{
|
||||
/**
|
||||
* Returns the validator functions.
|
||||
*/
|
||||
public function getValidators()
|
||||
{
|
||||
return $this->validators;
|
||||
} // }}}
|
||||
|
||||
// setValidators() {{{
|
||||
/**
|
||||
* Sets the validator functions.
|
||||
*/
|
||||
protected function setValidators($tests)
|
||||
{
|
||||
$parentClass = get_parent_class($this);
|
||||
$parentTests = [];
|
||||
|
||||
if ($parentClass !== false && $parentClass !== AbstractValidator::class)
|
||||
{
|
||||
$parentTests = $parentClass::getInstance()->getValidators();
|
||||
}
|
||||
$this->validators = array_merge($parentTests, $tests);
|
||||
} // }}}
|
||||
|
||||
// addValidator() {{{
|
||||
/**
|
||||
* Dynamically add a validator function
|
||||
* @param string $field The DomainObject Field to validate
|
||||
* @param callable $validator The Validator function to use
|
||||
* @param string $validatorIndex The internal index used to store the validator function. Use this to
|
||||
* remove or overwrite the validator
|
||||
*/
|
||||
public function addValidator(string $field, callable $validator, ?string $validatorIndex=null)
|
||||
{
|
||||
if (!isset($this->validators[$field])) $this->validators[$field] = [];
|
||||
$this->validators[$field][$validatorIndex] = $validator;
|
||||
} // }}}
|
||||
|
||||
// removeValidator() {{{
|
||||
/**
|
||||
* Dynamiocally remove a validator function
|
||||
*/
|
||||
public function removeValidator(string $field, $validatorIndex=null)
|
||||
{
|
||||
if (isset($validatorIndex))
|
||||
{
|
||||
unset($this->validators[$field][$validatorIndex]);
|
||||
} else
|
||||
{
|
||||
unset($this->validators[$field]);
|
||||
}
|
||||
} // }}}
|
||||
|
||||
// getInstance() {{{
|
||||
/**
|
||||
* Returnst the instances of the validator, instantiates a new one if there isn't one already.
|
||||
* @return Validator
|
||||
*/
|
||||
public static function getInstance(): Validator
|
||||
{
|
||||
if (!isset(static::$instance)) {
|
||||
static::$instance = new static();
|
||||
}
|
||||
|
||||
assert(
|
||||
array_column(
|
||||
(new \ReflectionClass(static::$instance))
|
||||
->getProperties(\ReflectionProperty::IS_STATIC | \ReflectionProperty::IS_PROTECTED),
|
||||
'class', 'name'
|
||||
)['instance'] === get_class(static::$instance),
|
||||
new \Exception('$instance has to be redeclared in '.get_class(static::$instance))
|
||||
);
|
||||
|
||||
return static::$instance;
|
||||
} // }}}
|
||||
|
||||
// validate() {{{
|
||||
/**
|
||||
* Validates a DomainObject.
|
||||
* @param DomainObject $domainObject
|
||||
* @return ResultCollection|bool returns true if validations passed a ResultCollection otherwise
|
||||
*/
|
||||
public function validate(Validatable $domainObject)
|
||||
{
|
||||
$this->loadDefaultValidators($domainObject);
|
||||
|
||||
$rc = new ResultCollection((new \ReflectionClass($domainObject))->getShortName());
|
||||
$passed = true;
|
||||
|
||||
// Validate properties
|
||||
foreach ($this->validators as $col => $validators)
|
||||
{
|
||||
if (!isset($domainObject->$col)) {
|
||||
$this->log()->notice('DomainObject '.get_class($domainObject)." has no field '$col'");
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
$valueObject = $domainObject->getValueObjectOf($col);
|
||||
foreach ($validators as $test)
|
||||
{
|
||||
if (true !== ($result = $test($valueObject))) {
|
||||
$rc->$col = $result;
|
||||
$passed = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (\OutOfRangeException $e) {
|
||||
self::log()->notice('Field not set', ['name' => $col]);
|
||||
}
|
||||
}
|
||||
|
||||
return $passed ?: $rc;
|
||||
} // }}}
|
||||
|
||||
// loadDefaultValidators() {{{
|
||||
/**
|
||||
* load vaildators defined in ValueObjects.
|
||||
* Defined as Default and as such meaning always used. An example is the EAN13 ValueObject
|
||||
* which always validates checksum and length
|
||||
*/
|
||||
private function loadDefaultValidators(DomainObject $domainObject)
|
||||
{
|
||||
if (! $this->validatorsLoaded)
|
||||
{
|
||||
foreach ($domainObject->dataTypes() as $col => $dt)
|
||||
{
|
||||
if (is_subclass_of($dt, Value::class) && !empty($validators = ($dt)::defaultValidators()))
|
||||
{
|
||||
if (!isset($this->validators[$col])) $this->validators[$col] = [];
|
||||
|
||||
$this->validators[$col] = array_merge($this->validators[$col], $validators);
|
||||
}
|
||||
}
|
||||
self::log()->debug('Registered Validators', $this->validators);
|
||||
|
||||
$this->validatorsLoaded = true;
|
||||
}
|
||||
} // }}}
|
||||
}
|
||||
|
||||
/* jEdit buffer local properties {{{
|
||||
* :folding=explicit:collapseFolds=1:
|
||||
}}}*/
|
||||
18
src/DomainObjects/Validation/AddressValidator.php
Normal file
18
src/DomainObjects/Validation/AddressValidator.php
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace VeruA\DomainObjects\Validation;
|
||||
|
||||
use VeruA\DomainObjects\ValueObjects\DataType;
|
||||
|
||||
class AddressValidator extends AbstractValidator
|
||||
{
|
||||
protected static AbstractValidator $instance;
|
||||
|
||||
protected function __construct()
|
||||
{
|
||||
$this->validators = [
|
||||
'id' => [DataType::required()],
|
||||
'email' => [DataType::notBlank()],
|
||||
];
|
||||
}
|
||||
}
|
||||
29
src/DomainObjects/Validation/ClientValidator.php
Normal file
29
src/DomainObjects/Validation/ClientValidator.php
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace VeruA\DomainObjects\Validation;
|
||||
|
||||
use VeruA\DomainObjects\ValueObjects\{
|
||||
DataType,
|
||||
Number,
|
||||
Varchar
|
||||
};
|
||||
use VeruA\DomainObjects\Validation\PersonValidator;
|
||||
|
||||
class ClientValidator extends PersonValidator
|
||||
{
|
||||
use Number;
|
||||
protected static AbstractValidator $instance;
|
||||
|
||||
protected function __construct()
|
||||
{
|
||||
$this->setValidators([
|
||||
'id' => [DataType::required()],
|
||||
'birthday' => [DataType::required()],
|
||||
'ahv' => [DataType::required(), /* DataType::unique() */],
|
||||
'childCount' => [self::min(0)], // from Number trait
|
||||
'address' => [[AddressValidator::getInstance(), 'validate']],
|
||||
'cardId' => [DataType::ifExists(DataType::length(20)), Varchar::isDecimal()],
|
||||
'cardId' => [DataType::notBlank()],
|
||||
]);
|
||||
}
|
||||
}
|
||||
10
src/DomainObjects/Validation/Error.php
Normal file
10
src/DomainObjects/Validation/Error.php
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace VeruA\DomainObjects\Validation;
|
||||
|
||||
/**
|
||||
* Result of an unsuccessful validation.
|
||||
*/
|
||||
class Error extends Result
|
||||
{
|
||||
}
|
||||
37
src/DomainObjects/Validation/InvoiceValidator.php
Normal file
37
src/DomainObjects/Validation/InvoiceValidator.php
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace VeruA\DomainObjects\Validation;
|
||||
|
||||
use VeruA\DomainObjects\ValueObjects\DataType;
|
||||
|
||||
class InvoiceValidator extends AbstractValidator
|
||||
{
|
||||
protected static AbstractValidator $instance;
|
||||
|
||||
protected function __construct()
|
||||
{
|
||||
$this->validators = [
|
||||
'reveiver' => [DataType::required(), DataType::length(2)],
|
||||
'id_client' => [DataType::relation('client')],
|
||||
'id_owner' => [DataType::relation('owner', 'spitex')],
|
||||
// @Deprecated: 'id_vers' => [DataType::relation('organisation')],
|
||||
'id_vers' => [DataType::notNull()],
|
||||
'vers_nr' => [],
|
||||
'id_arzt' => [DataType::relation('arzt')],
|
||||
'reason' => [],
|
||||
'status' => [],
|
||||
'id_kanton' => [DataType::relation('taxwert')],
|
||||
'client' => [DataType::relation('id_klient')],
|
||||
'biller' => [DataType::relation('id_owner')],
|
||||
'insurance' => [DataType::relation('id_vers')],
|
||||
'referrer' => [DataType::relation('id_arzt')],
|
||||
'schreiben' => [],
|
||||
'gesetz' => [DataType::unechterelation('tarif', 'taxwert')],
|
||||
'id_rechempfänger' => [DataType::relation('id', 'person')],
|
||||
'id_kt' => [DataType::relation('organisation')],
|
||||
'id_kt_2' => [DataType::relation('organisation')],
|
||||
'sr' => [DataType::relation('sammelrechnung')],
|
||||
'id_zk' => [DataType::relation('zusatzkosten')],
|
||||
];
|
||||
}
|
||||
}
|
||||
14
src/DomainObjects/Validation/OrganisationValidator.php
Normal file
14
src/DomainObjects/Validation/OrganisationValidator.php
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace VeruA\DomainObjects\Validation;
|
||||
|
||||
class AddressValidator extends AbstractValidator
|
||||
{
|
||||
protected static AbstractValidator $instance;
|
||||
|
||||
protected function __construct()
|
||||
{
|
||||
$this->objectTests = [
|
||||
];
|
||||
}
|
||||
}
|
||||
23
src/DomainObjects/Validation/OwnerValidator.php
Normal file
23
src/DomainObjects/Validation/OwnerValidator.php
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace VeruA\DomainObjects\Validation;
|
||||
|
||||
use VeruA\DomainObjects\ValueObjects\{
|
||||
DataType,
|
||||
Number,
|
||||
Varchar
|
||||
};
|
||||
|
||||
class OwnerValidator extends AbstractValidator
|
||||
{
|
||||
protected static AbstractValidator $instance;
|
||||
|
||||
protected function __construct()
|
||||
{
|
||||
$this->setValidators([
|
||||
'password' => [
|
||||
DataType::required(),
|
||||
],
|
||||
]);
|
||||
}
|
||||
}
|
||||
21
src/DomainObjects/Validation/PersonValidator.php
Normal file
21
src/DomainObjects/Validation/PersonValidator.php
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace VeruA\DomainObjects\Validation;
|
||||
|
||||
use VeruA\DomainObjects\ValueObjects\DataType;
|
||||
|
||||
class PersonValidator extends AbstractValidator
|
||||
{
|
||||
protected static AbstractValidator $instance;
|
||||
|
||||
protected function __construct()
|
||||
{
|
||||
$this->setValidators([
|
||||
'id' => [DataType::required()],
|
||||
'firstname' => [DataType::notBlank()],
|
||||
'lastname' => [DataType::notBlank()],
|
||||
'address' => [DataType::required()],
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
25
src/DomainObjects/Validation/Result.php
Normal file
25
src/DomainObjects/Validation/Result.php
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace VeruA\DomainObjects\Validation;
|
||||
|
||||
/**
|
||||
* Result of an unsuccessful validation.
|
||||
*/
|
||||
abstract class Result
|
||||
{
|
||||
/** @var string Error code, MUST match one of the error codes in translations/errors_XX.xml. */
|
||||
public $msgCode = '';
|
||||
|
||||
/** @var string Erroneous value. */
|
||||
public $value = '';
|
||||
|
||||
/** @var string Possible reason for the error. */
|
||||
public $hint = '';
|
||||
|
||||
public function __construct(string $msgCode, $value=null, ?string $hint=null)
|
||||
{
|
||||
$this->msgCode = $msgCode;
|
||||
$this->value = $value ?? '';
|
||||
$this->hint = $hint ?? '';
|
||||
}
|
||||
}
|
||||
63
src/DomainObjects/Validation/ResultCollection.php
Normal file
63
src/DomainObjects/Validation/ResultCollection.php
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace VeruA\DomainObjects\Validation;
|
||||
|
||||
/**
|
||||
* A collection of validation-results.
|
||||
*/
|
||||
class ResultCollection implements \IteratorAggregate
|
||||
{
|
||||
/** @var array $reults Maps field-names to a list of validation-results. */
|
||||
private $results = [];
|
||||
|
||||
private $DMO;
|
||||
|
||||
public function __construct(string $DMO='') {
|
||||
$this->DMO = strtolower($DMO);
|
||||
}
|
||||
|
||||
public function getIterator(): \ArrayIterator
|
||||
{
|
||||
return (new \ArrayObject($this->results))->getIterator();
|
||||
}
|
||||
|
||||
public function __get(string $fieldName)
|
||||
{
|
||||
switch ($fieldName)
|
||||
{
|
||||
case 'DMO':
|
||||
return $this->DMO;
|
||||
}
|
||||
|
||||
$result = [];
|
||||
if (isset($this->results[$fieldName])) {
|
||||
$result = $this->results[$fieldName];
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $fildName
|
||||
* @param Result|ResultCollection $fieldResult
|
||||
*/
|
||||
public function __set(string $fieldName, $fieldResult)
|
||||
{
|
||||
$this->results[$fieldName][] = $fieldResult;
|
||||
}
|
||||
|
||||
public function getResults(): Array
|
||||
{
|
||||
return $this->results;
|
||||
}
|
||||
|
||||
public function isInResults( string $field ): bool
|
||||
{
|
||||
return array_key_exists( $field, $this->results );
|
||||
}
|
||||
|
||||
public function resultsAreNtCaseIds():bool
|
||||
{
|
||||
return !array_key_exists('insuredId', $this->results) && !array_key_exists('caseId', $this->results);
|
||||
}
|
||||
}
|
||||
24
src/DomainObjects/Validation/TokenValidator.php
Normal file
24
src/DomainObjects/Validation/TokenValidator.php
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace VeruA\DomainObjects\Validation;
|
||||
|
||||
use VeruA\DomainObjects\ValueObjects\{DataType, Number, Varchar};
|
||||
|
||||
class TokenValidator extends AbstractValidator
|
||||
{
|
||||
protected static AbstractValidator $instance;
|
||||
|
||||
protected function __construct()
|
||||
{
|
||||
$this->setValidators([
|
||||
'ownerId' => [DataType::required()],
|
||||
'owner' => [DataType::required()],
|
||||
'token' => [
|
||||
DataType::required(),
|
||||
DataType::length(64),
|
||||
Varchar::matchRegEx('/^[A-Za-z0-9]+$/')
|
||||
],
|
||||
'creationDate' => [DataType::required()],
|
||||
]);
|
||||
}
|
||||
}
|
||||
17
src/DomainObjects/Validation/Validatable.php
Normal file
17
src/DomainObjects/Validation/Validatable.php
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace VeruA\DomainObjects\Validation;
|
||||
|
||||
use VeruA\DomainObjects\ValueObjects\Value;
|
||||
|
||||
interface Validatable
|
||||
{
|
||||
/**
|
||||
* Validates the Object.
|
||||
* @return ResultCollection|bool returns true if validations passed a ResultCollection otherwise
|
||||
*/
|
||||
public function validate();
|
||||
|
||||
public function getValueObjectOf(string $field): Value;
|
||||
|
||||
}
|
||||
19
src/DomainObjects/Validation/Validator.php
Normal file
19
src/DomainObjects/Validation/Validator.php
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace VeruA\DomainObjects\Validation;
|
||||
|
||||
interface Validator
|
||||
{
|
||||
/**
|
||||
* Returnst the instances of the validator, instantiates a new one if there isn't one already.
|
||||
* @return Validator
|
||||
*/
|
||||
public static function getInstance(): Validator;
|
||||
|
||||
/**
|
||||
* Validates a DomainObject.
|
||||
* @param Validatable $object
|
||||
* @return ResultCollection|bool returns true if validations passed a ResultCollection otherwise
|
||||
*/
|
||||
public function validate(Validatable $object);
|
||||
}
|
||||
12
src/DomainObjects/Validation/Warning.php
Normal file
12
src/DomainObjects/Validation/Warning.php
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace VeruA\DomainObjects\Validation;
|
||||
|
||||
use VeruA\DomainObjects\ValidationError;
|
||||
|
||||
/**
|
||||
* Result of a validation that was successful but produced a warning.
|
||||
*/
|
||||
class Warning extends Result
|
||||
{
|
||||
}
|
||||
40
src/DomainObjects/ValueObjects/AHV.php
Normal file
40
src/DomainObjects/ValueObjects/AHV.php
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace VeruA\DomainObjects\ValueObjects;
|
||||
|
||||
/**
|
||||
* An implementation of AHV
|
||||
* @todo rename to EAN and extend to use for arbitrary EAN encoded values
|
||||
*/
|
||||
class AHV extends EAN13
|
||||
{
|
||||
// in() {{{
|
||||
/**
|
||||
* Converts the $value stripping of all dots
|
||||
*/
|
||||
public function in( $value )
|
||||
{
|
||||
$this->value = trim( str_replace( '.', '', (string)$value ) );
|
||||
} // }}}
|
||||
|
||||
// out() {{{
|
||||
/**
|
||||
* returns the value with the AHV typical dots on the correct places
|
||||
*/
|
||||
public function out(): string
|
||||
{
|
||||
$outValue = $this->value;
|
||||
if ($outValue)
|
||||
{
|
||||
foreach ([ 3, 8, 13 ] as $dotPos)
|
||||
{
|
||||
$outValue = substr( $outValue, 0, $dotPos ) .'.'. substr( $outValue, $dotPos );
|
||||
}
|
||||
}
|
||||
return $outValue;
|
||||
} // }}}}
|
||||
}
|
||||
|
||||
/* jEdit buffer local properties {{{
|
||||
* :folding=explicit:collapseFolds=1:
|
||||
}}}*/
|
||||
54
src/DomainObjects/ValueObjects/Boolean.php
Normal file
54
src/DomainObjects/ValueObjects/Boolean.php
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
<?php namespace VeruA\DomainObjects\ValueObjects;
|
||||
|
||||
/**
|
||||
* A boolean value
|
||||
* Internally uses boolean
|
||||
*/
|
||||
class Boolean extends DataType implements Primitive
|
||||
{
|
||||
// in() {{{
|
||||
/**
|
||||
* Stores the $value as boolean casting it
|
||||
*
|
||||
* @param mixed The Value to be stored
|
||||
*/
|
||||
public function in( $value )
|
||||
{
|
||||
$this->value = (bool)$value;
|
||||
} // }}}
|
||||
|
||||
// __toString() {{{
|
||||
/**
|
||||
* converts true to 1 and false to 0
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return ($this->value) ? '1' : '0';
|
||||
} // }}}
|
||||
|
||||
// equals() {{{
|
||||
/**
|
||||
* Compares the boolean value
|
||||
* @param bool|\VeruA\DomainObjects\Boolean the value to compare
|
||||
*/
|
||||
public function equals( $compare )
|
||||
{
|
||||
if ($compare instanceof Boolean) $compare = $compare->value();
|
||||
return ($this->value === $compare);
|
||||
} // }}}
|
||||
|
||||
// out() {{{
|
||||
/**
|
||||
* Returns the $value as integer for db queries
|
||||
* @return int
|
||||
*/
|
||||
public function out(): int
|
||||
{
|
||||
return (int)$this->value;
|
||||
} // }}}
|
||||
}
|
||||
|
||||
/* jEdit buffer local properties {{{
|
||||
* :folding=explicit:collapseFolds=1:
|
||||
}}}*/
|
||||
12
src/DomainObjects/ValueObjects/Complex.php
Normal file
12
src/DomainObjects/ValueObjects/Complex.php
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace VeruA\DomainObjects\ValueObjects;
|
||||
|
||||
/**
|
||||
* A ValueObject that has a complex Value such as Date or Money which cannot be represented directly
|
||||
* as a string and is thus returned from a DomainObject as is
|
||||
*/
|
||||
interface Complex
|
||||
{
|
||||
public function isComplex(): bool;
|
||||
}
|
||||
233
src/DomainObjects/ValueObjects/DataType.php
Normal file
233
src/DomainObjects/ValueObjects/DataType.php
Normal file
|
|
@ -0,0 +1,233 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace VeruA\DomainObjects\ValueObjects;
|
||||
|
||||
use VeruA\DomainObjects\Validation\Error;
|
||||
|
||||
/**
|
||||
* A DataType is the smallest entity of Data.
|
||||
*
|
||||
* Every value of an \VeruA\DomainObjects\DomainObject is represented as such.
|
||||
*
|
||||
*/
|
||||
class DataType implements Value
|
||||
{
|
||||
|
||||
/** @var mixed $value The internal value of the DataType */
|
||||
protected $value;
|
||||
|
||||
// Constructor {{{
|
||||
/**
|
||||
* The constructor is normally called from the DomainObject when instatiated.
|
||||
*
|
||||
* @param mixde $value
|
||||
*/
|
||||
public function __construct( $value=null )
|
||||
{
|
||||
if (isset($value)) $this->in($value);
|
||||
}// }}}
|
||||
|
||||
// __toString() {{{
|
||||
/**
|
||||
* Make sure to overwrite this method in the implementations
|
||||
* @return string The string representation of the DataType
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return (string)$this->out();
|
||||
}// }}}
|
||||
|
||||
// equals() {{{
|
||||
/**
|
||||
* Compares the internal value with the $compare argument
|
||||
*
|
||||
* Remember that you get a DomainObject when using the DomainObjects values, thus comparison can have
|
||||
* undesired results, use the equals method to compare ValueObjects<br>
|
||||
* This has to be overwritten in the descendants to get the desired comparison behaviour
|
||||
* @param DataType|mixed $compare The value to be compared
|
||||
*/
|
||||
public function equals( $compare )
|
||||
{
|
||||
if ($compare instanceof DataType) $compare = $compare->value();
|
||||
return ($this->value == $compare);
|
||||
} // }}}
|
||||
|
||||
// in() {{{
|
||||
/**
|
||||
* Stores the $value applying the input filters
|
||||
*
|
||||
* This method should be overwritten in the concrete implementation
|
||||
* @todo Filters are yet to be implemented!
|
||||
* @param mixed The Value to be stored
|
||||
*/
|
||||
public function in( $value )
|
||||
{
|
||||
$this->value = $value;
|
||||
} // }}}
|
||||
|
||||
// out() {{{
|
||||
/**
|
||||
* Returns the $value applying the output filters
|
||||
*
|
||||
* This method should be overwritten in the concrete implementation
|
||||
* @todo Filters are yet to be implemented!
|
||||
*/
|
||||
public function out(): mixed
|
||||
{
|
||||
return (string)$this->value;
|
||||
} // }}}
|
||||
|
||||
// value() {{{
|
||||
/**
|
||||
* Returns the internal value
|
||||
*/
|
||||
public function value()
|
||||
{
|
||||
return $this->value;
|
||||
} // }}}
|
||||
|
||||
// defaultValidators() {{{
|
||||
/**
|
||||
* Overwrite this message if a DataType needs validation methods that are always applied
|
||||
*/
|
||||
public static function defaultValidators(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
// }}}
|
||||
|
||||
// validation methods {{{
|
||||
/**
|
||||
* @return callable Returns a predicate that tests for the existence of it's argument.
|
||||
*/
|
||||
public static function required(): callable
|
||||
{
|
||||
return function (?Value $valueObject)
|
||||
{
|
||||
return isset($valueObject) ? true : new Error(
|
||||
$msgCode = 'VALIDATION_REQUIRED',
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* NotBlank
|
||||
* @return callable
|
||||
*/
|
||||
public static function notBlank(): callable
|
||||
{
|
||||
return function (Value $valueObject) {
|
||||
return ($valueObject->value()) ? true : new Error('VALIDATION_NOTBLANK');
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* NotNull
|
||||
* @return callable
|
||||
*/
|
||||
public static function notNull(): callable
|
||||
{
|
||||
return function (Value $valueObject) {
|
||||
return ($valueObject->value() !== null) ? true : new Error('VALIDATION_NOTNULL');
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @return callable Returns a predicate that tests a value using $test if it exists.
|
||||
*/
|
||||
public static function ifExists(callable $test) : callable
|
||||
{
|
||||
return function (?Value $valueObject) use ($test)
|
||||
{
|
||||
return isset($valueObject) ? $test($valueObject) : true;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @return callable Returns a predicate that tests if its argument is of length $n.
|
||||
*/
|
||||
public static function length(int $n): callable
|
||||
{
|
||||
// assert($n >= 0, 'Strings can only be tested for positive lengths!');
|
||||
|
||||
return function(Value $valueObject) use ($n)
|
||||
{
|
||||
$value = (string) $valueObject->value();
|
||||
return (strlen($value) === $n) ? true : new Error(
|
||||
$msgCode = 'VALIDATION_LENGTH',
|
||||
$value = (string) $value,
|
||||
$hint = (string) $n,
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @return callable Returns a predicate that tests if its argument is of length $n or greater.
|
||||
*/
|
||||
public static function minLength(int $n)
|
||||
{
|
||||
assert($n >= 0, 'Strings can only be tested for positive lengths!');
|
||||
|
||||
return function(Value $valueObject) use ($n)
|
||||
{
|
||||
$value = (string) $valueObject->value();
|
||||
return (strlen($value) >= $n) ? true : new Error(
|
||||
$msgCode = 'VALIDATION_LENGTH',
|
||||
$value = (string) $value,
|
||||
$hint = (string) $n,
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @return callable Returns a predicate that tests if its argument is of length $n or less.
|
||||
*/
|
||||
public static function maxLength(int $n)
|
||||
{
|
||||
assert($n >= 0, 'Strings can only be tested for positive lengths!');
|
||||
|
||||
return function(Value $valueObject) use ($n)
|
||||
{
|
||||
$value = (string) $valueObject->value();
|
||||
return (strlen($value) <= $n) ? true : new Error(
|
||||
$msgCode = 'VALIDATION_LENGTH',
|
||||
$value = (string) $value,
|
||||
$hint = (string) $n,
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* not implemented - remove?
|
||||
* @return callable Returns a predicate that tests if it's argument is unique in it's environment.
|
||||
*/
|
||||
public static function unique()
|
||||
{
|
||||
// TODO: Not implemented yet!
|
||||
return function ($uniqueValue)
|
||||
{
|
||||
return new Error();
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @return callable Returns a predicate that test if it's argument is one of several elements.
|
||||
*/
|
||||
public static function oneOf($lst)
|
||||
{
|
||||
return function (Value $valueObject) use ($lst)
|
||||
{
|
||||
$value = $valueObject->value();
|
||||
return in_array($value, $lst, true) ? true : new Error(
|
||||
$msgCode = 'INVALID_VALUE',
|
||||
$value = (string) $value,
|
||||
$hint = implode("|", $lst),
|
||||
);
|
||||
};
|
||||
}
|
||||
// }}}
|
||||
}
|
||||
|
||||
/* jEdit buffer local properties {{{
|
||||
* :folding=explicit:collapseFolds=1:
|
||||
}}}*/
|
||||
72
src/DomainObjects/ValueObjects/Date.php
Normal file
72
src/DomainObjects/ValueObjects/Date.php
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
<?php namespace VeruA\DomainObjects\ValueObjects;
|
||||
|
||||
/**
|
||||
* A Date Value
|
||||
*
|
||||
*/
|
||||
class Date extends DataType implements Complex
|
||||
{
|
||||
|
||||
// Constructor {{{
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function __construct( $value=null, $props=[] )
|
||||
{
|
||||
parent::__construct( $value, $props );
|
||||
} // }}}
|
||||
|
||||
// in() {{{
|
||||
/**
|
||||
* Stores the $value as a DateTime Object
|
||||
*/
|
||||
public function in( $value )
|
||||
{
|
||||
if (isset($value))
|
||||
{
|
||||
if ($value instanceof \DateTime || $value instanceof \DateTimeImmutable) {
|
||||
$this->value = $value;
|
||||
} else {
|
||||
$this->value = new \DateTime($value);
|
||||
}
|
||||
}
|
||||
} // }}}
|
||||
|
||||
// out() {{{
|
||||
public function out(): string
|
||||
{
|
||||
return (isset($this->value)) ? $this->value->format("Y-m-d") : '';
|
||||
} // }}}
|
||||
|
||||
// __toString() {{{
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return (isset($this->value)) ? $this->value->format("d.m.Y") : '';
|
||||
} // }}}
|
||||
|
||||
// __get() {{{
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function __get($name)
|
||||
{
|
||||
switch ($name)
|
||||
{
|
||||
case 'timestamp':
|
||||
return $this->value()->getTimestamp();
|
||||
}
|
||||
} // }}}
|
||||
|
||||
// isComplex() {{{
|
||||
public function isComplex(): bool {
|
||||
return true;
|
||||
} // }}}
|
||||
|
||||
}
|
||||
|
||||
/* jEdit buffer local properties {{{
|
||||
* :folding=explicit:collapseFolds=1:
|
||||
}}}*/
|
||||
72
src/DomainObjects/ValueObjects/DateTime.php
Normal file
72
src/DomainObjects/ValueObjects/DateTime.php
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
<?php namespace VeruA\DomainObjects\ValueObjects;
|
||||
|
||||
/**
|
||||
* A Date Value
|
||||
*
|
||||
*/
|
||||
class DateTime extends DataType implements Complex
|
||||
{
|
||||
|
||||
// Constructor {{{
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function __construct( $value=null, $props=[] )
|
||||
{
|
||||
parent::__construct( $value, $props );
|
||||
} // }}}
|
||||
|
||||
// in() {{{
|
||||
/**
|
||||
* Stores the $value as a DateTime Object
|
||||
*/
|
||||
public function in( $value )
|
||||
{
|
||||
if (isset($value))
|
||||
{
|
||||
if ($value instanceof \DateTime || $value instanceof \DateTimeImmutable) {
|
||||
$this->value = $value;
|
||||
} else {
|
||||
$this->value = new \DateTime($value);
|
||||
}
|
||||
}
|
||||
} // }}}
|
||||
|
||||
// __toString() {{{
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return (isset($this->value)) ? $this->value->format("d.m.Y H:i:s") : '';
|
||||
} // }}}
|
||||
|
||||
// out() {{{
|
||||
public function out(): string
|
||||
{
|
||||
return (isset($this->value)) ? $this->value->format("Y-m-d H:i:s") : '';
|
||||
} // }}}
|
||||
|
||||
// __get() {{{
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function __get($name)
|
||||
{
|
||||
switch ($name)
|
||||
{
|
||||
case 'timestamp':
|
||||
return $this->value()->getTimestamp();
|
||||
}
|
||||
} // }}}
|
||||
|
||||
// isComplex() {{{
|
||||
public function isComplex(): bool {
|
||||
return true;
|
||||
} // }}}
|
||||
|
||||
}
|
||||
|
||||
/* jEdit buffer local properties {{{
|
||||
* :folding=explicit:collapseFolds=1:
|
||||
}}}*/
|
||||
33
src/DomainObjects/ValueObjects/Decimal.php
Normal file
33
src/DomainObjects/ValueObjects/Decimal.php
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
<?php namespace VeruA\DomainObjects\ValueObjects;
|
||||
|
||||
/**
|
||||
* An implementation of Decimal
|
||||
*/
|
||||
class Decimal extends DataType implements Primitive
|
||||
{
|
||||
// in() {{{
|
||||
/**
|
||||
* Stores the $value as int casting it
|
||||
*
|
||||
* @param mixed The Value to be stored
|
||||
*/
|
||||
public function in( $value )
|
||||
{
|
||||
$this->value = (double)$value;
|
||||
} // }}}
|
||||
|
||||
// equals() {{{
|
||||
/**
|
||||
* Compares the Float value
|
||||
* @param float|\VeruA\DomainObjects\Float the value to compare
|
||||
*/
|
||||
public function equals( $compare )
|
||||
{
|
||||
if (! $compare instanceof Float) $compare = new Float($compare);
|
||||
return ($this->value === $compare->value());
|
||||
} // }}}
|
||||
}
|
||||
|
||||
/* jEdit buffer local properties {{{
|
||||
* :folding=explicit:collapseFolds=1:
|
||||
}}}*/
|
||||
112
src/DomainObjects/ValueObjects/EAN13.php
Normal file
112
src/DomainObjects/ValueObjects/EAN13.php
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace VeruA\DomainObjects\ValueObjects;
|
||||
|
||||
use VeruA\DomainObjects\Validation\Error;
|
||||
|
||||
/**
|
||||
* An implementation of EAN13
|
||||
*/
|
||||
class EAN13 extends DataType implements Complex
|
||||
{
|
||||
// equals() {{{
|
||||
/**
|
||||
* Compares the EAN13-Numbers internal value
|
||||
* @param EAN13|string $compare the EAN Number to be compared with the datatypes one
|
||||
*/
|
||||
public function equals( $compare ): bool
|
||||
{
|
||||
if (! $compare instanceof EAN13) $compare = new EAN13($compare);
|
||||
return ($this->value() === $compare->value());
|
||||
} // }}}
|
||||
|
||||
// __toString() {{{
|
||||
/**
|
||||
* @return string The value as is
|
||||
*/
|
||||
public function __toString(): string
|
||||
{
|
||||
$outValue = (string)$this->value;
|
||||
if ($outValue)
|
||||
{
|
||||
foreach ([ 3, 8, 13 ] as $dotPos)
|
||||
{
|
||||
$outValue = substr( $outValue, 0, $dotPos ) .'.'. substr( $outValue, $dotPos );
|
||||
}
|
||||
}
|
||||
return $outValue;
|
||||
} // }}}
|
||||
|
||||
// in() {{{
|
||||
/**
|
||||
* Converts the $value stripping of all dots
|
||||
*/
|
||||
public function in( $value )
|
||||
{
|
||||
$this->value = (isset($value)) ? trim( str_replace( '.', '', (string)$value ) ) : '';
|
||||
} // }}}
|
||||
|
||||
// out() {{{
|
||||
/**
|
||||
* returns the value with the EAN13 typical dots on the correct places
|
||||
*/
|
||||
public function out(): string
|
||||
{
|
||||
return $this->value;
|
||||
} // }}}}
|
||||
|
||||
// defaultValidators() {{{
|
||||
public static function defaultValidators(): array
|
||||
{
|
||||
return [
|
||||
DataType::length(13),
|
||||
EAN13::checkdigit()
|
||||
];
|
||||
}
|
||||
// }}}
|
||||
|
||||
// validation methods {{{
|
||||
public static function checkdigit()
|
||||
{
|
||||
return function(EAN13 $ean)
|
||||
{
|
||||
$value = $ean->value();
|
||||
|
||||
if (!is_numeric($value)) {
|
||||
return new Error(
|
||||
$msgCode = "VALIDATION_EAN13_NONDIGITS",
|
||||
$value,
|
||||
$hint = ''
|
||||
);
|
||||
}
|
||||
|
||||
$lastPos = strlen( $value ) - 1;
|
||||
$sum = 0; $weight = 3;
|
||||
|
||||
for ( $i = $lastPos - 1; $i >= 0 ; $i-- ) {
|
||||
$sum += $value[ $i ] * $weight;
|
||||
$weight = ($weight == 3) ? 1 : 3;
|
||||
}
|
||||
if ( (ceil($sum / 10) * 10) - $sum == $value[ $lastPos ] ) { // checkdigit matches
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return new Error(
|
||||
$msgCode = "VALIDATION_EAN13_CHECKDIGIT",
|
||||
$value,
|
||||
$hint = ""
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
// }}}
|
||||
|
||||
// isComplex() {{{
|
||||
public function isComplex(): bool {
|
||||
return true;
|
||||
} // }}}
|
||||
}
|
||||
|
||||
/* jEdit buffer local properties {{{
|
||||
* :folding=explicit:collapseFolds=1:
|
||||
}}}*/
|
||||
14
src/DomainObjects/ValueObjects/Email.php
Normal file
14
src/DomainObjects/ValueObjects/Email.php
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace VeruA\DomainObjects\ValueObjects;
|
||||
|
||||
/**
|
||||
* An implementation of Email
|
||||
*/
|
||||
class Email extends Varchar
|
||||
{
|
||||
}
|
||||
|
||||
/* jEdit buffer local properties {{{
|
||||
* :folding=explicit:collapseFolds=1:
|
||||
}}}*/
|
||||
103
src/DomainObjects/ValueObjects/File.php
Normal file
103
src/DomainObjects/ValueObjects/File.php
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace VeruA\DomainObjects\ValueObjects;
|
||||
|
||||
use VeruA\Log;
|
||||
|
||||
/**
|
||||
* Class File
|
||||
*
|
||||
* Represents a file as a value object.
|
||||
* This class handles file-related operations such as resolving paths,
|
||||
* checking readability, and computing relative paths.
|
||||
*
|
||||
* @property-read bool $readable Indicates whether the file is readable.
|
||||
* @property-read string $realPath The absolute real path of the file.
|
||||
* @property-read string $relativePath The relative path of the file from the document root directory.
|
||||
*/
|
||||
class File extends DataType implements Complex
|
||||
{
|
||||
/**
|
||||
* @var string The default directory for file storage.
|
||||
*/
|
||||
protected $directory = 'file';
|
||||
|
||||
use Log;
|
||||
|
||||
/**
|
||||
* Stores the provided value as an SPLFileInfo object.
|
||||
*
|
||||
* This method takes the given path, resolves it relative to the defined directory,
|
||||
* and stores it as an SPLFileInfo instance.
|
||||
*
|
||||
* @param string $value The relative path to the file.
|
||||
* @return void
|
||||
*/
|
||||
public function in($value)
|
||||
{
|
||||
$path = __DIR__ . '/../../../' . $this->directory . '/';
|
||||
$path = realpath($path) ? realpath($path) . '/' : '';
|
||||
$this->value = new \SPLFileInfo($path . $value);
|
||||
$this->log()->debug($this);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic getter to retrieve file properties.
|
||||
*
|
||||
* @param string $name The name of the property.
|
||||
* @return mixed
|
||||
*/
|
||||
public function __get($name)
|
||||
{
|
||||
switch ($name)
|
||||
{
|
||||
case 'readable': return $this->isReadable();
|
||||
case 'realPath': return $this->value()->getRealPath();
|
||||
case 'relativePath': return $this->computeRelativePath();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the file is readable.
|
||||
*
|
||||
* @return bool True if the file is readable, false otherwise.
|
||||
*/
|
||||
public function isReadable(): bool
|
||||
{
|
||||
return $this->value()->isReadable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if the object represents a complex type.
|
||||
*
|
||||
* @return bool Always returns true for this class.
|
||||
*/
|
||||
public function isComplex(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the basename of the file without any directory components
|
||||
*
|
||||
* @return string The basename of the file.
|
||||
*/
|
||||
public function out(): string
|
||||
{
|
||||
return $this->value()->getBasename();
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the relative path of the file from the document root directory.
|
||||
*
|
||||
* This method calculates the relative path by removing the root directory's
|
||||
* real path from the file's absolute path.
|
||||
*
|
||||
* @return string The relative path of the file.
|
||||
*/
|
||||
private function computeRelativePath(): string
|
||||
{
|
||||
return str_replace(realpath(__DIR__ . '/../../../'), '', $this->realPath);
|
||||
}
|
||||
}
|
||||
22
src/DomainObjects/ValueObjects/Image.php
Normal file
22
src/DomainObjects/ValueObjects/Image.php
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace VeruA\DomainObjects\ValueObjects;
|
||||
|
||||
/**
|
||||
* Class Image
|
||||
*
|
||||
* Represents an image as a value object.
|
||||
* This class extends the File class, inheriting its functionality,
|
||||
* and sets a specific directory for image storage.
|
||||
*
|
||||
* @property-read bool $readable Indicates whether the file is readable.
|
||||
* @property-read string $realPath The absolute real path of the file.
|
||||
* @property-read string $relativePath The relative path of the file from the document root directory.
|
||||
*/
|
||||
class Image extends File
|
||||
{
|
||||
/**
|
||||
* @var string The default directory for image storage.
|
||||
*/
|
||||
protected $directory = 'img';
|
||||
}
|
||||
51
src/DomainObjects/ValueObjects/IntKey.php
Normal file
51
src/DomainObjects/ValueObjects/IntKey.php
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace VeruA\DomainObjects\ValueObjects;
|
||||
|
||||
/**
|
||||
* A key implementatin class storing an int key
|
||||
*/
|
||||
class IntKey extends Integer implements Key
|
||||
{
|
||||
// in() {{{
|
||||
/**
|
||||
* Stores the $value as int casting it
|
||||
*
|
||||
* @param mixed The Value to be stored
|
||||
*/
|
||||
public function in( $value )
|
||||
{
|
||||
if ($value === null)
|
||||
{
|
||||
$this->value = null;
|
||||
return;
|
||||
}
|
||||
if (!is_numeric($value)) {
|
||||
throw new \InvalidArgumentException("Argument has to be parseable to int: $value");
|
||||
}
|
||||
|
||||
$this->value = (int)$value;
|
||||
} // }}}
|
||||
|
||||
// equals() {{{
|
||||
/**
|
||||
* Compares the Integer value
|
||||
* @param int|\VeruA\DomainObjects\Integer the value to compare
|
||||
*/
|
||||
public function equals( $compare )
|
||||
{
|
||||
if (! $compare instanceof Integer) $compare = new Integer($compare);
|
||||
return ($this->value === $compare->value());
|
||||
} // }}}
|
||||
|
||||
// toIndex() {{{
|
||||
public function toIndex(): int
|
||||
{
|
||||
return $this->value();
|
||||
} // }}}
|
||||
|
||||
}
|
||||
|
||||
/* jEdit buffer local properties {{{
|
||||
* :folding=explicit:collapseFolds=1:
|
||||
}}}*/
|
||||
50
src/DomainObjects/ValueObjects/Integer.php
Normal file
50
src/DomainObjects/ValueObjects/Integer.php
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace VeruA\DomainObjects\ValueObjects;
|
||||
|
||||
/**
|
||||
* An implementation of Integer
|
||||
*/
|
||||
class Integer extends DataType implements Primitive
|
||||
{
|
||||
// in() {{{
|
||||
/**
|
||||
* Stores the $value as int casting it
|
||||
*
|
||||
* @param mixed The Value to be stored
|
||||
*/
|
||||
public function in( $value )
|
||||
{
|
||||
if ($value === null)
|
||||
{
|
||||
$this->value = null;
|
||||
return;
|
||||
}
|
||||
if (!is_numeric($value)) {
|
||||
throw new \InvalidArgumentException("Argument has to be parseable to int: $value");
|
||||
}
|
||||
|
||||
$this->value = (int)$value;
|
||||
} // }}}
|
||||
|
||||
// equals() {{{
|
||||
/**
|
||||
* Compares the Integer value
|
||||
* @param int|\VeruA\DomainObjects\Integer the value to compare
|
||||
*/
|
||||
public function equals( $compare )
|
||||
{
|
||||
if (! $compare instanceof Integer) $compare = new Integer($compare);
|
||||
return ($this->value === $compare->value());
|
||||
} // }}}
|
||||
|
||||
// out() {{{
|
||||
public function out(): int
|
||||
{
|
||||
return (int)$this->value;
|
||||
} // }}}
|
||||
}
|
||||
|
||||
/* jEdit buffer local properties {{{
|
||||
* :folding=explicit:collapseFolds=1:
|
||||
}}}*/
|
||||
11
src/DomainObjects/ValueObjects/Key.php
Normal file
11
src/DomainObjects/ValueObjects/Key.php
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace VeruA\DomainObjects\ValueObjects;
|
||||
|
||||
/**
|
||||
* A Key ValueObject
|
||||
*/
|
||||
interface Key
|
||||
{
|
||||
public function toIndex();
|
||||
}
|
||||
42
src/DomainObjects/ValueObjects/Number.php
Normal file
42
src/DomainObjects/ValueObjects/Number.php
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace VeruA\DomainObjects\ValueObjects;
|
||||
|
||||
use VeruA\DomainObjects\Validation\Error;
|
||||
|
||||
/**
|
||||
* A Value that is a Number should use this trait
|
||||
*/
|
||||
trait Number
|
||||
{
|
||||
/**
|
||||
* @return callable Returns a test which determines if a value is below a given threshold.
|
||||
*/
|
||||
public static function max($n): callable
|
||||
{
|
||||
return function ($x) use ($n)
|
||||
{
|
||||
return ($x->value() <= $n) ? true : new Error(
|
||||
$msgCode = 'INVALID_VALUE',
|
||||
$value = (string) $x,
|
||||
$hint = (string) $n,
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @return callable Returns a test which determines if a value is above a given threshold.
|
||||
*/
|
||||
public static function min($n): callable
|
||||
{
|
||||
return function ($x) use ($n)
|
||||
{
|
||||
return ($x->value() >= $n) ? true : new Error(
|
||||
$msgCode = 'INVALID_VALUE',
|
||||
$value = (string) $x,
|
||||
$hint = (string) $n,
|
||||
);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
51
src/DomainObjects/ValueObjects/Password.php
Normal file
51
src/DomainObjects/ValueObjects/Password.php
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace VeruA\DomainObjects\ValueObjects;
|
||||
|
||||
use VeruA\DomainObjects\Validation\Error;
|
||||
|
||||
/**
|
||||
* A Password with validation and hashing functionality
|
||||
* @author norb
|
||||
*/
|
||||
class Password extends Varchar
|
||||
{
|
||||
|
||||
/**
|
||||
* The constructor takes the unhhashed password and stores it hashed
|
||||
*
|
||||
* You have to manually execute the validatio method before you pass the cleartext password to
|
||||
* the constructor!
|
||||
*
|
||||
* The DomainObjects call the constructor with no argument and call the in() method manually,
|
||||
* not hashing the password. This is important if it is loaded from the database.
|
||||
*/
|
||||
public function __construct(string $password=null)
|
||||
{
|
||||
if (isset($password)) $this->in($this->hash($password));
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes the clearttext password and returnes the hashed string
|
||||
*
|
||||
* @todo Replace all usages of password hashing with this method, and update to phps
|
||||
* password_hash() function
|
||||
*
|
||||
* @param string $password The cleartext password to be hashed
|
||||
* @return bool|Error True if validatiion passed Error with the errors
|
||||
*/
|
||||
public function hash(string $password): string
|
||||
{
|
||||
return md5($password);
|
||||
}
|
||||
|
||||
public static function validate(string $password)
|
||||
{
|
||||
return DataType::minLength(8)(new DataType($password));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* jEdit buffer local properties {{{
|
||||
* :folding=explicit:collapseFolds=1:
|
||||
}}}*/
|
||||
14
src/DomainObjects/ValueObjects/Phone.php
Normal file
14
src/DomainObjects/ValueObjects/Phone.php
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace VeruA\DomainObjects\ValueObjects;
|
||||
|
||||
/**
|
||||
* An implementation of a Phonenumber
|
||||
*/
|
||||
class Phone extends Varchar
|
||||
{
|
||||
}
|
||||
|
||||
/* jEdit buffer local properties {{{
|
||||
* :folding=explicit:collapseFolds=1:
|
||||
}}}*/
|
||||
12
src/DomainObjects/ValueObjects/Primitive.php
Normal file
12
src/DomainObjects/ValueObjects/Primitive.php
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace VeruA\DomainObjects\ValueObjects;
|
||||
|
||||
/**
|
||||
* A ValueObject that has a primitive Value like int or string and is thus returned from a DomainObject
|
||||
* as value and not as ValueObject Instance
|
||||
*/
|
||||
interface Primitive
|
||||
{
|
||||
|
||||
}
|
||||
58
src/DomainObjects/ValueObjects/Street.php
Normal file
58
src/DomainObjects/ValueObjects/Street.php
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace VeruA\DomainObjects\ValueObjects;
|
||||
|
||||
/**
|
||||
* An implementation of a Street composed by name and number
|
||||
*/
|
||||
class Street extends Varchar
|
||||
{
|
||||
private string $name;
|
||||
private string $number;
|
||||
|
||||
// in() {{{
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function in($value)
|
||||
{
|
||||
$this->value = (string)trim($value);
|
||||
preg_match('/^(?P<name>(\d*\D+ (\d* )?)+)(?P<number>\d+.*)$/', $this->value, $match);
|
||||
$this->name = $match['name'];
|
||||
$this->number = $match['number'];
|
||||
} // }}}
|
||||
|
||||
public function __get(string $field): string
|
||||
{
|
||||
switch ($field)
|
||||
{
|
||||
case 'name':
|
||||
return $this->name;
|
||||
case 'number':
|
||||
return $this->number;
|
||||
default:
|
||||
throw new \OutOfRangeException('A Street Object is composed of only street->name and street->number');
|
||||
}
|
||||
}
|
||||
|
||||
public function __set(string $field, string $value)
|
||||
{
|
||||
switch ($field)
|
||||
{
|
||||
case 'name':
|
||||
$this->name = trim($value);
|
||||
break;
|
||||
case 'number':
|
||||
$this->number = trim($value);
|
||||
break;
|
||||
default:
|
||||
throw new \OutOfRangeException('A Street Object is composed of only street->name and street->number');
|
||||
}
|
||||
$this->value = "$this->name $this->value";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* jEdit buffer local properties {{{
|
||||
* :folding=explicit:collapseFolds=1:
|
||||
}}}*/
|
||||
24
src/DomainObjects/ValueObjects/Text.php
Normal file
24
src/DomainObjects/ValueObjects/Text.php
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
<?php declare(strict_types = 1);
|
||||
|
||||
namespace VeruA\DomainObjects\ValueObjects;
|
||||
|
||||
use VeruA\DomainObjects\Validation\Error;
|
||||
|
||||
class Text extends DataType implements Primitive {
|
||||
|
||||
// in() {{{
|
||||
/**
|
||||
* Stores the $value as string casting it
|
||||
*
|
||||
* @param mixed The Value to be stored
|
||||
*/
|
||||
public function in( $value )
|
||||
{
|
||||
$this->value = (string)$value;
|
||||
} // }}}
|
||||
|
||||
public function like( string $text )
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
14
src/DomainObjects/ValueObjects/URL.php
Normal file
14
src/DomainObjects/ValueObjects/URL.php
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace VeruA\DomainObjects\ValueObjects;
|
||||
|
||||
/**
|
||||
* An implementation of URL
|
||||
*/
|
||||
class URL extends Varchar
|
||||
{
|
||||
}
|
||||
|
||||
/* jEdit buffer local properties {{{
|
||||
* :folding=explicit:collapseFolds=1:
|
||||
}}}*/
|
||||
15
src/DomainObjects/ValueObjects/Value.php
Normal file
15
src/DomainObjects/ValueObjects/Value.php
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace VeruA\DomainObjects\ValueObjects;
|
||||
|
||||
/**
|
||||
* A ValueObject
|
||||
*/
|
||||
interface Value
|
||||
{
|
||||
public function __toString();
|
||||
public function in($value);
|
||||
public function out();
|
||||
public function value();
|
||||
public static function defaultValidators(): array;
|
||||
}
|
||||
73
src/DomainObjects/ValueObjects/Varchar.php
Normal file
73
src/DomainObjects/ValueObjects/Varchar.php
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
<?php declare(strict_types = 1);
|
||||
|
||||
namespace VeruA\DomainObjects\ValueObjects;
|
||||
|
||||
use VeruA\DomainObjects\Validation\Error;
|
||||
|
||||
/**
|
||||
* An implementation of Varchar
|
||||
*/
|
||||
class Varchar extends DataType implements Primitive
|
||||
{
|
||||
// in() {{{
|
||||
/**
|
||||
* Stores the $value as string casting it
|
||||
*
|
||||
* @param mixed The Value to be stored
|
||||
*/
|
||||
public function in( $value )
|
||||
{
|
||||
$this->value = (string)$value;
|
||||
} // }}}
|
||||
|
||||
// equals() {{{
|
||||
/**
|
||||
* Compares the String value
|
||||
* @param string|\VeruA\DomainObjects\Varchar the value to compare
|
||||
*/
|
||||
public function equals( $compare )
|
||||
{
|
||||
if (! $compare instanceof Varchar) $compare = new String($compare);
|
||||
return ($this->value === $compare->value());
|
||||
} // }}}
|
||||
|
||||
/**
|
||||
* Retuns a test tesing if its input matches a regular expression.
|
||||
* @param string $regex The regex to check against.
|
||||
* {@see https://www.php.net/manual/en/reference.pcre.pattern.syntax.php PCRE Regex Syntax}
|
||||
* @param string $translationId The translation id for the Error message from `translations/errors_[DE|FR].xml`
|
||||
* @return callable
|
||||
*/
|
||||
public static function matchRegEx(string $regex, string $translationId='INVALID_VALUE'): callable
|
||||
{
|
||||
return function (Value $value) use ($regex, $translationId)
|
||||
{
|
||||
return (preg_match($regex, (string) $value) === 1) ? true : new Error(
|
||||
$msgCode = $translationId,
|
||||
$value = (string) $value,
|
||||
$hint = $regex,
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a test testing if a string is a decimal number.
|
||||
*/
|
||||
public static function isDecimal(): callable
|
||||
{
|
||||
return function (Value $valueObject)
|
||||
{
|
||||
$value = (string) $valueObject->value();
|
||||
// TODO: Rewrite without using a regex!
|
||||
return preg_match('/^(\+|-)?[0-9]+(\.[0-9]+)?$/', (string) $value) ? true : new Error(
|
||||
$msgCode = 'INVALID_VALUE',
|
||||
$value = (string) $value,
|
||||
$hint = 'Number expected!',
|
||||
);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/* jEdit buffer local properties {{{
|
||||
* :folding=explicit:collapseFolds=1:
|
||||
}}}*/
|
||||
40
src/DomainObjects/ValueObjects/ZSR.php
Normal file
40
src/DomainObjects/ValueObjects/ZSR.php
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace VeruA\DomainObjects\ValueObjects;
|
||||
|
||||
/**
|
||||
* An implementation of a ZSR Number
|
||||
*
|
||||
* Allowed Format `/^[A-Z][0-9]{6}$/`
|
||||
*/
|
||||
class ZSR extends DataType implements Complex
|
||||
{
|
||||
// in() {{{
|
||||
/**
|
||||
* Converts the $value stripping of all dots
|
||||
*/
|
||||
public function in( $value )
|
||||
{
|
||||
$this->value = (isset($value)) ? trim( str_replace( ['.', ' '], '', $value ) ) : '';
|
||||
} // }}}
|
||||
|
||||
// defaultValidators() {{{
|
||||
public static function defaultValidators(): array
|
||||
{
|
||||
return [
|
||||
DataType::length(7),
|
||||
Varchar::matchRegex('/^[A-Z][0-9]{6}$/', 'VALIDATION_ZSR_FORMAT'),
|
||||
];
|
||||
}
|
||||
// }}}
|
||||
|
||||
// isComplex() {{{
|
||||
public function isComplex(): bool {
|
||||
return true;
|
||||
} // }}}
|
||||
|
||||
}
|
||||
|
||||
/* jEdit buffer local properties {{{
|
||||
* :folding=explicit:collapseFolds=1:
|
||||
}}}*/
|
||||
48
src/Log.php
Normal file
48
src/Log.php
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace VeruA;
|
||||
|
||||
use VeruA\App;
|
||||
use Monolog\{
|
||||
Logger,
|
||||
Handler\StreamHandler
|
||||
};
|
||||
|
||||
/**
|
||||
* Log trait, `use` it in every class you want to use the monolog logger
|
||||
*
|
||||
* ``` php
|
||||
* use VeruA\Log; // declare the namespace
|
||||
*
|
||||
* class Whatever
|
||||
* {
|
||||
* use Log; // use the trait in the class
|
||||
*
|
||||
* public function example()
|
||||
* {
|
||||
* // ...
|
||||
* // now you can use the log() method
|
||||
* $this->log()->debug('your log message');
|
||||
* // ...
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
trait Log
|
||||
{
|
||||
private static $logger;
|
||||
|
||||
private static function log($file = 'debug'): Logger
|
||||
{
|
||||
if (! isset(self::$logger))
|
||||
{
|
||||
self::$logger = new Logger(get_called_class());
|
||||
self::$logger->pushHandler(new StreamHandler('debug.log'));
|
||||
}
|
||||
return self::$logger;
|
||||
}
|
||||
}
|
||||
|
||||
/* jEdit buffer local properties {{{
|
||||
* :folding=explicit:collapseFolds=1:
|
||||
}}}*/
|
||||
Loading…
Add table
Add a link
Reference in a new issue