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()); + } +}