Browse Source

add the db scheme in the readme

nas 3 years ago
parent
commit
8aa68f8a0a
2 changed files with 219 additions and 60 deletions
  1. 68
    60
      README.md
  2. 151
    0
      docs/scheme_mld.svg

+ 68
- 60
README.md View File

@@ -1,4 +1,12 @@
1
-# PHP-CRUD-API
1
+# Todo API
2
+
3
+## Database
4
+
5
+![Database scheme in svg](docs/scheme_mld.svg "MCD")
6
+
7
+Its relying on PHP-CRUD-API, with the original README here :
8
+
9
+## PHP-CRUD-API
2 10
 
3 11
 Single file PHP script that adds a REST API to a MySQL/MariaDB, PostgreSQL, SQL Server or SQLite database. 
4 12
 
@@ -25,7 +33,7 @@ There are also proof-of-concept ports of this script that only support basic RES
25 33
 [Node.js](https://github.com/mevdschee/js-crud-api/blob/master/app.js) and
26 34
 [Python](https://github.com/mevdschee/py-crud-api/blob/master/api.py).
27 35
 
28
-## Requirements
36
+### Requirements
29 37
 
30 38
   - PHP 7.0 or higher with PDO drivers enabled for one of these database systems:
31 39
     - 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
33 41
     - SQL Server 2012 or higher (2017 for Linux support)
34 42
     - SQLite 3.16 or higher (spatial features NOT supported)
35 43
 
36
-## Installation
44
+### Installation
37 45
 
38 46
 This is a single file application! Upload "`api.php`" somewhere and enjoy!
39 47
 
@@ -58,7 +66,7 @@ In these integrations [Composer](https://getcomposer.org/) is used to load this
58 66
 For people that don't use composer, the file "`api.include.php`" is provided. This file contains everything 
59 67
 from "`api.php`" except the configuration from "`src/index.php`" and can be used by PHP's "include".
60 68
 
61
-## Configuration
69
+### Configuration
62 70
 
63 71
 Edit the following lines in the bottom of the file "`api.php`":
64 72
 
@@ -98,7 +106,7 @@ All configuration options are also available as environment variables. Write the
98 106
 
99 107
 The environment variables take precedence over the PHP configuration.
100 108
 
101
-## Limitations
109
+### Limitations
102 110
 
103 111
 These limitation and constrains apply:
104 112
 
@@ -110,7 +118,7 @@ These limitation and constrains apply:
110 118
   - SQLite cannot have bigint typed auto incrementing primary keys
111 119
   - SQLite does not support altering table columns (structure)
112 120
     
113
-## Features
121
+### Features
114 122
 
115 123
 The following features are supported:
116 124
 
@@ -138,7 +146,7 @@ The following features are supported:
138 146
   - Security enhancing middleware is included
139 147
   - Standard compliant: PSR-4, PSR-7, PSR-12, PSR-15 and PSR-17
140 148
 
141
-## Compilation
149
+### Compilation
142 150
 
143 151
 You can install all dependencies of this project using the following command:
144 152
 
@@ -150,7 +158,7 @@ You can compile all files into a single "`api.php`" file using:
150 158
 
151 159
 NB: The install script will patch the dependencies in the vendor directory for PHP 7.0 compatibility.
152 160
 
153
-### Development
161
+#### Development
154 162
 
155 163
 You can access the non-compiled code at the URL:
156 164
 
@@ -158,7 +166,7 @@ You can access the non-compiled code at the URL:
158 166
 
159 167
 The non-compiled code resides in the "`src`" and "`vendor`" directories. The "`vendor`" directory contains the dependencies.
160 168
 
161
-### Updating dependencies
169
+#### Updating dependencies
162 170
 
163 171
 You can update all dependencies of this project using the following command:
164 172
 
@@ -168,13 +176,13 @@ This script will install and run [Composer](https://getcomposer.org/) to update
168 176
 
169 177
 NB: The update script will patch the dependencies in the vendor directory for PHP 7.0 compatibility.
170 178
 
171
-## TreeQL, a pragmatic GraphQL
179
+### TreeQL, a pragmatic GraphQL
172 180
 
173 181
 [TreeQL](https://treeql.org) allows you to create a "tree" of JSON objects based on your SQL database structure (relations) and your query.
174 182
 
175 183
 It is loosely based on the REST standard and also inspired by json:api.
176 184
 
177
-### CRUD + List
185
+#### CRUD + List
178 186
 
179 187
 The example posts table has only a a few fields:
180 188
 
@@ -187,7 +195,7 @@ The example posts table has only a a few fields:
187 195
 
188 196
 The CRUD + List operations below act on this table.
189 197
 
190
-#### Create
198
+##### Create
191 199
 
192 200
 If you want to create a record the request can be written in URL format as: 
193 201
 
@@ -205,7 +213,7 @@ And it will return the value of the primary key of the newly created record:
205 213
 
206 214
     2
207 215
 
208
-#### Read
216
+##### Read
209 217
 
210 218
 To read a record from this table the request can be written in URL format as:
211 219
 
@@ -222,7 +230,7 @@ Where "1" is the value of the primary key of the record that you want to read. I
222 230
 
223 231
 On read operations you may apply joins.
224 232
 
225
-#### Update
233
+##### Update
226 234
 
227 235
 To update a record in this table the request can be written in URL format as:
228 236
 
@@ -238,7 +246,7 @@ This adjusts the title of the post. And the return value is the number of rows t
238 246
 
239 247
     1
240 248
 
241
-#### Delete
249
+##### Delete
242 250
 
243 251
 If you want to delete a record from this table the request can be written in URL format as:
244 252
 
@@ -248,7 +256,7 @@ And it will return the number of deleted rows:
248 256
 
249 257
     1
250 258
 
251
-#### List
259
+##### List
252 260
 
253 261
 To list records from this table the request can be written in URL format as:
254 262
 
@@ -269,7 +277,7 @@ It will return:
269 277
 
270 278
 On list operations you may apply filters and joins.
271 279
 
272
-### Filters
280
+#### Filters
273 281
 
274 282
 Filters provide search functionality, on list calls, using the "filter" parameter. You need to specify the column
275 283
 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:
309 317
 
310 318
 In the next section we dive deeper into how you can apply multiple filters on a single list call.
311 319
 
312
-### Multiple filters
320
+#### Multiple filters
313 321
 
314 322
 Filters can be a by applied by repeating the "filter" parameter in the URL. For example the following URL: 
315 323
 
@@ -325,7 +333,7 @@ by adding a letter (a-f) you can create almost any reasonably complex condition
325 333
 
326 334
 NB: You can only filter on the requested table (not on it's included tables) and filters are only applied on list calls.
327 335
 
328
-### Column selection
336
+#### Column selection
329 337
 
330 338
 By default all columns are selected. With the "include" parameter you can select specific columns. 
331 339
 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:
347 355
 
348 356
 NB: Columns that are used to include related entities are automatically added and cannot be left out of the output.
349 357
 
350
-### Ordering
358
+#### Ordering
351 359
 
352 360
 With the "order" parameter you can sort. By default the sort is in ascending order, but by specifying "desc" this can be reversed:
353 361
 
@@ -375,7 +383,7 @@ Output:
375 383
 
376 384
 NB: You may sort on multiple fields by using multiple "order" parameters. You can not order on "joined" columns.
377 385
 
378
-### Limit size
386
+#### Limit size
379 387
 
380 388
 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).
381 389
 
@@ -398,7 +406,7 @@ Output:
398 406
 
399 407
 NB: If you also want to know to the total number of records you may want to use the "page" parameter.
400 408
 
401
-### Pagination
409
+#### Pagination
402 410
 
403 411
 The "page" parameter holds the requested page. The default page size is 20, but can be adjusted (e.g. to 50).
404 412
 
@@ -427,7 +435,7 @@ Output:
427 435
 
428 436
 NB: Since pages that are not ordered cannot be paginated, pages will be ordered by primary key.
429 437
 
430
-### Joins
438
+#### Joins
431 439
 
432 440
 Let's say that you have a posts table that has comments (made by users) and the posts can have tags.
433 441
 
@@ -510,7 +518,7 @@ This may lead to the following JSON data:
510 518
 You see that the "belongsTo" relationships are detected and the foreign key value is replaced by the referenced object.
511 519
 In case of "hasMany" and "hasAndBelongsToMany" the table name is used a new property on the object.
512 520
 
513
-### Batch operations
521
+#### Batch operations
514 522
 
515 523
 When you want to create, read, update or delete you may specify multiple primary key values in the URL.
516 524
 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:
574 582
 
575 583
 The response status code will always be 424 (failed dependency) in case of any failure of one of the batch operations.
576 584
 
577
-### Spatial support
585
+#### Spatial support
578 586
 
579 587
 For spatial support there is an extra set of filters that can be applied on geometry columns and that starting with an "s":
580 588
 
@@ -592,7 +600,7 @@ For spatial support there is an extra set of filters that can be applied on geom
592 600
 
593 601
 These filters are based on OGC standards and so is the WKT specification in which the geometry columns are represented.
594 602
 
595
-#### GeoJSON
603
+##### GeoJSON
596 604
 
597 605
 The GeoJSON support is a read-only view on the tables and records in GeoJSON format. These requests are supported:
598 606
 
@@ -615,7 +623,7 @@ The following Geometry types are supported by the GeoJSON implementation:
615 623
 
616 624
 The GeoJSON functionality is enabled by default, but can be disabled using the "controllers" configuration.
617 625
 
618
-## Middleware
626
+### Middleware
619 627
 
620 628
 You can enable the following middleware using the "middlewares" config parameter:
621 629
 
@@ -709,7 +717,7 @@ If you don't specify these parameters in the configuration, then the default val
709 717
 
710 718
 In the sections below you find more information on the built-in middleware.
711 719
 
712
-### Authentication
720
+#### Authentication
713 721
 
714 722
 Currently there are three types of authentication supported. They all store the authenticated user in the `$_SESSION` super global.
715 723
 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
723 731
 
724 732
 Below you find more information on each of the authentication types.
725 733
 
726
-#### Database authentication
734
+##### Database authentication
727 735
 
728 736
 The database authentication middleware defines three new routes:
729 737
 
@@ -752,7 +760,7 @@ users can freely add, modify or delete any account! The minimal configuration is
752 760
 
753 761
 Note that this middleware uses session cookies and stores the logged in state on the server.
754 762
 
755
-#### Basic authentication
763
+##### Basic authentication
756 764
 
757 765
 The Basic type supports a file (by default '.htpasswd') that holds the users and their (hashed) passwords separated by a colon (':'). 
758 766
 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
763 771
 
764 772
 This example sends the string "username1:password1".
765 773
 
766
-#### JWT authentication
774
+##### JWT authentication
767 775
 
768 776
 The JWT type requires another (SSO/Identity) server to sign a token that contains claims. 
769 777
 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:
786 794
 
787 795
 NB: The JWT implementation only supports the RSA and HMAC based algorithms.
788 796
 
789
-##### Configure and test JWT authentication with Auth0
797
+###### Configure and test JWT authentication with Auth0
790 798
 
791 799
 First you need to create an account on [Auth0](https://auth0.com/auth/login).
792 800
 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
812 820
 
813 821
 [More info](https://auth0.com/docs/api-auth/tutorials/verify-access-token)
814 822
 
815
-##### Configure and test JWT authentication with Firebase
823
+###### Configure and test JWT authentication with Firebase
816 824
 
817 825
 First you need to create a Firebase project on the [Firebase console](https://console.firebase.google.com/).
818 826
 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
852 860
 
853 861
 [More info](https://firebase.google.com/docs/auth/admin/verify-id-tokens#verify_id_tokens_using_a_third-party_jwt_library)
854 862
 
855
-### Authorizing operations
863
+#### Authorizing operations
856 864
 
857 865
 The Authorization model acts on "operations". The most important ones are listed here:
858 866
 
@@ -873,7 +881,7 @@ These operations can display or change the definition of the database, table or
873 881
 This functionality is disabled by default and for good reason (be careful!). 
874 882
 Add the "columns" controller in the configuration to enable this functionality.
875 883
 
876
-### Authorizing tables, columns and records
884
+#### Authorizing tables, columns and records
877 885
 
878 886
 By default all tables, columns and paths are accessible. If you want to restrict access to some tables you may add the 'authorization' middleware 
879 887
 and define a 'authorization.tableHandler' function that returns 'false' for these tables.
@@ -905,7 +913,7 @@ The above example will disabled the `/openapi` route.
905 913
 
906 914
 NB: You need to handle the creation of invalid records with a validation (or sanitation) handler.
907 915
 
908
-### SQL GRANT authorization
916
+#### SQL GRANT authorization
909 917
 
910 918
 You can alternatively use database permissons (SQL GRANT statements) to define the authorization model. In this case you
911 919
 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.
924 932
 
925 933
 NB: You may want to retrieve the username and password from the session (the "$_SESSION" variable).
926 934
 
927
-### Sanitizing input
935
+#### Sanitizing input
928 936
 
929 937
 By default all input is accepted and sent to the database. If you want to strip (certain) HTML tags before storing you may add 
930 938
 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
935 943
 
936 944
 The above example will strip all HTML tags from strings in the input.
937 945
 
938
-### Type sanitation
946
+#### Type sanitation
939 947
 
940 948
 If you enable the 'sanitation' middleware, then you (automatically) also enable type sanitation. When this is enabled you may:
941 949
 
@@ -952,7 +960,7 @@ in which tables you want to apply type sanitation (defaults to 'all'). Example:
952 960
 
953 961
 Here we enable the type sanitation for date and timestamp fields in the posts and comments tables.
954 962
 
955
-### Validating input
963
+#### Validating input
956 964
 
957 965
 By default all input is accepted and sent to the database. If you want to validate the input in a custom way, 
958 966
 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:
982 990
 
983 991
 You can parse this output to make form fields show up with a red border and their appropriate error message.
984 992
 
985
-### Type validations
993
+#### Type validations
986 994
 
987 995
 If you enable the 'validation' middleware, then you (automatically) also enable type validation. 
988 996
 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
1013 1021
 
1014 1022
 NB: Types that are enabled will be checked for null values when the column is non-nullable.
1015 1023
 
1016
-### Multi-tenancy support
1024
+#### Multi-tenancy support
1017 1025
 
1018 1026
 Two forms of multi-tenancy are supported:
1019 1027
 
@@ -1022,7 +1030,7 @@ Two forms of multi-tenancy are supported:
1022 1030
 
1023 1031
 Below is an explanation of the corresponding middlewares.
1024 1032
 
1025
-#### Multi-tenancy middleware
1033
+##### Multi-tenancy middleware
1026 1034
 
1027 1035
 You may use the "multiTenancy" middleware when you have a single multi-tenant database. 
1028 1036
 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
1036 1044
 
1037 1045
 NB: You may want to retrieve the customer id from the session (the "$_SESSION" variable).
1038 1046
 
1039
-#### Reconnect middleware
1047
+##### Reconnect middleware
1040 1048
 
1041 1049
 You may use the "reconnect" middleware when you have a separate database for each tenant.
1042 1050
 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
1050 1058
 
1051 1059
 NB: You may want to retrieve the database name from the session (the "$_SESSION" variable).
1052 1060
 
1053
-### Prevent database scraping
1061
+#### Prevent database scraping
1054 1062
 
1055 1063
 You may use the "joinLimits" and "pageLimits" middleware to prevent database scraping.
1056 1064
 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
1068 1076
 
1069 1077
 NB: The maximum number of records is also applied when there is no page number specified in the request.
1070 1078
 
1071
-### Customization handlers
1079
+#### Customization handlers
1072 1080
 
1073 1081
 You may use the "customization" middleware to modify request and response and implement any other functionality.
1074 1082
 
@@ -1081,7 +1089,7 @@ You may use the "customization" middleware to modify request and response and im
1081 1089
 
1082 1090
 The above example will add a header "X-Time-Taken" with the number of seconds the API call has taken.
1083 1091
 
1084
-### XML middleware
1092
+#### XML middleware
1085 1093
 
1086 1094
 You may use the "xml" middleware to translate input and output from JSON to XML. This request:
1087 1095
 
@@ -1111,11 +1119,11 @@ Outputs:
1111 1119
 
1112 1120
 This functionality is disabled by default and must be enabled using the "middlewares" configuration setting.
1113 1121
 
1114
-### File uploads
1122
+#### File uploads
1115 1123
 
1116 1124
 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).
1117 1125
 
1118
-## OpenAPI specification
1126
+### OpenAPI specification
1119 1127
 
1120 1128
 On the "/openapi" end-point the OpenAPI 3.0 (formerly called "Swagger") specification is served. 
1121 1129
 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
1124 1132
 - [OpenAPI specification](https://swagger.io/specification/) is a manual for creating an OpenAPI specification.
1125 1133
 - [Swagger Petstore](https://petstore.swagger.io/) is an example documentation that is generated using OpenAPI.
1126 1134
 
1127
-## Cache
1135
+### Cache
1128 1136
 
1129 1137
 There are 4 cache engines that can be configured by the "cacheType" config parameter:
1130 1138
 
@@ -1144,7 +1152,7 @@ The default engine has no dependencies and will use temporary files in the syste
1144 1152
 You may use the "cachePath" config parameter to specify the file system path for the temporary files or
1145 1153
 in case that you use a non-default "cacheType" the hostname (optionally with port) of the cache server.
1146 1154
 
1147
-## Types
1155
+### Types
1148 1156
 
1149 1157
 These are the supported types with their length, category, JSON type and format:
1150 1158
 
@@ -1167,19 +1175,19 @@ These are the supported types with their length, category, JSON type and format:
1167 1175
 
1168 1176
 Note that geometry is a non-jdbc type and thus has limited support.
1169 1177
 
1170
-## Data types in JavaScript
1178
+### Data types in JavaScript
1171 1179
 
1172 1180
 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.
1173 1181
 
1174
-### 64 bit integers
1182
+#### 64 bit integers
1175 1183
 
1176 1184
 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.
1177 1185
 
1178
-### Inf and NaN floats
1186
+#### Inf and NaN floats
1179 1187
 
1180 1188
 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.
1181 1189
 
1182
-## Errors
1190
+### Errors
1183 1191
 
1184 1192
 The following errors may be reported:
1185 1193
 
@@ -1216,7 +1224,7 @@ The following JSON structure is used:
1216 1224
 
1217 1225
 NB: Any non-error response will have status: 200 OK
1218 1226
 
1219
-## Tests
1227
+### Tests
1220 1228
 
1221 1229
 I am testing mainly on Ubuntu and I have the following test setups:
1222 1230
 
@@ -1230,7 +1238,7 @@ I am testing mainly on Ubuntu and I have the following test setups:
1230 1238
 This covers not all environments (yet), so please notify me of failing tests and report your environment. 
1231 1239
 I will try to cover most relevant setups in the "docker" folder of the project.
1232 1240
 
1233
-### Running
1241
+#### Running
1234 1242
 
1235 1243
 To run the functional tests locally you may run the following command:
1236 1244
 
@@ -1239,7 +1247,7 @@ To run the functional tests locally you may run the following command:
1239 1247
 This runs the functional tests from the "tests" directory. It uses the database dumps (fixtures) and
1240 1248
 database configuration (config) from the corresponding subdirectories.
1241 1249
 
1242
-## Nginx config example
1250
+### Nginx config example
1243 1251
 
1244 1252
 ```
1245 1253
 server {
@@ -1270,7 +1278,7 @@ server {
1270 1278
 }
1271 1279
 ```
1272 1280
 
1273
-### Docker tests
1281
+#### Docker tests
1274 1282
 
1275 1283
 Install docker using the following commands and then logout and login for the changes to take effect:
1276 1284
 
@@ -1380,7 +1388,7 @@ As you can see the "run.sh" script gives you access to a prompt in a chosen the
1380 1388
 In this environment the local files are mounted. This allows for easy debugging on different environments.
1381 1389
 You may type "exit" when you are done.
1382 1390
 
1383
-### Docker image
1391
+#### Docker image
1384 1392
 
1385 1393
 There is a `Dockerfile` in the repository that is used to build an image at:
1386 1394
 
@@ -1388,7 +1396,7 @@ There is a `Dockerfile` in the repository that is used to build an image at:
1388 1396
 
1389 1397
 It will be automatically build on every release. The "latest" tag points to the last release.
1390 1398
 
1391
-### Docker compose
1399
+#### Docker compose
1392 1400
 
1393 1401
 This repository also contains a `docker-compose.yml` file that you can install/build/run using:
1394 1402
 

+ 151
- 0
docs/scheme_mld.svg View File

@@ -0,0 +1,151 @@
1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.0//EN'
3
+          'http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd'>
4
+<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"
5
+><!--Generated by the Batik Graphics2D SVG Generator--><defs id="genericDefs"
6
+  /><g
7
+  ><defs id="defs1"
8
+    ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath1"
9
+      ><path d="M0 0 L2147483647 0 L2147483647 2147483647 L0 2147483647 L0 0 Z"
10
+      /></clipPath
11
+      ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath2"
12
+      ><path d="M0 0 L0 120 L570 120 L570 0 Z"
13
+      /></clipPath
14
+      ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath3"
15
+      ><path d="M0 0 L0 170 L560 170 L560 0 Z"
16
+      /></clipPath
17
+      ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath4"
18
+      ><path d="M0 0 L0 110 L430 110 L430 0 Z"
19
+      /></clipPath
20
+      ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath5"
21
+      ><path d="M0 0 L0 100 L70 100 L70 0 Z"
22
+      /></clipPath
23
+      ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath6"
24
+      ><path d="M0 0 L0 320 L80 320 L80 0 Z"
25
+      /></clipPath
26
+      ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath7"
27
+      ><path d="M0 0 L0 160 L90 160 L90 0 Z"
28
+      /></clipPath
29
+      ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath8"
30
+      ><path d="M0 0 L0 140 L50 140 L50 0 Z"
31
+      /></clipPath
32
+      ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath9"
33
+      ><path d="M0 0 L0 340 L80 340 L80 0 Z"
34
+      /></clipPath
35
+    ></defs
36
+    ><g fill="rgb(0,0,0)" fill-opacity="1" transform="translate(60,400)" stroke-opacity="1" stroke="rgb(0,0,0)"
37
+    ><rect x="0.5" width="568.5" height="118.5" y="0.5" clip-path="url(#clipPath2)" stroke="none"
38
+    /></g
39
+    ><g fill="white" transform="translate(60,400)" stroke="white"
40
+    ><rect fill="none" x="0.5" width="568.5" height="118.5" y="0.5" clip-path="url(#clipPath2)"
41
+      /><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"
42
+      >Utilisateur</text
43
+      ><path fill="none" d="M1 24.1094 L569 24.1094" clip-path="url(#clipPath2)"
44
+      /><text x="5" font-size="14px" y="39.2188" clip-path="url(#clipPath2)" font-family="sans-serif" stroke="none" xml:space="preserve"
45
+      >- id : entier non null AUTO_INCREMENT</text
46
+      ><text x="5" font-size="14px" y="55.3281" clip-path="url(#clipPath2)" font-family="sans-serif" stroke="none" xml:space="preserve"
47
+      >- pseudonyme : chaine de caractère non null</text
48
+      ><text x="5" font-size="14px" y="71.4375" clip-path="url(#clipPath2)" font-family="sans-serif" stroke="none" xml:space="preserve"
49
+      >- mot de passe : chaine de caractère non null</text
50
+    ></g
51
+    ><g fill="rgb(0,0,0)" fill-opacity="1" transform="translate(60,90)" stroke-opacity="1" stroke="rgb(0,0,0)"
52
+    ><rect x="0.5" width="568.5" height="118.5" y="0.5" clip-path="url(#clipPath2)" stroke="none"
53
+    /></g
54
+    ><g fill="white" transform="translate(60,90)" stroke="white"
55
+    ><rect fill="none" x="0.5" width="568.5" height="118.5" y="0.5" clip-path="url(#clipPath2)"
56
+      /><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"
57
+      >Prévision</text
58
+      ><path fill="none" d="M1 24.1094 L569 24.1094" clip-path="url(#clipPath2)"
59
+      /><text x="5" font-size="14px" y="39.2188" clip-path="url(#clipPath2)" font-family="sans-serif" stroke="none" xml:space="preserve"
60
+      >- user : entier non signé non null</text
61
+      ><text x="5" font-size="14px" y="55.3281" clip-path="url(#clipPath2)" font-family="sans-serif" stroke="none" xml:space="preserve"
62
+      >- ticket : entier non signé non null</text
63
+      ><text x="5" font-size="14px" y="71.4375" clip-path="url(#clipPath2)" font-family="sans-serif" stroke="none" xml:space="preserve"
64
+      >- estimation pessimiste : timestamp non null DEFAULT '0000-00-00 00:00:00'</text
65
+      ><text x="5" font-size="14px" y="87.5469" clip-path="url(#clipPath2)" font-family="sans-serif" stroke="none" xml:space="preserve"
66
+      >- estimation mitigé : timestamp non null DEFAULT '0000-00-00 00:00:00'</text
67
+      ><text x="5" font-size="14px" y="103.6562" clip-path="url(#clipPath2)" font-family="sans-serif" stroke="none" xml:space="preserve"
68
+      >- estimation optimiste : timestamp non null DEFAULT '0000-00-00 00:00:00'</text
69
+    ></g
70
+    ><g fill="rgb(0,0,0)" fill-opacity="1" transform="translate(60,220)" stroke-opacity="1" stroke="rgb(0,0,0)"
71
+    ><rect x="0.5" width="558.5" height="168.5" y="0.5" clip-path="url(#clipPath3)" stroke="none"
72
+    /></g
73
+    ><g fill="white" transform="translate(60,220)" stroke="white"
74
+    ><rect fill="none" x="0.5" width="558.5" height="168.5" y="0.5" clip-path="url(#clipPath3)"
75
+      /><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"
76
+      >Ticket</text
77
+      ><path fill="none" d="M1 24.1094 L559 24.1094" clip-path="url(#clipPath3)"
78
+      /><text x="5" font-size="14px" y="39.2188" clip-path="url(#clipPath3)" font-family="sans-serif" stroke="none" xml:space="preserve"
79
+      >- id : entier non signé non null AUTO_INCREMENT,</text
80
+      ><text x="5" font-size="14px" y="55.3281" clip-path="url(#clipPath3)" font-family="sans-serif" stroke="none" xml:space="preserve"
81
+      >- nom : chaîne de caractère</text
82
+      ><text x="5" font-size="14px" y="71.4375" clip-path="url(#clipPath3)" font-family="sans-serif" stroke="none" xml:space="preserve"
83
+      >- date de création : timestamp non null DEFAULT current_timestamp(),</text
84
+      ><text x="5" font-size="14px" y="87.5469" clip-path="url(#clipPath3)" font-family="sans-serif" stroke="none" xml:space="preserve"
85
+      >- date de modification : timestamp </text
86
+      ><text x="5" font-size="14px" y="103.6562" clip-path="url(#clipPath3)" font-family="sans-serif" stroke="none" xml:space="preserve"
87
+      >- project : entier non signé </text
88
+      ><text x="5" font-size="14px" y="119.7656" clip-path="url(#clipPath3)" font-family="sans-serif" stroke="none" xml:space="preserve"
89
+      >- temps passé : timestamp </text
90
+      ><text x="5" font-size="14px" y="135.875" clip-path="url(#clipPath3)" font-family="sans-serif" stroke="none" xml:space="preserve"
91
+      >- description : chaîne de caractère</text
92
+      ><text x="5" font-size="14px" y="151.9844" clip-path="url(#clipPath3)" font-family="sans-serif" stroke="none" xml:space="preserve"
93
+      >- auteurice : entier non signé</text
94
+      ><text x="5" font-size="14px" y="168.0938" clip-path="url(#clipPath3)" font-family="sans-serif" stroke="none" xml:space="preserve"
95
+      >- ticket :</text
96
+    ></g
97
+    ><g fill="rgb(0,0,0)" fill-opacity="1" transform="translate(680,90)" stroke-opacity="1" stroke="rgb(0,0,0)"
98
+    ><rect x="0.5" width="428.5" height="108.5" y="0.5" clip-path="url(#clipPath4)" stroke="none"
99
+    /></g
100
+    ><g fill="white" transform="translate(680,90)" stroke="white"
101
+    ><rect fill="none" x="0.5" width="428.5" height="108.5" y="0.5" clip-path="url(#clipPath4)"
102
+      /><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"
103
+      >Assignation</text
104
+      ><path fill="none" d="M1 24.1094 L429 24.1094" clip-path="url(#clipPath4)"
105
+      /><text x="5" font-size="14px" y="39.2188" clip-path="url(#clipPath4)" font-family="sans-serif" stroke="none" xml:space="preserve"
106
+      >- ticket : entier non signé non null</text
107
+      ><text x="5" font-size="14px" y="55.3281" clip-path="url(#clipPath4)" font-family="sans-serif" stroke="none" xml:space="preserve"
108
+      >- utilisateur : entier non signé non null</text
109
+      ><text x="5" font-size="14px" y="71.4375" clip-path="url(#clipPath4)" font-family="sans-serif" stroke="none" xml:space="preserve"
110
+      >- assignation : timestamp DEFAULT CURRENT_TIMESTAMP</text
111
+      ><text x="5" font-size="14px" y="87.5469" clip-path="url(#clipPath4)" font-family="sans-serif" stroke="none" xml:space="preserve"
112
+      >- tempsPassé : entier</text
113
+    ></g
114
+    ><g transform="translate(10,240)"
115
+    ><path fill="none" d="M50.5 10.5 L10.5 10.5" clip-path="url(#clipPath5)"
116
+      /><path fill="none" d="M10.5 10.5 L10.5 80.5" clip-path="url(#clipPath5)"
117
+      /><path fill="none" d="M10.5 80.5 L50.5 80.5" clip-path="url(#clipPath5)"
118
+      /><path fill="white" d="M39.2417 4 L50.5 10.5 L39.2417 17 L39.2417 4" clip-path="url(#clipPath5)" stroke="none"
119
+      /><path fill="none" d="M39.2417 4 L50.5 10.5 L39.2417 17 L39.2417 4" clip-path="url(#clipPath5)"
120
+    /></g
121
+    ><g transform="translate(620,130)"
122
+    ><path fill="none" d="M10.5 300.5 L40.5 300.5" clip-path="url(#clipPath6)"
123
+      /><path fill="none" d="M40.5 300.5 L40.5 10.5" clip-path="url(#clipPath6)"
124
+      /><path fill="none" d="M40.5 10.5 L60.5 10.5" clip-path="url(#clipPath6)"
125
+      /><path fill="white" d="M21.7583 307 L10.5 300.5 L21.7583 294 L21.7583 307" clip-path="url(#clipPath6)" stroke="none"
126
+      /><path fill="none" d="M21.7583 307 L10.5 300.5 L21.7583 294 L21.7583 307" clip-path="url(#clipPath6)"
127
+    /></g
128
+    ><g transform="translate(610,120)"
129
+    ><path fill="none" d="M10.5 140.5 L30.5 140.5" clip-path="url(#clipPath7)"
130
+      /><path fill="none" d="M30.5 140.5 L30.5 10.5" clip-path="url(#clipPath7)"
131
+      /><path fill="none" d="M30.5 10.5 L70.5 10.5" clip-path="url(#clipPath7)"
132
+      /><path fill="white" d="M21.7583 147 L10.5 140.5 L21.7583 134 L21.7583 147" clip-path="url(#clipPath7)" stroke="none"
133
+      /><path fill="none" d="M21.7583 147 L10.5 140.5 L21.7583 134 L21.7583 147" clip-path="url(#clipPath7)"
134
+    /></g
135
+    ><g transform="translate(30,130)"
136
+    ><path fill="none" d="M30.5 120.5 L10.5 120.5" clip-path="url(#clipPath8)"
137
+      /><path fill="none" d="M10.5 120.5 L10.5 10.5" clip-path="url(#clipPath8)"
138
+      /><path fill="none" d="M10.5 10.5 L30.5 10.5" clip-path="url(#clipPath8)"
139
+      /><path fill="white" d="M19.2417 114 L30.5 120.5 L19.2417 127 L19.2417 114" clip-path="url(#clipPath8)" stroke="none"
140
+      /><path fill="none" d="M19.2417 114 L30.5 120.5 L19.2417 127 L19.2417 114" clip-path="url(#clipPath8)"
141
+    /></g
142
+    ><g transform="translate(0,110)"
143
+    ><path fill="none" d="M60.5 320.5 L10.5 320.5" clip-path="url(#clipPath9)"
144
+      /><path fill="none" d="M10.5 320.5 L10.5 10.5" clip-path="url(#clipPath9)"
145
+      /><path fill="none" d="M10.5 10.5 L60.5 10.5" clip-path="url(#clipPath9)"
146
+      /><path fill="white" d="M49.2417 314 L60.5 320.5 L49.2417 327 L49.2417 314" clip-path="url(#clipPath9)" stroke="none"
147
+      /><path fill="none" d="M49.2417 314 L60.5 320.5 L49.2417 327 L49.2417 314" clip-path="url(#clipPath9)"
148
+    /></g
149
+  ></g
150
+></svg
151
+>

Loading…
Cancel
Save