diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 0000000..1a127db
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,79 @@
+name: CI
+on:
+ pull_request:
+ branches: [ "dev" ]
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ env:
+ COMPOSE_FILE: docker-compose.yml:docker-compose.ci.override.yml
+ COMPOSE_PROJECT_NAME: ci-${{ github.job }}-${{ github.run_id }}
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Build services
+ run: docker compose build
+
+ - name: Show service logs if failed
+ if: failure()
+ run: docker compose logs
+
+ - name: Container runs
+ run: docker compose run --rm --no-deps -T findingaid php -v
+
+ - name: Teardown
+ if: always()
+ run: docker compose down -v --remove-orphans
+
+ lint:
+ needs: build
+ runs-on: ubuntu-latest
+ # TODO: Fix the linting errors
+ # Report the failure, but don't stop the job
+ continue-on-error: true
+ env:
+ COMPOSE_FILE: docker-compose.yml:docker-compose.ci.override.yml
+ COMPOSE_PROJECT_NAME: ci-${{ github.job }}-${{ github.run_id }}
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Build services
+ run: docker compose build
+
+ - name: Show service logs if failed
+ if: failure()
+ run: docker compose logs
+
+ - name: Run linting inside app container
+ run: docker compose run --rm -T findingaid /vendor/bin/phpcs -w --exclude=Generic.Files.LineLength --standard=PSR12 /tests /app
+
+ - name: Teardown
+ if: always()
+ run: docker compose down -v --remove-orphans
+
+ unit-test:
+ needs: build
+ runs-on: ubuntu-latest
+ env:
+ COMPOSE_FILE: docker-compose.yml:docker-compose.ci.override.yml
+ COMPOSE_PROJECT_NAME: ci-${{ github.job }}-${{ github.run_id }}
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Build services
+ run: docker compose build
+
+ - name: Start services
+ run: docker compose up -d findingaid
+
+ - name: Show service logs if failed
+ if: failure()
+ run: docker compose logs
+
+ - name: Run tests inside app container
+ run: docker compose run --rm -T findingaid /vendor/bin/phpunit -c /phpunit.xml /tests
+
+ - name: Teardown
+ if: always()
+ run: docker compose down -v --remove-orphans
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
new file mode 100644
index 0000000..635617e
--- /dev/null
+++ b/.github/workflows/publish.yml
@@ -0,0 +1,34 @@
+name: Publish release
+on:
+ push: [dev]
+
+permissions:
+ contents: read
+ packages: write
+
+jobs:
+ publish:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ with:
+ ref: ${{ github.sha }}
+
+ - uses: docker/setup-buildx-action@v3
+
+ - name: Login to GitHub Container Registry (ghcr)
+ uses: docker/login-action@v3
+ with:
+ registry: ghcr.io
+ username: ${{ github.actor }}
+ password: ${{ secrets.GITHUB_TOKEN }}
+
+ - name: Build and push
+ uses: docker/build-push-action@v6
+ with:
+ context: .
+ push: true
+ tags: |
+ ghcr.io/${{ github.repository_owner }}/findingaid:${{ github.sha }}
+ labels: |
+ org.opencontainers.image.revision=${{ github.sha }}
diff --git a/.gitignore b/.gitignore
index b4d3a69..97aaa5d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,3 +8,4 @@ misc/
public/minimal*
public/cache
is_prod
+.phpunit.result.cache
diff --git a/dockerfile b/Dockerfile
similarity index 61%
rename from dockerfile
rename to Dockerfile
index 6343d12..2632c0c 100644
--- a/dockerfile
+++ b/Dockerfile
@@ -9,7 +9,7 @@ RUN git clone https://github.com/douglascrockford/JSMin /tmp/jsmin && \
gcc /tmp/jsmin/jsmin.c -o /usr/bin/jsmin && \
rm -rf /tmp/jsmin
-FROM php:8.0-fpm-alpine AS development
+FROM php:8.3-fpm-alpine AS development
# add other deps for dev here
RUN apk add --no-cache \
@@ -35,22 +35,48 @@ ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
EXPOSE 9000
CMD ["php-fpm", "-F"]
-FROM php:8.0-fpm-alpine AS prod-builder
+FROM php:8.3-fpm-alpine AS prod-builder
RUN apk add --no-cache bash
COPY --from=composer:2.8 /usr/bin/composer /usr/bin/composer
COPY --from=jsmin /usr/bin/jsmin /usr/bin/jsmin
+WORKDIR /app
+COPY ./composer.json .
+COPY ./composer.lock .
+
+RUN composer install --no-interaction --no-dev
+
+COPY ./app .
+
+FROM php:8.3-fpm-alpine as CI
+
+RUN apk add --no-cache \
+ libzip-dev \
+ bash
+
WORKDIR /app
-COPY . .
+COPY --from=jsmin /usr/bin/jsmin /usr/bin/jsmin
+COPY --from=prod-builder /app .
+COPY --from=development /vendor /vendor
+COPY ./phpunit.xml /phpunit.xml
+
+COPY exe/build.sh /exe/build.sh
+COPY entrypoint.sh /usr/local/bin/entrypoint.sh
+RUN chmod +x /usr/local/bin/entrypoint.sh
+
+ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
+EXPOSE 9000
+CMD ["php-fpm", "-F"]
-FROM php:8.0-fpm-alpine AS production
+FROM php:8.3-fpm-alpine AS production
WORKDIR /app
COPY --from=prod-builder /app .
+COPY --from=prod-builder /vendor /vendor
COPY exe/build.sh /exe/build.sh
COPY entrypoint.sh /usr/local/bin/entrypoint.sh
diff --git a/app/config/config.php b/app/config/config.php
index 1358739..cd3f6dc 100644
--- a/app/config/config.php
+++ b/app/config/config.php
@@ -1,25 +1,25 @@
config = json_decode(file_get_contents($config_file), true);
}
- $repo_file = implode(DIRECTORY_SEPARATOR, array(
+ $repo_file = implode(DIRECTORY_SEPARATOR, [
APP,
'config',
'repo.json',
- ));
+ ]);
if (file_exists($repo_file)) {
$this->repo = json_decode(file_get_contents($repo_file), true);
}
@@ -48,11 +48,11 @@ public function get_repo($key)
public function get_nonuk($key)
{
if (!isset($this->nonuk)) {
- $nonuk_config_file = implode(DIRECTORY_SEPARATOR, array(
+ $nonuk_config_file = implode(DIRECTORY_SEPARATOR, [
APP,
'config',
'nonuk-metadata.json',
- ));
+ ]);
if (file_exists($nonuk_config_file)) {
$this->nonuk = json_decode(file_get_contents($nonuk_config_file), true);
}
diff --git a/app/controllers/component.php b/app/controllers/component.php
index 56da942..569ccbb 100644
--- a/app/controllers/component.php
+++ b/app/controllers/component.php
@@ -1,7 +1,7 @@
new Mustache_Loader_FilesystemLoader(
implode(
DIRECTORY_SEPARATOR,
- array(
+ [
APP,
'views',
'findingaid',
- )
+ ]
)
),
- ));
+ ]);
- $pieces = explode('_', $this->params['id']);
+ $pieces = explode('_', (string) $this->params['id']);
$id = $pieces[0];
$component_id = $pieces[1];
$model = new ComponentModel($id, $component_id);
@@ -35,24 +35,24 @@ public function render()
$container_list_template = load_template('findingaid/container_list');
$component_template = load_template('findingaid/component');
- $container_lists = array();
+ $container_lists = [];
foreach ($model->container_lists() as $container_list) {
$container_list_content = $m->render(
$container_list_template,
$container_list
);
- $container_lists[] = array(
+ $container_lists[] = [
'container_list' => $container_list_content,
- );
+ ];
}
$subcomponents = $model->subcomponents();
- $subcomponent_content = array();
+ $subcomponent_content = [];
foreach ($model->subcomponents() as $subcomponent) {
- $subcomponent_content[] = array(
+ $subcomponent_content[] = [
'subcomponent' => $m->render(
$component_template,
- array(
+ [
'label' => fa_brevity($subcomponent->title()),
'collapsible' => true,
'bioghist_head' => $model->bioghistHead(),
@@ -61,14 +61,14 @@ public function render()
'scopecontent' => $subcomponent->scopecontent(),
'processinfo_head' => $model->processinfoHead(),
'processinfo' => $subcomponent->processinfo(),
- )
+ ]
),
- );
+ ];
}
$component_content = $m->render(
$component_template,
- array(
+ [
'label' => fa_brevity($model->title()),
'collapsible' => true,
'container_lists' => $container_lists,
@@ -79,18 +79,18 @@ public function render()
'processinfo_head' => $model->processinfoHead(),
'processinfo' => $model->processinfo(),
'subcomponents' => $subcomponent_content,
- )
+ ]
);
- return array(
+ return [
$component_content,
- array(
+ [
'level' => (string)$model->level(),
- 'metadata' => array(
+ 'metadata' => [
'label' => fa_brevity($model->title()),
'id' => 'demo_id',
- ),
- ),
- );
+ ],
+ ],
+ ];
}
}
diff --git a/app/controllers/findingaid.php b/app/controllers/findingaid.php
index 07ea932..3c8345f 100644
--- a/app/controllers/findingaid.php
+++ b/app/controllers/findingaid.php
@@ -3,10 +3,10 @@ class Findingaid extends Controller
{
private $templates;
- public function __construct($params = array())
+ public function __construct($params = [])
{
parent::__construct($params);
- $templates = array();
+ $templates = [];
}
public function show()
@@ -25,29 +25,29 @@ public function show()
/* First, fill out top-level metadata, including the
* table of contents.
*/
- $m = new Mustache_Engine(array(
+ $m = new Mustache_Engine([
'partials_loader' => new Mustache_Loader_FilesystemLoader(
implode(
DIRECTORY_SEPARATOR,
- array(
+ [
APP,
'views',
'findingaid',
- )
+ ]
)
),
- ));
+ ]);
$model = new FindingaidModel($this->params['id']);
if ($model->exists) {
- $options = array(
- 'panels' => array(),
+ $options = [
+ 'panels' => [],
'title' => fa_brevity($model->title()),
- );
+ ];
- $toc_entries_unsorted = array();
- $toc_subentries = array();
+ $toc_entries_unsorted = [];
+ $toc_subentries = [];
foreach ($this->config->get('panels') as $stub) {
$panel = $stub;
$panel['heading_id'] = "fa-heading-{$panel['id']}";
@@ -56,7 +56,7 @@ public function show()
if (array_key_exists('field', $panel)) {
$data = $model->xpath("//{$panel['field']}");
foreach ($data as $datum) {
- $content = trim(fa_render($datum));
+ $content = trim((string) fa_render($datum));
if (strlen($content) > 0) {
$panel['single-field'] = $content;
$skip = false;
@@ -66,7 +66,7 @@ public function show()
if ($skip && array_key_exists('backup_field', $panel)) {
$data = $model->xpath("//{$panel['backup_field']}");
foreach ($data as $datum) {
- $content = trim(fa_render($datum));
+ $content = trim((string) fa_render($datum));
if (strlen($content) > 0) {
$panel['single-field'] = $content;
$skip = false;
@@ -76,33 +76,33 @@ public function show()
}
}
elseif (array_key_exists('fields', $panel)) {
- $panel['multi-field'] = array();
+ $panel['multi-field'] = [];
foreach ($panel['fields'] as $entry) {
$data = $model->xpath("//{$entry['field']}");
- $metadata = array();
+ $metadata = [];
foreach ($data as $datum) {
- $content = trim(fa_render($datum));
+ $content = trim((string) fa_render($datum));
if (strlen($content) > 0) {
- $metadata[] = array(
+ $metadata[] = [
'content' => $content,
- );
+ ];
$skip = false;
}
}
if (count($metadata) > 0) {
- $panel['multi-field'][] = array(
+ $panel['multi-field'][] = [
'field_id' => "fa-fields-{$panel['body_id']}-{$entry['id']}",
'label' => fa_brevity($entry['label']),
'entries' => $metadata,
- );
+ ];
$skip = false;
}
if (array_key_exists('in_toc', $entry)) {
if ($entry['in_toc']) {
- $toc_entry = array(
+ $toc_entry = [
'label' => fa_brevity($entry['label']),
'id' => "fa-fields-{$panel['body_id']}-{$entry['id']}",
- );
+ ];
$toc_entries_unsorted[$entry['id']] = $toc_entry;
}
}
@@ -112,25 +112,25 @@ public function show()
$component_count = count($model->xpath('contents/c'));
if ($component_count > 0) {
$skip = false;
- $templates = array('container_list', 'component');
+ $templates = ['container_list', 'component'];
foreach ($templates as $template) {
$this->templates[$template] = load_template("findingaid/$template");
}
foreach ($model->xpath('contents/c') as $c) {
$details = $this->render_component($m, $c);
- $panel['components'][] = array(
+ $panel['components'][] = [
'component' => $details[0],
- );
+ ];
if ($details[1]['level'] === 'series') {
$attributes = $c->attributes();
$toc_subentries[] = $details[1]['metadata'];
}
}
- $panel['contents_entries'] = array();
+ $panel['contents_entries'] = [];
if (count($toc_subentries) > 0) {
$panel['subentries'] = true;
$panel['contents_entries'] = $toc_subentries;
- $toc_subentries = array();
+ $toc_subentries = [];
}
}
}
@@ -143,10 +143,10 @@ public function show()
if (array_key_exists('in_toc', $panel)) {
$in_toc = $panel['in_toc'];
if ($in_toc) {
- $toc_entry = array(
+ $toc_entry = [
'label' => fa_brevity($panel['label']),
'id' => $panel['heading_id'],
- );
+ ];
if (isset($panel['subentries'])) {
$toc_entry['subentries'] = true;
$toc_entry['contents_entries'] = $panel['contents_entries'];
@@ -159,7 +159,7 @@ public function show()
}
$toc_config = $this->config->get('toc');
- $toc_entries = array();
+ $toc_entries = [];
foreach ($toc_config['entries'] as $entry) {
if (array_key_exists($entry, $toc_entries_unsorted)) {
$toc_entry = $toc_entries_unsorted[$entry];
@@ -167,7 +167,7 @@ public function show()
}
}
- $links = array();
+ $links = [];
foreach ($toc_config['links'] as $link) {
if (array_key_exists('skip', $link)) {
if ($link['skip']) {
@@ -183,8 +183,8 @@ public function show()
$data = $model->xpath("//{$link['field']}");
$raw_search = false;
foreach ($data as $datum) {
- if (strlen(trim($datum)) > 0) {
- $raw_search = trim($datum);
+ if (strlen(trim((string) $datum)) > 0) {
+ $raw_search = trim((string) $datum);
break;
}
}
@@ -192,16 +192,16 @@ public function show()
$data = $model->xpath("//{$link['backup_field']}");
$raw_search = false;
foreach ($data as $datum) {
- if (strlen(trim($datum)) > 0) {
- $raw_search = trim($datum);
+ if (strlen(trim((string) $datum)) > 0) {
+ $raw_search = trim((string) $datum);
break;
}
}
}
- $prod_indicator = implode(DIRECTORY_SEPARATOR, array(
+ $prod_indicator = implode(DIRECTORY_SEPARATOR, [
ROOT,
'is_prod',
- ));
+ ]);
if (file_exists($prod_indicator)) {
$url = 'https://exploreuk.uky.edu/?' .
$search_field . '=' . urlencode($raw_search);
@@ -215,8 +215,8 @@ public function show()
$data = $model->xpath("//{$link['field']}");
$url = false;
foreach ($data as $datum) {
- if (strlen(trim($datum)) > 0) {
- $url = trim($datum);
+ if (strlen(trim((string) $datum)) > 0) {
+ $url = trim((string) $datum);
break;
}
}
@@ -224,17 +224,17 @@ public function show()
$data = $model->xpath("//{$link['backup_field']}");
$url = false;
foreach ($data as $datum) {
- if (strlen(trim($datum)) > 0) {
- $url = trim($datum);
+ if (strlen(trim((string) $datum)) > 0) {
+ $url = trim((string) $datum);
break;
}
}
}
}
- $links[] = array(
+ $links[] = [
'label' => $link['label'],
'url' => $url,
- );
+ ];
}
}
@@ -243,23 +243,23 @@ public function show()
$toc_component = false;
if ($requestable and ($component_count == 0)) {
- $toc_component = array(
+ $toc_component = [
'summary' => '',
'id' => 'fa-no-components-request',
'container_list' => fa_brevity($model->title()),
'volume' => '',
'container' => '',
- );
+ ];
}
- $toc_options = array(
+ $toc_options = [
'id' => "fa-{$toc_config['id']}",
'label' => fa_brevity($toc_config['label']),
'entries' => $toc_entries,
'links' => $links,
'requestable' => $requestable,
'toc_component' => $toc_component,
- );
+ ];
$toc = $m->render(
load_template('findingaid/toc'),
@@ -275,7 +275,7 @@ public function show()
$requests_config = $this->config->get('requests');
$requests = $m->render(
load_template('findingaid/requests'),
- array(
+ [
'id' => $requests_config['summary']['id'],
'label' => fa_brevity($requests_config['summary']['label']),
'list_id' => $requests_config['summary']['list_id'],
@@ -284,78 +284,78 @@ public function show()
'call_number' => $model->unitid(),
'item_date' => $model->unitdate(),
'item_url' => 'https://exploreuk.uky.edu/catalog/' . $model->id() . '/',
- )
+ ]
);
}
else {
$requests = '';
}
- $css_hrefs = array(
+ $css_hrefs = [
"css/bootstrap.min.css",
"css/jquery-ui.min.css",
"css/extra.css",
"css/footer.css",
"css/lity.min.css",
"css/mediaelementplayer.min.css",
- );
+ ];
- $css = array();
+ $css = [];
foreach ($css_hrefs as $href) {
- $css[] = array('href' => $href);
+ $css[] = ['href' => $href];
}
- $layout = new Mustache_Engine(array(
+ $layout = new Mustache_Engine([
'partials_loader' => new Mustache_Loader_FilesystemLoader(
implode(
DIRECTORY_SEPARATOR,
- array(
+ [
APP,
'views',
'layouts',
- )
+ ]
)
),
- ));
+ ]);
$page = $layout->render(
load_template('layouts/application'),
- array(
+ [
'content' => $content,
'toc' => $toc,
'requests' => $requests,
'css' => $css,
- 'js' => array(array(
+ 'js' => [[
'href' => 'js/app.js',
'hash' => hash_file('sha256', implode(
DIRECTORY_SEPARATOR,
- array(
+ [
ROOT,
'public',
'js',
'app.js',
- )
+ ]
)),
- )),
+ ]],
'title' => $model->title(),
'requestable' => $requestable,
'repository' => $this->config->get_repo($repository),
- )
+ ]
);
set_cache($id, $page);
}
else {
- $layout = new Mustache_Engine(array(
+ $layout = new Mustache_Engine([
'partials_loader' => new Mustache_Loader_FilesystemLoader(
implode(
DIRECTORY_SEPARATOR,
- array(
+ [
APP,
'views',
'layouts',
- )
+ ]
)
),
- ));
+ ]);
$meta = $this->config->get_nonuk($id);
if ($meta) {
$repo = $meta['repository'];
@@ -372,20 +372,20 @@ public function show()
if ($is_kdl_partner) {
$page = $layout->render(
load_template('layouts/suggest_kdl'),
- array(
+ [
'title' => $meta['title'],
'repository' => $meta['repository'],
- )
+ ]
);
}
else {
$page = $layout->render(
load_template('layouts/suggest_former_kdl'),
- array(
+ [
'title' => $meta['title'],
'repository' => $meta['repository'],
'repo_url' => $repo_url,
- )
+ ]
);
}
}
@@ -410,28 +410,28 @@ public function render_component($renderer, $component_xml)
$heading_id = "fa-heading-{$attributes['id']}";
$body_id = "fa-body-{$attributes['id']}";
$component = new ComponentModel($this->params['id'], $attributes['id']);
- $subcomponent_content = array();
+ $subcomponent_content = [];
foreach ($component->subcomponents() as $subcomponent) {
$subcomponent_details = $this->render_component($renderer, $subcomponent->xml());
- $subcomponent_content[] = array(
+ $subcomponent_content[] = [
'subcomponent' => $subcomponent_details[0],
- );
+ ];
}
- $container_lists = array();
+ $container_lists = [];
foreach ($component->container_lists() as $container_list) {
$container_list_content = $renderer->render(
$this->templates['container_list'],
$container_list
);
- $container_lists[] = array(
+ $container_lists[] = [
'container_list' => $container_list_content,
- );
+ ];
}
$component_content = $renderer->render(
$this->templates['component'],
- array(
+ [
'label' => fa_brevity($component->title()),
'collapsible' => true,
'container_lists' => $container_lists,
@@ -445,26 +445,26 @@ public function render_component($renderer, $component_xml)
'subcomponents' => $subcomponent_content,
'heading_id' => $heading_id,
'body_id' => $body_id,
- )
+ ]
);
}
else {
error_log("FA: attributes_id not set");
}
- return array(
+ return [
$component_content,
- array(
+ [
'level' => (string)$component->level(),
- 'metadata' => array(
+ 'metadata' => [
'label' => fa_brevity($component->title()),
'id' => $heading_id,
- ),
- ),
- );
+ ],
+ ],
+ ];
}
private function cleanup($message)
{
- return preg_replace('/\s+/', ' ', $message);
+ return preg_replace('/\s+/', ' ', (string) $message);
}
}
diff --git a/app/controllers/overview.php b/app/controllers/overview.php
index ef8697e..1eba540 100644
--- a/app/controllers/overview.php
+++ b/app/controllers/overview.php
@@ -3,10 +3,10 @@ class Overview extends Controller
{
private $templates;
- public function __construct($params = array())
+ public function __construct($params = [])
{
parent::__construct($params);
- $templates = array();
+ $templates = [];
}
public function show()
@@ -29,47 +29,47 @@ public function show()
$model = new OverviewModel($this->params['id']);
if ($model->exists) {
- $options = array(
- 'panels' => array(),
+ $options = [
+ 'panels' => [],
'title' => fa_brevity($model->title()),
- );
+ ];
- $css_hrefs = array(
+ $css_hrefs = [
"css/bootstrap.min.css",
"css/jquery-ui.min.css",
"css/extra.css",
"css/footer.css",
"css/lity.min.css",
"css/mediaelementplayer.min.css",
- );
+ ];
- $css = array();
+ $css = [];
foreach ($css_hrefs as $href) {
- $css[] = array('href' => $href);
+ $css[] = ['href' => $href];
}
- $layout = new Mustache_Engine(array(
+ $layout = new Mustache_Engine([
'partials_loader' => new Mustache_Loader_FilesystemLoader(
implode(
DIRECTORY_SEPARATOR,
- array(
+ [
APP,
'views',
'layouts',
- )
+ ]
)
),
- ));
+ ]);
$page = $layout->render(
load_template('layouts/overview'),
- array(
+ [
'title' => $model->title(),
'bioghist' => $model->bioghist(),
'scopecontent' => $model->scopecontent(),
#'content' => $content,
'css' => $css,
#'title' => $model->title(),
- )
+ ]
);
}
diff --git a/app/core/application.php b/app/core/application.php
index 154f694..111687e 100644
--- a/app/core/application.php
+++ b/app/core/application.php
@@ -2,7 +2,7 @@
# Based on https://github.com/panique/mini
class Application
{
- private $url_params = array();
+ private $url_params = [];
private $url_controller = null;
public function __construct()
@@ -28,13 +28,13 @@ private function splitUrl()
}
}
if (isset($_GET['id'])) {
- $url = trim($_GET['id'], '/');
+ $url = trim((string) $_GET['id'], '/');
$url = filter_var($url, FILTER_SANITIZE_URL);
$url = explode('/', $url);
# /:id
if (count($url) >= 1) {
- $this->url_params = array();
+ $this->url_params = [];
foreach ($url as $param) {
if (strlen($param) > 0) {
$this->url_params['id'] = $param;
diff --git a/app/core/brevity.php b/app/core/brevity.php
index 7fe1a79..f314e74 100644
--- a/app/core/brevity.php
+++ b/app/core/brevity.php
@@ -8,9 +8,9 @@ function fa_brevity($message, $length = 0)
if ($length == 0) {
$length = FA_MAX_LENGTH;
}
- if (strlen($message) > $length) {
- $source_words = preg_split('/\b/', $message);
- $target_words = array();
+ if (strlen((string) $message) > $length) {
+ $source_words = preg_split('/\b/', (string) $message);
+ $target_words = [];
$current_length = 0;
foreach ($source_words as $word) {
if (($current_length == 0) || $current_length + strlen($word) <= $length) {
diff --git a/app/core/controller.php b/app/core/controller.php
index 7e6b06c..75c2847 100644
--- a/app/core/controller.php
+++ b/app/core/controller.php
@@ -1,13 +1,11 @@
params = $params;
$this->config = $g_config;
}
}
diff --git a/app/core/minter.php b/app/core/minter.php
index e699b33..c94924c 100644
--- a/app/core/minter.php
+++ b/app/core/minter.php
@@ -2,12 +2,10 @@
class Minter
{
private $counter;
- private $base;
- public function __construct($base)
+ public function __construct(private $base)
{
$this->counter = 0;
- $this->base = $base;
}
public function mint()
diff --git a/app/core/model.php b/app/core/model.php
index 6ecbba3..02950bb 100644
--- a/app/core/model.php
+++ b/app/core/model.php
@@ -5,11 +5,11 @@ class Model
protected function ppath()
{
- $array = array(
+ $array = [
ROOT,
'xml',
'pairtree_root',
- );
+ ];
$tree = $this->id;
while (strlen($tree) >= 2) {
$prefix = substr($tree, 0, 2);
diff --git a/app/core/render.php b/app/core/render.php
index 43306c8..697ffd3 100644
--- a/app/core/render.php
+++ b/app/core/render.php
@@ -3,22 +3,14 @@
function fa_render($fragment)
{
$node = dom_import_simplexml($fragment);
- $segments = array();
+ $segments = [];
foreach ($node->childNodes as $child) {
- switch ($child->nodeName) {
- case 'emph':
- $segments[] = fa_render_title($child);
- break;
- case 'extref':
- $segments[] = fa_render_extref($child);
- break;
- case 'title':
- $segments[] = fa_render_title($child);
- break;
- default:
- $segments[] = $child->textContent;
- break;
- }
+ $segments[] = match ($child->nodeName) {
+ 'emph' => fa_render_title($child),
+ 'extref' => fa_render_extref($child),
+ 'title' => fa_render_title($child),
+ default => $child->textContent,
+ };
}
return trim(implode('', $segments));
}
@@ -27,17 +19,11 @@ function fa_render_title($node)
{
$render = '';
if ($node->hasAttribute('render')) {
- switch ($node->getAttribute('render')) {
- case 'italic':
- $render = '' . $node->textContent . '';
- break;
- case 'doublequote':
- $render = '"' . $node->textContent . '"';
- break;
- default:
- $render = '"' . $node->textContent . '"';
- break;
- }
+ $render = match ($node->getAttribute('render')) {
+ 'italic' => '' . $node->textContent . '',
+ 'doublequote' => '"' . $node->textContent . '"',
+ default => '"' . $node->textContent . '"',
+ };
} else {
$render = $node->textContent;
}
@@ -64,7 +50,7 @@ function fa_render_extref_ns($node, $ns)
$href_attr = 'href';
$show_attr = 'show';
- if (strlen($ns) > 0) {
+ if (strlen((string) $ns) > 0) {
$href_attr = "$ns:href";
$show_attr = "$ns:show";
}
diff --git a/app/init.php b/app/init.php
index a433589..dc5fa42 100644
--- a/app/init.php
+++ b/app/init.php
@@ -7,25 +7,25 @@
define('ROOT', dirname(__DIR__));
}
-define('APP', implode(DIRECTORY_SEPARATOR, array(
+define('APP', implode(DIRECTORY_SEPARATOR, [
ROOT,
'app',
-)));
+]));
-define('CACHE_DIR', implode(DIRECTORY_SEPARATOR, array(
+define('CACHE_DIR', implode(DIRECTORY_SEPARATOR, [
ROOT,
'public',
'cache',
-)));
+]));
function get_template($path)
{
- $dir = implode(DIRECTORY_SEPARATOR, array(
+ $dir = implode(DIRECTORY_SEPARATOR, [
APP,
'views',
- ));
- $pieces = array($dir);
- foreach (explode('/', $path) as $piece) {
+ ]);
+ $pieces = [$dir];
+ foreach (explode('/', (string) $path) as $piece) {
$pieces[] = $piece;
}
$file = implode(DIRECTORY_SEPARATOR, $pieces) . '.mustache';
@@ -43,8 +43,8 @@ function load_template($path)
function get_path($dir, $path)
{
- $pieces = array($dir);
- foreach (explode('/', $path) as $piece) {
+ $pieces = [$dir];
+ foreach (explode('/', (string) $path) as $piece) {
$pieces[] = $piece;
}
$file = implode(DIRECTORY_SEPARATOR, $pieces) . '.php';
@@ -64,10 +64,10 @@ function get_cache($id)
if (!file_exists(CACHE_DIR)) {
mkdir(CACHE_DIR);
}
- $cache_file = implode(DIRECTORY_SEPARATOR, array(
+ $cache_file = implode(DIRECTORY_SEPARATOR, [
CACHE_DIR,
$id,
- ));
+ ]);
if (file_exists($cache_file)) {
return $cache_file;
}
@@ -90,10 +90,10 @@ function set_cache($id, $page)
if (!file_exists(CACHE_DIR)) {
mkdir(CACHE_DIR);
}
- $cache_file = implode(DIRECTORY_SEPARATOR, array(
+ $cache_file = implode(DIRECTORY_SEPARATOR, [
CACHE_DIR,
$id,
- ));
+ ]);
file_put_contents($cache_file, $page);
}
diff --git a/app/models/component_model.php b/app/models/component_model.php
index e8a13ae..d8ca011 100644
--- a/app/models/component_model.php
+++ b/app/models/component_model.php
@@ -1,17 +1,13 @@
id = $id;
- $this->component_id = $component_id;
- $this->basename = $id . '_' . $this->component_id . '.xml';
+ $this->basename = $this->id . '_' . $this->component_id . '.xml';
$this->config = $g_config;
$component_file = $this->ppath() . DIRECTORY_SEPARATOR . $this->basename;
if (file_exists($component_file)) {
@@ -22,19 +18,19 @@ public function __construct($id, $component_id)
foreach ($this->xpath($contents_config['component']) as $c) {
$cattrs = $c->attributes();
$cid = $cattrs['id'];
- $this->subcomponents[] = new ComponentModel($id, $cid);
+ $this->subcomponents[] = new ComponentModel($this->id, $cid);
}
}
public function links()
{
global $g_minter;
- $pieces = array();
+ $pieces = [];
if (count($this->xpath('did/dao')) > 0) {
$pieces = $this->xpath('did/dao');
}
- $results = array();
- $links_raw = array();
+ $results = [];
+ $links_raw = [];
foreach ($pieces as $piece) {
$dao = $piece['entityref'];
$links_file = $this->ppath() . DIRECTORY_SEPARATOR . $dao . '.json';
@@ -43,12 +39,12 @@ public function links()
break;
}
}
- $links = array();
+ $links = [];
$thumb_count = 0;
$ref_count = 0;
$image_threshold = 5;
foreach ($links_raw as $link_raw) {
- $link = array();
+ $link = [];
foreach ($link_raw['links'] as $use => $href) {
$use = str_replace(' ', '_', $use);
switch ($use) {
@@ -61,7 +57,7 @@ public function links()
$field = 'image_overflow';
}
if (empty($link[$field])) {
- $link[$field] = array();
+ $link[$field] = [];
}
$link[$field]['thumb'] = $href;
break;
@@ -74,21 +70,21 @@ public function links()
$field = 'image_overflow';
}
if (empty($link[$field])) {
- $link[$field] = array();
+ $link[$field] = [];
}
$link[$field]['full'] = $href;
$link[$field]['href_id'] = $g_minter->mint();
break;
case 'reference_audio':
if (empty($link['audio'])) {
- $link['audio'] = array();
+ $link['audio'] = [];
}
$link['audio']['href'] = $href;
$link['audio']['href_id'] = $g_minter->mint();
break;
case 'reference_video':
if (empty($link['video'])) {
- $link['video'] = array();
+ $link['video'] = [];
}
$link['video']['href'] = $href;
$link['video']['href_id'] = $g_minter->mint();
@@ -100,14 +96,14 @@ public function links()
$links[] = $link;
}
if (($thumb_count > $image_threshold) || ($ref_count > $image_threshold)) {
- $links[] = array('extra' => true);
+ $links[] = ['extra' => true];
}
return $links;
}
public function title()
{
- $pieces = array();
+ $pieces = [];
if (count($this->xpath('did/unitdate')) > 0) {
$pieces = array_merge(
$pieces,
@@ -118,7 +114,7 @@ public function title()
else {
$pieces = array_merge($pieces, $this->xpath('did/unittitle'));
}
- $segments = array();
+ $segments = [];
foreach ($pieces as $piece) {
$segments[] = fa_render($piece);
}
@@ -127,31 +123,31 @@ public function title()
public function container_lists()
{
- $container_lists = array();
- $order = array();
- $containers = array();
+ $container_lists = [];
+ $order = [];
+ $containers = [];
$contents_config = $this->config->get('contents');
- $buckets = array();
- $bucket = array();
- $cache = array();
+ $buckets = [];
+ $bucket = [];
+ $cache = [];
$tagged = null;
- $aspects = array();
- $section = array();
- $section_ids = array();
- $section_id_for = array();
+ $aspects = [];
+ $section = [];
+ $section_ids = [];
+ $section_id_for = [];
foreach ($this->xpath($contents_config['container']) as $container) {
$attributes = $container->attributes();
- $aspect = array(
+ $aspect = [
'type' => $this->container_type($attributes),
'content' => (string)$container,
- );
+ ];
if (isset($attributes['id'])) {
$id = trim($attributes['id']);
}
else {
- $id = md5($container->asXML());
+ $id = md5((string) $container->asXML());
}
$aspect['id'] = $id;
@@ -163,13 +159,13 @@ public function container_lists()
}
else {
$section_id_for[$id] = $id;
- $section[$id] = array($aspect);
+ $section[$id] = [$aspect];
$section_ids[] = $id;
}
}
foreach ($section_ids as $id) {
- $bucket = array();
+ $bucket = [];
foreach ($section[$id] as $thing) {
$bucket[] = $thing;
}
@@ -183,7 +179,7 @@ public function container_lists()
foreach ($buckets as $bucket) {
if (count($bucket) > 0) {
$request_target = "fa-request-target-" . md5(json_encode($bucket));
- $container_list_pieces = array();
+ $container_list_pieces = [];
$first = true;
foreach ($bucket as $aspect) {
$piece = $aspect['type'] . ' ' . $aspect['content'];
@@ -198,7 +194,7 @@ public function container_lists()
$full_container_list = fa_brevity($summary . ': '. $this->title(), FA_AEON_MAX);
array_shift($container_list_pieces);
$rest = implode(', ', $container_list_pieces);
- $container_list = array(
+ $container_list = [
'id' => $request_target,
'summary' => $summary,
'volume' => $volume,
@@ -206,7 +202,7 @@ public function container_lists()
'container_list' => $full_container_list,
'active' => $active,
'inactive' => $inactive,
- );
+ ];
$container_lists[] = $container_list;
}
}
@@ -252,9 +248,9 @@ public function processinfo()
public function render_paragraphs($p_list)
{
- $render = array();
+ $render = [];
foreach ($p_list as $p) {
- $render[] = array('p' => fa_render($p));
+ $render[] = ['p' => fa_render($p)];
}
return $render;
}
diff --git a/app/models/findingaid_model.php b/app/models/findingaid_model.php
index 4742812..7cca2be 100644
--- a/app/models/findingaid_model.php
+++ b/app/models/findingaid_model.php
@@ -1,19 +1,17 @@
id = $id;
$header_file = $this->ppath() . DIRECTORY_SEPARATOR . "header.xml";
if (file_exists($header_file)) {
$this->xml = new SimpleXMLElement(file_get_contents($header_file));
$this->exists = true;
}
- $metadata_file = $this->ppath() . DIRECTORY_SEPARATOR . "$id.xml";
+ $metadata_file = $this->ppath() . DIRECTORY_SEPARATOR . "{$this->id}.xml";
if (file_exists($metadata_file)) {
$this->metadata = new SimpleXMLElement(file_get_contents($metadata_file));
}
diff --git a/app/models/overview_model.php b/app/models/overview_model.php
index 9d08a6f..4bb4658 100644
--- a/app/models/overview_model.php
+++ b/app/models/overview_model.php
@@ -1,13 +1,11 @@
id = $id;
$header_file = $this->ppath() . DIRECTORY_SEPARATOR . "header.xml";
if (file_exists($header_file)) {
$this->xml = new SimpleXMLElement(file_get_contents($header_file));
@@ -22,17 +20,17 @@ public function headerXML()
public function bioghist()
{
- $result = array();
+ $result = [];
foreach ($this->xml->collection_overview->bioghist->p as $p) {
- $result[] = array('text' => $p);
+ $result[] = ['text' => $p];
}
return $result;
}
public function scopecontent() {
- $result = array();
+ $result = [];
foreach ($this->xml->collection_overview->scopecontent->p as $p) {
- $result[] = array('text' => $p);
+ $result[] = ['text' => $p];
}
return $result;
}
diff --git a/composer.json b/composer.json
index 0d07931..aa5c478 100644
--- a/composer.json
+++ b/composer.json
@@ -1,5 +1,10 @@
{
"require": {
"mustache/mustache": "~2.5"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^12.4",
+ "squizlabs/php_codesniffer": "^4.0",
+ "rector/rector": "^2.2"
}
}
diff --git a/composer.lock b/composer.lock
index 5e2b3ce..12d0950 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "87bcd1fc0d7193dd7932f342e3a0db97",
+ "content-hash": "b371cf797547805e154bf7e246cd0ea6",
"packages": [
{
"name": "mustache/mustache",
@@ -57,13 +57,1880 @@
"time": "2022-08-23T13:07:01+00:00"
}
],
- "packages-dev": [],
+ "packages-dev": [
+ {
+ "name": "myclabs/deep-copy",
+ "version": "1.13.4",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/myclabs/DeepCopy.git",
+ "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/07d290f0c47959fd5eed98c95ee5602db07e0b6a",
+ "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.1 || ^8.0"
+ },
+ "conflict": {
+ "doctrine/collections": "<1.6.8",
+ "doctrine/common": "<2.13.3 || >=3 <3.2.2"
+ },
+ "require-dev": {
+ "doctrine/collections": "^1.6.8",
+ "doctrine/common": "^2.13.3 || ^3.2.2",
+ "phpspec/prophecy": "^1.10",
+ "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13"
+ },
+ "type": "library",
+ "autoload": {
+ "files": [
+ "src/DeepCopy/deep_copy.php"
+ ],
+ "psr-4": {
+ "DeepCopy\\": "src/DeepCopy/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "description": "Create deep copies (clones) of your objects",
+ "keywords": [
+ "clone",
+ "copy",
+ "duplicate",
+ "object",
+ "object graph"
+ ],
+ "support": {
+ "issues": "https://github.com/myclabs/DeepCopy/issues",
+ "source": "https://github.com/myclabs/DeepCopy/tree/1.13.4"
+ },
+ "funding": [
+ {
+ "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2025-08-01T08:46:24+00:00"
+ },
+ {
+ "name": "nikic/php-parser",
+ "version": "v5.6.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/nikic/PHP-Parser.git",
+ "reference": "3a454ca033b9e06b63282ce19562e892747449bb"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/3a454ca033b9e06b63282ce19562e892747449bb",
+ "reference": "3a454ca033b9e06b63282ce19562e892747449bb",
+ "shasum": ""
+ },
+ "require": {
+ "ext-ctype": "*",
+ "ext-json": "*",
+ "ext-tokenizer": "*",
+ "php": ">=7.4"
+ },
+ "require-dev": {
+ "ircmaxell/php-yacc": "^0.0.7",
+ "phpunit/phpunit": "^9.0"
+ },
+ "bin": [
+ "bin/php-parse"
+ ],
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "5.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "PhpParser\\": "lib/PhpParser"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Nikita Popov"
+ }
+ ],
+ "description": "A PHP parser written in PHP",
+ "keywords": [
+ "parser",
+ "php"
+ ],
+ "support": {
+ "issues": "https://github.com/nikic/PHP-Parser/issues",
+ "source": "https://github.com/nikic/PHP-Parser/tree/v5.6.2"
+ },
+ "time": "2025-10-21T19:32:17+00:00"
+ },
+ {
+ "name": "phar-io/manifest",
+ "version": "2.0.4",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/phar-io/manifest.git",
+ "reference": "54750ef60c58e43759730615a392c31c80e23176"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/phar-io/manifest/zipball/54750ef60c58e43759730615a392c31c80e23176",
+ "reference": "54750ef60c58e43759730615a392c31c80e23176",
+ "shasum": ""
+ },
+ "require": {
+ "ext-dom": "*",
+ "ext-libxml": "*",
+ "ext-phar": "*",
+ "ext-xmlwriter": "*",
+ "phar-io/version": "^3.0.1",
+ "php": "^7.2 || ^8.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.0.x-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Arne Blankerts",
+ "email": "arne@blankerts.de",
+ "role": "Developer"
+ },
+ {
+ "name": "Sebastian Heuer",
+ "email": "sebastian@phpeople.de",
+ "role": "Developer"
+ },
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "Developer"
+ }
+ ],
+ "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)",
+ "support": {
+ "issues": "https://github.com/phar-io/manifest/issues",
+ "source": "https://github.com/phar-io/manifest/tree/2.0.4"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/theseer",
+ "type": "github"
+ }
+ ],
+ "time": "2024-03-03T12:33:53+00:00"
+ },
+ {
+ "name": "phar-io/version",
+ "version": "3.2.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/phar-io/version.git",
+ "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74",
+ "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.2 || ^8.0"
+ },
+ "type": "library",
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Arne Blankerts",
+ "email": "arne@blankerts.de",
+ "role": "Developer"
+ },
+ {
+ "name": "Sebastian Heuer",
+ "email": "sebastian@phpeople.de",
+ "role": "Developer"
+ },
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "Developer"
+ }
+ ],
+ "description": "Library for handling version information and constraints",
+ "support": {
+ "issues": "https://github.com/phar-io/version/issues",
+ "source": "https://github.com/phar-io/version/tree/3.2.1"
+ },
+ "time": "2022-02-21T01:04:05+00:00"
+ },
+ {
+ "name": "phpstan/phpstan",
+ "version": "2.1.31",
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/phpstan/phpstan/zipball/ead89849d879fe203ce9292c6ef5e7e76f867b96",
+ "reference": "ead89849d879fe203ce9292c6ef5e7e76f867b96",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.4|^8.0"
+ },
+ "conflict": {
+ "phpstan/phpstan-shim": "*"
+ },
+ "bin": [
+ "phpstan",
+ "phpstan.phar"
+ ],
+ "type": "library",
+ "autoload": {
+ "files": [
+ "bootstrap.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "description": "PHPStan - PHP Static Analysis Tool",
+ "keywords": [
+ "dev",
+ "static analysis"
+ ],
+ "support": {
+ "docs": "https://phpstan.org/user-guide/getting-started",
+ "forum": "https://github.com/phpstan/phpstan/discussions",
+ "issues": "https://github.com/phpstan/phpstan/issues",
+ "security": "https://github.com/phpstan/phpstan/security/policy",
+ "source": "https://github.com/phpstan/phpstan-src"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/ondrejmirtes",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/phpstan",
+ "type": "github"
+ }
+ ],
+ "time": "2025-10-10T14:14:11+00:00"
+ },
+ {
+ "name": "phpunit/php-code-coverage",
+ "version": "12.4.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/php-code-coverage.git",
+ "reference": "67e8aed88f93d0e6e1cb7effe1a2dfc2fee6022c"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/67e8aed88f93d0e6e1cb7effe1a2dfc2fee6022c",
+ "reference": "67e8aed88f93d0e6e1cb7effe1a2dfc2fee6022c",
+ "shasum": ""
+ },
+ "require": {
+ "ext-dom": "*",
+ "ext-libxml": "*",
+ "ext-xmlwriter": "*",
+ "nikic/php-parser": "^5.6.1",
+ "php": ">=8.3",
+ "phpunit/php-file-iterator": "^6.0",
+ "phpunit/php-text-template": "^5.0",
+ "sebastian/complexity": "^5.0",
+ "sebastian/environment": "^8.0.3",
+ "sebastian/lines-of-code": "^4.0",
+ "sebastian/version": "^6.0",
+ "theseer/tokenizer": "^1.2.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^12.3.7"
+ },
+ "suggest": {
+ "ext-pcov": "PHP extension that provides line coverage",
+ "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "12.4.x-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.",
+ "homepage": "https://github.com/sebastianbergmann/php-code-coverage",
+ "keywords": [
+ "coverage",
+ "testing",
+ "xunit"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
+ "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy",
+ "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/12.4.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ },
+ {
+ "url": "https://liberapay.com/sebastianbergmann",
+ "type": "liberapay"
+ },
+ {
+ "url": "https://thanks.dev/u/gh/sebastianbergmann",
+ "type": "thanks_dev"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/phpunit/php-code-coverage",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2025-09-24T13:44:41+00:00"
+ },
+ {
+ "name": "phpunit/php-file-iterator",
+ "version": "6.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/php-file-iterator.git",
+ "reference": "961bc913d42fe24a257bfff826a5068079ac7782"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/961bc913d42fe24a257bfff826a5068079ac7782",
+ "reference": "961bc913d42fe24a257bfff826a5068079ac7782",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^12.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "6.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "FilterIterator implementation that filters files based on a list of suffixes.",
+ "homepage": "https://github.com/sebastianbergmann/php-file-iterator/",
+ "keywords": [
+ "filesystem",
+ "iterator"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues",
+ "security": "https://github.com/sebastianbergmann/php-file-iterator/security/policy",
+ "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/6.0.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2025-02-07T04:58:37+00:00"
+ },
+ {
+ "name": "phpunit/php-invoker",
+ "version": "6.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/php-invoker.git",
+ "reference": "12b54e689b07a25a9b41e57736dfab6ec9ae5406"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/12b54e689b07a25a9b41e57736dfab6ec9ae5406",
+ "reference": "12b54e689b07a25a9b41e57736dfab6ec9ae5406",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.3"
+ },
+ "require-dev": {
+ "ext-pcntl": "*",
+ "phpunit/phpunit": "^12.0"
+ },
+ "suggest": {
+ "ext-pcntl": "*"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "6.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Invoke callables with a timeout",
+ "homepage": "https://github.com/sebastianbergmann/php-invoker/",
+ "keywords": [
+ "process"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/php-invoker/issues",
+ "security": "https://github.com/sebastianbergmann/php-invoker/security/policy",
+ "source": "https://github.com/sebastianbergmann/php-invoker/tree/6.0.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2025-02-07T04:58:58+00:00"
+ },
+ {
+ "name": "phpunit/php-text-template",
+ "version": "5.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/php-text-template.git",
+ "reference": "e1367a453f0eda562eedb4f659e13aa900d66c53"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/e1367a453f0eda562eedb4f659e13aa900d66c53",
+ "reference": "e1367a453f0eda562eedb4f659e13aa900d66c53",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^12.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "5.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Simple template engine.",
+ "homepage": "https://github.com/sebastianbergmann/php-text-template/",
+ "keywords": [
+ "template"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/php-text-template/issues",
+ "security": "https://github.com/sebastianbergmann/php-text-template/security/policy",
+ "source": "https://github.com/sebastianbergmann/php-text-template/tree/5.0.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2025-02-07T04:59:16+00:00"
+ },
+ {
+ "name": "phpunit/php-timer",
+ "version": "8.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/php-timer.git",
+ "reference": "f258ce36aa457f3aa3339f9ed4c81fc66dc8c2cc"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/f258ce36aa457f3aa3339f9ed4c81fc66dc8c2cc",
+ "reference": "f258ce36aa457f3aa3339f9ed4c81fc66dc8c2cc",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^12.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "8.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Utility class for timing",
+ "homepage": "https://github.com/sebastianbergmann/php-timer/",
+ "keywords": [
+ "timer"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/php-timer/issues",
+ "security": "https://github.com/sebastianbergmann/php-timer/security/policy",
+ "source": "https://github.com/sebastianbergmann/php-timer/tree/8.0.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2025-02-07T04:59:38+00:00"
+ },
+ {
+ "name": "phpunit/phpunit",
+ "version": "12.4.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/phpunit.git",
+ "reference": "a94ea4d26d865875803b23aaf78c3c2c670ea2ea"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/a94ea4d26d865875803b23aaf78c3c2c670ea2ea",
+ "reference": "a94ea4d26d865875803b23aaf78c3c2c670ea2ea",
+ "shasum": ""
+ },
+ "require": {
+ "ext-dom": "*",
+ "ext-json": "*",
+ "ext-libxml": "*",
+ "ext-mbstring": "*",
+ "ext-xml": "*",
+ "ext-xmlwriter": "*",
+ "myclabs/deep-copy": "^1.13.4",
+ "phar-io/manifest": "^2.0.4",
+ "phar-io/version": "^3.2.1",
+ "php": ">=8.3",
+ "phpunit/php-code-coverage": "^12.4.0",
+ "phpunit/php-file-iterator": "^6.0.0",
+ "phpunit/php-invoker": "^6.0.0",
+ "phpunit/php-text-template": "^5.0.0",
+ "phpunit/php-timer": "^8.0.0",
+ "sebastian/cli-parser": "^4.2.0",
+ "sebastian/comparator": "^7.1.3",
+ "sebastian/diff": "^7.0.0",
+ "sebastian/environment": "^8.0.3",
+ "sebastian/exporter": "^7.0.2",
+ "sebastian/global-state": "^8.0.2",
+ "sebastian/object-enumerator": "^7.0.0",
+ "sebastian/type": "^6.0.3",
+ "sebastian/version": "^6.0.0",
+ "staabm/side-effects-detector": "^1.0.5"
+ },
+ "bin": [
+ "phpunit"
+ ],
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "12.4-dev"
+ }
+ },
+ "autoload": {
+ "files": [
+ "src/Framework/Assert/Functions.php"
+ ],
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "The PHP Unit Testing framework.",
+ "homepage": "https://phpunit.de/",
+ "keywords": [
+ "phpunit",
+ "testing",
+ "xunit"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/phpunit/issues",
+ "security": "https://github.com/sebastianbergmann/phpunit/security/policy",
+ "source": "https://github.com/sebastianbergmann/phpunit/tree/12.4.2"
+ },
+ "funding": [
+ {
+ "url": "https://phpunit.de/sponsors.html",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ },
+ {
+ "url": "https://liberapay.com/sebastianbergmann",
+ "type": "liberapay"
+ },
+ {
+ "url": "https://thanks.dev/u/gh/sebastianbergmann",
+ "type": "thanks_dev"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2025-10-30T08:41:39+00:00"
+ },
+ {
+ "name": "rector/rector",
+ "version": "2.2.7",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/rectorphp/rector.git",
+ "reference": "022038537838bc8a4e526af86c2d6e38eaeff7ef"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/rectorphp/rector/zipball/022038537838bc8a4e526af86c2d6e38eaeff7ef",
+ "reference": "022038537838bc8a4e526af86c2d6e38eaeff7ef",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.4|^8.0",
+ "phpstan/phpstan": "^2.1.26"
+ },
+ "conflict": {
+ "rector/rector-doctrine": "*",
+ "rector/rector-downgrade-php": "*",
+ "rector/rector-phpunit": "*",
+ "rector/rector-symfony": "*"
+ },
+ "suggest": {
+ "ext-dom": "To manipulate phpunit.xml via the custom-rule command"
+ },
+ "bin": [
+ "bin/rector"
+ ],
+ "type": "library",
+ "autoload": {
+ "files": [
+ "bootstrap.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "description": "Instant Upgrade and Automated Refactoring of any PHP code",
+ "homepage": "https://getrector.com/",
+ "keywords": [
+ "automation",
+ "dev",
+ "migration",
+ "refactoring"
+ ],
+ "support": {
+ "issues": "https://github.com/rectorphp/rector/issues",
+ "source": "https://github.com/rectorphp/rector/tree/2.2.7"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/tomasvotruba",
+ "type": "github"
+ }
+ ],
+ "time": "2025-10-29T15:46:12+00:00"
+ },
+ {
+ "name": "sebastian/cli-parser",
+ "version": "4.2.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/cli-parser.git",
+ "reference": "90f41072d220e5c40df6e8635f5dafba2d9d4d04"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/90f41072d220e5c40df6e8635f5dafba2d9d4d04",
+ "reference": "90f41072d220e5c40df6e8635f5dafba2d9d4d04",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^12.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "4.2-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Library for parsing CLI options",
+ "homepage": "https://github.com/sebastianbergmann/cli-parser",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/cli-parser/issues",
+ "security": "https://github.com/sebastianbergmann/cli-parser/security/policy",
+ "source": "https://github.com/sebastianbergmann/cli-parser/tree/4.2.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ },
+ {
+ "url": "https://liberapay.com/sebastianbergmann",
+ "type": "liberapay"
+ },
+ {
+ "url": "https://thanks.dev/u/gh/sebastianbergmann",
+ "type": "thanks_dev"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/sebastian/cli-parser",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2025-09-14T09:36:45+00:00"
+ },
+ {
+ "name": "sebastian/comparator",
+ "version": "7.1.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/comparator.git",
+ "reference": "dc904b4bb3ab070865fa4068cd84f3da8b945148"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/dc904b4bb3ab070865fa4068cd84f3da8b945148",
+ "reference": "dc904b4bb3ab070865fa4068cd84f3da8b945148",
+ "shasum": ""
+ },
+ "require": {
+ "ext-dom": "*",
+ "ext-mbstring": "*",
+ "php": ">=8.3",
+ "sebastian/diff": "^7.0",
+ "sebastian/exporter": "^7.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^12.2"
+ },
+ "suggest": {
+ "ext-bcmath": "For comparing BcMath\\Number objects"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "7.1-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ },
+ {
+ "name": "Jeff Welch",
+ "email": "whatthejeff@gmail.com"
+ },
+ {
+ "name": "Volker Dusch",
+ "email": "github@wallbash.com"
+ },
+ {
+ "name": "Bernhard Schussek",
+ "email": "bschussek@2bepublished.at"
+ }
+ ],
+ "description": "Provides the functionality to compare PHP values for equality",
+ "homepage": "https://github.com/sebastianbergmann/comparator",
+ "keywords": [
+ "comparator",
+ "compare",
+ "equality"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/comparator/issues",
+ "security": "https://github.com/sebastianbergmann/comparator/security/policy",
+ "source": "https://github.com/sebastianbergmann/comparator/tree/7.1.3"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ },
+ {
+ "url": "https://liberapay.com/sebastianbergmann",
+ "type": "liberapay"
+ },
+ {
+ "url": "https://thanks.dev/u/gh/sebastianbergmann",
+ "type": "thanks_dev"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/sebastian/comparator",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2025-08-20T11:27:00+00:00"
+ },
+ {
+ "name": "sebastian/complexity",
+ "version": "5.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/complexity.git",
+ "reference": "bad4316aba5303d0221f43f8cee37eb58d384bbb"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/bad4316aba5303d0221f43f8cee37eb58d384bbb",
+ "reference": "bad4316aba5303d0221f43f8cee37eb58d384bbb",
+ "shasum": ""
+ },
+ "require": {
+ "nikic/php-parser": "^5.0",
+ "php": ">=8.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^12.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "5.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Library for calculating the complexity of PHP code units",
+ "homepage": "https://github.com/sebastianbergmann/complexity",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/complexity/issues",
+ "security": "https://github.com/sebastianbergmann/complexity/security/policy",
+ "source": "https://github.com/sebastianbergmann/complexity/tree/5.0.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2025-02-07T04:55:25+00:00"
+ },
+ {
+ "name": "sebastian/diff",
+ "version": "7.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/diff.git",
+ "reference": "7ab1ea946c012266ca32390913653d844ecd085f"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/7ab1ea946c012266ca32390913653d844ecd085f",
+ "reference": "7ab1ea946c012266ca32390913653d844ecd085f",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^12.0",
+ "symfony/process": "^7.2"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "7.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ },
+ {
+ "name": "Kore Nordmann",
+ "email": "mail@kore-nordmann.de"
+ }
+ ],
+ "description": "Diff implementation",
+ "homepage": "https://github.com/sebastianbergmann/diff",
+ "keywords": [
+ "diff",
+ "udiff",
+ "unidiff",
+ "unified diff"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/diff/issues",
+ "security": "https://github.com/sebastianbergmann/diff/security/policy",
+ "source": "https://github.com/sebastianbergmann/diff/tree/7.0.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2025-02-07T04:55:46+00:00"
+ },
+ {
+ "name": "sebastian/environment",
+ "version": "8.0.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/environment.git",
+ "reference": "24a711b5c916efc6d6e62aa65aa2ec98fef77f68"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/24a711b5c916efc6d6e62aa65aa2ec98fef77f68",
+ "reference": "24a711b5c916efc6d6e62aa65aa2ec98fef77f68",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^12.0"
+ },
+ "suggest": {
+ "ext-posix": "*"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "8.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ }
+ ],
+ "description": "Provides functionality to handle HHVM/PHP environments",
+ "homepage": "https://github.com/sebastianbergmann/environment",
+ "keywords": [
+ "Xdebug",
+ "environment",
+ "hhvm"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/environment/issues",
+ "security": "https://github.com/sebastianbergmann/environment/security/policy",
+ "source": "https://github.com/sebastianbergmann/environment/tree/8.0.3"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ },
+ {
+ "url": "https://liberapay.com/sebastianbergmann",
+ "type": "liberapay"
+ },
+ {
+ "url": "https://thanks.dev/u/gh/sebastianbergmann",
+ "type": "thanks_dev"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/sebastian/environment",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2025-08-12T14:11:56+00:00"
+ },
+ {
+ "name": "sebastian/exporter",
+ "version": "7.0.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/exporter.git",
+ "reference": "016951ae10980765e4e7aee491eb288c64e505b7"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/016951ae10980765e4e7aee491eb288c64e505b7",
+ "reference": "016951ae10980765e4e7aee491eb288c64e505b7",
+ "shasum": ""
+ },
+ "require": {
+ "ext-mbstring": "*",
+ "php": ">=8.3",
+ "sebastian/recursion-context": "^7.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^12.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "7.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ },
+ {
+ "name": "Jeff Welch",
+ "email": "whatthejeff@gmail.com"
+ },
+ {
+ "name": "Volker Dusch",
+ "email": "github@wallbash.com"
+ },
+ {
+ "name": "Adam Harvey",
+ "email": "aharvey@php.net"
+ },
+ {
+ "name": "Bernhard Schussek",
+ "email": "bschussek@gmail.com"
+ }
+ ],
+ "description": "Provides the functionality to export PHP variables for visualization",
+ "homepage": "https://www.github.com/sebastianbergmann/exporter",
+ "keywords": [
+ "export",
+ "exporter"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/exporter/issues",
+ "security": "https://github.com/sebastianbergmann/exporter/security/policy",
+ "source": "https://github.com/sebastianbergmann/exporter/tree/7.0.2"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ },
+ {
+ "url": "https://liberapay.com/sebastianbergmann",
+ "type": "liberapay"
+ },
+ {
+ "url": "https://thanks.dev/u/gh/sebastianbergmann",
+ "type": "thanks_dev"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/sebastian/exporter",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2025-09-24T06:16:11+00:00"
+ },
+ {
+ "name": "sebastian/global-state",
+ "version": "8.0.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/global-state.git",
+ "reference": "ef1377171613d09edd25b7816f05be8313f9115d"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/ef1377171613d09edd25b7816f05be8313f9115d",
+ "reference": "ef1377171613d09edd25b7816f05be8313f9115d",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.3",
+ "sebastian/object-reflector": "^5.0",
+ "sebastian/recursion-context": "^7.0"
+ },
+ "require-dev": {
+ "ext-dom": "*",
+ "phpunit/phpunit": "^12.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "8.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ }
+ ],
+ "description": "Snapshotting of global state",
+ "homepage": "https://www.github.com/sebastianbergmann/global-state",
+ "keywords": [
+ "global state"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/global-state/issues",
+ "security": "https://github.com/sebastianbergmann/global-state/security/policy",
+ "source": "https://github.com/sebastianbergmann/global-state/tree/8.0.2"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ },
+ {
+ "url": "https://liberapay.com/sebastianbergmann",
+ "type": "liberapay"
+ },
+ {
+ "url": "https://thanks.dev/u/gh/sebastianbergmann",
+ "type": "thanks_dev"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/sebastian/global-state",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2025-08-29T11:29:25+00:00"
+ },
+ {
+ "name": "sebastian/lines-of-code",
+ "version": "4.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/lines-of-code.git",
+ "reference": "97ffee3bcfb5805568d6af7f0f893678fc076d2f"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/97ffee3bcfb5805568d6af7f0f893678fc076d2f",
+ "reference": "97ffee3bcfb5805568d6af7f0f893678fc076d2f",
+ "shasum": ""
+ },
+ "require": {
+ "nikic/php-parser": "^5.0",
+ "php": ">=8.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^12.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "4.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Library for counting the lines of code in PHP source code",
+ "homepage": "https://github.com/sebastianbergmann/lines-of-code",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/lines-of-code/issues",
+ "security": "https://github.com/sebastianbergmann/lines-of-code/security/policy",
+ "source": "https://github.com/sebastianbergmann/lines-of-code/tree/4.0.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2025-02-07T04:57:28+00:00"
+ },
+ {
+ "name": "sebastian/object-enumerator",
+ "version": "7.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/object-enumerator.git",
+ "reference": "1effe8e9b8e068e9ae228e542d5d11b5d16db894"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/1effe8e9b8e068e9ae228e542d5d11b5d16db894",
+ "reference": "1effe8e9b8e068e9ae228e542d5d11b5d16db894",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.3",
+ "sebastian/object-reflector": "^5.0",
+ "sebastian/recursion-context": "^7.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^12.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "7.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ }
+ ],
+ "description": "Traverses array structures and object graphs to enumerate all referenced objects",
+ "homepage": "https://github.com/sebastianbergmann/object-enumerator/",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/object-enumerator/issues",
+ "security": "https://github.com/sebastianbergmann/object-enumerator/security/policy",
+ "source": "https://github.com/sebastianbergmann/object-enumerator/tree/7.0.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2025-02-07T04:57:48+00:00"
+ },
+ {
+ "name": "sebastian/object-reflector",
+ "version": "5.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/object-reflector.git",
+ "reference": "4bfa827c969c98be1e527abd576533293c634f6a"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/4bfa827c969c98be1e527abd576533293c634f6a",
+ "reference": "4bfa827c969c98be1e527abd576533293c634f6a",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^12.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "5.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ }
+ ],
+ "description": "Allows reflection of object attributes, including inherited and non-public ones",
+ "homepage": "https://github.com/sebastianbergmann/object-reflector/",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/object-reflector/issues",
+ "security": "https://github.com/sebastianbergmann/object-reflector/security/policy",
+ "source": "https://github.com/sebastianbergmann/object-reflector/tree/5.0.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2025-02-07T04:58:17+00:00"
+ },
+ {
+ "name": "sebastian/recursion-context",
+ "version": "7.0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/recursion-context.git",
+ "reference": "0b01998a7d5b1f122911a66bebcb8d46f0c82d8c"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/0b01998a7d5b1f122911a66bebcb8d46f0c82d8c",
+ "reference": "0b01998a7d5b1f122911a66bebcb8d46f0c82d8c",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^12.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "7.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ },
+ {
+ "name": "Jeff Welch",
+ "email": "whatthejeff@gmail.com"
+ },
+ {
+ "name": "Adam Harvey",
+ "email": "aharvey@php.net"
+ }
+ ],
+ "description": "Provides functionality to recursively process PHP variables",
+ "homepage": "https://github.com/sebastianbergmann/recursion-context",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/recursion-context/issues",
+ "security": "https://github.com/sebastianbergmann/recursion-context/security/policy",
+ "source": "https://github.com/sebastianbergmann/recursion-context/tree/7.0.1"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ },
+ {
+ "url": "https://liberapay.com/sebastianbergmann",
+ "type": "liberapay"
+ },
+ {
+ "url": "https://thanks.dev/u/gh/sebastianbergmann",
+ "type": "thanks_dev"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/sebastian/recursion-context",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2025-08-13T04:44:59+00:00"
+ },
+ {
+ "name": "sebastian/type",
+ "version": "6.0.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/type.git",
+ "reference": "e549163b9760b8f71f191651d22acf32d56d6d4d"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/e549163b9760b8f71f191651d22acf32d56d6d4d",
+ "reference": "e549163b9760b8f71f191651d22acf32d56d6d4d",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^12.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "6.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Collection of value objects that represent the types of the PHP type system",
+ "homepage": "https://github.com/sebastianbergmann/type",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/type/issues",
+ "security": "https://github.com/sebastianbergmann/type/security/policy",
+ "source": "https://github.com/sebastianbergmann/type/tree/6.0.3"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ },
+ {
+ "url": "https://liberapay.com/sebastianbergmann",
+ "type": "liberapay"
+ },
+ {
+ "url": "https://thanks.dev/u/gh/sebastianbergmann",
+ "type": "thanks_dev"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/sebastian/type",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2025-08-09T06:57:12+00:00"
+ },
+ {
+ "name": "sebastian/version",
+ "version": "6.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/version.git",
+ "reference": "3e6ccf7657d4f0a59200564b08cead899313b53c"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/3e6ccf7657d4f0a59200564b08cead899313b53c",
+ "reference": "3e6ccf7657d4f0a59200564b08cead899313b53c",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.3"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "6.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Library that helps with managing the version number of Git-hosted PHP projects",
+ "homepage": "https://github.com/sebastianbergmann/version",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/version/issues",
+ "security": "https://github.com/sebastianbergmann/version/security/policy",
+ "source": "https://github.com/sebastianbergmann/version/tree/6.0.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2025-02-07T05:00:38+00:00"
+ },
+ {
+ "name": "squizlabs/php_codesniffer",
+ "version": "4.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git",
+ "reference": "06113cfdaf117fc2165f9cd040bd0f17fcd5242d"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/06113cfdaf117fc2165f9cd040bd0f17fcd5242d",
+ "reference": "06113cfdaf117fc2165f9cd040bd0f17fcd5242d",
+ "shasum": ""
+ },
+ "require": {
+ "ext-simplexml": "*",
+ "ext-tokenizer": "*",
+ "ext-xmlwriter": "*",
+ "php": ">=7.2.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^8.4.0 || ^9.3.4 || ^10.5.32 || 11.3.3 - 11.5.28 || ^11.5.31"
+ },
+ "bin": [
+ "bin/phpcbf",
+ "bin/phpcs"
+ ],
+ "type": "library",
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Greg Sherwood",
+ "role": "Former lead"
+ },
+ {
+ "name": "Juliette Reinders Folmer",
+ "role": "Current lead"
+ },
+ {
+ "name": "Contributors",
+ "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer/graphs/contributors"
+ }
+ ],
+ "description": "PHP_CodeSniffer tokenizes PHP files and detects violations of a defined set of coding standards.",
+ "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer",
+ "keywords": [
+ "phpcs",
+ "standards",
+ "static analysis"
+ ],
+ "support": {
+ "issues": "https://github.com/PHPCSStandards/PHP_CodeSniffer/issues",
+ "security": "https://github.com/PHPCSStandards/PHP_CodeSniffer/security/policy",
+ "source": "https://github.com/PHPCSStandards/PHP_CodeSniffer",
+ "wiki": "https://github.com/PHPCSStandards/PHP_CodeSniffer/wiki"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/PHPCSStandards",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/jrfnl",
+ "type": "github"
+ },
+ {
+ "url": "https://opencollective.com/php_codesniffer",
+ "type": "open_collective"
+ },
+ {
+ "url": "https://thanks.dev/u/gh/phpcsstandards",
+ "type": "thanks_dev"
+ }
+ ],
+ "time": "2025-09-15T11:28:58+00:00"
+ },
+ {
+ "name": "staabm/side-effects-detector",
+ "version": "1.0.5",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/staabm/side-effects-detector.git",
+ "reference": "d8334211a140ce329c13726d4a715adbddd0a163"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/staabm/side-effects-detector/zipball/d8334211a140ce329c13726d4a715adbddd0a163",
+ "reference": "d8334211a140ce329c13726d4a715adbddd0a163",
+ "shasum": ""
+ },
+ "require": {
+ "ext-tokenizer": "*",
+ "php": "^7.4 || ^8.0"
+ },
+ "require-dev": {
+ "phpstan/extension-installer": "^1.4.3",
+ "phpstan/phpstan": "^1.12.6",
+ "phpunit/phpunit": "^9.6.21",
+ "symfony/var-dumper": "^5.4.43",
+ "tomasvotruba/type-coverage": "1.0.0",
+ "tomasvotruba/unused-public": "1.0.0"
+ },
+ "type": "library",
+ "autoload": {
+ "classmap": [
+ "lib/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "description": "A static analysis tool to detect side effects in PHP code",
+ "keywords": [
+ "static analysis"
+ ],
+ "support": {
+ "issues": "https://github.com/staabm/side-effects-detector/issues",
+ "source": "https://github.com/staabm/side-effects-detector/tree/1.0.5"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/staabm",
+ "type": "github"
+ }
+ ],
+ "time": "2024-10-20T05:08:20+00:00"
+ },
+ {
+ "name": "theseer/tokenizer",
+ "version": "1.2.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/theseer/tokenizer.git",
+ "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/theseer/tokenizer/zipball/737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2",
+ "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2",
+ "shasum": ""
+ },
+ "require": {
+ "ext-dom": "*",
+ "ext-tokenizer": "*",
+ "ext-xmlwriter": "*",
+ "php": "^7.2 || ^8.0"
+ },
+ "type": "library",
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Arne Blankerts",
+ "email": "arne@blankerts.de",
+ "role": "Developer"
+ }
+ ],
+ "description": "A small library for converting tokenized PHP source code into XML and potentially other formats",
+ "support": {
+ "issues": "https://github.com/theseer/tokenizer/issues",
+ "source": "https://github.com/theseer/tokenizer/tree/1.2.3"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/theseer",
+ "type": "github"
+ }
+ ],
+ "time": "2024-03-03T12:36:25+00:00"
+ }
+ ],
"aliases": [],
"minimum-stability": "stable",
- "stability-flags": [],
+ "stability-flags": {},
"prefer-stable": false,
"prefer-lowest": false,
- "platform": [],
- "platform-dev": [],
- "plugin-api-version": "2.2.0"
+ "platform": {},
+ "platform-dev": {},
+ "plugin-api-version": "2.6.0"
}
diff --git a/docker-compose.ci.override.yml b/docker-compose.ci.override.yml
new file mode 100644
index 0000000..7d21902
--- /dev/null
+++ b/docker-compose.ci.override.yml
@@ -0,0 +1,36 @@
+services:
+ findingaid:
+ build:
+ context: .
+ target: CI
+ volumes:
+ - ./app:/app
+ - ./public:/public
+ - cache:/public/cache
+ - ./xml:/xml
+ - vendor:/vendor
+ - ./tests:/tests
+ networks:
+ - app_net
+
+ web:
+ image: nginx:1.29.0
+ ports:
+ - 8080:80
+ volumes:
+ - ./app:/app
+ - ./public:/public
+ - cache:/public/cache
+ - ./nginx/default.conf:/etc/nginx/conf.d/default.conf
+ networks:
+ - app_net
+ depends_on:
+ - findingaid
+
+networks:
+ app_net:
+ driver: bridge
+
+volumes:
+ vendor:
+ cache:
diff --git a/phpunit.xml b/phpunit.xml
new file mode 100644
index 0000000..9671a4d
--- /dev/null
+++ b/phpunit.xml
@@ -0,0 +1,10 @@
+
+
+
+
+ tests
+
+
+
+
diff --git a/rector.php b/rector.php
new file mode 100644
index 0000000..decc013
--- /dev/null
+++ b/rector.php
@@ -0,0 +1,18 @@
+withPaths([
+ __DIR__ . '/app',
+])
+// uncomment to reach your current PHP version
+//->withPhpSets()
+->withSets([
+ LevelSetList::UP_TO_PHP_84,
+])
+->withTypeCoverageLevel(0)
+->withDeadCodeLevel(0)
+->withCodeQualityLevel(0);
diff --git a/tests/MinterTest.php b/tests/MinterTest.php
new file mode 100644
index 0000000..7898947
--- /dev/null
+++ b/tests/MinterTest.php
@@ -0,0 +1,22 @@
+assertSame('fa_1', $m->mint());
+ }
+
+ public function testCounterIncrementsEachTime(): void
+ {
+ $m = new Minter('fa');
+ $m->mint(); // fa_1
+ $m->mint(); // fa_2
+ $this->assertSame('fa_3', $m->mint());
+ }
+}