Skip to content

Latest commit

 

History

History
673 lines (488 loc) · 15.4 KB

README.md

File metadata and controls

673 lines (488 loc) · 15.4 KB

Datatypes for ILIAS

This service should contain standard datatypes for ILIAS that are used in many locations in the system and do not belong to a certain service.

The keywords “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in RFC 2119.

Table of Contents

Other examples for data types that could (and maybe should) be added here:

  • Option (akin to rusts type)
  • (il)Datetime
  • ObjectId, ReferenceId
  • HTML, Text, Markdown
  • List, List, ...

This is not to be confused with the service for types. This services is about the data, not the types thereof. It still uses types to talk about data (like a lot of code does), but it does not reify types as data (which the service for types and the PHP-ReflectionClass does).

Result

A result encapsulates a value or an error and simplifies the handling of those.

Example 1: Ok

<?php

$f = new \ILIAS\Data\Factory;

// Build a value that is ok.
$pi = $f->ok(3.1416);

// Value is ok and thus no error.
itIsTrueThat($pi->isOK());
itIsTrueThat(!$pi->isError());

// Do some transformation with the value.
$r = 10;
$A = $pi->map(function($value_of_pi) use ($r) { return 2 * $value_of_pi * $r; });

// Still ok and no error.
itIsTrueThat($A->isOk());
itIsTrueThat(!$A->isError());

// Retrieve the contained value.
$A_value = $A->value();
itIsTrueThat($A_value == 2 * 3.1416 * 10);

// No error contained...
$raised = false;
try {
	$A->error();
	itIsTrueThat(false); // Won't happen, error raises.
}
catch(\LogicException $e) {
	$raised = true;
}
itIsTrueThat($raised);

?>

Example 2: Error

<?php

$f = new \ILIAS\Data\Factory;

// Build a value that is ok.
$pi = $f->ok(3.1416);

// Build a value that is not ok.
$error = $f->error("There was some error...");

// This is of course an error.
itIsTrueThat(!$error->isOK());
itIsTrueThat($error->isError());

// Transformations do nothing.
$A = $error->map(function($v) { itIsTrueThat(false); });

// Attempts to retrieve the value will throw.
$raised = false;
try {
	$A->value();
	itIsTrueThat(false); // Won't happen.
}
catch (\ILIAS\Data\NotOKException $e) {
	$raised = true;
}
itIsTrueThat($raised);

// For retrieving a default could be supplied.
$v = $error->valueOr("default");
itIsTrueThat($v == "default");

// Result also has an interface for chaining computations known as promise
// interface (or monad interface for pros!).

$pi = $pi->then(function($value_of_pi) use ($f) {
	// replace contained value with a more accurate number.
	return $f->ok(3.1415927);
});

// $pi is ok("3.1415927") now. If one had used map instead of then, $pi
// would have been ok(ok(3.1415927).

// One could also inject an error with then, this is not possible with map.
$pi = $pi->then(function($_) use ($f) {
	return $f->error("Do not know value of Pi.");
});

// The error can be catched later on and be corrected:
$pi = $pi->except(function($e) use ($f) {
	itIsTrueThat($e === "Do not know value of Pi.");
	return $f->ok(3); // for large threes
});

itIsTrueThat($pi->value() === 3);

?>

Color

Color is a data type representing a color in HTML. Construct a color with a hex-value or list of RGB-values.

Example

<?php

$f = new \ILIAS\Data\Factory;

//construct color with rgb-values:
$rgb = $f->color(array(255,255,0));

//construct color with hex-value:
$hex = $f->color('#ffff00');

itIsTrueThat($rgb->asHex() === '#ffff00');
itIsTrueThat($hex->asRGBString() === 'rgb(255, 255, 0)');
?>

URI

Object representing an uri valid according to RFC 3986 with restrictions imposed on valid characters and obliagtory parts. Construct a uri with a valid string.

Example

<?php

$f = new \ILIAS\Data\Factory;

