Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Cognitive Code Analysis Laravel Package

phauthentic/cognitive-code-analysis

A PHP library for measuring cognitive complexity in source code. It parses PHP and reports complexity scores to help identify hard-to-understand methods, improve maintainability, and integrate code-quality checks into CI and static analysis.

View on GitHub
Deep Wiki
Context7

Getting Started

phauthentic/cognitive-code-analysis is a framework-agnostic PHP static analysis CLI (phpcca) that scores cognitive complexity per method, with a separate churn command for hotspot analysis. It slots into a Laravel project as a dev-only Composer dependency and is driven entirely from the CLI, so there is no service provider or Artisan command to wire up.

Minimal setup:

composer require --dev phauthentic/cognitive-code-analysis

# Interactive setup — writes phpcca.yaml in the current directory
vendor/bin/phpcca init

# Non-interactive (good for scaffolding/onboarding scripts and CI bootstrap)
vendor/bin/phpcca init --silent
vendor/bin/phpcca init --path=./phpcca.yaml

Then run your first analysis against the code you actually own:

vendor/bin/phpcca analyse app/

Because analyse auto-discovers ./phpcca.yaml, no --config flag is needed once init has run at the project root. The bundled defaults enable showOnlyMethodsExceedingThreshold: true, so the first run is intentionally quiet — you see the methods that breach scoreThreshold, not the whole codebase. That filtered view is the right first use case: treat it as a baseline of "methods that need attention" in app/, and expand scope only after the baseline is clean.

Where to look first:

  • phpcca.yaml — generated by init; the only file most teams need to edit (threshold, filtering, paths).
  • docs/Configuration.md — config keys, auto-discovery rules, --config precedence.
  • docs/CI-Integration.md — end-to-end GitHub Actions and GitLab CI recipes, report formats, changed-file analysis.
  • readme.md — the init → analyse workflow and command overview.

Verify you are running against the intended config immediately: since 1.11.1 every analyse and churn run prints the active config source and cache state at startup:

Config: ./phpcca.yaml
Cache: enabled

Relative paths are shown when the config sits inside the working directory, which makes it obvious at a glance whether auto-discovery picked up your file or a stray config elsewhere.

Implementation Patterns

Day-to-day local loop. Analyse the directory you are working in rather than the whole repository, and lean on the threshold filter to keep output scannable:

vendor/bin/phpcca analyse app/Http/Controllers/
vendor/bin/phpcca analyse app/ --config=phpcca.yaml

For a Laravel codebase, scope to app/, src/, or individual domains. Do not point it at vendor/, storage/, or bootstrap/cache/ — the signal-to-noise ratio collapses and runtime grows for no benefit. Keep the scope in the config file rather than retyping paths, so local runs and CI runs analyse the same surface.

Config-per-context. --config always beats auto-discovery, which makes it cheap to keep a strict config for CI and a looser one for local exploration:

vendor/bin/phpcca analyse app/ --config=phpcca.strict.yaml   # CI gate
vendor/bin/phpcca analyse app/ --config=phpcca.yaml          # local

This is also the migration path for teams that keep a differently named file: cca.yaml and config.yml are no longer auto-discovered, but an explicit --config keeps them working unchanged.

Pull-request gating with the GitHub Action. The new composite action removes the need to hand-roll shell steps. It lives in a separate repository and is consumed at @v1:

name: Cognitive Code Analysis

on:
  pull_request:
    paths:
      - '**/*.php'

permissions:
  pull-requests: write
  contents: read

jobs:
  analyse:
    runs-on: ubuntu-24.04
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - uses: Phauthentic/cognitive-code-analysis-github-action@v1
        with:
          install-mode: phar        # or: composer
          post-comment: true
          upload-artifact: true
          emit-annotations: true

install-mode: phar skips a Composer install entirely, which is the fastest path on PRs. install-mode: composer reuses the dependency you already have. Choose one deliberately: phar for speed and isolation, composer when you need to pin the package version alongside the rest of your dependencies. post-comment gives reviewers the report inline; emit-annotations surfaces findings on the diff; upload-artifact retains the full report; SARIF upload is available when you want findings in the code-scanning UI; threshold failure is opt-in, so start non-blocking and tighten later.

Changed-files-only analysis outside GitHub Actions. The action is a convenience wrapper; the underlying CLI takes a comma-separated list of paths. This is the pattern to reuse in GitLab CI, Bitbucket, or a custom Jenkins pipeline:

