Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
125 changes: 125 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
name: Tests

on:
push:
branches: [master]
pull_request:

# A newer push to the same branch or pull request cancels the run it supersedes.
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
phpunit:
name: PHP ${{ matrix.php }} / ${{ matrix.mariadb && format('MariaDB {0}', matrix.mariadb) || format('MySQL {0}', matrix.mysql) }} / PostgreSQL ${{ matrix.pgsql }} / default ${{ matrix.adapter || 'mysql' }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
# One baseline (PHP 8.4, MySQL 8.4, PostgreSQL 18); every other job
# changes exactly one axis so a failure points at a single variable.
# The model-level tests run against the default adapter (PHPAR_ADAPTER),
# MySQL unless a row says otherwise; the adapter tests always cover all
# three. SQLite is bundled with each PHP build and is exercised in every job.
matrix:
include:
- { php: '8.4', mysql: '8.4', pgsql: '18' }
# MySQL axis
- { php: '8.4', mysql: '5.7', pgsql: '18' }
- { php: '8.4', mysql: '8.0', pgsql: '18' }
# MariaDB, through the same adapter: 10.11 (Debian 12, Ubuntu 24.04,
# RHEL 9/10), 11.8 (Debian 13) and the current 12.3 LTS.
- { php: '8.4', mariadb: '10.11', pgsql: '18' }
- { php: '8.4', mariadb: '11.8', pgsql: '18' }
- { php: '8.4', mariadb: '12.3', pgsql: '18' }
# PostgreSQL axis, with PostgreSQL as the default adapter
- { php: '8.4', mysql: '8.4', pgsql: '14', adapter: pgsql }
- { php: '8.4', mysql: '8.4', pgsql: '16', adapter: pgsql }
- { php: '8.4', mysql: '8.4', pgsql: '18', adapter: pgsql }
# PHP axis
- { php: '8.2', mysql: '8.4', pgsql: '18' }
- { php: '8.3', mysql: '8.4', pgsql: '18' }
- { php: '8.5', mysql: '8.4', pgsql: '18' }

# Data directories live on tmpfs: the suite commits tens of thousands of
# tiny transactions and each one fsyncs, which is slow on the runner's
# network-backed disk. The databases are throwaway, so nothing is lost.
services:
mysql:
# The MariaDB image accepts the MYSQL_* variables and speaks the same protocol.
image: ${{ matrix.mariadb && format('mariadb:{0}', matrix.mariadb) || format('mysql:{0}', matrix.mysql) }}
env:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: test
MYSQL_USER: test
MYSQL_PASSWORD: test
ports:
- 3306:3306
options: >-
--tmpfs /var/lib/mysql:rw
--health-cmd "${{ matrix.mariadb && 'healthcheck.sh --connect --innodb_initialized' || 'mysqladmin ping -h 127.0.0.1 -uroot -proot' }}"
--health-interval 5s
--health-timeout 5s
--health-retries 20

postgres:
image: postgres:${{ matrix.pgsql }}
env:
POSTGRES_USER: test
POSTGRES_PASSWORD: test
POSTGRES_DB: test
# Keep the data directory on the tmpfs above. The image default is a
# declared volume (/var/lib/postgresql/data up to 17, a versioned
# subdirectory from 18), and 18 refuses a mount at the old path.
PGDATA: /var/lib/postgresql/pgdata
ports:
- 5432:5432
options: >-
--tmpfs /var/lib/postgresql:rw
--health-cmd "pg_isready -h 127.0.0.1 -U test"
--health-interval 5s
--health-timeout 5s
--health-retries 20

memcached:
image: memcached:1.6-alpine
ports:
- 11211:11211

steps:
- uses: actions/checkout@v7

- name: Set up PHP ${{ matrix.php }}
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
extensions: pdo_mysql, pdo_pgsql, pdo_sqlite, memcached
coverage: none

- name: Install dependencies
run: composer install --no-interaction --prefer-dist --no-progress

- name: Run tests
run: vendor/bin/phpunit
env:
PHPAR_ADAPTER: ${{ matrix.adapter || 'mysql' }}
PHPAR_MYSQL: mysql://test:test@127.0.0.1/test
PHPAR_PGSQL: pgsql://test:test@127.0.0.1/test

phpcs:
name: Coding standard
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7

- name: Set up PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.4'
coverage: none

- name: Install dependencies
run: composer install --no-interaction --prefer-dist --no-progress

- name: Run phpcs
run: vendor/bin/phpcs
37 changes: 0 additions & 37 deletions .travis.yml

This file was deleted.

1 change: 0 additions & 1 deletion CHANGELOG
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ Version 1.0 - June 27, 2010

Versio 1.0 RC1 - May 7, 2010

- support for Oracle
- support for PostgreSQL
- added delegators
- added setters
Expand Down
40 changes: 32 additions & 8 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,17 +27,41 @@ Or run a single test file by specifying its path:
vendor/bin/phpunit test/InflectorTest.php
```

#### Skipped Tests ####
#### Databases ####

You might notice that some tests are marked as skipped. To obtain more information about skipped
tests, pass the `--verbose` flag to PHPUnit:
Most tests need a MySQL server, and the PostgreSQL and memcached tests are skipped when their server
or PHP extension is missing. To see why a test was skipped:

```sh
vendor/bin/phpunit --verbose
vendor/bin/phpunit --display-skipped
```

Some common steps for fixing skipped tests are to:
The suite connects to `mysql://test:test@127.0.0.1/test` and `pgsql://test:test@127.0.0.1/test` by
default, and to memcached on `localhost:11211`. Override the database locations with the `PHPAR_MYSQL`,
`PHPAR_PGSQL` and `PHPAR_SQLITE` environment variables. The model-level tests run against MySQL unless
`PHPAR_ADAPTER` names another connection (`pgsql` or `sqlite`); the adapter tests always cover all three.

* Install `memcached` and the PHP memcached extension (e.g., `brew install php56-memcache memcached` on macOS)
* Install the PDO drivers for PostgreSQL (e.g., `brew install php56-pdo-pgsql` on macOS)
* Create a MySQL database and a PostgreSQL database. You can either create these such that they are available at the default locations of `mysql://test:test@127.0.0.1/test` and `pgsql://test:test@127.0.0.1/test` respectively. Alternatively, you can set the `PHPAR_MYSQL` and `PHPAR_PGSQL` environment variables to specify a different location for the MySQL and PostgreSQL databases.
The easiest way to get the servers is Docker. `compose.yaml` defines the same versions that CI tests,
each on its own port, so you can run several side by side:

```sh
docker compose up -d mysql84 pgsql18 memcached
PHPAR_MYSQL=mysql://test:test@127.0.0.1:33084/test \
PHPAR_PGSQL=pgsql://test:test@127.0.0.1:54318/test \
vendor/bin/phpunit
```

Ports follow the version: `mysql57` is 33057, `mysql80` is 33080, `mysql84` is 33084, `mariadb1011` is
33111, `mariadb118` is 33118, `mariadb123` is 33123, `pgsql14` is 54314, `pgsql16` is 54316 and `pgsql18`
is 54318. MariaDB uses the MySQL adapter, so point `PHPAR_MYSQL` at it. The containers keep their data on tmpfs and skip fsyncs, so
they start empty every time and run fast even when Docker lives inside a VM.

You also need the PHP extensions `pdo_mysql`, `pdo_pgsql`, `pdo_sqlite` and `memcached`.

#### Continuous integration ####

`.github/workflows/tests.yml` runs the suite on GitHub Actions against a small matrix: a baseline of
PHP 8.4, MySQL 8.4 and PostgreSQL 18, plus one job per other supported version of each, changing a
single axis at a time, and three MariaDB versions through the MySQL adapter. The PostgreSQL rows run
the model-level tests with PostgreSQL as the default adapter. A separate job runs `vendor/bin/phpcs`, so a pull request that breaks the coding standard fails
CI as well. Update the matrix when a PHP or database version reaches end of life.
11 changes: 5 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ Of course, there are some differences which will be obvious to the user if they
- MySQL
- SQLite
- PostgreSQL
- Oracle

## Features ##

Expand Down Expand Up @@ -65,11 +64,11 @@ ActiveRecord\Config::initialize(function($cfg)
{
$cfg->set_model_directory('/path/to/your/model_directory');
$cfg->set_connections(
array(
[
'development' => 'mysql://username:password@localhost/development_database_name',
'test' => 'mysql://username:password@localhost/test_database_name',
'production' => 'mysql://username:password@localhost/production_database_name'
)
]
);
});
```
Expand All @@ -80,11 +79,11 @@ Alternatively (w/o the 5.3 closure):
$cfg = ActiveRecord\Config::instance();
$cfg->set_model_directory('/path/to/your/model_directory');
$cfg->set_connections(
array(
[
'development' => 'mysql://username:password@localhost/development_database_name',
'test' => 'mysql://username:password@localhost/test_database_name',
'production' => 'mysql://username:password@localhost/production_database_name'
)
]
);
```

Expand Down Expand Up @@ -122,7 +121,7 @@ $post = Post::find_by_name_and_id('The Bridge Builder',100);
$post = Post::find_by_name_or_id('The Bridge Builder',100);

# finding using a conditions array
$posts = Post::find('all',array('conditions' => array('name=? or id > ?','The Bridge Builder',100)));
$posts = Post::find('all',['conditions' => ['name=? or id > ?','The Bridge Builder',100]]);
```

### Create ###
Expand Down
75 changes: 75 additions & 0 deletions compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# Database servers for running the test suite locally, mirroring the versions
# tested in .github/workflows/tests.yml. Start only what you need, e.g.:
#
# docker compose up -d mysql84 pgsql18 memcached
# PHPAR_MYSQL=mysql://test:test@127.0.0.1:33084/test \
# PHPAR_PGSQL=pgsql://test:test@127.0.0.1:54318/test \
# vendor/bin/phpunit
#
# The databases are throwaway, so they keep their data on tmpfs and skip
# per-commit fsyncs. That is the difference between a one-minute and a
# five-second run when Docker runs inside a VM (macOS, Windows).

x-mysql: &mysql
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: test
MYSQL_USER: test
MYSQL_PASSWORD: test
tmpfs:
- /var/lib/mysql
command: --innodb-flush-log-at-trx-commit=0 --innodb-doublewrite=0 --skip-log-bin

x-pgsql: &pgsql
environment:
POSTGRES_USER: test
POSTGRES_PASSWORD: test
POSTGRES_DB: test
PGDATA: /var/lib/postgresql/pgdata # see the note in the workflow file
tmpfs:
- /var/lib/postgresql
command: -c fsync=off -c synchronous_commit=off -c full_page_writes=off

services:
mysql57:
<<: *mysql
image: mysql:5.7
platform: linux/amd64 # no arm64 image exists; runs emulated on Apple silicon
ports: ["127.0.0.1:33057:3306"]
mysql80:
<<: *mysql
image: mysql:8.0
ports: ["127.0.0.1:33080:3306"]
mysql84:
<<: *mysql
image: mysql:8.4
ports: ["127.0.0.1:33084:3306"]
mariadb1011:
<<: *mysql
image: mariadb:10.11
ports: ["127.0.0.1:33111:3306"]
mariadb118:
<<: *mysql
image: mariadb:11.8
ports: ["127.0.0.1:33118:3306"]
mariadb123:
<<: *mysql
image: mariadb:12.3
ports: ["127.0.0.1:33123:3306"]

pgsql14:
<<: *pgsql
image: postgres:14
ports: ["127.0.0.1:54314:5432"]
pgsql16:
<<: *pgsql
image: postgres:16
ports: ["127.0.0.1:54316:5432"]
pgsql18:
<<: *pgsql
image: postgres:18
ports: ["127.0.0.1:54318:5432"]

memcached:
image: memcached:1.6-alpine
ports: ["127.0.0.1:11211:11211"]
Loading