Properties: Difference between revisions

From Sunhill Framework Documentation
Completed documentation (for now)
 
(15 intermediate revisions by the same user not shown)
Line 1: Line 1:
A '''property''' is a logical piece of information. The property class capsulates everything that has to do with type, validation, semantic meaning and access rights. The data itself is retrieved and stored to a [[Storages|storage]].  
A '''property''' is a logical piece of information. The property class capsulates everything that has to do with type, validation, semantic meaning and access rights. The data itself is retrieved and stored to a [[Storages|storage]].  
{{:Property storage linkage}}
The basic class of a property is [[Classes/AbstractProperty|AbstractProperty]]. Properties are managed via the [[PropertyManager|property manager]].


== Reading a property value ==
== Reading a property value ==
Line 22: Line 25:
  $duration->getHumanValue()
  $duration->getHumanValue()
return <code>1 minute 2 seconds</code>
return <code>1 minute 2 seconds</code>
== Default value ==
When the storage responds that there is no value stored for this property it is possible to return a default value when reading this property or when a persistant storage tries to write an unitinitialized property.
=== setDefault(mixed $default): static ===
Sets the default value for this template. When null is passed the property will return null by default. This is a different behavior as setting no default value. In the latter case an exception would be raised when reading the value.
{{Note|When setting null as a default value, the method nullable() is also called.
=== default(): static ===
Alias for setDefault()
=== getDefault(): mixed ===
Returns the default value.
{{Warning|It returns null when there is no default value or when the default value is set to null. So check defaultsNull() too}}
=== defaultsNull(): boolean ===
Returns true, when the default value was set to null.
=== hasDefault(): boolean ===
Returns true, when the property has a default value at all.


== Writing a property value ==
== Writing a property value ==
Line 37: Line 60:
=== isValid(mixed $input): bool ===
=== isValid(mixed $input): bool ===
Checks if the given input is valid for this property.
Checks if the given input is valid for this property.
=== nullable(bool $value = true): static ===
When null is passed as a value this is only possile, when this property if nullable. This methods marks it at nullable.
{{Note|This also sets the default value to null}}
=== setNullable(bool $value = true): static ===
Alias to nullable(true)
=== notNullable(bool $value = true): static ===
Alias to nullable(false)
=== getNullable(): bool ===
Returns the current value of nullable.


== Capabilities ==
== Capabilities ==
Line 102: Line 138:
Due the fact that every property needs a storage to handle the values there are these methods that handle the storage
Due the fact that every property needs a storage to handle the values there are these methods that handle the storage


=== $property->setStorage(AbstractStorage $storage) ===
=== setStorage(AbstractStorage $storage) ===
This method sets the active storage for this property. Normally this is done by the property manager.
This method sets the active storage for this property. Normally this is done by the property manager.


=== $property->getStorage(): AbstractStorage ===
=== getStorage(): AbstractStorage ===
Returns the current set storage for this property.
Returns the current set storage for this property.
=== isValidStorage(AbstractStorage $storage): bool ===
Checks if the given storage is a valid one. By default this method returns true. Use this for properties that need a certain kind of storage (e.g. PersistentPoolStorage).
=== createStorage(): ?AbstractStorage ===
With this method it is possible for derrived properties to create a default storage.


== commit() and rollback() ==
== commit() and rollback() ==
As users should not interact with storages the the following method are passed to the storage.
As users should not interact with storages the the following method are passed to the storage.


=== $property->commit() ===
=== commit() ===
this methods is to make a change to the value of a property persistent
this methods is to make a change to the value of a property persistent


=== $propery->rollback() ===
=== rollback() ===
revoke the changes made to the value of this property
revoke the changes made to the value of this property
=== isDirty(): bool ===
Returns true when an initialized value was changed or an uninitialized property was assigned a value.


== Name of property ==
== Name of property ==
Every property should have a name. The name does not have necessarily be unique.
Every property should have a name. The name does not have necessarily be unique.


=== $property->setName(string $name) ===
=== setName(string $name) ===


Sets the name of the property to the given name if it is a valid name. Inavlid names are:
Sets the name of the property to the given name if it is a valid name. Inavlid names are:
Line 127: Line 172:
* Empty names ('')
* Empty names ('')
    
    
=== $property->name(string $name) ===
=== name(string $name) ===
Is an alias to ->setName();
Is an alias to ->setName();


=== $property->forceName(string $name) ===
=== forceName(string $name) ===
Skips the validation of the property name and should normally not be uses. It is uses internally for objects to define internal variables like _uuid.
Skips the validation of the property name and should normally not be uses. It is uses internally for objects to define internal variables like _uuid.


=== $property->getName() ===
=== getName() ===
Returns the name of the property.
Returns the name of the property.


=== $property->isValidPropertyName(string $test) ===
=== isValidPropertyName(string $test) ===
Tests if the given name would pass the validation test.  
Tests if the given name would pass the validation test.  


Line 144: Line 189:
means that propertyA is a part of propertyB. Both can share the same storage or define a storage on their own.  
means that propertyA is a part of propertyB. Both can share the same storage or define a storage on their own.  


=== $property->setOwner(AbstractProperty: $owner): AbstractProperty ===
=== setOwner(AbstractProperty: $owner): AbstractProperty ===
Sets the owner for this property. $owner must be a valid property.
Sets the owner for this property. $owner must be a valid property.


=== $property->getOwner(): ?AbstractProperty ===
=== getOwner(): ?AbstractProperty ===
Returns the current set owner (or null if no owner is set) of this property.
Returns the current set owner (or null if no owner is set) of this property.


=== $property->getPath(): string ===
=== getPath(): string ===
This method is used for [[InfoMarket]] to identifiy a InfoMarket item. It combines the name of each owning property.
This method is used for [[InfoMarket]] to identifiy a InfoMarket item. It combines the name of each owning property.
Example:
Example:
Line 186: Line 231:
=== getMetadata() ===
=== getMetadata() ===
Returns an associative array with all the above metadata as elements.
Returns an associative array with all the above metadata as elements.
=== getStructure() ===
Returns either a stdClass() or an array of stdClass-es with the structure of the property or the included properties. This is needed for the underlying storage to do its job (sometimes)


== InfoMarket interaction ==
== InfoMarket interaction ==
Line 205: Line 253:


=== hasInfo(string $key): bool ===
=== hasInfo(string $key): bool ===
Returns if the property has a information atom with this name.  
Returns if the property has a information atom with this name.
 
== Other basic property types ==
There are some other predefined property types (besides the [[Types]] and [[Semantics]]) that can be used as a base for own properties.
 
* [[Simple properties]]
* [[Array properties]]
* [[Record properties]]
* [[Storable record properties]]
* [[Pooled record properties]]
* [[Objects]]
* [[Collections]]
* [[Reference properties]]


== Writing own property classes ==
== Writing own property classes ==
For more informations about reading own property classes see [[Writing own property classes|here]].
For more informations about reading own property classes see [[Writing own property classes|here]].


<!--
[[Category:Properties]]
{{Outdated}}
A property is a like a member variable of an Collection or ORMObject. They are accessed like normal members and normally you don't have to worry about there internal details. The only thing is, that you have to define them in the static setupProperties() method. This method takes a PropertyList parameter. A PropertyList is just a helper class that provides some defining methods to make it easy to define the properties (in fact it uses an similar concept like migrations of laravel). Via this PropertyList parameter you define the properties of your class. All property defining methods (like integer(), string(), etc.) take a name of the property as a parameter.
 
== Names of properties ==
The rules for property names are the same as for php variables, any alphanumeric character including "_" can be used, the name must't start with a digit. However, there are a few more restrictions for naming:
 
* A name must't start with an underscore ("_") because these names are reserved internally.
* The name must not be '''tags''', '''attributes''', '''id''', '''classname'''
 
== Modifiers for all properties ==
While defining properties you can modifiy some parameters of the property. Modifier always return the property object so it is possible to build a modifier chain. These are the modifiers that are avaiable to all properties:
 
=== readonly() / setReadonly() ===
These modifiers are synonym and mark this property as readonly. A attempt to give this property a new value will raise an exception.
 
=== searchable() / setSearchable() ===
These modifiers are synonym and mark this properts as searchable. The attempt to search for a non-searchable property will raise an exception. See Searching for more details about searching.
 
=== unit() / setUnit() ===
Every property can have an unit. This is part of the semantics mechanism an explained in detail there
 
=== semantic() / setSemantic() ===
 
== Property types ==
 
=== Integer ===
<code>...
$list->integer('integer_property);
...</code>
Adds an integer property to this collection/object. Only integer values or integer strings can be assigned to this property.
$object->integer_property = 123;
$object->integer_property = '123';
Note: If you assign a non integer value to this property an exception will be raised.
$object->integer_property = 'ABC'; // raises InvalidValueException
 
=== String ===
<code>...
$list->string('string_property);
// or
$list->varchar('string_property);
...</code>
Adds a string property to this collection/object. Any scalar value can be assigned to this property:
$object->string_property = 1;
$object->string_property = 'ABC';
$object->string_property = 1.2;
Any non-scalar value will raise an InvalidValueException
$object->string_property = $another_object; // raises InvalidValueException
Both methods take a second integer parameter that defines the maximal string length of this property
<code>$list->string('string_property',10); // defines a string with maximum length of 10</code>
Note: If you later assign a value to this property that is longer than 10 characters, no exception will be raised. The property truncates the given string to a maximum length of 10.
 
=== Float ===
...
$list->float('float_property');
...
Adds a float property to this collection/object. Any integer or float value can be assigned to this property:
$object->float_property = 1;
$object->float_property = 2.3;
 
=== Text ===
...
$list->text('text_property');
...
Adds a text field property to the collection/object. A text of any length can be assigned to a text field property.
$object->text_property = file_get_contents('a_very_large_text.txt');
``
### Date/Datetime/Time
```php
...
$list->date('date_property');
$list->datetime('datetime_property');
$list->time('time_property');
...
Adds a date/datetime/time property to the collection/object. At the moment only integer (Unix timestamps) or strings in the form of "YYYY-MM-DD HH:MM:SS" and their partial forms can be assigned.
$object->date_property = '2023-06-14';
$object->date_property = '2023-6-2'; // is expanded to 2023-06-02
$object->date_property = 1686778521; // is converted to 2023-06-02
 
=== Enum ===
...
$list->enum('enum_property')->setEnumValues(['Dog','Cat','Mouse']);
...
Adds an enum property to the collection/object.
 
==== setEnumValues ====
It's necessary to chain the setEnumValues method to tell the property which values are allowed. This method takes an array of strings. When a value other than defined in this array is assigned, an InvalidValueException is raised.
$object->enum_property = 'Dog'; // OK
$object->enum_property = 'Elephant'; // raises InvalidValueException
 
=== Array ===
...
$list->array('array_property')->setElementType(PropertyString::class);
...
Adds an array property to the collection/object. This property can be access like any regular array.
$object->array_property = ['A','B','C'];
echo $object->array_property[1]; // Returns 'B'
$object->array_property[] = 'D'; // Adds 'D' to the end
echo count($object->array_property); // Returns 4
echo empty($object->array_property); // Returns false
 
==== setElementType ====
While defining an array you must hint the allowed element type. The method setElementType takes a string that have to be the class name of an Property (e.g. PropertyString::class). Any scalar property type like Integer, Varchar, Date, Time, Datetime, Boolean, Enum or Object is allowed. Array, Maps and external References are not allowed as an element type.
 
=== Map ===
...
$list->map('map_property')->setElementType(PropertyString::class);
...
 
==== setElementType ====
While defining a map you must hint the allowed element type. The method setElementType takes a string that have to be the class name of an Property (e.g. PropertyString::class). Any scalar property type like Integer, Varchar, Date, Time, Datetime, Boolean, Enum is allowed. Array, Maps and external References are not allowed as an element type.
 
==== setMaxiumKeyLength ====
The keys of maps are always strings. The maxium length of the key is defaulted to 20. With this method the default value can be changed.
 
=== Object ===
...
$list->object('object_property')->setAllowedClasses([Class1::class,Class2::class]);
...
Adds an object field to the collection/object. An object field is a reference to another object. The property can be accessed like any other object.
$object->object_property = new Class1();
$object->object_property->name = 'Some name';
 
==== setAllowedClasses ====
Defines what kind of objects are allowed to be assigned to this field.
 
=== Collection ===
...
$list->collection('collection_property')->setAllowedClasses([Class1::class,Class2::class]);
...
Adds a collection field to the collection/object. An collection field is a reference to another collection. The property can be accessed like any other collection.
...
use Sunhill\ORM\Objects\ORMObject;
use Sunhill\ORM\Objects\Collection;
class MyCollection extends Collection
{
    protected static function setupProperties(PropertyList $list)
    {
        $list->string('name');
    }
}
class MyObject extends ORMObject
{
    protected static function setupProperties(PropertyList $list)
    {
        $list->collection('object_property')->setAllowedClass(MyCollection::class);
    }
}
...
$object = new MyObject();
$object->object_property = new MyCollection();
$object->object_property->name = 'Some name';
...
 
==== setAllowedClass ====
Defines which collection is allowed to be assigned to this field. This method takes a string that is the name of the collection class that are allowed to be assigned this property.
 
=== Keyfield ===
...
$list->keyfield('keyfield_property')->setBuildRule(':field1 :field2');
A keyfield is a virtual field that makes it possible to combine one or more other fields to a new field
$object->field1 = 'ABC';
$object->field2 = 'DEF';
echo $object->keyfield = 'ABC DEF';
 
==== setBuildRule() ====
Keyfields need a rule how they are built. This is done with this method. Every string starting with a colon and a series of alphanumeric characters is interpreted as a field of the owning collection. In the example above the buildRule references the two fields called field1 and field2. Keyfield rules can be more complex (like ":name (:year)") and can even refer to fields of object/collection fields. When an object defines the property 'object_field' that refers to another object than you can define a keyfield with "object_field->name". The keyfield then takes the name of the refered object. If the object field is empty an empty string will be replaced.
 
=== Calculated fields ===
...
$list->calculated('calc_property')->setCallback(function($collection) {
return md5($collection->name);
});
...
Calculated field offer the possibility to store automatically complex calculations in the storage. Calculated fields are read only by nature, any attempt to assign a value to them will raise an exception. Calculated values are stored as string in the storage and can be searched too. You should only use calculated fields when you need the searching capabilities or it's quite expensive to calculate this field. Calculated fields need a callback (see next paragraph).
 
=== setCallback() ===
This method takes either a string or a closure. When a string is passed this string is assumed to be the name of a method of the owning collection that performs the calculation. This method then takes no parameter and has to return the calculated value. If the parameter is a closure, this function takes the calling propertiescollection as parameter and returns the calculated value the same way as the method.
 
=== External reference ===
...
$list->externalReference('external_property');
...
-->

Latest revision as of 16:44, 8 November 2024

A property is a logical piece of information. The property class capsulates everything that has to do with type, validation, semantic meaning and access rights. The data itself is retrieved and stored to a storage.

Every property needs exactly one storage. The linkage between property and storage can be done:


The basic class of a property is AbstractProperty. Properties are managed via the property manager.

Reading a property value

A typical read process would be:

  1. The property is called to return a value
  2. The property checks if the current user is allowed to read the information (see here).
  3. The property fetches the value from the connected storage
  4. Optional it formats the output to a human readable form

getValue():mixed

The method to call to read a property's value.

Calling this method initiates the algorithm as above.

getHumanValue(): mixed

Returns the value of the property in a human readable format.

Example:

$duration->getValue()

returns 62

$duration->getHumanValue()

return 1 minute 2 seconds

Default value

When the storage responds that there is no value stored for this property it is possible to return a default value when reading this property or when a persistant storage tries to write an unitinitialized property.

setDefault(mixed $default): static

Sets the default value for this template. When null is passed the property will return null by default. This is a different behavior as setting no default value. In the latter case an exception would be raised when reading the value. {{Note|When setting null as a default value, the method nullable() is also called.

default(): static

Alias for setDefault()

getDefault(): mixed

Returns the default value. Warning: It returns null when there is no default value or when the default value is set to null. So check defaultsNull() too

defaultsNull(): boolean

Returns true, when the default value was set to null.

hasDefault(): boolean

Returns true, when the property has a default value at all.

Writing a property value

A typical write/modify process would be:

  1. The property is called to write/modify a value
  2. The property checks if the current user is allowed to write or modify the information
  3. The property checks if the given value is valid for the type and semantic meaning of the property
  4. The property passes the value to the storage

setValue(mixed $value)

The method to write a property's value

Calling this method initiates the algorithm as above.

isValid(mixed $input): bool

Checks if the given input is valid for this property.

nullable(bool $value = true): static

When null is passed as a value this is only possile, when this property if nullable. This methods marks it at nullable. Note: This also sets the default value to null

setNullable(bool $value = true): static

Alias to nullable(true)

notNullable(bool $value = true): static

Alias to nullable(false)

getNullable(): bool

Returns the current value of nullable.

Capabilities

You can assign any property a capability that is needed to read, write, modify or delete it. By default no capability is set. If one is set, the property needs a method to check if the current user has a certain capability. Due the fact that no user management system is forced a interface has to be created and given to the properties.

$property::setUserManager(string $user_manager)

is a static method that takes the name of a user manager (normally the namespace or facade name of laravel) that has to define a method called hasCapability(string $capabilty): bool that has to return true if the current user has the given capability.

The different capabilities

  • read capability = Is needed to read a property
  • write capability = Is needed to write a previously empty property
  • modify capability = Is needed to modify a previously set property.
  • delete capability = Is needed to delete a property

readCapability(): ?string

If empty or null this property does not need a certain capabilty.

getReadCapability(): ?string

Is an alias for ->readCapability()

setReadCapability(string $capability)

Sets the read capability for the property.

writeCapability(): ?string

If empty or null this property does not need a certain capabilty.

getWriteCapability(): ?string

Is an alias for ->writeCapability()

setWriteCapability(string $capability)

Sets the write capability for the property.

modifyCapability(): ?string

Returns the modify capability of this property.

getModifyCapability(): ?string

Alias for modify Capability.

setModifyCapability(string $capability): static

Sets the modify capability of this property.

readable/writeable

A property can be unreadable or unwriteable by default. Note: A unreadable or write-only property could be something like a reboot button that you can't read but you can "push" it.

isReadable(): bool

Returns if the current property is readable.

getReadable(): bool

Alias for isReadable()

setReadable(bool $readable = true): AbstractProperty

Sets the value for readable for this property.

isWriteable(): bool

Returns if the property is writeable.

getWriteable(): bool

Alias for isWriteable()

setWriteable(bool $writeable = true)

Sets the value for writeable for this property.

Storage interaction

Due the fact that every property needs a storage to handle the values there are these methods that handle the storage

setStorage(AbstractStorage $storage)

This method sets the active storage for this property. Normally this is done by the property manager.

getStorage(): AbstractStorage

Returns the current set storage for this property.

isValidStorage(AbstractStorage $storage): bool

Checks if the given storage is a valid one. By default this method returns true. Use this for properties that need a certain kind of storage (e.g. PersistentPoolStorage).

createStorage(): ?AbstractStorage

With this method it is possible for derrived properties to create a default storage.

commit() and rollback()

As users should not interact with storages the the following method are passed to the storage.

commit()

this methods is to make a change to the value of a property persistent

rollback()

revoke the changes made to the value of this property

isDirty(): bool

Returns true when an initialized value was changed or an uninitialized property was assigned a value.

Name of property

Every property should have a name. The name does not have necessarily be unique.

setName(string $name)

Sets the name of the property to the given name if it is a valid name. Inavlid names are:

  • Names that start with an underscore _
  • Reserved names like 'object', 'string' or 'id'
  • Empty names ()

name(string $name)

Is an alias to ->setName();

forceName(string $name)

Skips the validation of the property name and should normally not be uses. It is uses internally for objects to define internal variables like _uuid.

getName()

Returns the name of the property.

isValidPropertyName(string $test)

Tests if the given name would pass the validation test.

Ownership of properties

A property can be owned by another property.This is useful in records and arrays but also for the InfoMarket. The statement

$propertyA->owner == $propertyB;

means that propertyA is a part of propertyB. Both can share the same storage or define a storage on their own.

setOwner(AbstractProperty: $owner): AbstractProperty

Sets the owner for this property. $owner must be a valid property.

getOwner(): ?AbstractProperty

Returns the current set owner (or null if no owner is set) of this property.

getPath(): string

This method is used for InfoMarket to identifiy a InfoMarket item. It combines the name of each owning property. Example:

"grandfather.father.son"

Metadata

Each property has some metadata that explains what kind of data it stores.

getSemantic(): string

Returns what semantic id this property has. See Semantics.

getSemanticKeywords(): array

Returns the semantic keywords of this property. See Semantics.

getUnit(): string

Returns the unit of this property. See Units.

getUpdate(): string

This is a hint for the caching of data. This returns how often this value should be updated or in other words is likely to change. See Caching.

getAccessType(): string

Returns a hint how the data is represented.

  • string
  • integer
  • date
  • datetime
  • time
  • float
  • boolean
  • array
  • record
  • blob

getMetadata()

Returns an associative array with all the above metadata as elements.

getStructure()

Returns either a stdClass() or an array of stdClass-es with the structure of the property or the included properties. This is needed for the underlying storage to do its job (sometimes)

InfoMarket interaction

All properties could be integrated into the Info market.

requestItem(array $path)

Returns the item that fits to the given path elements.

Information

Every property can hold some additional information items that can be used for information passing.

These information are bound to the property not the object so all the following methods are static.

getInfo(string $key, $default = null)

Returns the information with the name $key. If this information is not stored return the value of $default if not null.

getAllInfos()

Returns all informations that are stored to this property.

hasInfo(string $key): bool

Returns if the property has a information atom with this name.

Other basic property types

There are some other predefined property types (besides the Types and Semantics) that can be used as a base for own properties.

Writing own property classes

For more informations about reading own property classes see here.