// construct uri
$uri = $f->uri('https://example.org:12345/test?search=test#frag');

itIsTrueThat($uri->getBaseURI() === 'https://example.org:12345/test');
itIsTrueThat($uri->getSchema() === 'https');
itIsTrueThat($uri->getAuthority() === 'example.org:12345');
itIsTrueThat($uri->getHost() === 'example.org');
itIsTrueThat($uri->getPath() === 'test');
itIsTrueThat($uri->getQuery() === 'search=test');
itIsTrueThat($uri->getFragment() === 'frag');
itIsTrueThat($uri->getPort() === 12345);
itIsTrueThat($uri->getParameters() === ['search' => 'test']);
itIsTrueThat($uri->getParameter('search') === 'test');
?>

DataSize

Object representing the size of some data. Construct a data size object with a size and an unit.

Example

<?php

$f = new \ILIAS\Data\Factory;

// construct data size
$data_size = $f->dataSize(123, 'GB');

itIsTrueThat($data_size->getSize() === 123.0);
itIsTrueThat($data_size->getUnit() === 1000000000);
itIsTrueThat($data_size->inBytes() === 123000000000.0);
?>

Password

Object representing a password. Construct a password with a string.

Example

<?php

$f = new \ILIAS\Data\Factory;

// construct password
$password = $f->Password('secret');

itIsTrueThat($password->toString() === 'secret');
?>

ClientId

Object representing a a alphanummeric string plus #, _, . and -. Construct a client with a valid string.

Example

<?php

$f = new \ILIAS\Data\Factory;

// construct client id
$client_id = $f->clientId('Client_Id-With.Special#Chars');

itIsTrueThat($client_id->toString() === 'Client_Id-With.Special#Chars');
?>

ReferenceId

ReferenceId is a data type representing an integer. Construct a reference id with an integer.

Example

<?php

$f = new \ILIAS\Data\Factory;

// construct reference id
$ref_id = $f->refId(9);

itIsTrueThat($ref_id->toInt() === 9);
?>

ObjectId

ObjectId is a data type representing an integer. Construct an object id with an integer.

Example

<?php

$f = new \ILIAS\Data\Factory;

// construct object id
$ref_id = $f->objId(9);

itIsTrueThat($ref_id->toInt() === 9);
?>

Alphanumeric

Alphanumeric is a data type representing an alphanumeric value. Construct an alphanumeric with an integer and an alphanumeric value.

Example

<?php

$f = new \ILIAS\Data\Factory;

// construct alphanumric with integers
$numeric = $f->alphanumeric(963);

// construct alphanumeric with mixed values as string
$alphanumeric = $f->alphanumeric('23da33');

itIsTrueThat($numeric->getValue() === 963);
itIsTrueThat($alphanumeric->getValue() === '23da33');
?>

PositiveInteger

PositiveInteger is a data type representing an positive integer. Construct an positive integer with an integer.

Example

<?php

$f = new \ILIAS\Data\Factory;

// construct a positive integer
$positive_integer = $f->positiveInteger(963);

itIsTrueThat($positive_integer->getValue() === 963);
?>

DateFormat

DateFormat is a data type representing a dateformat. Construct a date format representing a standard, german_short, german_long or custom date format.

Example

<?php

$f = new \ILIAS\Data\Factory;

// construct standard date format
$standard = $f->dateFormat()->standard();

// construct german short date format
$german_short = $f->dateFormat()->germanShort();

// construct german long date format
$german_long = $f->dateFormat()->germanLong();

// construct custom date format
$custom = $f->dateFormat()->custom()->twoDigitYear()->dash()->month()->dash()->day()->get();

itIsTrueThat($standard->toString() === "Y-m-d");
itIsTrueThat($standard->toArray() === ['Y', '-', 'm', '-', 'd']);

itIsTrueThat($german_short->toString() === "d.m.Y");
itIsTrueThat($german_short->toArray() === ['d', '.', 'm', '.', 'Y']);

