Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
199 commits
Select commit Hold shift + click to select a range
981bfce
First Commit
eldadfux Jan 21, 2021
9af3100
Updated CI
eldadfux Jan 21, 2021
5d4039f
Updated CI
eldadfux Jan 21, 2021
0ad8288
Updated tests
eldadfux Jan 21, 2021
c0490ba
Changed namespace
eldadfux Jan 21, 2021
6b64298
Fixed autoloading
eldadfux Jan 23, 2021
808536a
New Adapters
eldadfux Jan 23, 2021
3a2fd11
New Adapters
eldadfux Jan 23, 2021
f129112
Removed mocks
eldadfux Jan 23, 2021
ebf396d
Dont allow key with _
eldadfux Jan 23, 2021
59ad0d2
Updated key tests
eldadfux Jan 23, 2021
43e132c
Added types
eldadfux Jan 23, 2021
1922ef0
Added tests
eldadfux Jan 23, 2021
3320f6d
Updated tests
eldadfux Jan 24, 2021
3a53099
Added MongoDB adapter
eldadfux Jan 25, 2021
f0b2433
Create database from namespace
eldadfux Jan 28, 2021
733481f
Draft spec
eldadfux Feb 4, 2021
cc80ce4
Updated tests
eldadfux Feb 6, 2021
85a2aab
Commit lock file
eldadfux Feb 6, 2021
871441b
Updated networks
eldadfux Feb 6, 2021
e257ed9
Updatd CI flow
eldadfux Feb 6, 2021
a74f051
Enabled MySQL tests
eldadfux Feb 6, 2021
e1bee5a
Fixed Psalm errors
eldadfux Feb 6, 2021
e74ab8c
Updated CI
eldadfux Feb 6, 2021
fbbb26e
Added Cockroach
eldadfux Feb 15, 2021
e1c6313
Updated cockroach version
eldadfux Feb 15, 2021
93cca4a
Updated test commands
eldadfux Feb 27, 2021
9c5c2c7
Updated types
eldadfux Mar 7, 2021
f109bfd
Added list databases method
eldadfux Mar 18, 2021
ca15bc0
Updated README
eldadfux Mar 18, 2021
17a07f0
POC 2
eldadfux Mar 22, 2021
690e730
New naming
eldadfux Apr 15, 2021
3cb471b
Update validators with new abstract methods
kodumbeats Apr 16, 2021
b02d2f4
Merge pull request #1 from kodumbeats/v0
eldadfux Apr 16, 2021
037ce36
Merge branch 'v0' of github.com:utopia-php/database into v0
eldadfux Apr 18, 2021
b88735a
Updated metadata handling
eldadfux Apr 18, 2021
8f36578
Save arrays and objects inline
eldadfux Apr 18, 2021
6d3bb28
POC - update, filters and casting
eldadfux Apr 18, 2021
bfe8319
Updated Readme
eldadfux Apr 19, 2021
64dae60
Updated Readme and fixed minor errors
eldadfux Apr 20, 2021
125762e
Fixed Psalm errors
eldadfux Apr 20, 2021
b40b56b
Added delete method
eldadfux Apr 21, 2021
617da88
Updated todos + a new dependency
eldadfux Apr 21, 2021
e97579c
Changed permissions data structure format
eldadfux Apr 22, 2021
a5fc0f4
Syncing collection metadata
eldadfux Apr 22, 2021
0358575
Added test for metadata sync
eldadfux Apr 22, 2021
3cf58ce
Add function to parse query expressions
kodumbeats Apr 22, 2021
514bf70
Add method to parse custom filter queries
kodumbeats Apr 22, 2021
80eec64
Add tests for parsing queries
kodumbeats Apr 22, 2021
69e6bc7
Add test for parsing query expressions
kodumbeats Apr 22, 2021
c658106
Added read and write authorization
eldadfux Apr 22, 2021
68189e2
Fixd psalm warnings
eldadfux Apr 22, 2021
a86c8fc
Duplicated document error
eldadfux Apr 22, 2021
5ab6872
Updated TODOs
eldadfux Apr 22, 2021
9e48eb8
Updated docs
eldadfux Apr 23, 2021
bfd8068
Updated readme
eldadfux Apr 23, 2021
26a08c1
Updated support table
eldadfux Apr 23, 2021
087fbe2
Improved docs
eldadfux Apr 23, 2021
980f168
Update README.md
eldadfux Apr 23, 2021
f474a0d
Update README.md
eldadfux Apr 23, 2021
cdf5267
Refactor query into standalone class
kodumbeats Apr 23, 2021
3f75885
Add getters for object properties
kodumbeats Apr 23, 2021
2a8a5b3
Add method to get all query details
kodumbeats Apr 23, 2021
f763ba4
Add return typing
kodumbeats Apr 23, 2021
06f02f7
Clean up code
kodumbeats Apr 23, 2021
e01fcc4
Call parseExpression as a static method
kodumbeats Apr 23, 2021
65a2166
Add tests for query class
kodumbeats Apr 23, 2021
1bb848d
Refactor parsing code into query class and tests
kodumbeats Apr 23, 2021
e802153
Add type hinting
kodumbeats Apr 23, 2021
83a09a3
Merge branch 'v0' into v0
kodumbeats Apr 23, 2021
c18b485
Add types to constructor params
kodumbeats Apr 23, 2021
b2f6603
Rename operand to value
kodumbeats Apr 23, 2021
f581824
Change to protected method
kodumbeats Apr 23, 2021
fe6becb
Use bracket syntax for switch
kodumbeats Apr 23, 2021
1c6e60c
Treat query expression as kv pair
kodumbeats Apr 23, 2021
179a0d5
Create query validator
kodumbeats Apr 23, 2021
8ada10e
Remove references to old var
kodumbeats Apr 23, 2021
8934ce7
Revert "Change to protected method"
kodumbeats Apr 23, 2021
38b02cf
Revert "Treat query expression as kv pair"
kodumbeats Apr 23, 2021
c2b9dc2
Use value instead of operand
kodumbeats Apr 23, 2021
8c8afb3
Merge branch 'v0' of github.com:kodumbeats/database into v0
kodumbeats Apr 23, 2021
7071923
Clarify intended behavior for parseExpression()
kodumbeats Apr 23, 2021
0ec83e0
Add and fix query tests
kodumbeats Apr 23, 2021
e3f1efb
Constructor expects array of $values by default
kodumbeats Apr 23, 2021
0659fe8
Properly scope parseExpression
kodumbeats Apr 23, 2021
cd66453
Added a space :)
eldadfux Apr 23, 2021
728b29e
Merge branch 'v0' of github.com:utopia-php/database into v0
eldadfux Apr 23, 2021
0e079a8
Work in progress structure validator
eldadfux Apr 24, 2021
f4445ce
Structure and filters - work in progress.
eldadfux Apr 24, 2021
8c771d6
Use query not filter
eldadfux Apr 24, 2021
ece4105
Added missing tests
eldadfux Apr 25, 2021
6b3bcd2
Typecast expression values and handle comma-separated values
kodumbeats Apr 26, 2021
a1b472d
Test with integer param
kodumbeats Apr 26, 2021
e74da85
Test for typecasted bool expressions
kodumbeats Apr 26, 2021
f7e86b6
Test multiple query values
kodumbeats Apr 26, 2021
a14a730
Cleanup for readability
kodumbeats Apr 26, 2021
631ecfd
Reserve query validator for separate PR
kodumbeats Apr 26, 2021
4d6189b
Only consider periods oudside parentheses
kodumbeats Apr 26, 2021
1f4c64f
Test for float values
kodumbeats Apr 26, 2021
fa28286
Handle null as value
kodumbeats Apr 26, 2021
2ec2fc8
Refactor elseifs into switch
kodumbeats Apr 26, 2021
ab2a6b7
Use single array_map to trim whitespace and typecast
kodumbeats Apr 26, 2021
b01d9dd
Remove unneeded switch case
kodumbeats Apr 26, 2021
7db5c8f
Trim whitespace and remove escape slashes
kodumbeats Apr 26, 2021
40cd42c
Test for whitespace and escaped character
kodumbeats Apr 26, 2021
53cf8dc
Use strrpos to find last occurrence of parenthesis
kodumbeats Apr 26, 2021
ba852c2
Correct comments
kodumbeats Apr 26, 2021
87dd5b3
Test constructor function
kodumbeats Apr 26, 2021
1522284
Properly handle whitespace between values
kodumbeats Apr 26, 2021
60391ec
Merge pull request #3 from kodumbeats/v0
eldadfux Apr 26, 2021
ae17f4d
Fix typo
kodumbeats Apr 26, 2021
a4e720a
Upgrade utopia-php/cache to 0.4.0
kodumbeats Apr 26, 2021
aab2201
Use redis cache in testing
kodumbeats Apr 26, 2021
3eed65f
Check cache first on getDocument
kodumbeats Apr 26, 2021
23d23f2
Update cache on document update or delete
kodumbeats Apr 27, 2021
d70b393
Install redis lib in testing container
kodumbeats Apr 27, 2021
bf3dd6c
Properly assign $document
kodumbeats Apr 27, 2021
71119bf
Hydrate document string to Document object
kodumbeats Apr 27, 2021
bb055ab
Fix call to adapter
kodumbeats Apr 27, 2021
4df301e
Save array copy of Document object
kodumbeats Apr 27, 2021
286a74b
Require cache as contructor param
kodumbeats Apr 27, 2021
3f30840
Ensure cache is empty before testing
kodumbeats Apr 27, 2021
cf18aa1
Ensure tests pass without saving to cache
kodumbeats Apr 27, 2021
66c9f70
Debugging getArrayCopy method
kodumbeats Apr 27, 2021
c173d23
Find method - work in progress
eldadfux Apr 28, 2021
57be09e
Legacy code that considers arrays as nested documents
kodumbeats Apr 28, 2021
53d521c
Validate cache read access with authorization validator
kodumbeats Apr 28, 2021
f2cdd98
Add cache to readme example
kodumbeats Apr 28, 2021
2549ca2
Create query validator
kodumbeats Apr 28, 2021
e16e398
Remove unused import
kodumbeats Apr 28, 2021
1ebfacb
Rename to avoid namespace conflict
kodumbeats Apr 28, 2021
78ed2c0
Test query validator
kodumbeats Apr 28, 2021
8b3d3cb
Remove debugging code
kodumbeats Apr 28, 2021
767c225
Remove unnecessary validation
kodumbeats Apr 28, 2021
949c9d3
Test error handling
kodumbeats Apr 28, 2021
49dba96
Test for success
kodumbeats Apr 28, 2021
7366f85
Test various types of queries
kodumbeats Apr 28, 2021
ea0c622
Test floats - gettype returns double for legacy reasons
kodumbeats Apr 28, 2021
e5a6989
Updated docs
eldadfux Apr 29, 2021
19486f4
Find method - work in progress
eldadfux Apr 29, 2021
2350e5c
Cache updated documentId on updateDocument
kodumbeats Apr 29, 2021
25aed1b
Add assertions for validator response
kodumbeats Apr 29, 2021
1c6daa3
Remove debugging code
kodumbeats Apr 29, 2021
32ed736
Merge pull request #4 from kodumbeats/v0-cache-layer
eldadfux Apr 29, 2021
88bc6c5
Updated composer.json
eldadfux Apr 29, 2021
3e6fab6
Updated names to avoid conflicts
eldadfux Apr 29, 2021
0d87b57
Commented mongo tests
eldadfux Apr 29, 2021
57231e2
Commented postgres tests
eldadfux Apr 29, 2021
4eced76
Fixed MySQL tests
eldadfux Apr 29, 2021
1d8df79
Merge pull request #5 from kodumbeats/feat-query-validator
eldadfux Apr 29, 2021
82c3435
Fixed Psalm errors and warnings
eldadfux Apr 29, 2021
db25e1a
Updated CI
eldadfux Apr 29, 2021
ba2190d
Fixed DB errors
eldadfux Apr 29, 2021
a40d4d7
Cast and hint to appropriate types for psalm
kodumbeats Apr 29, 2021
7f38155
Correct type declaration for return array
kodumbeats Apr 29, 2021
2bf2c22
Add more specific typehint
kodumbeats Apr 29, 2021
a1acd05
Merge pull request #6 from kodumbeats/v0-fix-psalm-warnings
eldadfux Apr 29, 2021
9a4047c
Update README
eldadfux Apr 30, 2021
7a903b5
Added support for 'OR' conditions and new operators
eldadfux Apr 30, 2021
d0b6220
Added support for list collections
eldadfux Apr 30, 2021
aacf09c
Added state managment methods
eldadfux May 1, 2021
48d4144
Fixed typo
eldadfux May 1, 2021
5f0a80e
Work in progress: limits section
eldadfux May 1, 2021
5000c9c
Updated TODO list
eldadfux May 1, 2021
9f43534
Added support for find order attributes
eldadfux May 1, 2021
bd9756f
Added tests for limit + offset options
eldadfux May 1, 2021
78db6a0
Updated TODO list
eldadfux May 1, 2021
2e20691
Denormalized data for faster reads
eldadfux May 1, 2021
4d7c15c
Added swoole setup
eldadfux May 1, 2021
888ecb2
Added format layer for structure validation
eldadfux May 1, 2021
82ffc79
Update TODO list
eldadfux May 1, 2021
518265a
Added constant
eldadfux May 2, 2021
2348065
Added count method (with optional limit)
eldadfux May 3, 2021
81a16f8
Fixed limit tests
eldadfux May 3, 2021
43744d2
Updated cache key
eldadfux May 3, 2021
8dde2a3
Fixed array param
eldadfux May 3, 2021
dd598a2
Added exists method
eldadfux May 3, 2021
2299091
Null safety
eldadfux May 3, 2021
0ab68d0
Removed cache file
eldadfux May 4, 2021
19f605f
Fix for filters
eldadfux May 4, 2021
52c8cac
Fixed empty doc warning
eldadfux May 4, 2021
4cdea0e
Added support for unique index
eldadfux May 5, 2021
64c1eba
Added find first and find last methods
eldadfux May 5, 2021
a41bbe4
added failure tests
eldadfux May 5, 2021
40a0d40
Test object nesting
eldadfux May 5, 2021
392c40a
Added test for filters
eldadfux May 6, 2021
1664bda
Added casting and filtering status
eldadfux May 6, 2021
5fb8838
Updated filters logic
eldadfux May 6, 2021
04c4a09
Added tests for array filters
eldadfux May 6, 2021
5492744
Minor fix/test
eldadfux May 6, 2021
2bb3db2
Updated tests
eldadfux May 6, 2021
aeabf0f
More tests
eldadfux May 6, 2021
11a149d
Better error message
eldadfux May 6, 2021
ee26734
Allow null value for optional attrubutes
eldadfux May 8, 2021
0f4aecd
Allow null values
eldadfux May 8, 2021
20d189c
Allow null values
eldadfux May 8, 2021
6813402
Updated auth validator
eldadfux May 8, 2021
8afa110
Updated tests
eldadfux May 8, 2021
d54bbae
Fix for find method
eldadfux May 9, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/vendor/
/.idea/
.DS_Store
mock.json
data-tests.php
loader.php
.phpunit.result.cache
32 changes: 32 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
dist: xenial

