mirror of
https://github.com/Karaka-Management/Developer-Guide.git
synced 2026-01-11 20:38:42 +00:00
merge
This commit is contained in:
commit
f960946849
24
.github/workflows/image.yml
vendored
Normal file
24
.github/workflows/image.yml
vendored
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
name: Compress images
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- '**.jpg'
|
||||
- '**.png'
|
||||
- '**.webp'
|
||||
pull_request:
|
||||
paths:
|
||||
- '**.jpg'
|
||||
- '**.png'
|
||||
- '**.webp'
|
||||
jobs:
|
||||
build:
|
||||
name: calibreapp/image-actions
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Repo
|
||||
uses: actions/checkout@master
|
||||
|
||||
- name: Compress Images
|
||||
uses: calibreapp/image-actions@master
|
||||
with:
|
||||
githubToken: ${{ secrets.GITHUB_TOKEN }}
|
||||
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
vendor
|
||||
92
SUMMARY.md
92
SUMMARY.md
|
|
@ -1,60 +1,58 @@
|
|||
# General
|
||||
* [Introduction]({%}?page=README)
|
||||
* [Setup]({%}?page=general/setup)
|
||||
* [Application Structure]({%}?page=general/structure)
|
||||
* [Introduction]({%}&page=README)
|
||||
* [Setup]({%}&page=general/setup)
|
||||
* [Application Structure]({%}&page=general/structure)
|
||||
|
||||
## Quality & Standards
|
||||
* [Code Inspection]({%}?page=quality/inspections)
|
||||
* [Documentation Standards]({%}?page=standards/documentation)
|
||||
* [General Code Standards]({%}?page=standards/general)
|
||||
* [Security Standards]({%}?page=security/security_guidelines)
|
||||
* [Html Coding Standards]({%}?page=standards/html)
|
||||
* [Php Coding Standards]({%}?page=standards/php)
|
||||
* [Code Inspections & Tests]({%}&page=quality/inspections)
|
||||
* [Documentation Standards]({%}&page=standards/documentation)
|
||||
* [General Code Standards]({%}&page=standards/general)
|
||||
* [Security Standards]({%}&page=security/security_guidelines)
|
||||
* [Html Coding Standards]({%}&page=standards/html)
|
||||
* [Php Coding Standards]({%}&page=standards/php)
|
||||
|
||||
## Examples
|
||||
* [Application Sample]({%}?page=example_app/app)
|
||||
* [Modules]({%}?page=example_module/module)
|
||||
* [Packages]({%}?page=example_module/packages)
|
||||
* [Application Sample]({%}&page=example_app/app)
|
||||
* [Modules]({%}&page=example_module/module)
|
||||
* [Packages]({%}&page=example_module/packages)
|
||||
|
||||
## API
|
||||
### Application
|
||||
* [Routing]({%}?page=basics/routing)
|
||||
* [Dispatching]({%}?page=basics/dispatching)
|
||||
* [Localization]({%}?page=services/localization)
|
||||
* [Views]({%}?page=basics/views)
|
||||
|
||||
### Messaging
|
||||
* [Requests]({%}?page=basics/requests)
|
||||
* [Responses]({%}?page=basics/responses)
|
||||
* [Mail]({%}?page=services/mail)
|
||||
* [Uri]({%}?page=services/uri)
|
||||
### Message
|
||||
* [Uri]({%}&page=services/uri)
|
||||
* [Requests]({%}&page=basics/requests)
|
||||
* [Responses]({%}&page=basics/responses)
|
||||
* [Mail]({%}&page=services/mail)
|
||||
|
||||
### DataStorage
|
||||
* [Cache]({%}?page=datastorage/cache)
|
||||
* [Session]({%}?page=datastorage/session)
|
||||
* [Cookie]({%}?page=datastorage/cookie)
|
||||
* [LocalStorage]({%}?page=datastorage/localstorage)
|
||||
* [Filesystem]({%}?page=services/filesystem)
|
||||
* [Database Connection]({%}?page=datastorage/database/connection)
|
||||
* [DataMapper]({%}?page=datastorage/database/datamapper)
|
||||
* [Queries]({%}?page=datastorage/database/queries)
|
||||
* [LocalStorage]({%}&page=datastorage/localstorage)
|
||||
* [Database Connection]({%}&page=datastorage/database/connection)
|
||||
* [DataMapper]({%}&page=datastorage/database/datamapper)
|
||||
* [Queries]({%}&page=datastorage/database/queries)
|
||||
* [Cache]({%}&page=datastorage/cache)
|
||||
* [Session]({%}&page=datastorage/session)
|
||||
* [Cookie]({%}&page=datastorage/cookie)
|
||||
|
||||
### System
|
||||
* [Filesystem]({%}&page=services/filesystem)
|
||||
* [Events]({%}&page=services/events)
|
||||
* [Logging]({%}&page=services/logging)
|
||||
* [Tasks]({%}&page=services/tasks)
|
||||
|
||||
### StdLib
|
||||
* [Localization]({%}&page=services/localization)
|
||||
* [Money]({%}&page=services/money)
|
||||
* [Queues]({%}&page=services/queues)
|
||||
* [Collection]({%}&page=services/collection)
|
||||
|
||||
### UI
|
||||
* [Styles and Layout]({%}?page=frontend/styles_and_layout)
|
||||
* [Charting]({%}?page=services/charting)
|
||||
* [Codes]({%}?page=services/codes)
|
||||
* [Styles and Layout]({%}&page=frontend/styles_and_layout)
|
||||
* [Charting]({%}&page=services/charting)
|
||||
* [Codes]({%}&page=services/codes)
|
||||
* [Routing]({%}&page=basics/routing)
|
||||
* [Dispatching]({%}&page=basics/dispatching)
|
||||
* [Views]({%}&page=basics/views)
|
||||
* [Validation]({%}&page=services/validation)
|
||||
|
||||
### Security
|
||||
* [Encoding]({%}?page=services/encoding)
|
||||
* [Encryption]({%}?page=services/encryption)
|
||||
|
||||
### Datatypes
|
||||
* [Money]({%}?page=services/money)
|
||||
* [Queues]({%}?page=services/queues)
|
||||
* [Collection]({%}?page=services/collection)
|
||||
|
||||
### Misc.
|
||||
* [Events]({%}?page=services/events)
|
||||
* [Logging]({%}?page=services/logging)
|
||||
* [Tasks]({%}?page=services/tasks)
|
||||
* [Validation]({%}?page=services/validation)
|
||||
* [Encoding]({%}&page=services/encoding)
|
||||
* [Encryption]({%}&page=services/encryption)
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
# Dispatching
|
||||
|
||||
The dispatching is the follow up on the routing. In the dispatcher the route destination get resolved and executed. Dispatching can be performed on module instance methods, static functions and anonymous functions.
|
||||
The dispatching is the follow up on the routing. In the dispatcher the route destination gets resolved and executed. Dispatching can be performed on module instance methods, static functions and anonymous functions.
|
||||
|
||||
The return of the `dispatch()` call is an array of all end point returns.
|
||||
|
||||
## Basic
|
||||
|
||||
The dispatcher accepts a string representation of the method or static function which should be dispatched, a closure which should be executed or an array of the above.
|
||||
The dispatcher accepts a string representation of the method or static function which should be dispatched, a closure which should be executed or an array of the just mentioned options.
|
||||
|
||||
The `dispatch()` function accepts additionally a variable amount of parameters which will be passed to the routed method/function.
|
||||
|
||||
|
|
@ -38,14 +38,14 @@ $dispatcher->dispatch(function($para1, $para2) { ... }, $staticToCallPara1, $sta
|
|||
|
||||
## Routing
|
||||
|
||||
The dispatcher accepts the resoults from the `route()` method of the router which is an array of routes.
|
||||
The dispatcher accepts the results from the `route()` method of the router which is an array of routes.
|
||||
|
||||
```php
|
||||
$dispatcher->dispatch($router->route($request->getUri()->getRoute()));
|
||||
$dispatcher->dispatch($router->route($request->uri->getRoute()));
|
||||
```
|
||||
|
||||
Based on the function definition returned by the router it's possible to pass more parameters to the function such e.g. request and response objects.
|
||||
|
||||
```php
|
||||
$dispatcher->dispatch($router->route($request->getUri()->getRoute()), $request, $response);
|
||||
$dispatcher->dispatch($router->route($request->uri->getRoute()), $request, $response);
|
||||
```
|
||||
|
|
|
|||
|
|
@ -162,4 +162,8 @@ $router->route(
|
|||
'APP_NAME',
|
||||
ORG_ID, ACCOUNT
|
||||
);
|
||||
```
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
* 2-character routes on the first level are discouraged because they may conflict with ISO 639-1 codes (e.g. /hr/staff/list)
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
## Cache
|
||||
|
||||
For caching the `CacheManager` provides access to the caching systems in place. Out of the box the CacheManager supports and automatically initializes either Redis or Memcached depending on the client configuration. The caching is not mandatory and therfor shouldn't be missuesed as in-memory database. It is not necessary to check if Redis or Memcached are available the CacheManager automatically handles the caching based on their existence.
|
||||
For caching the `CacheManager` provides access to the caching systems in place. Out of the box the CacheManager supports and automatically initializes either Redis or Memcached depending on the client configuration. The caching is not mandatory and therefor shouldn't be misused as in-memory database. It is not necessary to check if Redis or Memcached are available the CacheManager automatically handles the caching based on their existence.
|
||||
|
||||
### HTTP Cache
|
||||
|
||||
|
|
@ -9,7 +9,7 @@ By default only stylesheets, javascript and layout images as well as module imag
|
|||
Example usage for 30 days caching:
|
||||
|
||||
```php
|
||||
$resposne->setHeader('Cache-Control', 'Cache-Control: max-age=2592000');
|
||||
$response->setHeader('Cache-Control', 'Cache-Control: max-age=2592000');
|
||||
```
|
||||
|
||||
In order to trigger a re-cache of stylesheets or javascript files make sure to update the version in the `Controller.php` file. This way version updates will result in a new virtual file uri and result in a re-cache.
|
||||
|
|
@ -17,5 +17,5 @@ In order to trigger a re-cache of stylesheets or javascript files make sure to u
|
|||
Example usage:
|
||||
|
||||
```php
|
||||
$head->addAsset(AssetType::JS, $request->getUri()->getBase() . 'Modules/Media/Controller.js?v=' . self::MODULE_VERSION);
|
||||
$head->addAsset(AssetType::JS, $request->uri->getBase() . 'Modules/Media/Controller.js?v=' . self::MODULE_VERSION);
|
||||
```
|
||||
|
|
@ -2,6 +2,6 @@
|
|||
|
||||
## PHP
|
||||
|
||||
Only use cookies when absolutely necessary. Most of the time session data or local storage is the prefered choice. The `CookieJar` class provides you with all the necessary functionality similar to the `SessionManager`. The super global `$_COOKIE` is also overwritten and shouldn't be used anywhere.
|
||||
Only use cookies when absolutely necessary. Most of the time session data or local storage is the preferred choice. The `CookieJar` class provides you with all the necessary functionality similar to the `SessionManager`. The super global `$_COOKIE` is also overwritten and shouldn't be used anywhere.
|
||||
|
||||
## JavaScript
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ $con = new MysqlConnection([
|
|||
'login' => 'root', /* db login name */
|
||||
'password' => 'root', /* db login password */
|
||||
'database' => 'oms', /* db name */
|
||||
'prefix' => 'oms_', /* db table prefix */
|
||||
]);
|
||||
```
|
||||
|
||||
|
|
@ -32,7 +31,6 @@ $con = ConnectionFactory::create([
|
|||
'login' => 'root',
|
||||
'password' => 'root',
|
||||
'database' => 'oms',
|
||||
'prefix' => 'oms_',
|
||||
]);
|
||||
```
|
||||
|
||||
|
|
@ -62,7 +60,6 @@ $dbPool->create('read',
|
|||
'login' => 'root',
|
||||
'password' => 'root',
|
||||
'database' => 'oms',
|
||||
'prefix' => 'oms_',
|
||||
]
|
||||
);
|
||||
```
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
## Models
|
||||
|
||||
Models can be constructed in what ever way you like, all of the mapping logic is defined in the data mapper itself. It is however recommended to provide the following member variables if applicable (names can be different):
|
||||
Models can be constructed in what ever way you like, all of the mapping logic is defined in the data mapper itself. However, it is recommended to provide the following member variables if applicable (names can be different):
|
||||
|
||||
```php
|
||||
private $id = 0;
|
||||
|
|
@ -32,6 +32,21 @@ In a similar fashion as the `$createdAt` variable often it is also necessary to
|
|||
|
||||
One model can only be stored in one table. With the `$table` variable it's possible to specify the table name. This variable is compulsory. It's important to note that by extending a model you also need to implement a data mapper that can access multiple tables. In that case it's also necessary to extend the data mapper of the extended module.
|
||||
|
||||
### Model
|
||||
|
||||
The `$model` variable can be optionally used in order to specify the model this mapper is supposed to populate. By default the mapper will try to find a model in the same directory as the mapper without the `Mapper` suffix in its name.
|
||||
|
||||
Default behavior example:
|
||||
|
||||
* Mapper name: `\test\path\TestMapper`
|
||||
* Default maodel: `\test\path\Test`
|
||||
|
||||
If the model is defined somewhere else or has a different name, the `$model` variable name should be used to define the correct model. E.g.
|
||||
|
||||
```php
|
||||
protected static string $model = OtherModel::class;
|
||||
```
|
||||
|
||||
### Columns
|
||||
|
||||
In the `$columns` array all columns, respective model variables and data types need to be specified.
|
||||
|
|
@ -45,6 +60,17 @@ protected static array $columns = [
|
|||
|
||||
The `name` contains the field name in the database, the `type` represents the data type and `internal` is the string representation of the model variable name.
|
||||
|
||||
#### Searchable columns
|
||||
|
||||
In order to make columns searchable you have to add `'autocomplete' => true` as column information to the respective column.
|
||||
|
||||
```php
|
||||
protected static array $columns = [
|
||||
'db_field_name_1' => ['name' => 'db_field_name_1', 'type' => 'int', 'internal' => 'model_var_name_1', 'autocomplete' => true],
|
||||
'db_field_name_2' => ['name' => 'db_field_name_2', 'type' => 'string', 'internal' => 'model_var_name_2'],
|
||||
];
|
||||
```
|
||||
|
||||
#### Types
|
||||
|
||||
Possible types are:
|
||||
|
|
@ -53,9 +79,9 @@ Possible types are:
|
|||
* string
|
||||
* bool
|
||||
* float
|
||||
* \DateTime
|
||||
* serializable (will call `serialize()`)
|
||||
* json (will call `jsonSerialize()`)
|
||||
* DateTime
|
||||
* Serializable (will call `serialize()`)
|
||||
* Json (will call `jsonSerialize()`)
|
||||
|
||||
### Has many
|
||||
|
||||
|
|
@ -66,7 +92,7 @@ protected static array $hasMany = [
|
|||
'model_var_name_3' => [
|
||||
'mapper' => HasManyMapper::class,
|
||||
'table' => 'relation_table_name',
|
||||
'dst' => 'relation_destinaiton_name',
|
||||
'dst' => 'relation_destination_name',
|
||||
'src' => 'relation_source_name',
|
||||
],
|
||||
];
|
||||
|
|
@ -74,6 +100,8 @@ protected static array $hasMany = [
|
|||
|
||||
The `mapper` contains the class name of the mapper responsible for the many models that belong to this model. The `table` contains the name of the table where the relations are defined (this can be the same table as the source model or a relation table). If a model is only in relation with one other model this relation can be defined in the same table as the model and this `table` field can be `null`. The `dst` field contains the name of field where the primary key of the destination is defined. The `src` field is only required for models which have a relation table. This field contains the name of the field where the primary key of the source model is defined.
|
||||
|
||||
#### Relation is defined in the model table
|
||||
|
||||
A many to one or one to one relation would look like the following:
|
||||
|
||||
```php
|
||||
|
|
@ -81,12 +109,14 @@ protected static array $hasMany = [
|
|||
'model_var_name_3' => [
|
||||
'mapper' => HasManyMapper::class,
|
||||
'table' => null,
|
||||
'dst' => 'relation_destinaiton_name',
|
||||
'dst' => 'relation_destination_name',
|
||||
'src' => null,
|
||||
],
|
||||
];
|
||||
```
|
||||
|
||||
#### Relation is defined in a relation table
|
||||
|
||||
A many to many relation which can only be defined in a relation table looks like the following:
|
||||
|
||||
```php
|
||||
|
|
@ -94,15 +124,34 @@ protected static array $hasMany = [
|
|||
'model_var_name_3' => [
|
||||
'mapper' => HasManyMapper::class,
|
||||
'table' => 'relation_table_name',
|
||||
'dst' => 'relation_destinaiton_name',
|
||||
'dst' => 'relation_destination_name',
|
||||
'src' => 'relation_source_name',
|
||||
],
|
||||
];
|
||||
```
|
||||
|
||||
#### Single field relations
|
||||
|
||||
By defining a `column` it's also possible to only populate the model with a single column/field value from another table or model.
|
||||
|
||||
```php
|
||||
protected static array $hasMany = [
|
||||
'my_title' => [
|
||||
'mapper' => L11nTagMapper::class,
|
||||
'table' => 'tag_l11n',
|
||||
'external' => 'tag_l11n_tag',
|
||||
'column' => 'title',
|
||||
'conditional' => true,
|
||||
'self' => null,
|
||||
],
|
||||
];
|
||||
```
|
||||
|
||||
In the example above the model member variable `my_title` will be populated with the value `title` from the `L11nTagMapper`. Here the `L11nTagMapper` will to a reverse lookup of the column name for the variable `title` and return the content.
|
||||
|
||||
### Owns one
|
||||
|
||||
It's possible to also define a relation in the source module itself. This can be acomplished by using the `$ownsOne` variable. In this case the model itself has to specify a field where the primary key of the source model is defined.
|
||||
It's possible to also define a relation in the source module itself. This can be accomplished by using the `$ownsOne` variable. In this case the model itself has to specify a field where the primary key of the source model is defined.
|
||||
|
||||
```php
|
||||
protected static array $ownsOne = [
|
||||
|
|
@ -113,11 +162,11 @@ protected static array $ownsOne = [
|
|||
];
|
||||
```
|
||||
|
||||
The `mapper` field contains the class name of the mapper of the source model. The `src` field contains the database field name where the primary key is stored that is used for the realation.
|
||||
The `mapper` field contains the class name of the mapper of the source model. The `src` field contains the database field name where the primary key is stored that is used for the relation.
|
||||
|
||||
### Belongs to
|
||||
|
||||
The reverse of a has one is a belongs to. This allows to also load models that a specific model belongs to. This can be acomplished by using the `$belongsTo` variable. In this case the model itself has to specify a field where the primary key of the source model is defined.
|
||||
The reverse of a has one is a belongs to. This allows to also load models that a specific model belongs to. This can be accomplished by using the `$belongsTo` variable. In this case the model itself has to specify a field where the primary key of the source model is defined.
|
||||
|
||||
```php
|
||||
protected static array $belongsTo = [
|
||||
|
|
@ -129,3 +178,19 @@ protected static array $belongsTo = [
|
|||
```
|
||||
|
||||
The `mapper` field contains the class name of the mapper of the destination model. The `dest` field contains the database field name where the primary key is stored that this model belongs to.
|
||||
|
||||
## Conditionals
|
||||
|
||||
Conditionals provide a general way to filter the desired result of models. You can think about conditionals as SQL `WHERE` clauses. A conditional uses the model member variable name instead of the database table name.
|
||||
|
||||
```php
|
||||
WithConditionalMapper::withConditional('language', 'en')::getAll();
|
||||
```
|
||||
|
||||
This query returns all models of the `WithConditionalMapper` which have a member variable with the value `en`. In the background the mapper does a reverse lookup, checks the column name which is associated with the `language` member variable and filters the database result accordingly.
|
||||
|
||||
By default conditionals are recursive and get applied to all models which are somehow referenced in the request (e.g. has many models which have also a `language` member variable). In some cases this is undesired and the user wants to specify the models where the conditionals should be applied to. This can be achieved in the following way:
|
||||
|
||||
```php
|
||||
WithConditionalMapper::withConditional('language', 'en', [FirstModelToApplyTo::class, SecondModelToApplyTo::class, ...])::getAll();
|
||||
```
|
||||
|
|
@ -14,34 +14,25 @@ The database query builder provides a uniform way to write default database quer
|
|||
|
||||
The query builder is used for regular CRUD operations on the database.
|
||||
|
||||
#### Prefix
|
||||
|
||||
Projects often use a prefix for all of the tables. For this project the default prefix is `oms_`.
|
||||
|
||||
```php
|
||||
$query = new Builder();
|
||||
$query->prefix('oms_');
|
||||
```
|
||||
|
||||
#### Select, Insert, Update, Delete
|
||||
|
||||
Both `select` and `insert` expect the column names as parameter. The `where`, `from` and `into` clause can be necessary depending on the type of operation like a normal sql query.
|
||||
|
||||
```php
|
||||
$query->prefix(...)->select('columnA', 'columnB')->from('table')->where(...);
|
||||
$query->prefix(...)->insert('columnA', 'columnB')->values('a', 'b')->into('table');
|
||||
$query->select('columnA', 'columnB')->from('table')->where(...);
|
||||
$query->insert('columnA', 'columnB')->values('a', 'b')->into('table');
|
||||
```
|
||||
|
||||
The `update` expects the table name which should be updated and then the `set` function to define the columns and new values.
|
||||
|
||||
```php
|
||||
$query->prefix(...)->update('table')->set(['columnA' => 'a'])->set(['columnB' => 'b'])->where(...);
|
||||
$query->update('table')->set(['columnA' => 'a'])->set(['columnB' => 'b'])->where(...);
|
||||
```
|
||||
|
||||
The `delete` function only expects the `from` and `where` clause to identify the to delete columns in a table.
|
||||
|
||||
```php
|
||||
$query->prefix(...)->delete()->from('table')->where(...);
|
||||
$query->delete()->from('table')->where(...);
|
||||
```
|
||||
|
||||
##### Random
|
||||
|
|
@ -51,8 +42,8 @@ $query->prefix(...)->delete()->from('table')->where(...);
|
|||
The `from` part of a query accepts `string`, `array`, `\Closure`, `From`, `Builder` as parameter.
|
||||
|
||||
```php
|
||||
$query->prefix(...)->select(...)->from('table');
|
||||
$query->prefix(...)->select(...)->from('tableA', 'tableB');
|
||||
$query->select(...)->from('table');
|
||||
$query->select(...)->from('tableA', 'tableB');
|
||||
```
|
||||
|
||||
#### Into
|
||||
|
|
@ -64,7 +55,7 @@ The `into` part of a query accepts `string`, `array`, `\Closure`, `Into`, `Build
|
|||
The basic `where` clause expects a column, operator, value and boolean concatenater which is used to concatenate multiple where clauses.
|
||||
|
||||
```php
|
||||
$query->prefix(...)->select(...)->from(...)->where('columnA', '=', 123)->where('columnB', '=', 'abc', 'or');
|
||||
$query->select(...)->from(...)->where('columnA', '=', 123)->where('columnB', '=', 'abc', 'or');
|
||||
```
|
||||
|
||||
For easier use additional `where` clauses are defined such as:
|
||||
|
|
@ -80,7 +71,7 @@ For easier use additional `where` clauses are defined such as:
|
|||
The `limit` expects an integer.
|
||||
|
||||
```php
|
||||
$query->prefix(...)->select(...)->from(...)->where(...)->limit(3);
|
||||
$query->select(...)->from(...)->where(...)->limit(3);
|
||||
```
|
||||
|
||||
#### Offset
|
||||
|
|
@ -88,7 +79,7 @@ $query->prefix(...)->select(...)->from(...)->where(...)->limit(3);
|
|||
The `offset` expects an integer.
|
||||
|
||||
```php
|
||||
$query->prefix(...)->select(...)->from(...)->where(...)->offset(3);
|
||||
$query->select(...)->from(...)->where(...)->offset(3);
|
||||
```
|
||||
|
||||
#### Order
|
||||
|
|
@ -96,7 +87,7 @@ $query->prefix(...)->select(...)->from(...)->where(...)->offset(3);
|
|||
The ordering is performed by `orderBy`.
|
||||
|
||||
```php
|
||||
$query->prefix(...)->select(...)->from(...)->where(...)->orderBy('columnA', 'DESC');
|
||||
$query->select(...)->from(...)->where(...)->orderBy('columnA', 'DESC');
|
||||
```
|
||||
|
||||
The `newest` and `oldest` operation are a small wrapper which automatically order by `DESC` and `ASC` respectively.
|
||||
|
|
@ -106,7 +97,7 @@ The `newest` and `oldest` operation are a small wrapper which automatically orde
|
|||
Grouping of columns can be achieved through `groupBy`.
|
||||
|
||||
```php
|
||||
$query->prefix(...)->select(...)->from(...)->where(...)->groupBy('columnA', 'columnB');
|
||||
$query->select(...)->from(...)->where(...)->groupBy('columnA', 'columnB');
|
||||
```
|
||||
|
||||
#### Join
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# Sessions
|
||||
|
||||
Sessions are handled via the `SessionManager`. Sessions can be set and manipulated from the web application as well as the socket or console application.
|
||||
Sessions are handled via the `SessionManager`. Sessions can be set and manipulated from the web application as well as the socket or console application.
|
||||
|
||||
## HTTP
|
||||
|
||||
|
|
@ -8,4 +8,4 @@ The Http session will be saved automatically, there is no need to access the sup
|
|||
|
||||
## Socket & Console
|
||||
|
||||
The session will be stored and assoziated with the logged in user in memory. A disconnect or quit is considered as a logout and therefor results in the destruction of the session object of this user and will be empty for the next login.
|
||||
The session will be stored and associated with the logged in user in memory. A disconnect or quit is considered as a logout and therefor results in the destruction of the session object of this user and will be empty for the next login.
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ echo $App->run(); // outputs the application response
|
|||
|
||||
namespace app;
|
||||
|
||||
use phpOMS\ApplicationAbstract; /* provides many member variables which are often shared with controllers */
|
||||
use phpOMS\Application\ApplicationAbstract; /* provides many member variables which are often shared with controllers */
|
||||
use phpOMS\Dispatcher\Dispatcher;
|
||||
use phpOMS\Message\Http\HttpRequest;
|
||||
use phpOMS\Message\Http\HttpResponse;
|
||||
|
|
@ -78,7 +78,7 @@ class Application extends ApplicationAbstract
|
|||
/* get data from url endpoints defined by the routes */
|
||||
$dispatch = $this->dispatcher->dispatch(
|
||||
$this->router->route(
|
||||
$request->getUri()->getRoute(),
|
||||
$request->uri->getRoute(),
|
||||
$request->getData('CSRF'), // optional: only required if csrf tokens are used otherwise use null
|
||||
$request->getRouteVerb() // e.g. get, post, put ...
|
||||
),
|
||||
|
|
@ -91,7 +91,7 @@ class Application extends ApplicationAbstract
|
|||
$pageView->addData('dispatch', $dispatch);
|
||||
|
||||
// push the headers (no changes to the header are possible afterwards)
|
||||
$response->getHeader()->push();
|
||||
$response->header->push();
|
||||
|
||||
// renders the content of the response object (depends on the content type, text/html, json, ...)
|
||||
return $response->getBody();
|
||||
|
|
@ -107,10 +107,10 @@ class Application extends ApplicationAbstract
|
|||
$request->createRequestHashs(0);
|
||||
|
||||
// if your application is located in a web-subfolder for easier handling
|
||||
$request->getUri()->setRootPath('/');
|
||||
$request->uri->setRootPath('/');
|
||||
|
||||
// this will allow you to create urls based on request data
|
||||
UriFactory::setupUriBuilder($request->getUri());
|
||||
UriFactory::setupUriBuilder($request->uri);
|
||||
|
||||
return $request;
|
||||
}
|
||||
|
|
@ -121,9 +121,9 @@ class Application extends ApplicationAbstract
|
|||
$response = new HttpResponse();
|
||||
|
||||
// you could use the request content-type in order to define the response content-type
|
||||
$response->getHeader()->set('content-type', 'text/html; charset=utf-8');
|
||||
$response->header->set('content-type', 'text/html; charset=utf-8');
|
||||
|
||||
$response->getHeader()->set('x-xss-protection', '1; mode=block');
|
||||
$response->header->set('x-xss-protection', '1; mode=block');
|
||||
// more CSP can be defined here
|
||||
|
||||
return $response;
|
||||
|
|
@ -203,7 +203,7 @@ return [
|
|||
|
||||
namespace app\controller;
|
||||
|
||||
use phpOMS\ApplicationAbstract;
|
||||
use phpOMS\Application\ApplicationAbstract;
|
||||
use phpOMS\Message\RequestAbstract;
|
||||
use phpOMS\Message\ResponseAbstract;
|
||||
use phpOMS\Views\View;
|
||||
|
|
|
|||
|
|
@ -139,12 +139,12 @@ namespace Modules\Navigation\Admin;
|
|||
|
||||
use phpOMS\DataStorage\Database\DatabaseType;
|
||||
use phpOMS\DataStorage\Database\DatabasePool;
|
||||
use phpOMS\Module\InfoManager;
|
||||
use phpOMS\Module\ModuleInfo;
|
||||
use phpOMS\Module\InstallerAbstract;
|
||||
|
||||
class Installer extends InstallerAbstract
|
||||
final class Installer extends InstallerAbstract
|
||||
{
|
||||
public static function install(string $path, Pool $dbPool, InfoManager $info)
|
||||
public static function install(string $path, Pool $dbPool, ModuleInfo $info)
|
||||
{
|
||||
parent::install($path, $dbPool, $info);
|
||||
|
||||
|
|
@ -157,7 +157,7 @@ class Installer extends InstallerAbstract
|
|||
}
|
||||
```
|
||||
|
||||
If your application doesn't need to implement any database tables for itself the switch statement can be omitted. From the directory structur at the beginning we can however see that some modules accept information form other modules. The following example shows how the navigation module is accepting information during the installation of other modules:
|
||||
If your application doesn't need to implement any database tables for itself the switch statement can be omitted. From the directory structure at the beginning we can however see that some modules accept information form other modules. The following example shows how the navigation module is accepting information during the installation of other modules:
|
||||
|
||||
```php
|
||||
public static function installExternal(Pool $dbPool, array $data)
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ Flexboxes are preferred for all content containers.
|
|||
```html
|
||||
<div class="row">
|
||||
<div class="col-xs-12 col-sm-6 col-md-3 col-lg-1">
|
||||
<section class="box wf-100">...</section>
|
||||
<section class="portlet">...</section>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
|
@ -26,7 +26,7 @@ A container (e.g. section, div, table, etc) can be sized by using `.wf-*` classe
|
|||
|
||||
## Icons
|
||||
|
||||
This project uses font-awesome for its icons, the following example allows for stacked icons e.g. creating new/undread email notifications:
|
||||
This project uses font-awesome for its icons, the following example allows for stacked icons e.g. creating new/unread email notifications:
|
||||
|
||||
```html
|
||||
<i class="fa fa-lg infoIcon fa-envelope">
|
||||
|
|
@ -49,7 +49,7 @@ The following snippet creates a 100% input with a button next to it.
|
|||
|
||||
### Input with dictionary
|
||||
|
||||
The following snippet creates a dictionary button (e.g. for opening a popup window to search for accounts/groups etc) right befor an input field.
|
||||
The following snippet creates a dictionary button (e.g. for opening a popup window to search for accounts/groups etc) right before an input field.
|
||||
|
||||
```html
|
||||
<span class="input">
|
||||
|
|
@ -58,23 +58,47 @@ The following snippet creates a dictionary button (e.g. for opening a popup wind
|
|||
</span>
|
||||
```
|
||||
|
||||
### Checkbox
|
||||
|
||||
The following snippet creates a checkbox.
|
||||
|
||||
```html
|
||||
<label class="checkbox" for="iID">
|
||||
<input id="iID" type="checkbox" name="name" value="1">
|
||||
<span class="checkmark"></span>
|
||||
Text
|
||||
</label>
|
||||
```
|
||||
|
||||
### Radio
|
||||
|
||||
The following snippet creates a checkbox.
|
||||
|
||||
```html
|
||||
<label class="checkbox" for="iID">
|
||||
<input id="iID" type="radio" name="name" value="1">
|
||||
<span class="checkmark"></span>
|
||||
Text
|
||||
</label
|
||||
|
||||
## Section
|
||||
|
||||
A section is a container for information that can and should be grouped together.
|
||||
|
||||
```html
|
||||
<section class="box wf-100">
|
||||
<h1>Title</h1>
|
||||
<div class="inner">
|
||||
<section class="portlet">
|
||||
<div class="portlet-head">Title</div>
|
||||
<div class="portlet-body">
|
||||
...
|
||||
</div>
|
||||
<div class="portlet-foot">Footer</div>
|
||||
</section>
|
||||
```
|
||||
|
||||
Additional coloring of sections can be achieved by adding a coloring class.
|
||||
|
||||
```html
|
||||
<section class="box green">
|
||||
<section class="portlet green">
|
||||
...
|
||||
</section>
|
||||
```
|
||||
|
|
|
|||
268
general/app_flow.drawio.svg
Normal file
268
general/app_flow.drawio.svg
Normal file
|
|
@ -0,0 +1,268 @@
|
|||
<svg host="65bd71144e" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="391px" height="457px" viewBox="-0.5 -0.5 391 457" content="<mxfile host="" modified="2020-11-14T22:52:30.884Z" agent="5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Code/1.46.1 Chrome/78.0.3904.130 Electron/7.3.1 Safari/537.36" version="13.6.5" etag="IFN7UMR82D_5cHEK2kDX"><diagram id="f52d839b-af3d-9e28-9e5e-6aed9f243001" name="Page-1">3VrbcpswEP0av2ZA4mI/5p6HZqaTtE36KIMCamVEQcR2v77CiIAsJbEbLNxmMh6xSGJ19hztymYCzxer6wLl6S2LMZ0AJ15N4MUEAH/mic/asG4MMPQbQ1KQuDG5neGe/MbS6EhrRWJcKh05Y5STXDVGLMtwxBUbKgq2VLs9Mao+NUcJ1gz3EaK69YHEPJVWN5h1N24wSVL56CkImhtzFP1MClZl8nkTAJ82f83tBWrnkgstUxSzZc8ELyfwvGCMN63F6hzTGtoWtmbc1St3X/wucMZ3GSDj9IxohVuPN37xdYsFjgU08pIVPGUJyxC97Kxnm/XiekZHXKV8QUXTFc0fmPO1jC6qOBOmboZPjOWyn+61XEjJqiKSfkjPOCoSLHtJUtUe9obJlV5jtsC8WIsOBaaIk2c1uEhyJHnp9zL0MyPCEeBIOntTGS3JZuDN1Ckan+SoDm3R6LnRmTYxMMcDaPH4WuJCjwmlQgo19suUcHyfow1KSyFGNQKvIvuMC45Xb6LWrj5QV++6cvXLThm+7JL2NNHaTDgrCL0Bh+tqeBwtP32dn+12NhxBdwXO13C74TwXljv8q8Il11BUMbLAKn+LVW3K6LEqNLAK+gOwCv47rGoppNAKjEWr1psecg94fprnR8cnUYNY4xOAQ9IHrwh/7LW/111ORAElLjPh2aMcsrlobvp7sK4UTOKndY0kDBFFZUmi1nxF6LshUchpyMlgtD0PTA8qawW4jGV4CzVnjyB0gTzxlVB+BHk4+LbwWjnkK1KDs93KIYEdWve65XWHUovwfgWT5x1ee+A97e2oqWETg4EBrjdaYtAL1wm8kv8goMLBs7moY4OkbomEQUkkPGDZ0SUOCOwlDlc/ft2xihsKftuo+MGWxp2pvXQa2NvHLYkVGKq44U+vOwOsV3EXpMwRj9JjpF4rUAvUg4f9PmTIEmI33hkOpRCOxTvvsOeuUYRtAng8YevH/lsWVxSLKsupZ6k/t5PxORPFDKP0CKXvuaE16Xv/X9aBBnJ6o5HTO8DxzIiNAcP9A2FE6e8QDy0BDA3qR3l+BLoOxtS1jsoF4miOSjw6LmHojIYLnNnb72yUOm1Zo2Ti6VibHdRLnW8EL0dnnJZhQ3unXagngC94kQvkx1fiNi6+Z/HQATRc7nCZs8ywQ1n94c/f4oqjYxIYMAkG+OHPC/Vc1rxk8HGiaAgYcNo9lR1OQOKyexGg+Wq0e9kCXv4B</diagram></mxfile>" style="background-color: rgb(255, 255, 255);">
|
||||
<defs/>
|
||||
<g>
|
||||
<path d="M 35 50 L 35.03 70 L 35.03 55.03 L 35.03 68.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<path d="M 35.03 73.88 L 31.53 66.88 L 35.03 68.63 L 38.53 66.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<ellipse cx="35" cy="25" rx="25" ry="25" fill="#ffffff" stroke="#000000" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 48px; height: 1px; padding-top: 25px; margin-left: 11px;">
|
||||
<div style="box-sizing: border-box; font-size: 0; text-align: center; ">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">
|
||||
User
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="35" y="29" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">
|
||||
User
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 35.03 110 L 35.03 130 L 35.03 120 L 35.03 133.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<path d="M 35.03 138.88 L 31.53 131.88 L 35.03 133.63 L 38.53 131.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<rect x="0" y="75" width="70" height="35" fill="#ffffff" stroke="#000000" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 68px; height: 1px; padding-top: 93px; margin-left: 1px;">
|
||||
<div style="box-sizing: border-box; font-size: 0; text-align: center; ">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">
|
||||
Http Request
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="35" y="96" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">
|
||||
Http Request
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 35.03 175 L 35.03 195.03 L 35.03 190 L 35.03 203.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<path d="M 35.03 208.88 L 31.53 201.88 L 35.03 203.63 L 38.53 201.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<rect x="0" y="140" width="70" height="35" fill="#ffffff" stroke="#000000" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 68px; height: 1px; padding-top: 158px; margin-left: 1px;">
|
||||
<div style="box-sizing: border-box; font-size: 0; text-align: center; ">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">
|
||||
WebApp
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="35" y="161" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">
|
||||
WebApp
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 76.37 236.26 L 92.51 236.29 L 92.51 248.51 L 108.63 248.5" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<path d="M 71.12 236.25 L 78.12 232.76 L 76.37 236.26 L 78.11 239.76 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<path d="M 113.88 248.5 L 106.88 252.01 L 108.63 248.5 L 106.88 245.01 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<path d="M 35.03 245 L 35.03 265.03 L 35.03 261.03 L 35.01 274.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<path d="M 35 279.88 L 31.51 272.88 L 35.01 274.63 L 38.51 272.89 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<path d="M 76.37 218.76 L 92.51 218.8 L 92.51 206.51 L 108.63 206.5" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<path d="M 71.12 218.75 L 78.13 215.27 L 76.37 218.76 L 78.11 222.27 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<path d="M 113.88 206.5 L 106.88 210.01 L 108.63 206.5 L 106.88 203.01 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<rect x="0" y="210" width="70" height="35" fill="#ffffff" stroke="#000000" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 68px; height: 1px; padding-top: 228px; margin-left: 1px;">
|
||||
<div style="box-sizing: border-box; font-size: 0; text-align: center; ">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">
|
||||
???
|
||||
<br/>
|
||||
Application
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="35" y="231" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">
|
||||
???...
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<rect x="115" y="189" width="70" height="35" fill="#ffffff" stroke="#000000" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 68px; height: 1px; padding-top: 207px; margin-left: 116px;">
|
||||
<div style="box-sizing: border-box; font-size: 0; text-align: center; ">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">
|
||||
Router
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="150" y="210" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">
|
||||
Router
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 150 272.37 L 150 286 L 150 278 L 150 291.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<path d="M 150 267.12 L 153.5 274.12 L 150 272.37 L 146.5 274.12 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<path d="M 150 296.88 L 146.5 289.88 L 150 291.63 L 153.5 289.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<rect x="115" y="231" width="70" height="35" fill="#ffffff" stroke="#000000" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 68px; height: 1px; padding-top: 249px; margin-left: 116px;">
|
||||
<div style="box-sizing: border-box; font-size: 0; text-align: center; ">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">
|
||||
Dispatcher
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="150" y="252" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">
|
||||
Dispatcher
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 150 333 L 150 353.03 L 150 340 L 150 353.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<path d="M 150 358.88 L 146.5 351.88 L 150 353.63 L 153.5 351.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<path d="M 191.37 315.49 L 205.03 315.49 L 195.03 315.49 L 208.63 315.49" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<path d="M 186.12 315.49 L 193.12 311.99 L 191.37 315.49 L 193.12 318.99 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<path d="M 213.88 315.49 L 206.88 318.99 L 208.63 315.49 L 206.88 311.99 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<rect x="115" y="298" width="70" height="35" fill="#ffffff" stroke="#000000" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 68px; height: 1px; padding-top: 316px; margin-left: 116px;">
|
||||
<div style="box-sizing: border-box; font-size: 0; text-align: center; ">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">
|
||||
Modules /
|
||||
<br/>
|
||||
Controller
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="150" y="319" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">
|
||||
Modules /...
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 291.37 315.49 L 305.03 315.49 L 300 315.49 L 313.63 315.49" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<path d="M 286.12 315.49 L 293.12 311.99 L 291.37 315.49 L 293.12 318.99 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<path d="M 318.88 315.49 L 311.88 318.99 L 313.63 315.49 L 311.88 311.99 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<path d="M 250 339.37 L 250 353.03 L 250 340 L 250 353.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<path d="M 250 334.12 L 253.5 341.12 L 250 339.37 L 246.5 341.12 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<path d="M 250 358.88 L 246.5 351.88 L 250 353.63 L 253.5 351.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<rect x="215" y="298" width="70" height="35" fill="#ffffff" stroke="#000000" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 68px; height: 1px; padding-top: 316px; margin-left: 216px;">
|
||||
<div style="box-sizing: border-box; font-size: 0; text-align: center; ">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">
|
||||
Mapper
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="250" y="319" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">
|
||||
Mapper
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<rect x="320" y="298" width="70" height="35" fill="#ffffff" stroke="#000000" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 68px; height: 1px; padding-top: 316px; margin-left: 321px;">
|
||||
<div style="box-sizing: border-box; font-size: 0; text-align: center; ">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">
|
||||
Database
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="355" y="319" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">
|
||||
Database
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 150 395 L 150 415.03 L 150 401.03 L 150 414.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<path d="M 150 419.88 L 146.5 412.88 L 150 414.63 L 153.5 412.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<rect x="115" y="360" width="70" height="35" fill="#ffffff" stroke="#000000" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 68px; height: 1px; padding-top: 378px; margin-left: 116px;">
|
||||
<div style="box-sizing: border-box; font-size: 0; text-align: center; ">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">
|
||||
View
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="150" y="381" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">
|
||||
View
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<rect x="115" y="421" width="70" height="35" fill="#ffffff" stroke="#000000" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 68px; height: 1px; padding-top: 439px; margin-left: 116px;">
|
||||
<div style="box-sizing: border-box; font-size: 0; text-align: center; ">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">
|
||||
Template
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="150" y="442" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">
|
||||
Template
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<ellipse cx="35" cy="311" rx="30" ry="30" fill="#ffffff" stroke="#000000" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 58px; height: 1px; padding-top: 311px; margin-left: 6px;">
|
||||
<div style="box-sizing: border-box; font-size: 0; text-align: center; ">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">
|
||||
Response
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="35" y="315" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">
|
||||
Response
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<rect x="215" y="360" width="70" height="35" fill="#ffffff" stroke="#000000" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 68px; height: 1px; padding-top: 378px; margin-left: 216px;">
|
||||
<div style="box-sizing: border-box; font-size: 0; text-align: center; ">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">
|
||||
Model
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="250" y="381" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">
|
||||
Model
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
</g>
|
||||
<switch>
|
||||
<g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"/>
|
||||
<a transform="translate(0,-5)" xlink:href="https://desk.draw.io/support/solutions/articles/16000042487" target="_blank">
|
||||
<text text-anchor="middle" font-size="10px" x="50%" y="100%">
|
||||
Viewer does not support full SVG 1.1
|
||||
</text>
|
||||
</a>
|
||||
</switch>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 23 KiB |
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 43 KiB |
|
|
@ -7,7 +7,7 @@ In order to setup the application for development for the first time please see
|
|||
Make sure your dev-environment or server fulfills the following requirements:
|
||||
|
||||
* PHP >= 7.4
|
||||
* PHP extensions: mbstring, gd, zip, dom, mysql/pgsql/sqlsrv, sqlite, bcmath, imap*, redis*, memcached*, ftp*, socket*, curl*, xml*
|
||||
* PHP extensions: mbstring, gd, zip, dom, mysql/pgsql/sqlsrv, sqlite, bcmath, imap\*, redis\*, memcached\*, ftp\*, socket\*, curl\*, xml\*
|
||||
* databases: mysql, postgresql, sqlsrv
|
||||
* webserver: apache2
|
||||
* mod_headers
|
||||
|
|
@ -35,7 +35,7 @@ The following steps will setup the application, download all necessary tools and
|
|||
After the installation you'll have access to the following content:
|
||||
|
||||
* Application: `http://127.0.0.1`
|
||||
* Code Coverager: `http://127.0.0.1/Build/coverage/`
|
||||
* Code Coverage: `http://127.0.0.1/Build/coverage/`
|
||||
* Test Report: `${INSPECTION_PATH}/test/ReportExternal`
|
||||
* Unit Test Report: `${INSPECTION_PATH}/test/testdox.txt`
|
||||
* PHPStan Report: `${INSPECTION_PATH}/test/phpstan.json`
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ The user request gets passed through the entire application to all modules. The
|
|||
|
||||
The routes usually reference endpoints in the module `controllers` which collects the model data through the model `mapper` and creates a partial response `view` with an assigned `template` and the collected model data.
|
||||
|
||||

|
||||

|
||||
|
||||
In the following only the WebApplication and Application are mentioned as the other components are explained in detail in their respective documentation.
|
||||
|
||||
|
|
@ -31,6 +31,6 @@ Furthermore the Application also performs a `CSRF` check, defines the `CSP`, aut
|
|||
|
||||
## Database
|
||||
|
||||
A short extract of the database structure can be seen below. Please note that this only contains the very basic tables from a fresh install without very limited modules and even then we only included the key tables for simplicity reasons.
|
||||
A short extract of the database structure can be seen below. Please note that this only contains the very basic tables from a fresh install with very few modules and even then we only included the key tables for simplicity reasons.
|
||||
|
||||

|
||||

|
||||
|
|
@ -1,6 +1,55 @@
|
|||
# Inspections
|
||||
# Code Inspections & Tests
|
||||
|
||||
Code inspections are very important in order to maintain the same code quality throughout the application. The Build repository contains all esential configuration files for the respective inspection tools. Every provided module will be evaluated based on the predefined code and quality standards. Only modules that pass all code, quality and unit tests are accepted. This also applies to updates and bug fixes. Any change will have to be re-evaluated.
|
||||
Code inspections are very important in order to maintain the same code quality throughout the application. The `Build` repository and package managers such as `composer` and `npm` contain all esential configuration files for the respective inspection tools. The framework and every module will be evaluated based on the defined code and quality standards. Only code that passes all code, quality and test standards are accepted. Updates and bug fixes also must follow the standards.
|
||||
|
||||
## How and what to test?
|
||||
|
||||
In this project multiple levels of tests must be implemented such as unit tests, integration tests and system tests.
|
||||
|
||||
The following testing requirements must be met:
|
||||
|
||||
* 90% code coverage in the tests
|
||||
* all tests must pass without warnings, errors and exceptions
|
||||
* no warnings and errors during static code inspections
|
||||
* no usage of deprecated function calls
|
||||
* no code style violations
|
||||
* every test should have a short description for the test report
|
||||
* every file containing code (except enums, traits, interfaces and template files) must have their own test file with tests
|
||||
|
||||
When testing it makes sense to test for the happy path/branch of how a method should work and to `try` and break things by trying to find inputs and paths which may lead to unexpected behavior and errors.
|
||||
|
||||
### Unit tests
|
||||
|
||||
The smallest/lowest level of testing are the unit tests. Unit tests should be implemented for models and framework methods. Every public function should be covered by at least one unit test. If a method has multiple branches every branch should be covered by a separate unit test. In some cases it might make sense to cover multiple branches in one unit test/test function, such a decision should however be made conciously.
|
||||
|
||||
### Integration tests
|
||||
|
||||
Integration tests are the second level or middle level of tests. These types of tests are used for example for module controllers. In such tests you should mock a request and test the response.
|
||||
|
||||
For large controllers it can make sense to define a `*ControllerTest` which uses `Traits` in order to categorize different suits of tests. For example in the `Admin` ApiControllerTest we implemented different traits for group, account and module tests.
|
||||
|
||||
### System tests
|
||||
|
||||
The system tests are the highest level of tests and test the overall functionality and if the implementation fulfills the specifications.
|
||||
|
||||
### Modules
|
||||
|
||||
Every module must implement the following tests if applicable:
|
||||
|
||||
* general module tests (e.g. install, update, delete, status change)
|
||||
* admin tests (`use \Modules\tests\ModuleTestTrait;`)
|
||||
* model tests (unit tests)
|
||||
* controller tests (e.g. ApiController tests)
|
||||
* view tests
|
||||
|
||||
You can find an example in the TestModule.
|
||||
|
||||
## Test documentation
|
||||
|
||||
* every test must have a short test description
|
||||
* every test and description must be added to the test report
|
||||
* every test needs a test category (e.g. framework, module etc.)
|
||||
* every test should have a @covers annotation to specify which class it covers
|
||||
|
||||
## Tools
|
||||
|
||||
|
|
@ -14,7 +63,7 @@ Tools used for the code inspection are:
|
|||
|
||||
These tools are all installed by running the `setup.sh` script from the Build repository.
|
||||
|
||||
## PHPUnit
|
||||
### PHPUnit
|
||||
|
||||
This application uses PHPUnit as unit testing framework. Unit tests for specific classes need to be named in the same manner as the testing class.
|
||||
|
||||
|
|
@ -30,23 +79,23 @@ In order to also create a code coverage report run:
|
|||
php vendor/bin/phpunit -c tests/PHPUnit/phpunit_default.xml
|
||||
```
|
||||
|
||||
### Modules
|
||||
#### Modules
|
||||
|
||||
Every module needs to have a `Admin` directory containing a class called `AdminTest.php` which is used for testing the installation, activation, deactivation, uninstall and remove of the module. Tests that install, update, remove etc. a module need to have a group called `admin`. After running the `AdminTest.php` test the final state of the module should be installed and active, only this way it's possible to further test the controller and models. A code coverage of at least 80% is mandatory for every module for integration.
|
||||
|
||||
## PHPStan
|
||||
### PHPStan
|
||||
|
||||
With phpstan the code base is statically analyzed based on its configuration. This will help you to follow some of the "best" practices we enforce.
|
||||
|
||||
```sh
|
||||
php vendor/bin/phpstan analyse --autoload-file=phpOMS/Autoloader.php -l 7 -c Build/Config/phpstan.neon --error-format=prettyJson ./ > Build/test/phpstan.json
|
||||
php vendor/bin/phpstan analyse --autoload-file=phpOMS/Autoloader.php -l 8 -c Build/Config/phpstan.neon --error-format=prettyJson ./ > Build/test/phpstan.json
|
||||
```
|
||||
|
||||
## Jasmine
|
||||
### Jasmine
|
||||
|
||||
The javascript testing is done with jasmine. The javascript testing directory is structured the same way as the `Framework`. Unit tests for specific classes need to be named in the same manner as the testing class.
|
||||
|
||||
## PHP CS
|
||||
### PHP CS
|
||||
|
||||
Besides the code tests and static code analysis the code style is another very imporant inspection to ensure the code quality.
|
||||
|
||||
|
|
@ -54,7 +103,7 @@ Besides the code tests and static code analysis the code style is another very i
|
|||
php vendor/bin/phpcs ./ --standard="Build/Config/phpcs.xml" -s --report-junit=Build/test/junit_phpcs.xml
|
||||
```
|
||||
|
||||
## Git Hooks (Linux only)
|
||||
### Git Hooks (Linux only)
|
||||
|
||||
The git hooks perform various checks and validations during the `commit` and warn the developer about invalid code or code style/guideline violations.
|
||||
|
||||
|
|
|
|||
0
quality/release.md
Normal file
0
quality/release.md
Normal file
|
|
@ -23,7 +23,7 @@ if($request->getData('CSRF') === null) {
|
|||
$response->setStatusCode(RequestStatus::R_403);
|
||||
|
||||
/* optional */
|
||||
$response->set($request->getUri()->__toString(), new Notify('Unknown referrer!', NotifyType::INFO));
|
||||
$response->set($request->uri->__toString(), new Notify('Unknown referrer!', NotifyType::INFO));
|
||||
|
||||
return;
|
||||
}
|
||||
|
|
@ -56,13 +56,13 @@ Scripts and frames must be provided by the own server or google. This is importa
|
|||
The default CSP looks like the following:
|
||||
|
||||
```php
|
||||
$response->getHeader()->set('content-security-policy', 'script-src \'self\'; frame-src \'self\'', true);
|
||||
$response->header->set('content-security-policy', 'script-src \'self\'; frame-src \'self\'', true);
|
||||
```
|
||||
|
||||
In order to whitelist inline javascript you can use the following logic. This however requires you to know the inline script beforehand `$script`. After setting the CSP header they automatically get locked so that further changes are not possible. This is a security measure in order to prevent any malicious adjustments.
|
||||
|
||||
```php
|
||||
$response->getHeader()->set('content-security-policy', 'script-src \'self\' \'sha256-' . base64_encode(hash('sha256', $script, true)) . '\'; frame-src \'self\'', true);
|
||||
$response->header->set('content-security-policy', 'script-src \'self\' \'sha256-' . base64_encode(hash('sha256', $script, true)) . '\'; frame-src \'self\'', true);
|
||||
```
|
||||
|
||||
### X-XSS-Protection
|
||||
|
|
@ -70,7 +70,7 @@ $response->getHeader()->set('content-security-policy', 'script-src \'self\' \'sh
|
|||
This header tells the client browser to use local xss protection if available.
|
||||
|
||||
```php
|
||||
$response->getHeader()->set('x-xss-protection', '1; mode=block');
|
||||
$response->header->set('x-xss-protection', '1; mode=block');
|
||||
```
|
||||
|
||||
### X-Content-Type-Options
|
||||
|
|
@ -78,7 +78,7 @@ $response->getHeader()->set('x-xss-protection', '1; mode=block');
|
|||
By using this header browsers which support this feature will ignore the content/mime and recognize the file by the provided header only.
|
||||
|
||||
```php
|
||||
$response->getHeader()->set('x-content-type-options', 'nosniff');
|
||||
$response->header->set('x-content-type-options', 'nosniff');
|
||||
```
|
||||
|
||||
### X-Frame-Options
|
||||
|
|
@ -86,7 +86,7 @@ $response->getHeader()->set('x-content-type-options', 'nosniff');
|
|||
The x-frame-options is providing the same protection for frames as the content-security-policy header. Please only use this header in addition to the content-security-policy if you have to but make sure the rules don't contradict with the content-security-policy.
|
||||
|
||||
```php
|
||||
$response->getHeader()->set('x-frame-options', 'SAMEORIGIN');
|
||||
$response->header->set('x-frame-options', 'SAMEORIGIN');
|
||||
```
|
||||
|
||||
## Superglobals
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ Now the event will be removed from the event manager once executed.
|
|||
|
||||
### Resetting events
|
||||
|
||||
In case an event should be reset (all conditions mut be met again befor it can be triggered) after it got successfully triggered one more parameter can be added.
|
||||
In case an event should be reset (all conditions must be met again before it can be triggered) after it got successfully triggered one more parameter can be added.
|
||||
|
||||
```php
|
||||
$eventManager->attach('eventId', function() { echo 'Hello World'; }, false, true);
|
||||
|
|
@ -40,7 +40,7 @@ $eventManager->trigger('eventId');
|
|||
|
||||
## Multi Condition Events
|
||||
|
||||
In some cases it is required that multiple conditions are met before an event is supposed to be triggered. This can be achived by registering these conditions through the `addGroup()` function.
|
||||
In some cases it is required that multiple conditions are met before an event is supposed to be triggered. This can be achieved by registering these conditions through the `addGroup()` function.
|
||||
|
||||
```php
|
||||
$eventManager->addGroup('eventId', 'conditionName');
|
||||
|
|
@ -58,8 +58,8 @@ $eventManager->trigger('eventId', 'conditionName'); // No output (if remove = fa
|
|||
$eventManager->trigger('eventId', 'conditionName'); // No output (if remove = true)
|
||||
```
|
||||
|
||||
The order in which these conditions are triggered doesn't mapper. A multi condition event SHOULD be atteched with the optional boolean parameter `true`. These events can only be executed once and will be removed afterwards. In case the optional boolean parameter was not set to `true` the event will remain in the event manager and will be triggered whenever `trigger('eventId')` is called.
|
||||
The order in which these conditions are triggered doesn't mapper. A multi condition event SHOULD be attached with the optional boolean parameter `true`. These events can only be executed once and will be removed afterwards. In case the optional boolean parameter was not set to `true` the event will remain in the event manager and will be triggered whenever `trigger('eventId')` is called.
|
||||
|
||||
## Frontend vs. Backend
|
||||
|
||||
The only key difference between the frontend and backend implementation is that the frontend prevents runnning the same event in quick succession (less than 500 ms) in order to prevent undesired effects which can happen due to quick UI interaction.
|
||||
The only key difference between the frontend and backend implementation is that the frontend prevents running the same event in quick succession (less than 500 ms) in order to prevent undesired effects which can happen due to quick UI interaction.
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ Some default parameters can be used for easier use.
|
|||
|
||||
While it's also possible to define parameters at the frontend and make use of the default values certain prefixes have a special meaning.
|
||||
|
||||
* \#somid = value of the element with the specified id
|
||||
* \#someid = value of the element with the specified id
|
||||
* .somclass = values of the elements with the specified class
|
||||
|
||||
### Dynamic Parameters
|
||||
|
|
|
|||
|
|
@ -1,5 +1,35 @@
|
|||
# Documentation
|
||||
|
||||
## Module
|
||||
|
||||
Every module must have two types of documentation. One for the end-user, which also includes information for the administrator and module configuration and another documentation for developers. Documentation must be available in at least english language.
|
||||
|
||||
### User
|
||||
|
||||
The user documentation should cover the following aspects:
|
||||
|
||||
* Installation, update, status change and delete process
|
||||
* Dependencies and requirements
|
||||
* Configuration options
|
||||
* Permission management
|
||||
* How to use the module and its functionality from an end-user perspective
|
||||
|
||||
### Developer
|
||||
|
||||
The developer documentation should cover the following aspects:
|
||||
|
||||
* Database UML diagram (incl. relations to other modules)
|
||||
* How to interact with the controllers, views and models from other modules
|
||||
* How to interact with the controllers, views and models from within the module
|
||||
* Best practices (does and don'ts)
|
||||
* Module specific guidelines & contribution information
|
||||
|
||||
## Database
|
||||
|
||||
### Diagramms
|
||||
|
||||
Every module that has a database table must implement a UML diagram illustrating the internal table relations as well as the relations with external tables from other modules.
|
||||
|
||||
## Php
|
||||
|
||||
The php documentation is based on PhpDocumentor, therefore only valid PhpDocumentor comments are valid for files, classes, functions/methods and (member) variables.
|
||||
|
|
|
|||
|
|
@ -119,6 +119,15 @@ if (...) {
|
|||
$result = condition ? expr1 : expr2;
|
||||
```
|
||||
|
||||
Multiline ternary expressions should be indented.
|
||||
|
||||
|
||||
```php
|
||||
$result = condition
|
||||
? very long expr1 which should be written like this
|
||||
: very long expr2 which should be written like this;
|
||||
```
|
||||
|
||||
Multiline `if` conditions should begin with a logical opperator `or`/`and`.
|
||||
|
||||
```php
|
||||
|
|
@ -132,7 +141,9 @@ if (isTrue == true
|
|||
|
||||
Switch statements must have a `default` case.
|
||||
|
||||
## Constants
|
||||
## Naming
|
||||
|
||||
### Constants
|
||||
|
||||
Constants must be written with capital letters and snake case.
|
||||
|
||||
|
|
@ -140,18 +151,38 @@ Constants must be written with capital letters and snake case.
|
|||
CONSTANT_TEST = true;
|
||||
```
|
||||
|
||||
## Variables
|
||||
### Function
|
||||
|
||||
Variables must be written in camel case.
|
||||
Functions must be written in camelCase.
|
||||
|
||||
### Boolean variables
|
||||
### Variables
|
||||
|
||||
Variables must be written in camelCase.
|
||||
|
||||
#### Boolean variables
|
||||
|
||||
Boolean variable names should start with a boolean expression (e.g. is, has)
|
||||
|
||||
#### Boolean return value
|
||||
##### Boolean return value
|
||||
|
||||
Functions which return a boolean value should start with expressions such as is*, has* or similar expressions to indicate that the function returns a boolean value.
|
||||
|
||||
### Database
|
||||
|
||||
#### Tables
|
||||
|
||||
Tables must be written in snake_case
|
||||
|
||||
#### Fields / Columns
|
||||
|
||||
Fields/columns must be written in snake_case and must be preceded by the table name.
|
||||
|
||||
```sql
|
||||
table_name_field_name
|
||||
```
|
||||
|
||||
This allows every field/column name to be unique.
|
||||
|
||||
## Quotation
|
||||
|
||||
All string representations should use single quotes `''` unless `""` provides significant benefits in a specific use case.
|
||||
|
|
@ -162,14 +193,66 @@ All string representations should use single quotes `''` unless `""` provides si
|
|||
|
||||
## Todos
|
||||
|
||||
Most issues should be documented in the code as todos and vice versa.
|
||||
Most issues should be documented in the code as todo and vice versa.
|
||||
|
||||
```php
|
||||
/**
|
||||
* @todo Orange-Management/Repository#IssueNumber
|
||||
* @todo Orange-Management/Repository#IssueNumber [issue:information]
|
||||
* Below comes the issue/todo description.
|
||||
* This way developers can see todos directly in the code without going to an external source.
|
||||
* Todos must not have empty lines in their descriptions.
|
||||
* If the external ressources have empty lines they must be removed in the todo comment.
|
||||
* 1. list item 1
|
||||
* 2. list item 2
|
||||
*/
|
||||
```
|
||||
```
|
||||
|
||||
The issue information can be used to provide additional information such as priority, difficulty and type.
|
||||
|
||||
### Priority
|
||||
|
||||
Structure:
|
||||
|
||||
```php
|
||||
[p:{PRIORITY}]
|
||||
```
|
||||
|
||||
Possible priorities are:
|
||||
|
||||
* high
|
||||
* low
|
||||
* medium
|
||||
|
||||
### Difficulty
|
||||
|
||||
Structure:
|
||||
|
||||
```php
|
||||
[d:{DIFFICULTY}]
|
||||
```
|
||||
|
||||
Possible difficulties are:
|
||||
|
||||
* first
|
||||
* beginner
|
||||
* expert
|
||||
* medium
|
||||
|
||||
Difficulties marked with first are perfect for people who would like to contribute to the project for the first time.
|
||||
|
||||
### Type
|
||||
|
||||
Structure:
|
||||
|
||||
```php
|
||||
[t:{TYPE}]
|
||||
```
|
||||
|
||||
Possible types are:
|
||||
|
||||
* feature
|
||||
* optimization
|
||||
* performance
|
||||
* question
|
||||
* security
|
||||
* todo (= default)
|
||||
|
|
@ -73,6 +73,12 @@ Class constants MUST have a access modifier
|
|||
public CONST_NAME = ...;
|
||||
```
|
||||
|
||||
## Preferred Functions
|
||||
|
||||
### file_exists
|
||||
|
||||
Instead of using `\file_exists()` the functions `\is_dir()` or `\is_file()` should be used.
|
||||
|
||||
## Deprecated functions and variables
|
||||
|
||||
The following functions and (super-) global variables MUST NOT be used.
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user