From 041f793b53a27978121ba527bee38bfba99de88b Mon Sep 17 00:00:00 2001 From: DevBot CI Date: Mon, 17 Aug 2026 07:59:35 +0000 Subject: [PATCH] Publish 2026-08-17T07:59:34Z (v1.0.1) --- .github/workflows/build.yml | 2 +- CHANGELOG.md | 11 +++- README.md | 18 ++++-- composer.json | 10 ++-- manifest.json | 2 +- src/Abstracts/AbstractWith.php | 10 +--- tests/Abstracts/AbstractWithTest.php | 89 ++++++++++++++-------------- 7 files changed, 77 insertions(+), 65 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7e1cae2..16e6d8a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -8,7 +8,7 @@ on: jobs: build: if: github.event.pull_request.merged == true - runs-on: ubuntu-latest + runs-on: [self-hosted, debian-13-sh] steps: - uses: actions/checkout@v4 - name: Build install archive diff --git a/CHANGELOG.md b/CHANGELOG.md index 9d3babe..633c211 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,8 +5,15 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [Unreleased] +## 1.0.1 ### Added -- Forgejo → GitHub publish pipeline, Packagist notify workflows, and library-oriented issue templates +- `AbstractWith` extends `\Lombok\Helper` and forwards unmatched `__call` to Lombok after `WithHandler` +- Runtime dependency on `marcin-orlowski/lombok-php` `^1.2` for `#[Getter]` / `#[Setter]` + +## 1.0.0 + +### Added + +- Initial release diff --git a/README.md b/README.md index 6af36a8..f13b4ca 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ Reusable PHP 8.3 attributes and runtime helpers. -See [docs/getting-started.md](docs/getting-started.md) for full documentation. +See [the documentation](https://readme.devcraft.club/dev/dev-tools/1.0.1/getting_started) for the full guide. ## Local installation @@ -18,7 +18,7 @@ Add a Composer path repository in the consuming project and require the package: } ], "require": { - "devcraft/dev-tools": "@dev" + "devcraftclub/dev-tools": "@dev" } } ``` @@ -27,13 +27,17 @@ Path repositories must be configured by the consuming root project; Composer does not inherit them transitively. Publish this package later, or replace the path repository with a normal repository and version. +The package depends on [`marcin-orlowski/lombok-php`](https://github.com/MarcinOrlowski/lombok-php) `^1.2`. + ## Fluent properties ```php +use Lombok\Getter; use Devcraft\Abstracts\AbstractWith; use Devcraft\Attributes\With; use Devcraft\Attributes\WithItem; +#[Getter] final class Query extends AbstractWith { #[With] @@ -47,6 +51,10 @@ final class Query extends AbstractWith } ``` -`AbstractWith` routes unresolved calls through `WithHandler::handles()` and -`WithHandler::call()`. One `WithItem` descriptor appends a value. Two -descriptors set a key/value pair. Arrays in a descriptor represent union types. +`AbstractWith` extends `\Lombok\Helper`. Unresolved calls go to `WithHandler` +first (`with*` / `with*Item`), then to Lombok getters and setters (`get*` / +`set*` / `is*`). One `WithItem` descriptor appends a value. Two descriptors set +a key/value pair. Arrays in a descriptor represent union types. + +If a subclass defines `__construct()`, call `parent::__construct()` so Lombok +can wire accessors. `with*` methods do not depend on that call. diff --git a/composer.json b/composer.json index d9338b2..a994d07 100644 --- a/composer.json +++ b/composer.json @@ -1,19 +1,19 @@ { "name": "devcraftclub/dev-tools", "description": "Reusable PHP attributes and validation utilities", - "type": "library", - "version": "1.0.0", + "version": "1.0.1", "homepage": "https://github.com/DevCraftClub/DevTools", "support": { "email": "dev@devcraft.club", "issues": "https://github.com/DevCraftClub/DevTools/issues", "forum": "https://devcraft.club", - "docs": "https://readme.devcraft.club/dev/dev-tools/1.0.0/guides/english" + "docs": "https://readme.devcraft.club/dev/dev-tools/1.0.1/en/getting_started" }, "require": { "php": ">=8.3", "psr/log": "^3.0", - "analog/analog": "^1.0" + "analog/analog": "^1.0", + "marcin-orlowski/lombok-php": "^1.2" }, "require-dev": { "phpunit/phpunit": "^11.0" @@ -43,7 +43,7 @@ "name": "Maxim Harder", "email": "dev@devcraft.club", "role": "developer", - "homepage": "https://devcraft.club" + "homepage": "https://maxim-harder.de" }, { "name": "DevCraft", diff --git a/manifest.json b/manifest.json index be04d21..e8a16dd 100644 --- a/manifest.json +++ b/manifest.json @@ -1,4 +1,4 @@ { - "version": "1.0.0", + "version": "1.0.1", "name": "dev-tools" } diff --git a/src/Abstracts/AbstractWith.php b/src/Abstracts/AbstractWith.php index 491e5c5..e121ae5 100644 --- a/src/Abstracts/AbstractWith.php +++ b/src/Abstracts/AbstractWith.php @@ -4,21 +4,17 @@ namespace Devcraft\Abstracts; -use BadMethodCallException; +use Lombok\Helper; use Devcraft\Runtime\WithHandler; -abstract class AbstractWith { +abstract class AbstractWith extends Helper { public function __call(string $methodName, array $arguments): mixed { if(WithHandler::handles($this, $methodName)) { return WithHandler::call($this, $methodName, $arguments); } - throw new BadMethodCallException(sprintf( - 'Call to undefined method %s::%s()', - $this::class, - $methodName, - )); + return parent::__call($methodName, $arguments); } } diff --git a/tests/Abstracts/AbstractWithTest.php b/tests/Abstracts/AbstractWithTest.php index b12f586..f8298c0 100644 --- a/tests/Abstracts/AbstractWithTest.php +++ b/tests/Abstracts/AbstractWithTest.php @@ -4,57 +4,58 @@ namespace Devcraft\DevTools\Tests\Abstracts; +use Lombok\Getter; +use Lombok\Setter; use BadMethodCallException; -use Devcraft\Abstracts\AbstractWith; -use Devcraft\Attributes\With; use PHPUnit\Framework\TestCase; +use Devcraft\Attributes\With; +use Devcraft\Abstracts\AbstractWith; -final class AbstractWithFixture extends AbstractWith +#[Getter, Setter] +final class AccessorFixture extends AbstractWith { - #[With] - private ?int $page = null; + #[With] + private ?int $page = null; - #[With] - private string $cursor = ''; - - public function page(): ?int - { - return $this->page; - } - - public function cursor(): string - { - return $this->cursor; - } + private bool $visible = false; } final class AbstractWithTest extends TestCase { - public function testRoutesKnownVirtualMethodsAndSupportsFluentChaining(): void - { - $fixture = new AbstractWithFixture(); - - $returned = $fixture - ->withPage(7) - ->withCursor('next-page'); - - self::assertSame($fixture, $returned); - self::assertSame(7, $fixture->page()); - self::assertSame('next-page', $fixture->cursor()); - } - - public function testUnknownMethodThrowsBadMethodCallException(): void - { - $fixture = new AbstractWithFixture(); - - $this->expectException(BadMethodCallException::class); - $this->expectExceptionMessage(sprintf( - 'Call to undefined method %s::%s()', - AbstractWithFixture::class, - 'missing', - )); - - $fixture->missing(); - } -} + public function testWithRoutesToWithHandlerAndGetterReadsValue(): void + { + $fixture = new AccessorFixture(); + + $returned = $fixture->withPage(4); + self::assertSame($fixture, $returned); + self::assertSame(4, $fixture->getPage()); + } + + public function testSetterMutatesAndReturnsSameInstance(): void + { + $fixture = new AccessorFixture(); + + $returned = $fixture->setPage(9); + + self::assertSame($fixture, $returned); + self::assertSame(9, $fixture->getPage()); + } + + public function testBooleanPropertyUsesIsPrefix(): void + { + $fixture = new AccessorFixture(); + + self::assertFalse($fixture->isVisible()); + self::assertSame($fixture, $fixture->setVisible(true)); + self::assertTrue($fixture->isVisible()); + } + + public function testUnknownMethodThrowsBadMethodCallException(): void + { + $fixture = new AccessorFixture(); + + $this->expectException(BadMethodCallException::class); + $fixture->missing(); + } +}