add the db scheme in the readme
This commit is contained in:
parent
0e66e87052
commit
8aa68f8a0a
2 changed files with 219 additions and 60 deletions
128
README.md
128
README.md
|
@ -1,4 +1,12 @@
|
|||
# PHP-CRUD-API
|
||||
# Todo API
|
||||
|
||||
## Database
|
||||
|
||||

|
||||
|
||||
Its relying on PHP-CRUD-API, with the original README here :
|
||||
|
||||
## PHP-CRUD-API
|
||||
|
||||
Single file PHP script that adds a REST API to a MySQL/MariaDB, PostgreSQL, SQL Server or SQLite database.
|
||||
|
||||
|
@ -25,7 +33,7 @@ There are also proof-of-concept ports of this script that only support basic RES
|
|||
[Node.js](https://github.com/mevdschee/js-crud-api/blob/master/app.js) and
|
||||
[Python](https://github.com/mevdschee/py-crud-api/blob/master/api.py).
|
||||
|
||||
## Requirements
|
||||
### Requirements
|
||||
|
||||
- PHP 7.0 or higher with PDO drivers enabled for one of these database systems:
|
||||
- MySQL 5.6 / MariaDB 10.0 or higher for spatial features in MySQL
|
||||
|
@ -33,7 +41,7 @@ There are also proof-of-concept ports of this script that only support basic RES
|
|||
- SQL Server 2012 or higher (2017 for Linux support)
|
||||
- SQLite 3.16 or higher (spatial features NOT supported)
|
||||
|
||||
## Installation
|
||||
### Installation
|
||||
|
||||
This is a single file application! Upload "`api.php`" somewhere and enjoy!
|
||||
|
||||
|
@ -58,7 +66,7 @@ In these integrations [Composer](https://getcomposer.org/) is used to load this
|
|||
For people that don't use composer, the file "`api.include.php`" is provided. This file contains everything
|
||||
from "`api.php`" except the configuration from "`src/index.php`" and can be used by PHP's "include".
|
||||
|
||||
## Configuration
|
||||
### Configuration
|
||||
|
||||
Edit the following lines in the bottom of the file "`api.php`":
|
||||
|
||||
|
@ -98,7 +106,7 @@ All configuration options are also available as environment variables. Write the
|
|||
|
||||
The environment variables take precedence over the PHP configuration.
|
||||
|
||||
## Limitations
|
||||
### Limitations
|
||||
|
||||
These limitation and constrains apply:
|
||||
|
||||
|
@ -110,7 +118,7 @@ These limitation and constrains apply:
|
|||
- SQLite cannot have bigint typed auto incrementing primary keys
|
||||
- SQLite does not support altering table columns (structure)
|
||||
|
||||
## Features
|
||||
### Features
|
||||
|
||||
The following features are supported:
|
||||
|
||||
|
@ -138,7 +146,7 @@ The following features are supported:
|
|||
- Security enhancing middleware is included
|
||||
- Standard compliant: PSR-4, PSR-7, PSR-12, PSR-15 and PSR-17
|
||||
|
||||
## Compilation
|
||||
### Compilation
|
||||
|
||||
You can install all dependencies of this project using the following command:
|
||||
|
||||
|
@ -150,7 +158,7 @@ You can compile all files into a single "`api.php`" file using:
|
|||
|
||||
NB: The install script will patch the dependencies in the vendor directory for PHP 7.0 compatibility.
|
||||
|
||||
### Development
|
||||
#### Development
|
||||
|
||||
You can access the non-compiled code at the URL:
|
||||
|
||||
|
@ -158,7 +166,7 @@ You can access the non-compiled code at the URL:
|
|||
|
||||
The non-compiled code resides in the "`src`" and "`vendor`" directories. The "`vendor`" directory contains the dependencies.
|
||||
|
||||
### Updating dependencies
|
||||
#### Updating dependencies
|
||||
|
||||
You can update all dependencies of this project using the following command:
|
||||
|
||||
|
@ -168,13 +176,13 @@ This script will install and run [Composer](https://getcomposer.org/) to update
|
|||
|
||||
NB: The update script will patch the dependencies in the vendor directory for PHP 7.0 compatibility.
|
||||
|
||||
## TreeQL, a pragmatic GraphQL
|
||||
### TreeQL, a pragmatic GraphQL
|
||||
|
||||
[TreeQL](https://treeql.org) allows you to create a "tree" of JSON objects based on your SQL database structure (relations) and your query.
|
||||
|
||||
It is loosely based on the REST standard and also inspired by json:api.
|
||||
|
||||
### CRUD + List
|
||||
#### CRUD + List
|
||||
|
||||
The example posts table has only a a few fields:
|
||||
|
||||
|
@ -187,7 +195,7 @@ The example posts table has only a a few fields:
|
|||
|
||||
The CRUD + List operations below act on this table.
|
||||
|
||||
#### Create
|
||||
##### Create
|
||||
|
||||
If you want to create a record the request can be written in URL format as:
|
||||
|
||||
|
@ -205,7 +213,7 @@ And it will return the value of the primary key of the newly created record:
|
|||
|
||||
2
|
||||
|
||||
#### Read
|
||||
##### Read
|
||||
|
||||
To read a record from this table the request can be written in URL format as:
|
||||
|
||||
|
@ -222,7 +230,7 @@ Where "1" is the value of the primary key of the record that you want to read. I
|
|||
|
||||
On read operations you may apply joins.
|
||||
|
||||
#### Update
|
||||
##### Update
|
||||
|
||||
To update a record in this table the request can be written in URL format as:
|
||||
|
||||
|
@ -238,7 +246,7 @@ This adjusts the title of the post. And the return value is the number of rows t
|
|||
|
||||
1
|
||||
|
||||
#### Delete
|
||||
##### Delete
|
||||
|
||||
If you want to delete a record from this table the request can be written in URL format as:
|
||||
|
||||
|
@ -248,7 +256,7 @@ And it will return the number of deleted rows:
|
|||
|
||||
1
|
||||
|
||||
#### List
|
||||
##### List
|
||||
|
||||
To list records from this table the request can be written in URL format as:
|
||||
|
||||
|
@ -269,7 +277,7 @@ It will return:
|
|||
|
||||
On list operations you may apply filters and joins.
|
||||
|
||||
### Filters
|
||||
#### Filters
|
||||
|
||||
Filters provide search functionality, on list calls, using the "filter" parameter. You need to specify the column
|
||||
name, a comma, the match type, another commma and the value you want to filter on. These are supported match types:
|
||||
|
@ -309,7 +317,7 @@ Output:
|
|||
|
||||
In the next section we dive deeper into how you can apply multiple filters on a single list call.
|
||||
|
||||
### Multiple filters
|
||||
#### Multiple filters
|
||||
|
||||
Filters can be a by applied by repeating the "filter" parameter in the URL. For example the following URL:
|
||||
|
||||
|
@ -325,7 +333,7 @@ by adding a letter (a-f) you can create almost any reasonably complex condition
|
|||
|
||||
NB: You can only filter on the requested table (not on it's included tables) and filters are only applied on list calls.
|
||||
|
||||
### Column selection
|
||||
#### Column selection
|
||||
|
||||
By default all columns are selected. With the "include" parameter you can select specific columns.
|
||||
You may use a dot to separate the table name from the column name. Multiple columns should be comma separated.
|
||||
|
@ -347,7 +355,7 @@ Output:
|
|||
|
||||
NB: Columns that are used to include related entities are automatically added and cannot be left out of the output.
|
||||
|
||||
### Ordering
|
||||
#### Ordering
|
||||
|
||||
With the "order" parameter you can sort. By default the sort is in ascending order, but by specifying "desc" this can be reversed:
|
||||
|
||||
|
@ -375,7 +383,7 @@ Output:
|
|||
|
||||
NB: You may sort on multiple fields by using multiple "order" parameters. You can not order on "joined" columns.
|
||||
|
||||
### Limit size
|
||||
#### Limit size
|
||||
|
||||
The "size" parameter limits the number of returned records. This can be used for top N lists together with the "order" parameter (use descending order).
|
||||
|
||||
|
@ -398,7 +406,7 @@ Output:
|
|||
|
||||
NB: If you also want to know to the total number of records you may want to use the "page" parameter.
|
||||
|
||||
### Pagination
|
||||
#### Pagination
|
||||
|
||||
The "page" parameter holds the requested page. The default page size is 20, but can be adjusted (e.g. to 50).
|
||||
|
||||
|
@ -427,7 +435,7 @@ Output:
|
|||
|
||||
NB: Since pages that are not ordered cannot be paginated, pages will be ordered by primary key.
|
||||
|
||||
### Joins
|
||||
#### Joins
|
||||
|
||||
Let's say that you have a posts table that has comments (made by users) and the posts can have tags.
|
||||
|
||||
|
@ -510,7 +518,7 @@ This may lead to the following JSON data:
|
|||
You see that the "belongsTo" relationships are detected and the foreign key value is replaced by the referenced object.
|
||||
In case of "hasMany" and "hasAndBelongsToMany" the table name is used a new property on the object.
|
||||
|
||||
### Batch operations
|
||||
#### Batch operations
|
||||
|
||||
When you want to create, read, update or delete you may specify multiple primary key values in the URL.
|
||||
You also need to send an array instead of an object in the request body for create and update.
|
||||
|
@ -574,7 +582,7 @@ of the batch failed due to an integrity violation:
|
|||
|
||||
The response status code will always be 424 (failed dependency) in case of any failure of one of the batch operations.
|
||||
|
||||
### Spatial support
|
||||
#### Spatial support
|
||||
|
||||
For spatial support there is an extra set of filters that can be applied on geometry columns and that starting with an "s":
|
||||
|
||||
|
@ -592,7 +600,7 @@ For spatial support there is an extra set of filters that can be applied on geom
|
|||
|
||||
These filters are based on OGC standards and so is the WKT specification in which the geometry columns are represented.
|
||||
|
||||
#### GeoJSON
|
||||
##### GeoJSON
|
||||
|
||||
The GeoJSON support is a read-only view on the tables and records in GeoJSON format. These requests are supported:
|
||||
|
||||
|
@ -615,7 +623,7 @@ The following Geometry types are supported by the GeoJSON implementation:
|
|||
|
||||
The GeoJSON functionality is enabled by default, but can be disabled using the "controllers" configuration.
|
||||
|
||||
## Middleware
|
||||
### Middleware
|
||||
|
||||
You can enable the following middleware using the "middlewares" config parameter:
|
||||
|
||||
|
@ -709,7 +717,7 @@ If you don't specify these parameters in the configuration, then the default val
|
|||
|
||||
In the sections below you find more information on the built-in middleware.
|
||||
|
||||
### Authentication
|
||||
#### Authentication
|
||||
|
||||
Currently there are three types of authentication supported. They all store the authenticated user in the `$_SESSION` super global.
|
||||
This variable can be used in the authorization handlers to decide wether or not sombeody should have read or write access to certain tables, columns or records.
|
||||
|
@ -723,7 +731,7 @@ The following overview shows the kinds of authentication middleware that you can
|
|||
|
||||
Below you find more information on each of the authentication types.
|
||||
|
||||
#### Database authentication
|
||||
##### Database authentication
|
||||
|
||||
The database authentication middleware defines three new routes:
|
||||
|
||||
|
@ -752,7 +760,7 @@ users can freely add, modify or delete any account! The minimal configuration is
|
|||
|
||||
Note that this middleware uses session cookies and stores the logged in state on the server.
|
||||
|
||||
#### Basic authentication
|
||||
##### Basic authentication
|
||||
|
||||
The Basic type supports a file (by default '.htpasswd') that holds the users and their (hashed) passwords separated by a colon (':').
|
||||
When the passwords are entered in plain text they fill be automatically hashed.
|
||||
|
@ -763,7 +771,7 @@ You need to send an "Authorization" header containing a base64 url encoded and c
|
|||
|
||||
This example sends the string "username1:password1".
|
||||
|
||||
#### JWT authentication
|
||||
##### JWT authentication
|
||||
|
||||
The JWT type requires another (SSO/Identity) server to sign a token that contains claims.
|
||||
Both servers share a secret so that they can either sign or verify that the signature is valid.
|
||||
|
@ -786,7 +794,7 @@ This example sends the signed claims:
|
|||
|
||||
NB: The JWT implementation only supports the RSA and HMAC based algorithms.
|
||||
|
||||
##### Configure and test JWT authentication with Auth0
|
||||
###### Configure and test JWT authentication with Auth0
|
||||
|
||||
First you need to create an account on [Auth0](https://auth0.com/auth/login).
|
||||
Once logged in, you have to create an application (its type does not matter). Collect the `Domain`
|
||||
|
@ -812,7 +820,7 @@ You can also change the `url` variable, used to test the API with authentication
|
|||
|
||||
[More info](https://auth0.com/docs/api-auth/tutorials/verify-access-token)
|
||||
|
||||
##### Configure and test JWT authentication with Firebase
|
||||
###### Configure and test JWT authentication with Firebase
|
||||
|
||||
First you need to create a Firebase project on the [Firebase console](https://console.firebase.google.com/).
|
||||
Add a web application to this project and grab the code snippet for later use.
|
||||
|
@ -852,7 +860,7 @@ You can also change the `url` variable, used to test the API with authentication
|
|||
|
||||
[More info](https://firebase.google.com/docs/auth/admin/verify-id-tokens#verify_id_tokens_using_a_third-party_jwt_library)
|
||||
|
||||
### Authorizing operations
|
||||
#### Authorizing operations
|
||||
|
||||
The Authorization model acts on "operations". The most important ones are listed here:
|
||||
|
||||
|
@ -873,7 +881,7 @@ These operations can display or change the definition of the database, table or
|
|||
This functionality is disabled by default and for good reason (be careful!).
|
||||
Add the "columns" controller in the configuration to enable this functionality.
|
||||
|
||||
### Authorizing tables, columns and records
|
||||
#### Authorizing tables, columns and records
|
||||
|
||||
By default all tables, columns and paths are accessible. If you want to restrict access to some tables you may add the 'authorization' middleware
|
||||
and define a 'authorization.tableHandler' function that returns 'false' for these tables.
|
||||
|
@ -905,7 +913,7 @@ The above example will disabled the `/openapi` route.
|
|||
|
||||
NB: You need to handle the creation of invalid records with a validation (or sanitation) handler.
|
||||
|
||||
### SQL GRANT authorization
|
||||
#### SQL GRANT authorization
|
||||
|
||||
You can alternatively use database permissons (SQL GRANT statements) to define the authorization model. In this case you
|
||||
should not use the "authorization" middleware, but you do need to use the "reconnect" middleware. The handlers of the
|
||||
|
@ -924,7 +932,7 @@ as the permissions are not read in the reflection step.
|
|||
|
||||
NB: You may want to retrieve the username and password from the session (the "$_SESSION" variable).
|
||||
|
||||
### Sanitizing input
|
||||
#### Sanitizing input
|
||||
|
||||
By default all input is accepted and sent to the database. If you want to strip (certain) HTML tags before storing you may add
|
||||
the 'sanitation' middleware and define a 'sanitation.handler' function that returns the adjusted value.
|
||||
|
@ -935,7 +943,7 @@ the 'sanitation' middleware and define a 'sanitation.handler' function that retu
|
|||
|
||||
The above example will strip all HTML tags from strings in the input.
|
||||
|
||||
### Type sanitation
|
||||
#### Type sanitation
|
||||
|
||||
If you enable the 'sanitation' middleware, then you (automatically) also enable type sanitation. When this is enabled you may:
|
||||
|
||||
|
@ -952,7 +960,7 @@ in which tables you want to apply type sanitation (defaults to 'all'). Example:
|
|||
|
||||
Here we enable the type sanitation for date and timestamp fields in the posts and comments tables.
|
||||
|
||||
### Validating input
|
||||
#### Validating input
|
||||
|
||||
By default all input is accepted and sent to the database. If you want to validate the input in a custom way,
|
||||
you may add the 'validation' middleware and define a 'validation.handler' function that returns a boolean
|
||||
|
@ -982,7 +990,7 @@ Then the server will return a '422' HTTP status code and nice error message:
|
|||
|
||||
You can parse this output to make form fields show up with a red border and their appropriate error message.
|
||||
|
||||
### Type validations
|
||||
#### Type validations
|
||||
|
||||
If you enable the 'validation' middleware, then you (automatically) also enable type validation.
|
||||
This includes the following error messages:
|
||||
|
@ -1013,7 +1021,7 @@ Here we enable the type validation for date and timestamp fields in the posts an
|
|||
|
||||
NB: Types that are enabled will be checked for null values when the column is non-nullable.
|
||||
|
||||
### Multi-tenancy support
|
||||
#### Multi-tenancy support
|
||||
|
||||
Two forms of multi-tenancy are supported:
|
||||
|
||||
|
@ -1022,7 +1030,7 @@ Two forms of multi-tenancy are supported:
|
|||
|
||||
Below is an explanation of the corresponding middlewares.
|
||||
|
||||
#### Multi-tenancy middleware
|
||||
##### Multi-tenancy middleware
|
||||
|
||||
You may use the "multiTenancy" middleware when you have a single multi-tenant database.
|
||||
If your tenants are identified by the "customer_id" column, then you can use the following handler:
|
||||
|
@ -1036,7 +1044,7 @@ It also sets the column "customer_id" on "create" to "12" and removes the column
|
|||
|
||||
NB: You may want to retrieve the customer id from the session (the "$_SESSION" variable).
|
||||
|
||||
#### Reconnect middleware
|
||||
##### Reconnect middleware
|
||||
|
||||
You may use the "reconnect" middleware when you have a separate database for each tenant.
|
||||
If the tenant has it's own database named "customer_12", then you can use the following handler:
|
||||
|
@ -1050,7 +1058,7 @@ to use the same credentials, then you should also implement the "usernameHandler
|
|||
|
||||
NB: You may want to retrieve the database name from the session (the "$_SESSION" variable).
|
||||
|
||||
### Prevent database scraping
|
||||
#### Prevent database scraping
|
||||
|
||||
You may use the "joinLimits" and "pageLimits" middleware to prevent database scraping.
|
||||
The "joinLimits" middleware limits the table depth, number of tables and number of records returned in a join operation.
|
||||
|
@ -1068,7 +1076,7 @@ If you want to allow no more than 10 pages with a maximum of 25 records each, yo
|
|||
|
||||
NB: The maximum number of records is also applied when there is no page number specified in the request.
|
||||
|
||||
### Customization handlers
|
||||
#### Customization handlers
|
||||
|
||||
You may use the "customization" middleware to modify request and response and implement any other functionality.
|
||||
|
||||
|
@ -1081,7 +1089,7 @@ You may use the "customization" middleware to modify request and response and im
|
|||
|
||||
The above example will add a header "X-Time-Taken" with the number of seconds the API call has taken.
|
||||
|
||||
### XML middleware
|
||||
#### XML middleware
|
||||
|
||||
You may use the "xml" middleware to translate input and output from JSON to XML. This request:
|
||||
|
||||
|
@ -1111,11 +1119,11 @@ Outputs:
|
|||
|
||||
This functionality is disabled by default and must be enabled using the "middlewares" configuration setting.
|
||||
|
||||
### File uploads
|
||||
#### File uploads
|
||||
|
||||
File uploads are supported through the [FileReader API](https://caniuse.com/#feat=filereader), check out the [example](https://github.com/mevdschee/php-crud-api/blob/master/examples/clients/upload/vanilla.html).
|
||||
|
||||
## OpenAPI specification
|
||||
### OpenAPI specification
|
||||
|
||||
On the "/openapi" end-point the OpenAPI 3.0 (formerly called "Swagger") specification is served.
|
||||
It is a machine readable instant documentation of your API. To learn more, check out these links:
|
||||
|
@ -1124,7 +1132,7 @@ It is a machine readable instant documentation of your API. To learn more, check
|
|||
- [OpenAPI specification](https://swagger.io/specification/) is a manual for creating an OpenAPI specification.
|
||||
- [Swagger Petstore](https://petstore.swagger.io/) is an example documentation that is generated using OpenAPI.
|
||||
|
||||
## Cache
|
||||
### Cache
|
||||
|
||||
There are 4 cache engines that can be configured by the "cacheType" config parameter:
|
||||
|
||||
|
@ -1144,7 +1152,7 @@ The default engine has no dependencies and will use temporary files in the syste
|
|||
You may use the "cachePath" config parameter to specify the file system path for the temporary files or
|
||||
in case that you use a non-default "cacheType" the hostname (optionally with port) of the cache server.
|
||||
|
||||
## Types
|
||||
### Types
|
||||
|
||||
These are the supported types with their length, category, JSON type and format:
|
||||
|
||||
|
@ -1167,19 +1175,19 @@ These are the supported types with their length, category, JSON type and format:
|
|||
|
||||
Note that geometry is a non-jdbc type and thus has limited support.
|
||||
|
||||
## Data types in JavaScript
|
||||
### Data types in JavaScript
|
||||
|
||||
Javascript and Javascript object notation (JSON) are not very well suited for reading database records. Decimal, date/time, binary and geometry types must be represented as strings in JSON (binary is base64 encoded, geometries are in WKT format). Below are two more serious issues described.
|
||||
|
||||
### 64 bit integers
|
||||
#### 64 bit integers
|
||||
|
||||
JavaScript does not support 64 bit integers. All numbers are stored as 64 bit floating point values. The mantissa of a 64 bit floating point number is only 53 bit and that is why all integer numbers bigger than 53 bit may cause problems in JavaScript.
|
||||
|
||||
### Inf and NaN floats
|
||||
#### Inf and NaN floats
|
||||
|
||||
The valid floating point values 'Infinite' (calculated with '1/0') and 'Not a Number' (calculated with '0/0') cannot be expressed in JSON, as they are not supported by the [JSON specification](https://www.json.org). When these values are stored in a database then you cannot read them as this script outputs database records as JSON.
|
||||
|
||||
## Errors
|
||||
### Errors
|
||||
|
||||
The following errors may be reported:
|
||||
|
||||
|
@ -1216,7 +1224,7 @@ The following JSON structure is used:
|
|||
|
||||
NB: Any non-error response will have status: 200 OK
|
||||
|
||||
## Tests
|
||||
### Tests
|
||||
|
||||
I am testing mainly on Ubuntu and I have the following test setups:
|
||||
|
||||
|
@ -1230,7 +1238,7 @@ I am testing mainly on Ubuntu and I have the following test setups:
|
|||
This covers not all environments (yet), so please notify me of failing tests and report your environment.
|
||||
I will try to cover most relevant setups in the "docker" folder of the project.
|
||||
|
||||
### Running
|
||||
#### Running
|
||||
|
||||
To run the functional tests locally you may run the following command:
|
||||
|
||||
|
@ -1239,7 +1247,7 @@ To run the functional tests locally you may run the following command:
|
|||
This runs the functional tests from the "tests" directory. It uses the database dumps (fixtures) and
|
||||
database configuration (config) from the corresponding subdirectories.
|
||||
|
||||
## Nginx config example
|
||||
### Nginx config example
|
||||
|
||||
```
|
||||
server {
|
||||
|
@ -1270,7 +1278,7 @@ server {
|
|||
}
|
||||
```
|
||||
|
||||
### Docker tests
|
||||
#### Docker tests
|
||||
|
||||
Install docker using the following commands and then logout and login for the changes to take effect:
|
||||
|
||||
|
@ -1380,7 +1388,7 @@ As you can see the "run.sh" script gives you access to a prompt in a chosen the
|
|||
In this environment the local files are mounted. This allows for easy debugging on different environments.
|
||||
You may type "exit" when you are done.
|
||||
|
||||
### Docker image
|
||||
#### Docker image
|
||||
|
||||
There is a `Dockerfile` in the repository that is used to build an image at:
|
||||
|
||||
|
@ -1388,7 +1396,7 @@ There is a `Dockerfile` in the repository that is used to build an image at:
|
|||
|
||||
It will be automatically build on every release. The "latest" tag points to the last release.
|
||||
|
||||
### Docker compose
|
||||
#### Docker compose
|
||||
|
||||
This repository also contains a `docker-compose.yml` file that you can install/build/run using:
|
||||
|
||||
|
|
151
docs/scheme_mld.svg
Normal file
151
docs/scheme_mld.svg
Normal file
|
@ -0,0 +1,151 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.0//EN'
|
||||
'http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd'>
|
||||
<svg fill-opacity="1" xmlns:xlink="http://www.w3.org/1999/xlink" color-rendering="auto" color-interpolation="auto" text-rendering="auto" stroke="black" stroke-linecap="square" width="1150" stroke-miterlimit="10" shape-rendering="auto" stroke-opacity="1" fill="black" stroke-dasharray="none" font-weight="normal" stroke-width="1" viewBox="-20 70 1150 470" height="470" xmlns="http://www.w3.org/2000/svg" font-family="'Dialog'" font-style="normal" stroke-linejoin="miter" font-size="12px" stroke-dashoffset="0" image-rendering="auto"
|
||||
><!--Generated by the Batik Graphics2D SVG Generator--><defs id="genericDefs"
|
||||
/><g
|
||||
><defs id="defs1"
|
||||
><clipPath clipPathUnits="userSpaceOnUse" id="clipPath1"
|
||||
><path d="M0 0 L2147483647 0 L2147483647 2147483647 L0 2147483647 L0 0 Z"
|
||||
/></clipPath
|
||||
><clipPath clipPathUnits="userSpaceOnUse" id="clipPath2"
|
||||
><path d="M0 0 L0 120 L570 120 L570 0 Z"
|
||||
/></clipPath
|
||||
><clipPath clipPathUnits="userSpaceOnUse" id="clipPath3"
|
||||
><path d="M0 0 L0 170 L560 170 L560 0 Z"
|
||||
/></clipPath
|
||||
><clipPath clipPathUnits="userSpaceOnUse" id="clipPath4"
|
||||
><path d="M0 0 L0 110 L430 110 L430 0 Z"
|
||||
/></clipPath
|
||||
><clipPath clipPathUnits="userSpaceOnUse" id="clipPath5"
|
||||
><path d="M0 0 L0 100 L70 100 L70 0 Z"
|
||||
/></clipPath
|
||||
><clipPath clipPathUnits="userSpaceOnUse" id="clipPath6"
|
||||
><path d="M0 0 L0 320 L80 320 L80 0 Z"
|
||||
/></clipPath
|
||||
><clipPath clipPathUnits="userSpaceOnUse" id="clipPath7"
|
||||
><path d="M0 0 L0 160 L90 160 L90 0 Z"
|
||||
/></clipPath
|
||||
><clipPath clipPathUnits="userSpaceOnUse" id="clipPath8"
|
||||
><path d="M0 0 L0 140 L50 140 L50 0 Z"
|
||||
/></clipPath
|
||||
><clipPath clipPathUnits="userSpaceOnUse" id="clipPath9"
|
||||
><path d="M0 0 L0 340 L80 340 L80 0 Z"
|
||||
/></clipPath
|
||||
></defs
|
||||
><g fill="rgb(0,0,0)" fill-opacity="1" transform="translate(60,400)" stroke-opacity="1" stroke="rgb(0,0,0)"
|
||||
><rect x="0.5" width="568.5" height="118.5" y="0.5" clip-path="url(#clipPath2)" stroke="none"
|
||||
/></g
|
||||
><g fill="white" transform="translate(60,400)" stroke="white"
|
||||
><rect fill="none" x="0.5" width="568.5" height="118.5" y="0.5" clip-path="url(#clipPath2)"
|
||||
/><text x="248" font-size="14px" y="18.1094" text-decoration="underline" clip-path="url(#clipPath2)" font-family="sans-serif" stroke="none" xml:space="preserve"
|
||||
>Utilisateur</text
|
||||
><path fill="none" d="M1 24.1094 L569 24.1094" clip-path="url(#clipPath2)"
|
||||
/><text x="5" font-size="14px" y="39.2188" clip-path="url(#clipPath2)" font-family="sans-serif" stroke="none" xml:space="preserve"
|
||||
>- id : entier non null AUTO_INCREMENT</text
|
||||
><text x="5" font-size="14px" y="55.3281" clip-path="url(#clipPath2)" font-family="sans-serif" stroke="none" xml:space="preserve"
|
||||
>- pseudonyme : chaine de caractère non null</text
|
||||
><text x="5" font-size="14px" y="71.4375" clip-path="url(#clipPath2)" font-family="sans-serif" stroke="none" xml:space="preserve"
|
||||
>- mot de passe : chaine de caractère non null</text
|
||||
></g
|
||||
><g fill="rgb(0,0,0)" fill-opacity="1" transform="translate(60,90)" stroke-opacity="1" stroke="rgb(0,0,0)"
|
||||
><rect x="0.5" width="568.5" height="118.5" y="0.5" clip-path="url(#clipPath2)" stroke="none"
|
||||
/></g
|
||||
><g fill="white" transform="translate(60,90)" stroke="white"
|
||||
><rect fill="none" x="0.5" width="568.5" height="118.5" y="0.5" clip-path="url(#clipPath2)"
|
||||
/><text x="253" font-size="14px" y="18.1094" text-decoration="underline" clip-path="url(#clipPath2)" font-family="sans-serif" stroke="none" xml:space="preserve"
|
||||
>Prévision</text
|
||||
><path fill="none" d="M1 24.1094 L569 24.1094" clip-path="url(#clipPath2)"
|
||||
/><text x="5" font-size="14px" y="39.2188" clip-path="url(#clipPath2)" font-family="sans-serif" stroke="none" xml:space="preserve"
|
||||
>- user : entier non signé non null</text
|
||||
><text x="5" font-size="14px" y="55.3281" clip-path="url(#clipPath2)" font-family="sans-serif" stroke="none" xml:space="preserve"
|
||||
>- ticket : entier non signé non null</text
|
||||
><text x="5" font-size="14px" y="71.4375" clip-path="url(#clipPath2)" font-family="sans-serif" stroke="none" xml:space="preserve"
|
||||
>- estimation pessimiste : timestamp non null DEFAULT '0000-00-00 00:00:00'</text
|
||||
><text x="5" font-size="14px" y="87.5469" clip-path="url(#clipPath2)" font-family="sans-serif" stroke="none" xml:space="preserve"
|
||||
>- estimation mitigé : timestamp non null DEFAULT '0000-00-00 00:00:00'</text
|
||||
><text x="5" font-size="14px" y="103.6562" clip-path="url(#clipPath2)" font-family="sans-serif" stroke="none" xml:space="preserve"
|
||||
>- estimation optimiste : timestamp non null DEFAULT '0000-00-00 00:00:00'</text
|
||||
></g
|
||||
><g fill="rgb(0,0,0)" fill-opacity="1" transform="translate(60,220)" stroke-opacity="1" stroke="rgb(0,0,0)"
|
||||
><rect x="0.5" width="558.5" height="168.5" y="0.5" clip-path="url(#clipPath3)" stroke="none"
|
||||
/></g
|
||||
><g fill="white" transform="translate(60,220)" stroke="white"
|
||||
><rect fill="none" x="0.5" width="558.5" height="168.5" y="0.5" clip-path="url(#clipPath3)"
|
||||
/><text x="258" font-size="14px" y="18.1094" text-decoration="underline" clip-path="url(#clipPath3)" font-family="sans-serif" stroke="none" xml:space="preserve"
|
||||
>Ticket</text
|
||||
><path fill="none" d="M1 24.1094 L559 24.1094" clip-path="url(#clipPath3)"
|
||||
/><text x="5" font-size="14px" y="39.2188" clip-path="url(#clipPath3)" font-family="sans-serif" stroke="none" xml:space="preserve"
|
||||
>- id : entier non signé non null AUTO_INCREMENT,</text
|
||||
><text x="5" font-size="14px" y="55.3281" clip-path="url(#clipPath3)" font-family="sans-serif" stroke="none" xml:space="preserve"
|
||||
>- nom : chaîne de caractère</text
|
||||
><text x="5" font-size="14px" y="71.4375" clip-path="url(#clipPath3)" font-family="sans-serif" stroke="none" xml:space="preserve"
|
||||
>- date de création : timestamp non null DEFAULT current_timestamp(),</text
|
||||
><text x="5" font-size="14px" y="87.5469" clip-path="url(#clipPath3)" font-family="sans-serif" stroke="none" xml:space="preserve"
|
||||
>- date de modification : timestamp </text
|
||||
><text x="5" font-size="14px" y="103.6562" clip-path="url(#clipPath3)" font-family="sans-serif" stroke="none" xml:space="preserve"
|
||||
>- project : entier non signé </text
|
||||
><text x="5" font-size="14px" y="119.7656" clip-path="url(#clipPath3)" font-family="sans-serif" stroke="none" xml:space="preserve"
|
||||
>- temps passé : timestamp </text
|
||||
><text x="5" font-size="14px" y="135.875" clip-path="url(#clipPath3)" font-family="sans-serif" stroke="none" xml:space="preserve"
|
||||
>- description : chaîne de caractère</text
|
||||
><text x="5" font-size="14px" y="151.9844" clip-path="url(#clipPath3)" font-family="sans-serif" stroke="none" xml:space="preserve"
|
||||
>- auteurice : entier non signé</text
|
||||
><text x="5" font-size="14px" y="168.0938" clip-path="url(#clipPath3)" font-family="sans-serif" stroke="none" xml:space="preserve"
|
||||
>- ticket :</text
|
||||
></g
|
||||
><g fill="rgb(0,0,0)" fill-opacity="1" transform="translate(680,90)" stroke-opacity="1" stroke="rgb(0,0,0)"
|
||||
><rect x="0.5" width="428.5" height="108.5" y="0.5" clip-path="url(#clipPath4)" stroke="none"
|
||||
/></g
|
||||
><g fill="white" transform="translate(680,90)" stroke="white"
|
||||
><rect fill="none" x="0.5" width="428.5" height="108.5" y="0.5" clip-path="url(#clipPath4)"
|
||||
/><text x="174" font-size="14px" y="18.1094" text-decoration="underline" clip-path="url(#clipPath4)" font-family="sans-serif" stroke="none" xml:space="preserve"
|
||||
>Assignation</text
|
||||
><path fill="none" d="M1 24.1094 L429 24.1094" clip-path="url(#clipPath4)"
|
||||
/><text x="5" font-size="14px" y="39.2188" clip-path="url(#clipPath4)" font-family="sans-serif" stroke="none" xml:space="preserve"
|
||||
>- ticket : entier non signé non null</text
|
||||
><text x="5" font-size="14px" y="55.3281" clip-path="url(#clipPath4)" font-family="sans-serif" stroke="none" xml:space="preserve"
|
||||
>- utilisateur : entier non signé non null</text
|
||||
><text x="5" font-size="14px" y="71.4375" clip-path="url(#clipPath4)" font-family="sans-serif" stroke="none" xml:space="preserve"
|
||||
>- assignation : timestamp DEFAULT CURRENT_TIMESTAMP</text
|
||||
><text x="5" font-size="14px" y="87.5469" clip-path="url(#clipPath4)" font-family="sans-serif" stroke="none" xml:space="preserve"
|
||||
>- tempsPassé : entier</text
|
||||
></g
|
||||
><g transform="translate(10,240)"
|
||||
><path fill="none" d="M50.5 10.5 L10.5 10.5" clip-path="url(#clipPath5)"
|
||||
/><path fill="none" d="M10.5 10.5 L10.5 80.5" clip-path="url(#clipPath5)"
|
||||
/><path fill="none" d="M10.5 80.5 L50.5 80.5" clip-path="url(#clipPath5)"
|
||||
/><path fill="white" d="M39.2417 4 L50.5 10.5 L39.2417 17 L39.2417 4" clip-path="url(#clipPath5)" stroke="none"
|
||||
/><path fill="none" d="M39.2417 4 L50.5 10.5 L39.2417 17 L39.2417 4" clip-path="url(#clipPath5)"
|
||||
/></g
|
||||
><g transform="translate(620,130)"
|
||||
><path fill="none" d="M10.5 300.5 L40.5 300.5" clip-path="url(#clipPath6)"
|
||||
/><path fill="none" d="M40.5 300.5 L40.5 10.5" clip-path="url(#clipPath6)"
|
||||
/><path fill="none" d="M40.5 10.5 L60.5 10.5" clip-path="url(#clipPath6)"
|
||||
/><path fill="white" d="M21.7583 307 L10.5 300.5 L21.7583 294 L21.7583 307" clip-path="url(#clipPath6)" stroke="none"
|
||||
/><path fill="none" d="M21.7583 307 L10.5 300.5 L21.7583 294 L21.7583 307" clip-path="url(#clipPath6)"
|
||||
/></g
|
||||
><g transform="translate(610,120)"
|
||||
><path fill="none" d="M10.5 140.5 L30.5 140.5" clip-path="url(#clipPath7)"
|
||||
/><path fill="none" d="M30.5 140.5 L30.5 10.5" clip-path="url(#clipPath7)"
|
||||
/><path fill="none" d="M30.5 10.5 L70.5 10.5" clip-path="url(#clipPath7)"
|
||||
/><path fill="white" d="M21.7583 147 L10.5 140.5 L21.7583 134 L21.7583 147" clip-path="url(#clipPath7)" stroke="none"
|
||||
/><path fill="none" d="M21.7583 147 L10.5 140.5 L21.7583 134 L21.7583 147" clip-path="url(#clipPath7)"
|
||||
/></g
|
||||
><g transform="translate(30,130)"
|
||||
><path fill="none" d="M30.5 120.5 L10.5 120.5" clip-path="url(#clipPath8)"
|
||||
/><path fill="none" d="M10.5 120.5 L10.5 10.5" clip-path="url(#clipPath8)"
|
||||
/><path fill="none" d="M10.5 10.5 L30.5 10.5" clip-path="url(#clipPath8)"
|
||||
/><path fill="white" d="M19.2417 114 L30.5 120.5 L19.2417 127 L19.2417 114" clip-path="url(#clipPath8)" stroke="none"
|
||||
/><path fill="none" d="M19.2417 114 L30.5 120.5 L19.2417 127 L19.2417 114" clip-path="url(#clipPath8)"
|
||||
/></g
|
||||
><g transform="translate(0,110)"
|
||||
><path fill="none" d="M60.5 320.5 L10.5 320.5" clip-path="url(#clipPath9)"
|
||||
/><path fill="none" d="M10.5 320.5 L10.5 10.5" clip-path="url(#clipPath9)"
|
||||
/><path fill="none" d="M10.5 10.5 L60.5 10.5" clip-path="url(#clipPath9)"
|
||||
/><path fill="white" d="M49.2417 314 L60.5 320.5 L49.2417 327 L49.2417 314" clip-path="url(#clipPath9)" stroke="none"
|
||||
/><path fill="none" d="M49.2417 314 L60.5 320.5 L49.2417 327 L49.2417 314" clip-path="url(#clipPath9)"
|
||||
/></g
|
||||
></g
|
||||
></svg
|
||||
>
|
After Width: | Height: | Size: 11 KiB |
Loading…
Add table
Add a link
Reference in a new issue