The previous chapter introduced you to modeling. With your knowledge you can now setup a fully functional online database. Its generic user interface is driven by the schema. If you want to tailor the user interface and work flows to your requirements, you need to start coding. These two approaches are most powerful when combined. It is easy to integrate the base components with simple links during programming.
Topincs application development uses PHP. A basic understanding of PHP and in particular object-oriented programming will be helpful from now on. In many cases the coding artifacts are no longer than 10 lines. You will look for complicated class hierarchies in vain. We aim to keep the code simple and independent, yet we value eternal programmer wisdom highly: don't repeat yourself!
The fundamental programming concepts in Topincs are:
API reference
Hint: Both works: get_child_age
or getChildAge
!
Hint: Use the strict equals comparison operator === or equals
if you want to know if two tobjects represent the same topic!
You gain access to data in the store by retrieving a tobject. There is a 1-1 correspondence between a tobject and a topic. A tobject is a PHP object with an interface determined by modeled constraints of the type of the topic. By calling methods on the tobject you retrieve or manipulate the names, occurrences, and associations of the topic. The interface also performs automatic conversion, e.g. from native PHP objects like DateTime
to the correct value representation and back. The following example illustrates the basic usage of a tobject.
// Maria's wish has the system id 1351.
$wish = Tobject::get(1351);
echo $wish->id;
// 1351
echo $wish;
// 2021, Switzerland, Maria, Ball
// If not in string context, use the label method.
$label = $wish->label();
// The default link uses the label as the link text.
echo $wish->a();
echo $wish->get_child_name();
// Maria
echo $wish->get_child_age();
// 8
echo $wish->get_gift();
// Ball
echo $wish->get_year();
// 2021
echo $wish->get_country();
// Switzerland
During one PHP runtime – instantiated either by a service request or a job execution – a topic that is retrieved multiple times will always result in the same tobject. This behavior can be used to aggregate additional information on the tobject by storing computational results or frequently used data. This simple behavior of tobjects becomes very useful in any sort of complex computation since it reduces the need to revert to secondary data structures thus reducing the overall complexity of source code.
Hint: If you need to ensure a certain property structure on a tobject in more than one service, you can declare an init
method in a domain class.
$year = Tobject::get($some_year_id);
$year->age_sum = 0;
$year->wish_count = 0;
foreach ($year->get_all_wishs() as $wish) {
$wish->age_sum += $wish->get_child_age();
$wish->wish_count + 1;
}
echo $wish->age_sum / $wish->wish_count;
// By id:
Tobject::_get(1234);
// By a topic reference
Tobject::get("id:1234");
Tobject::get("si:year/2020");
Tobject::get("sl:someurl");
Hint: Keeping serialization names constant is a good idea, but a broken interface can be repaired by using a domain class!
The interface of a topic depends on its topic type and is driven by constraints and serialization names. This sounds more complicated than it is. Basically it is just a formality, since Topincs already suggests serialization names. We need to confirm them on the Programming interface page which you can access through the admin menu. If the suggested name is not to your liking, simply choose a different one. In the following video you will see how the interface of the Santa Claus system was setup.
Check it out
The following table illustrates the relationship between serialization names and method names.
Serialization name | Item type | Method name examples |
---|---|---|
child-name | Name type | has_child_name get_child_name |
child-age | Occurrence type | get_child_age set_child_age |
country | Role type | get_all_countrys delete_all_countrys |
wish | Topic type | make_Wish isa_Wish |
The interface allows access and manipulation of statements about the topic that a tobject represents. There is these method families: has
, count
, get
, set
, add
, delete
, and word
.
Hint: The individual statements are independent from each other.
// has
if ($year->has_wish()) {
...
}
// count
echo $year->count_wishs();
// get
$age = $wish->get_child_age();
foreach ($year->get_all_wishs() as $wish) {
...
}
// add
$year->add_wish($wish);
// Christmas is postponed #1:
$next_year->add_all_wishs($this_year->get_all_wishs());
// delete
$session->delete_end(); // delete one
$year->delete_all_wishs();
// set (delete all and then add)
$wish->set_child_name("Maria");
// Christmans is postponed #2:
// Existing wishes on next year are first deleted.
$next_year->set_all_wishs($this_year->get_all_wishs());
// word (similar to get, but respects language preference in a multilingual store)
echo $gift->word_description();
// Get the topic type of the tobject
if ($something->type() === "wish") {
...
}
// Creating a wish
$wish = Tobject::make_Wish()
->set_child_name("Henry")
->set_child_age(9)
->set_gift($bike_id)
->set_year("si:year/2021")
->set_country($france_id);
// Deleting a single topic
$wish->delete();
// Deleting many topics
$year->get_all_wishs()->delete();
// This deletes only the associations
$year->delete_all_wishs();
// Iterate over all years
foreach (Tobject::all_years() as $year) {
...
}
// If you need them in an array
$years = Tobject::all_years()->to_array();
A Topincs service satisfies a domain specific need. They are little programs with a name, input and output. Services are called by HTTP requests.
GET
or POST
.When you provide a read-only view of data in the store, you should use the GET
verb. When the service modifies data in the store or sends out an email, use POST
.
A service is created through the admin menu. Visit the index of Services and click Define. You need to specify a formal name, a label, a service type (GET or POST), and a format (HTML, JSON, PDF, etc.). Like everything else in Topincs, services are just topics. After creating the service the source code can be edited by clicking on Source code in the menu on the topic page. Initially there is a number of files initially present, but you can easily create a new one to outsource common code by simply declaring it.
One mandatory PHP file comes with every service, it is called GET.php
or POST.php
depending on the service type. This is the computational component of the service. In GET services it usually queries and aggregates information from the database. In POST services it manipulates data or sends out an email. A second PHP file is present, if you specified a format for the service. In most cases it will be HTML. We recommend that this stays largely free from sophisticated computation and simply performs the output. It is called the presentational component. It is optional, e.g. if the POST service simply sends out a HTTP location header after it is done. There can be more than one presentational component, e.g. when you output a table in CSV or XLSX format.
Hint: By default, parameters are accessed parsed. In rare case you might need them unparsed. Use get_unparsed
.
API reference
Service arguments should be added during the service creation, but may also be added later. There is two kinds of arguments: topic arguments and value arguments. For the first ones you need to specify one or more topic types of which the instances can be used as parameters. They will be rendered as a select box in the parameter query form. For the latter you need to specify a datatype.
On a service call the arguments are bound to parameter values. Topic parameters will be tobjects. Value parameters will be converted to the corresponding PHP type. The service can access parameters via their formal name through the variable $p
which is an instance of ServiceParameters
. If you add an argument later to a service, you need to manually adjust the service code to actually assign it to a variable in your computational component.
Santa Claus wants to be on top of things, so he needs an overview over all wishes of the current year. We will implement a service with one optional value argument. A positive integer holding a year. The computational component will try to fetch the year topic and then iterate over all wishes, group them by country and display selected properties in one table per country.
// Receiving one parameter:
$year = $p->get("year");
// Specifying a default value:
$year = $p->get("year", (new DateTime())->format("Y"));
// Receiving many in an array:
$wishes = $p->get_all("wish");
// Store URL:
https://www.topincs.com/santaclaus/
// URL for the service with the formal name 'overview':
https://www.topincs.com/santaclaus/overview
// Service URL with the argument 'year' bound:
https://www.topincs.com/santaclaus/overview?year=2021
// If mandatory arguments are bound, the service is called.
// Otherwise the service form shows.
// To force the form append an ampersand:
https://www.topincs.com/santaclaus/overview?year=2021&
// *= makes a parameter immutable in the service form:
https://www.topincs.com/santaclaus/overview?year*=2021&
Check it out
Hint: Is it easy to call a service from JavaScript or PHP.
Services can be accessed unparameterized from the default main menu. An auto-generated form will be presented to gather the service parameters, e.g. which year to display. This service form is very similar to the base component form, but the data it collects are just passed to the service and not persisted unless the service code does so. Services complement the base components for application development.
There is numerous things you can do with a service. Many items on the following list will become clearer, once you have read through the next chapter User interface.
Hint: It is good programming practice to have only one class per file!
A domain class extends a tobject with arbitrary methods. It can be registered for one or more topic types. The tobject will have methods of all domain classes that are registered (loaded) at call time. It is convenient to think of a domain class as being assigned to a topic type, but this correspondence is not essential to a domain class. A domain class is rather a mixin which has certain implicit expectations towards the tobject. It may hold instance methods or static methods.
A domain class is created on the page of the topic type. Click Create domain class, provide a name, click Ok and you can edit the source code of the class. You can use it in service by simply requiring it.
Santa Claus wants the children to receive an email confirmation, so that they can be sure their wish was heard. Since we want to do that in various places in the application we create a domain class.
A trigger is a piece of PHP code that is executed when certain events in the web database happen. Examples for events are:
A trigger is created in the programming section on the schema page of the store. First specify on which events the trigger fires. There is three classes of events:
After the trigger topic is created, click on Source code to program the trigger. The parameters passed to the trigger code are explained in the source code file. For item events the following table explains what the parameter $topic_id
is bound to:
Item type | $topic_id is bound to |
---|---|
Name | id of the topic |
Occurrence | id of the topic |
Role | id of the player |
Topic | id of the topic |
Check it out
<?php
require_once("domain/Year.php");
$wish = Tobject::get($topic_id);
$today = new DateTime();
$year = $today->format("Y");
$wish->set_year(Year::fetch($year));
Programming in Topincs empowers you to achieve more with less effort. A programming interface comes alive in a matter of seconds by assigning serialization names. The smallest unit of application development is a service. Domain classes are a flexible tool to tie computational behavior to one or more topic types. They make it possible to change the underlying data in the topic map and still keep dependent code functional by using a domain class as an adapter and importing it in the scripts that rely on the old data schema. These properties make it possible to quickly react to changes in the requirements.
This page cannot be displayed in your browser. Use Firefox, Opera, Safari, or Chrome instead.
Saving …