CHANGED_FILES=$(git diff --name-only --diff-filter=ACMR $BASE_SHA...$HEAD_SHA | grep '\.php$' | tr '\n' ' ')
ANALYSE_PATH=$(echo "$CHANGED_FILES" | tr ' ' ',')
bin/phpcca analyse "$ANALYSE_PATH" --report-type=markdown --report-file=cca-report.md

The comma separator is the contract, not spaces. Build the list with tr ' ' ',' (as above) or paste -sd,, quote the argument, and guard the empty case — a PR touching no PHP files produces an empty path argument.

GitLab CI. The integration guide covers merge-request notes and the Code Quality widget. The shape is the same: run analyse with a markdown report, then publish the artifact / post the note in a job that has the MR context. Keep the report file path stable so the publish step does not need to parse the tool's stdout.

Hotspot triage with churn. analyse tells you where complexity lives; churn adds change frequency, which is what you actually want when deciding what to refactor first. A method that is complex and frequently edited is a better target than a complex method nobody has touched in a year. Run churn on a schedule or before planning refactoring work, not on every commit.

Thresholds as a ratchet. Start with the bundled defaults so the first report is short and credible. Once the current offenders are addressed, consider enabling the action's threshold failure so new violations cannot land. Changing scoreThreshold and showOnlyMethodsExceedingThreshold together lets you widen the net gradually without a wall of legacy findings.

Gotchas and Tips

The config filename changed, and auto-discovery is strict. cca.yaml (1.11.0) and config.yml are no longer picked up automatically. Auto-discovery looks for ./phpcca.yaml in the working directory only. If you upgraded and your runs suddenly behave as if unconfigured, this is almost certainly why — check the Config: line at the top of the output. Either rename the file or pass --config explicitly; the latter is the zero-risk option during migration.

init now writes a different filename. Scripts, Dockerfiles, and onboarding docs that expect cca.yaml from bin/phpcca init will silently produce a file the next analyse run does not discover. Update any init invocation that hardcodes the output name, or use init --path= to be explicit.

Default filtering hides methods. The bundled phpcca.yaml sets showOnlyMethodsExceedingThreshold: true. This is a good default but a common source of confusion: "the tool only found three methods" usually means everything else is under scoreThreshold, not that analysis failed. Set showOnlyMethodsExceedingThreshold: false in your phpcca.yaml when you want the complete picture, and note that a config created by an older init may not carry the new default at all — defaults come from the bundled file, so an old config keeps old behaviour until you regenerate or edit it.

The startup status lines change console output. Config: and Cache: lines are now printed by analyse and churn. Anything that parses stdout — CI scripts, golden-file tests, log scrapers, report wrappers — must tolerate them. This is the most likely source of breakage in downstream automation even though the CLI itself has no breaking changes. Prefer --report-file over parsing stdout when you need machine-readable output.

Cache status is visible for a reason. If results look stale after a refactor, check the Cache: line before assuming a bug. A config change, a different working directory, or a different --config path can all mean you are not looking at the cached run you think you are. When in doubt, re-run with an explicit --config and compare.

Comma-separated, not space-separated. Path arguments for multi-file analysis are comma-delimited. Passing space-separated paths produces a confusing "file not found" for a concatenated string. Also watch for paths containing spaces — quote the whole argument.

Checkout depth in CI. The GitHub Action analyses changed files, which requires a git history to diff against. The documented example uses fetch-depth: 0; a shallow default checkout can leave the action unable to determine the changed set. The same applies to any manual git diff based pipeline.

Permissions are easy to forget. post-comment: true needs pull-requests: write. Without it the analysis runs and the comment step fails, which looks like a tool error but is a workflow permissions problem.

Version-pin the action separately from the package. The action lives in its own repository and is versioned @v1 independently of the 1.11.1 package release. Pinning @v1 gets you fixes; pinning a SHA gets you reproducibility. Decide per team, but do not assume the action version tracks the CLI version.

Extension points live in config, not code. The practical levers are scoreThreshold, showOnlyMethodsExceedingThreshold, and the path list in phpcca.yaml, plus --config for swapping whole configurations. There is no plugin API to reach for; if you need different reporting, generate the markdown/SARIF output and post-process it rather than trying to hook the internals.

Laravel-specific: keep it out of production. It is a dev dependency and a build-time check. Do not add it to runtime require, and do not let an analysis step become a deploy blocker until the baseline is clean — enable threshold failure only after the initial findings are triaged.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle