Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/harness.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,6 @@ permissions: {}

jobs:
harness:
uses: Pollora/harness/.github/workflows/php-package.yml@v0.1.15
uses: Pollora/harness/.github/workflows/php-package.yml@v0.1.23
permissions:
contents: read
17 changes: 14 additions & 3 deletions .harness.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,18 @@
"mode": "enforce",
"ratchet": {
"phpstan_level": 5,
"phpstan_baseline": 58,
"coverage": 53
}
"phpstan_baseline": 56,
"coverage": 53,
"exempted_rules": 2
},
"allow_rules": [
{
"rule": "ARCH-01",
"reason": "Modules\\Domain and Plugin\\Domain extend Illuminate\\Support\\Collection (ModuleCollection, PluginCollection); both are published classes, so removing the dependency changes the public contract. To lift at the next major."
},
{
"rule": "ARCH-03",
"reason": "The application layer of Modules, Plugin and Theme still builds Infrastructure services directly (registrars, managers, discovery orchestrator), and the module named Application is read as a layer. Route, Schedule and VersionCheck are fixed; the rest needs ports, one module at a time."
}
]
}
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
- `pollora:make:post-type` (and its `pollora:make-posttype` alias) can create the theme views of the new post type: `--single-view` writes `single-{slug}.blade.php`, `--archive-view` writes `archive-{slug}.blade.php`, `--with-views` writes both. They go to `resources/views` of the theme given with `--theme`, or of the active theme, and are named after the slug discovery registers the post type under (cut to 20 characters), so the template hierarchy renders them with no route. An existing view is left as it is, with a warning

### Changed
- The architecture rules of the Pollora harness (`tests/Arch.php`) now run in CI: `pollora/harness` is required at `^0.1.23` and the workflow calls it at `v0.1.23`. Two rules stay exempted in `.harness.json` with a reason (ARCH-01 and ARCH-03, the dependencies the Modules, Plugin and Theme application layers still have on infrastructure); the number of exempted rules is capped by the ratchet
- `PluginManager` and `ThemeManager` read the console detection service from the container they receive instead of the `resolve()` helper, and the plugin and theme modules read `VAPOR_MAINTENANCE_MODE` from the environment variables instead of `env()` outside a configuration file. Nothing changes for a site
- `WordPressTypeResolverInterface` moved to `Pollora\Route\Domain\Contracts`; the former name, `Pollora\Route\Infrastructure\Services\Contracts\WordPressTypeResolverInterface`, is an alias and keeps working
- `PackageVersionChecker` depends on the new `Pollora\VersionCheck\Domain\Contracts\VersionSourceResolver`, which `VersionSources` implements and the container binds to it

## [v13.40.0](https://github.com/Pollora/framework/compare/v13.39.3...v13.40.0) - 2026-11-04

### Changed
Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@
"wp-cli/wp-cli": "^2.12",
"larastan/larastan": "^3.13",
"orchestra/testbench": "^11.3.0",
"pollora/harness": "^0.1.15"
"pollora/harness": "^0.1.23"
},
"autoload-dev": {
"psr-4": {
Expand Down
12 changes: 0 additions & 12 deletions phpstan-baseline.neon
Original file line number Diff line number Diff line change
Expand Up @@ -66,12 +66,6 @@ parameters:
count: 1
path: src/Plugin/Infrastructure/Models/LaravelPluginModule.php

-
message: '#^Called ''env'' outside of the config directory which returns null when the config is cached, use ''config''\.$#'
identifier: larastan.noEnvCallsOutsideOfConfig
count: 1
path: src/Plugin/Infrastructure/Models/LaravelPluginModule.php

-
message: '#^Called ''env'' outside of the config directory which returns null when the config is cached, use ''config''\.$#'
identifier: larastan.noEnvCallsOutsideOfConfig
Expand Down Expand Up @@ -156,12 +150,6 @@ parameters:
count: 1
path: src/Theme/Infrastructure/Models/LaravelThemeModule.php

-
message: '#^Called ''env'' outside of the config directory which returns null when the config is cached, use ''config''\.$#'
identifier: larastan.noEnvCallsOutsideOfConfig
count: 1
path: src/Theme/Infrastructure/Models/LaravelThemeModule.php

-
message: '#^Call to an undefined method Illuminate\\Contracts\\View\\View\:\:makeLoader\(\)\.$#'
identifier: method.notFound
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
use Pollora\Modules\UI\Console\ModuleOutdatedCommand;
use Pollora\Modules\UI\Http\ModulesAdminPage;
use Pollora\Modules\UI\Http\ModuleVersionsHealthCheck;
use Pollora\VersionCheck\Domain\Contracts\VersionSourceResolver;
use Pollora\VersionCheck\Infrastructure\Sources\HttpGet;
use Pollora\VersionCheck\Infrastructure\Sources\VersionSources;

Expand Down Expand Up @@ -68,6 +69,8 @@ public function register(): void
base_path('composer.json'),
$app->make('config')->get('modules.versions.github_token'),
));