arch:
- amd64

os: linux

language: shell

services:
- docker

notifications:
email:
- team@appwrite.io

before_script: docker run --rm --interactive --tty --volume "$(pwd)":/app composer update --ignore-platform-reqs --optimize-autoloader --no-plugins --no-scripts --prefer-dist

before_install:
- >
if [ ! -z "${DOCKERHUB_PULL_USERNAME:-}" ]; then
echo "${DOCKERHUB_PULL_PASSWORD}" | docker login --username "${DOCKERHUB_PULL_USERNAME}" --password-stdin
fi

install:
- docker-compose up -d
- sleep 10

script:
- docker ps
- docker-compose exec tests vendor/bin/phpunit --configuration phpunit.xml tests
- docker-compose exec tests vendor/bin/psalm --show-info=true
46 changes: 46 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
FROM composer:2.0 as step0

ARG TESTING=false
ENV TESTING=$TESTING

WORKDIR /usr/local/src/

COPY composer.lock /usr/local/src/
COPY composer.json /usr/local/src/

RUN composer update --ignore-platform-reqs --optimize-autoloader \
--no-plugins --no-scripts --prefer-dist

FROM php:7.4-cli-alpine as final

LABEL maintainer="team@appwrite.io"

ENV PHP_SWOOLE_VERSION=v4.6.6

RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone

RUN \
apk update \
&& apk add --no-cache postgresql-libs postgresql-dev make automake autoconf gcc g++ git brotli-dev \
&& pecl install mongodb redis \
&& docker-php-ext-enable mongodb redis \
&& docker-php-ext-install opcache pgsql pdo_mysql pdo_pgsql \
## Swoole Extension
&& git clone --depth 1 --branch $PHP_SWOOLE_VERSION https://github.com/swoole/swoole-src.git \
&& cd swoole-src \
&& phpize \
&& ./configure --enable-http2 \
&& make && make install \
&& cd .. \
&& rm -rf /var/cache/apk/*

WORKDIR /usr/src/code

RUN echo extension=swoole.so >> /usr/local/etc/php/conf.d/swoole.ini

COPY --from=step0 /usr/local/src/vendor /usr/src/code/vendor

# Add Source Code
COPY . /usr/src/code

CMD [ "tail", "-f", "/dev/null" ]
196 changes: 195 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,195 @@
# database
# Utopia Database

[![Build Status](https://travis-ci.org/utopia-php/abuse.svg?branch=master)](https://travis-ci.com/utopia-php/database)
![Total Downloads](https://img.shields.io/packagist/dt/utopia-php/database.svg)
[![Discord](https://img.shields.io/discord/564160730845151244)](https://appwrite.io/discord)

Utopia framework database library is simple and lite library for managing application persistency using multiple database adapters. This library is aiming to be as simple and easy to learn and use. This library is maintained by the [Appwrite team](https://appwrite.io).

Although this library is part of the [Utopia Framework](https://github.com/utopia-php/framework) project it is dependency free, and can be used as standalone with any other PHP project or framework.

## Getting Started

Install using composer:
```bash
composer require utopia-php/database
```

Initialization:

```php
<?php

require_once __DIR__ . '/../../vendor/autoload.php';

```

### Concepts

A list of the utopia/php concepts and their relevant equivalent using the different adapters

- **Database** - An instance of the utopia/database library that abstracts one of the supported adapters and provides a unified API for CRUD operation and queries on a specific schema or isolated scope inside the underlining database.
- **Adapter** - An implementation of an underlying database engine that this library can support - below is a list of [supported adapters](#supported-adapters) and supported capabilities for each Adapter.
- **Collection** - A set of documents stored on the same adapter scope. For SQL-based adapters, this will be equivalent to a table. For a No-SQL adapter, this will equivalent to a native collection.
- **Document** - A simple JSON object that will be stored in one of the utopia/database collections. For SQL-based adapters, this will be equivalent to a row. For a No-SQL adapter, this will equivalent to a native document.
- **Attribute** - A simple document attribute. For SQL-based adapters, this will be equivalent to a column. For a No-SQL adapter, this will equivalent to a native document field.
- **Index** - A simple collection index used to improve the performance of your database queries.
- **Permissions** - Using permissions, you can decide which roles will grant read or write access for a specific document. The special attributes `$read` and `$write` are used to store permissions metadata for each document in the collection. A permission role can be any string you want. You can use `Authorization::setRole()` to delegate new roles to your users, once obtained a new role a user would gain read or write access to a relevant document.

### Reserved Attributes

- `$id` - the documnet unique ID, you can set your own custom ID or a random UID will be generated by the library.
- `$collection` - an attribute containing the name of the collection the document is stored in.
- `$read` - an attribute containing an array of strings. Each string represent a specific role. If your user obtains that role he will have read access for this document.
- `$write` - an attribute containing an array of strings. Each string represent a specific role. If your user obtains that role he will have write access for this document.

### Attribute Types

The database document interface only supports primitives types (`strings`, `integers`, `floats`, and `booleans`) translated to their native database types for each of the relevant database adapters. Complex types like arrays or objects will be encoded to JSON strings when stored and decoded back when fetched from their adapters.

### Examples

Some examples to help you get started.

**Creating a database:**

```php
use PDO;
use Utopia\Database\Database;
use Utopia\Database\Adapter\MariaDB;
use Utopia\Cache\Cache;
use Utopia\Cache\Adapter\None as NoCache;

$dbHost = 'mariadb';
$dbPort = '3306';
$dbUser = 'root';
$dbPass = 'password';

$pdo = new PDO("mysql:host={$dbHost};port={$dbPort};charset=utf8mb4", $dbUser, $dbPass, [
PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8mb4',
PDO::ATTR_TIMEOUT => 3, // Seconds
PDO::ATTR_PERSISTENT => true,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
]);

$cache = new Cache(new NoCache()); // or use any cache adapter you wish

$database = new Database(new MariaDB($pdo), $cache);
$database->setNamespace('mydb');

$database->create(); // Creates a new schema named `mydb`
```

**Creating a collection:**

```php
$database->createCollection('movies');

// Add attributes
$database->createAttribute('movies', 'name', Database::VAR_STRING, 128, true);
$database->createAttribute('movies', 'director', Database::VAR_STRING, 128, true);
$database->createAttribute('movies', 'year', Database::VAR_INTEGER, 0, true);
$database->createAttribute('movies', 'price', Database::VAR_FLOAT, 0, true);
$database->createAttribute('movies', 'active', Database::VAR_BOOLEAN, 0, true);
$database->createAttribute('movies', 'generes', Database::VAR_STRING, 32, true, true, true);

// Create an Index
$database->createIndex('movies', 'index1', Database::INDEX_KEY, ['year'], [128], [Database::ORDER_ASC]);
```

**Create a document:**

```php
static::getDatabase()->createDocument('movies', new Document([
'$read' => ['*', 'user1', 'user2'],
'$write' => ['*', 'user1x', 'user2x'],
'name' => 'Captain Marvel',
'director' => 'Anna Boden & Ryan Fleck',
'year' => 2019,
'price' => 25.99,
'active' => true,
'generes' => ['science fiction', 'action', 'comics'],
]));
```

**Find:**

```php
$documents = static::getDatabase()->find('movies', [
new Query('year', Query::TYPE_EQUAL, [2019]),
]);
```

### Adapters

Below is a list of supported adapters, and thier compatibly tested versions alongside a list of supported features and relevant limits.

| Adapter | Status | Version |
|---------|---------|---|
| MariaDB | ✅ | 10.5 |
| MySQL | ✅ | 8.0 |
| Postgres | 🛠 | 13.0 |
| MongoDB | 🛠 | 3.6 |
| SQLlite | 🛠 | 3.35 |

` ✅ - supported, 🛠 - work in progress`

## TODOS

- [ ] CRUD: Updated databases list method
- [ ] CRUD: Validate original document before editing `$id`
- [ ] CRUD: Test no one can overwrite exciting documents/collections without permission
- [ ] FIND: Test for find timeout limits
- [ ] FIND: Add a query validator (Limit queries to indexed attaributes only?)
- [ ] FIND: Add support for more operators (search/match/like)
- [ ] TEST: Missing Collection, DocumentId validators tests
- [ ] TEST: Validate row size is not larger than allowed by adapter (MySQL/MariaDB ~16k)
- [ ] TEST: Add test for creation of a unique index

## Open Issues

- Lazy index creation, maybe add a queue attribute to populate before creating the index?
- In queries for arrays, should we create a dedicated index?

## Limitations (to be completed per adapter)

- ID max size can be 255 bytes
- ID can only contain [^A-Za-z0-9]
- Document max size is x bytes
- Collection can have a max of x attributes
- Collection can have a max of x indexes
- Index value max size is x bytes. Values over x bytes are truncated

## System Requirements

Utopia Framework requires PHP 7.3 or later. We recommend using the latest PHP version whenever possible.

## Tests

To run all unit tests, use the following Docker command:

```bash
docker-compose exec tests vendor/bin/phpunit --configuration phpunit.xml tests
```

To run static code analysis, use the following Psalm command:

```bash
docker-compose exec tests vendor/bin/psalm --show-info=true
```
## Authors

**Eldad Fux**

+ [https://twitter.com/eldadfux](https://twitter.com/eldadfux)
+ [https://github.com/eldadfux](https://github.com/eldadfux)

**Brandon Leckemby**

+ [https://github.com/kodumbeats](https://github.com/kodumbeats)
+ [blog.leckemby.me](blog.leckemby.me)

## Copyright and license

The MIT License (MIT) [http://www.opensource.org/licenses/mit-license.php](http://www.opensource.org/licenses/mit-license.php)
Loading