itIsTrueThat($german_long->toString() === "l, d.m.Y");
itIsTrueThat($german_long->toArray() === ['l', ',', ' ', 'd', '.', 'm', '.', 'Y']);

itIsTrueThat($custom->toString() === "y-m-d");
itIsTrueThat($custom->toArray() === ['y', '-', 'm', '-', 'd']);
?>

Range

Range is a data type representing a naive range of whole positive numbers. Construct an range with a start integer and a length integer.

Example

<?php

$f = new \ILIAS\Data\Factory;

// construct a range
$range = $f->range(10, 20);

itIsTrueThat($range->unpack() === [10, 20]);
itIsTrueThat($range->getStart() === 10);
itIsTrueThat($range->getLength() === 20);
itIsTrueThat($range->getEnd() === 30);
?>

Order

Order is a data type representing a subject with a specific order. Construct an order with a subject and a direction.

Example

<?php

$f = new \ILIAS\Data\Factory;

// construct a order
$order1 = $f->order('subject1', 'ASC');

// append subject to order
$order2 = $order1->append('subject2', 'DESC');

// join the subjects to an order statement
$join = $order2->join('sort', function($pre, $k, $v) { return "$pre $k $v,"; });

itIsTrueThat($order1->get() === ['subject1' => 'ASC']);
itIsTrueThat($order2->get() === ['subject1' => 'ASC', 'subject2' => 'DESC']);
itIsTrueThat($join === 'sort subject1 ASC, subject2 DESC,');
?>

Clock

This package provides a fully psr-20 compliant clock handling.

Example

System Clock

The \ILIAS\Data\Clock\SystemClock returns a \DateTimeImmutable instance always referring to the current default system timezone.

<?php
$f = new \ILIAS\Data\Factory;

$clock = $f->clock()->system();
$now = $clock->now();
?>

UTC Clock

The \ILIAS\Data\Clock\UtcClock returns a \DateTimeImmutable instance always referring to the UTC timezone.

<?php
$f = new \ILIAS\Data\Factory;

$clock = $f->clock()->utc();
$now = $clock->now();
?>

Local Clock

The \ILIAS\Data\Clock\UtcClock returns a \DateTimeImmutable instance always referring to the timezone passed to the factory method.

<?php
$f = new \ILIAS\Data\Factory;

$clock = $f->clock()->local(new \DateTimeZone('Europe/Berlin'));
$now = $clock->now();
?>

Dimension

CardinalDimension

Object representing a metric order, where the distances of the categories are known and can be described quantitatively. Construct a cardinal dimension object with numerical or textual variables representing the categories.

Example

<?php

$f = new \ILIAS\Data\Factory;

// construct dimension
$cardinal = $f->dimension()->cardinal(["low", "medium", "high"]);

itIsTrueThat($cardinal->getLabels() === ["low", "medium", "high"]);
?>

RangeDimension

Object representing a range on a cardinal dimension. Construct a range dimension object with an existing cardinal dimension.

Example

<?php

$f = new \ILIAS\Data\Factory;

// construct dimensions
$cardinal = $f->dimension()->cardinal(["low", "medium", "high"]);
$range = $f->dimension()->range($cardinal);

itIsTrueThat($range->getLabels() === $cardinal->getLabels());
?>

Dataset

Object representing a dataset for one or more dimensions. Construct a dataset with an amount of named dimensions. Extend a dataset with one or more items by determining e.g. points for each dimension of the dataset.

Example

<?php

$f = new \ILIAS\Data\Factory;

// construct dimensions and dataset
$cardinal = $f->dimension()->cardinal([
    0 => "very low",
    1 => "low",
    2 => "medium",
    3 => "high",
    4 => "very high"
]);
$range = $f->dimension()->range($cardinal);
$dataset = $f->dataset([
    "Measurement 1" => $cardinal,
    "Measurement 2" => $cardinal,
    "Target" => $range
]);
$dataset = $dataset->withPoint(
    "Item 1",
    [
        "Measurement 1" => 1,
        "Measurement 2" => 0,
        "Target" => [0, 1.5],
    ]
);
$dataset = $dataset->withPoint(
    "Item 2",
    [
        "Measurement 1" => -1,
        "Measurement 2" => 1.75,
        "Target" => [0.95, 1.05],
    ]
);

itIsTrueThat($dataset->getMinValueForDimension("Measurement 1") === -1.0);
itIsTrueThat($dataset->getMaxValueForDimension("Target") === 1.5);
?>

HTMLMetadata

When working with HTML metadata, you MUST always type-hint \ILIAS\Data\Meta\Html\Tag, except in rare cases where you have to work with a collection of tags explicitly (\ILIAS\Data\Meta\Html\TagCollection).

Currently the factory can only provide UserDefined metadata which accepts key => value pairs mapped to a HTML-meta-tags name and content attribute.

If you have to use something more speficic like e.g. the pragma directive feel free to implement it, derrived from the abstract class \ILIAS\Data\Meta\Html\Tag.

Example

<?php

$f = new \ILIAS\Data\Factory;

$viewport_metadata = $f->htmlMetadata()->userDefined('viewport', 'widht=device-width');

class ExpectsHtmlMetadata {
    public function __construct(
        protected \ILIAS\Data\Meta\Html\Tag $html_metadata,
    ) {
    }
    
    public function getMetadata(): \ILIAS\Data\Meta\Html\Tag
    {
        return $this->html_metadata;
    }
}

$class = new ExpectsHtmlMetadata(
    $f->htmlMetadata()->collection([
        $f->htmlMetadata()->userDefined('description', 'Lorem ipsum dolor sit amet.'),
        $viewport_metadata
    ])
);

itIsTrueThat(is_string($viewport_metadata->toHtml()));
itIsTrueThat(is_string($class->getMetadata()->toHtml()));
?>

OpenGraphMetadata

OpenGraph metadata is HTML metadata as well, but it's more structured and follows the open-graph-protocol (ogp.me).

The factory currently only provides the website-type (of all the possible object-types documented here). If you ever need a more specific object-type for e.g. articles or books, feel free to implement it accordingly.

The factory also provides resources (\ILIAS\Data\Meta\Html\OpenGraph\Resource), which MUST NOT be used in any other way than the factory itself. These resources are structured properties which cannot be used standalone and MUST belong to an object-type.

Example

<?php

$f = new \ILIAS\Data\Factory;

$structured_image = $f->openGraphMetadata()->image($f->uri('https://picsum.photos/200/300'), 'image/jpeg');

$minimal_website_graph = $basic_website_graph = $f->openGraphMetadata()->website(
    $f->uri('https://docu.ilias.de/object/101'),
    $structured_image,
    'object title 101'
);

$full_website_graph = $f->openGraphMetadata()->website(
    $f->uri('https://docu.ilias.de/object/101'),
    $structured_image,
    'object title 101',
    'ILIAS',
    'lorem ipsum dolor sit amet.',
    'en_US',
    ['de_DE', 'de_CH'],
    [
        $f->openGraphMetadata()->image($f->uri('https://picsum.photos/100/100'), 'image/jpeg'),
    ]
);

itIsTrueThat(is_string($minimal_website_graph->toHtml()));
itIsTrueThat(is_string($full_website_graph->toHtml()));
?>

Helper

To make this run, we need a little helper:

<?php

function itIsTrueThat(bool $truth) {
    if (!$truth) {
        throw new \LogicException("Some code in the Data/README.md is wrong!");
    }
}

?>

LanguageTag

This represents a RFC 5646 compliant language tag. To create a language tag:

(new \ILIAS\Data\Factory())->languageTag('de');

If the given string is no valid tag an exception is thrown.

The language tag can have several different forms, which are represented with the classes: Standard, Irregular, Regular and Privateuse.

The specific meaning of the different language tags can be found in the RFC.