$this->app->bind(VersionSourceResolver::class, VersionSources::class);
}

public function boot(): void
Expand Down
2 changes: 1 addition & 1 deletion src/Plugin/Application/Services/PluginManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ public function __construct(
protected ?ModuleRepositoryInterface $repository = null,
?ConsoleDetectionService $consoleDetectionService = null
) {
$this->consoleDetectionService = $consoleDetectionService ?? resolve(ConsoleDetectionService::class);
$this->consoleDetectionService = $consoleDetectionService ?? $app->get(ConsoleDetectionService::class);
}

/**
Expand Down
3 changes: 2 additions & 1 deletion src/Plugin/Infrastructure/Models/LaravelPluginModule.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use Illuminate\Container\Container;
use Illuminate\Foundation\AliasLoader;
use Illuminate\Foundation\Application;
use Illuminate\Support\Env;
use Illuminate\Support\Str;
use Pollora\Hook\Domain\Contract\Action;
use Pollora\Plugin\Domain\Models\PluginModule;
Expand Down Expand Up @@ -49,7 +50,7 @@ public function __construct(
public function getCachedServicesPath(): string
{
// Check if we are running on a Laravel Vapor managed instance
if (! is_null(config('vapor.maintenance_mode', env('VAPOR_MAINTENANCE_MODE')))) {
if (! is_null(config('vapor.maintenance_mode', Env::get('VAPOR_MAINTENANCE_MODE')))) {
return Str::replaceLast('config.php', $this->getSnakeName().'_plugin.php', $this->app->getCachedConfigPath());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
namespace Pollora\Route\Application\UseCases;

use Illuminate\Routing\Route;
use Pollora\Route\Infrastructure\Services\Contracts\WordPressTypeResolverInterface;
use Pollora\Route\Domain\Contracts\WordPressTypeResolverInterface;
use Psr\Log\LoggerInterface;

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
namespace Pollora\Route\Application\UseCases;

use Illuminate\Contracts\Container\Container;
use Pollora\Route\Infrastructure\Services\Contracts\WordPressTypeResolverInterface;
use Pollora\Route\Domain\Contracts\WordPressTypeResolverInterface;
use Psr\Log\LoggerInterface;

/**
Expand Down
41 changes: 41 additions & 0 deletions src/Route/Domain/Contracts/WordPressTypeResolverInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php

declare(strict_types=1);

namespace Pollora\Route\Domain\Contracts;

/**
* Interface for resolving WordPress types.
*/
interface WordPressTypeResolverInterface
{
/**
* Resolve a WordPress type by its class name.
*/
public function resolve(string $typeName): mixed;

/**
* Resolve WP_Post object.
*/
public function resolvePost(): ?\WP_Post;

/**
* Resolve WP_Term object.
*/
public function resolveTerm(): ?\WP_Term;

/**
* Resolve WP_User object.
*/
public function resolveUser(): ?\WP_User;

/**
* Resolve WP_Query object.
*/
public function resolveQuery(): ?\WP_Query;

/**
* Resolve WP object.
*/
public function resolveWP(): ?\WP;
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@
use Pollora\Route\Application\UseCases\RegisterWordPressTypesUseCase;
use Pollora\Route\Domain\Contracts\ConditionResolverInterface;
use Pollora\Route\Domain\Contracts\WordPressRouteInterface;
use Pollora\Route\Domain\Contracts\WordPressTypeResolverInterface;
use Pollora\Route\Infrastructure\Listeners\ApplyApplicationRouteContext;
use Pollora\Route\Infrastructure\Middleware\WordPressBindings;
use Pollora\Route\Infrastructure\Middleware\WordPressHeaders;
use Pollora\Route\Infrastructure\Middleware\WordPressShutdown;
use Pollora\Route\Infrastructure\Middleware\WordPressTemplateEnhancement;
use Pollora\Route\Infrastructure\Services\Contracts\WordPressConditionManagerInterface;
use Pollora\Route\Infrastructure\Services\Contracts\WordPressTypeResolverInterface;
use Pollora\Route\Infrastructure\Services\ExtendedRouter;
use Pollora\Route\Infrastructure\Services\Resolvers\WordPressTypeResolver;
use Pollora\Route\Infrastructure\Services\WordPressConditionManager;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,38 +4,10 @@

namespace Pollora\Route\Infrastructure\Services\Contracts;

/**
* Interface for resolving WordPress types.
*/
interface WordPressTypeResolverInterface
{
/**
* Resolve a WordPress type by its class name.
*/
public function resolve(string $typeName): mixed;

/**
* Resolve WP_Post object.
*/
public function resolvePost(): ?\WP_Post;

/**
* Resolve WP_Term object.
*/
public function resolveTerm(): ?\WP_Term;
use Pollora\Route\Domain\Contracts\WordPressTypeResolverInterface as DomainWordPressTypeResolverInterface;

/**
* Resolve WP_User object.
*/
public function resolveUser(): ?\WP_User;

/**
* Resolve WP_Query object.
*/
public function resolveQuery(): ?\WP_Query;

/**
* Resolve WP object.
*/
public function resolveWP(): ?\WP;
}
/*
* The interface moved to the domain layer, where the application layer may
* depend on it. The former name keeps working.
*/
class_alias(DomainWordPressTypeResolverInterface::class, 'Pollora\\Route\\Infrastructure\\Services\\Contracts\\WordPressTypeResolverInterface');
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

namespace Pollora\Route\Infrastructure\Services\Resolvers;

use Pollora\Route\Infrastructure\Services\Contracts\WordPressTypeResolverInterface;
use Pollora\Route\Domain\Contracts\WordPressTypeResolverInterface;

/**
* Concrete implementation for resolving WordPress types.
Expand Down
8 changes: 6 additions & 2 deletions src/Schedule/Application/Services/ScheduleStatus.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

use Illuminate\Contracts\Config\Repository;
use Pollora\Schedule\Event;
use Pollora\Schedule\Infrastructure\Drivers\LaravelQueueDriver;
use Pollora\Schedule\Schedule;
use Pollora\Schedule\Support\CronIndex;

Expand All @@ -18,6 +17,11 @@
*/
final readonly class ScheduleStatus
{
/**
* Name the queue driver files its events under (LaravelQueueDriver::NAME).
*/
private const string QUEUE_DRIVER = 'laravel';

public function __construct(private Repository $config) {}

/**
Expand Down Expand Up @@ -90,7 +94,7 @@ public function late(): int
{
$limit = time() - $this->lateAfter();

return count(array_filter(Schedule::engine()->index(), static fn (Event $event): bool => $event->driver === LaravelQueueDriver::NAME && $event->timestamp < $limit));
return count(array_filter(Schedule::engine()->index(), static fn (Event $event): bool => $event->driver === self::QUEUE_DRIVER && $event->timestamp < $limit));
}

/**
Expand Down
2 changes: 1 addition & 1 deletion src/Theme/Application/Services/ThemeManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ public function __construct(
protected ?ThemeRegistrarInterface $registrar = null,
?ConsoleDetectionService $consoleDetectionService = null
) {
$this->consoleDetectionService = $consoleDetectionService ?? resolve(ConsoleDetectionService::class);
$this->consoleDetectionService = $consoleDetectionService ?? $app->make(ConsoleDetectionService::class);
}

/**
Expand Down
3 changes: 2 additions & 1 deletion src/Theme/Infrastructure/Models/LaravelThemeModule.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use Illuminate\Container\Container;
use Illuminate\Foundation\AliasLoader;
use Illuminate\Foundation\Application;
use Illuminate\Support\Env;
use Illuminate\Support\Str;
use Pollora\Hook\Domain\Contract\Action;
use Pollora\Theme\Domain\Models\ThemeModule;
Expand Down Expand Up @@ -36,7 +37,7 @@ public function __construct(
public function getCachedServicesPath(): string
{
// Check if we are running on a Laravel Vapor managed instance
if (! is_null(config('vapor.maintenance_mode', env('VAPOR_MAINTENANCE_MODE')))) {
if (! is_null(config('vapor.maintenance_mode', Env::get('VAPOR_MAINTENANCE_MODE')))) {
return Str::replaceLast('config.php', $this->getSnakeName().'_theme.php', $this->app->getCachedConfigPath());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
namespace Pollora\VersionCheck\Application\Services;

use Composer\InstalledVersions;
use Pollora\VersionCheck\Domain\Contracts\VersionSourceResolver;
use Pollora\VersionCheck\Domain\Services\StableVersions;
use Pollora\VersionCheck\Infrastructure\Sources\VersionSources;

/**
* Whether an installed Composer package is up to date.
Expand All @@ -22,7 +22,7 @@ class PackageVersionChecker

public const int NEGATIVE_TTL = 3600;

public function __construct(private readonly VersionSources $sources) {}
public function __construct(private readonly VersionSourceResolver $sources) {}

public function current(string $package): ?string
{
Expand Down
13 changes: 13 additions & 0 deletions src/VersionCheck/Domain/Contracts/VersionSourceResolver.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

declare(strict_types=1);

namespace Pollora\VersionCheck\Domain\Contracts;

/**
* Finds where a package's releases are read.
*/
interface VersionSourceResolver
{
public function for(string $package): VersionSource;
}
3 changes: 2 additions & 1 deletion src/VersionCheck/Infrastructure/Sources/VersionSources.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace Pollora\VersionCheck\Infrastructure\Sources;

use Pollora\VersionCheck\Domain\Contracts\VersionSource;
use Pollora\VersionCheck\Domain\Contracts\VersionSourceResolver;

/**
* Where a package's releases are read, from the repositories of the project's
Expand All @@ -18,7 +19,7 @@
* The first one that knows the package answers: a repository that does not
* serve it (401, 403, 404) hands over to the next, as in Composer.
*/
class VersionSources
class VersionSources implements VersionSourceResolver
{
/**
* @var array<int, array<string, mixed>>|null
Expand Down
4 changes: 3 additions & 1 deletion tests/Feature/ModuleActivation/ModuleVersionsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
use Pollora\Modules\UI\Console\ModuleOutdatedCommand;
use Pollora\Modules\UI\Http\ModuleVersionsHealthCheck;
use Pollora\VersionCheck\Application\Services\PackageVersionChecker;
use Pollora\VersionCheck\Domain\Contracts\VersionSourceResolver;
use Pollora\VersionCheck\Domain\Services\StableVersions;
use Pollora\VersionCheck\Infrastructure\Sources\ComposerRepositorySource;
use Pollora\VersionCheck\Infrastructure\Sources\FirstAnsweringSource;
Expand Down Expand Up @@ -215,7 +216,8 @@ public function getPath(): string
}, array_keys($this->paths));
}
});
$this->app->instance(VersionSources::class, new VersionSources(new HttpGet, $this->directory.'/composer.json'));
$this->app->instance(VersionSources::class, $sources = new VersionSources(new HttpGet, $this->directory.'/composer.json'));
$this->app->instance(VersionSourceResolver::class, $sources);

fakeHttp(['https://repo.packagist.org/p2/nwidart/laravel-modules.json' => ['packages' => ['nwidart/laravel-modules' => [['version' => '99.0.0']]]]]);
});
Expand Down
4 changes: 3 additions & 1 deletion tests/Feature/ModuleActivation/ModulesAdminPageTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
use Pollora\Modules\Infrastructure\Activation\ConnectorActivator;
use Pollora\Modules\Infrastructure\Activation\JsonStateConnector;
use Pollora\Modules\UI\Http\ModulesAdminPage;
use Pollora\VersionCheck\Domain\Contracts\VersionSourceResolver;
use Pollora\VersionCheck\Infrastructure\Sources\HttpGet;
use Pollora\VersionCheck\Infrastructure\Sources\VersionSources;

Expand Down Expand Up @@ -100,7 +101,8 @@ public function find(string $name): ?object
}
});

$this->app->instance(VersionSources::class, new VersionSources(new HttpGet, $this->directory.'/composer.json'));
$this->app->instance(VersionSources::class, $sources = new VersionSources(new HttpGet, $this->directory.'/composer.json'));
$this->app->instance(VersionSourceResolver::class, $sources);

$this->page = $this->app->make(ModulesAdminPage::class);
});
Expand Down
Loading
Loading