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
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@
/phpunit.xml.dist export-ignore
/phpcs.xml.dist export-ignore
/cli-config.php export-ignore
/cp export-ignore
15 changes: 11 additions & 4 deletions .github/workflows/main.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@ jobs:
strategy:
matrix:
php-versions: ['8.3', '8.4']
name: PHP ${{ matrix.php-versions }}
dependency-versions: ['highest', 'lowest']
name: PHP ${{ matrix.php-versions }} (${{ matrix.dependency-versions }} deps)
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php-versions }}
Expand All @@ -26,10 +27,16 @@ jobs:
- uses: actions/cache@v4
with:
path: ${{ steps.composer-cache.outputs.dir }}
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
restore-keys: ${{ runner.os }}-composer-
key: ${{ runner.os }}-composer-${{ matrix.dependency-versions }}-${{ hashFiles('**/composer.lock') }}
restore-keys: ${{ runner.os }}-composer-${{ matrix.dependency-versions }}-
- name: composer validate
run: composer validate --strict
- name: composer install
if: matrix.dependency-versions == 'highest'
run: composer install --no-progress --prefer-dist --optimize-autoloader
- name: composer update --prefer-lowest
if: matrix.dependency-versions == 'lowest'
run: composer update --no-progress --prefer-dist --prefer-stable --prefer-lowest --optimize-autoloader
- name: phpunit
run: php vendor/bin/phpunit
- name: phpcs
Expand Down
63 changes: 22 additions & 41 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@ Welcome to the Accessor Generator composer plugin.
## Goals
The goal of this plugin is to provide dynamically generated get, set, add, remove
accessor methods for Classes based on information that we can read from PHP 8 native
attributes or from doc comments.
Currently we can process Doctrine ORM annotations and their native attribute equivalents.
attributes.

Since the code is automatically generated you do not have to (unit) test it and it
will be very consistent with a lot of added boilerplate code that will make your code
Expand All @@ -15,6 +14,27 @@ functions.

- Imports through grouped `use` statements is not supported. (https://wiki.php.net/rfc/group_use_declarations)

## Upgrading to 7.0

Version 7.0 drops docblock-annotation support entirely (`doctrine/annotations` is no longer a
dependency) - only native PHP attributes (`#[AG\Generate]`, `#[AG\Enumerator]`, `#[ORM\...]`) are
read. If your entities are already fully on attribute syntax, this is likely all you need to check:

- `Hostnet\Component\AccessorGenerator\Annotation\Generate` and `...\Annotation\Enumerator` (the
deprecated docblock-annotation classes) are removed. If any of your entities import
`Hostnet\Component\AccessorGenerator\Annotation as AG` and apply it as a native attribute
(`#[AG\Generate(...)]`), repoint that import to
`Hostnet\Component\AccessorGenerator\Attribute as AG` instead.
- `PropertyProcessorInterface::getProcessableNamespace()` is removed. It only existed to support
docblock-annotation parsing; if you have a custom `PropertyProcessorInterface` implementation,
drop that method from it.
- Generated `set`/`add`/`remove` accessor methods (previously undeclared) now declare a native
`: static` return type. A hand-written subclass that overrides one of these without an explicit
return type will fail to load with a `must be compatible with ...: static` error - add `: static`
to the override (this is also valid against the previous major, so it can be done ahead of the
upgrade). The generated `Enumerator` accessor class's `set`/`remove`/`clear` methods already
declared an explicit return type before and keep it unchanged.

## Installation

Add `hostnet/accessor-generator-plugin-lib` to your `composer.json` and run
Expand Down Expand Up @@ -49,30 +69,6 @@ class Period
}
```

Docblock-style annotations are also supported and can be mixed freely with native attributes:

```php
use Doctrine\ORM\Mapping as ORM;
use Hostnet\Component\AccessorGenerator\Annotation as AG;

/**
* @ORM\Entity
* @ORM\Table(name="periode")
*/
class Period
{
use Generated\PeriodMethodsTrait;

/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(name="id", type="integer")
* @AG\Generate
*/
private int $id;
}
```

The files will be generated in a subdirectory and namespace (Generated) relative to the current
file. This file can be included as trait.

Expand All @@ -85,13 +81,6 @@ the attribute.
#[AG\Generate(add: 'none', set: 'none', remove: 'none', get: 'none', is: 'none')]
```

Docblock equivalent:
```php
/**
* @AG\Generate(add="none",set="none",remove="none",get="none",is="none")
*/
```

`Is` is an alias for get. If your property is of type boolean an `isProperty` method is
generated instead of a `getProperty` method. For `ORM\GeneratedValue` properties, no
setters will be generated. **Note that the example above will generate no code at all.**
Expand All @@ -111,14 +100,6 @@ plus the length of the sealed data itself.
private $encrypted_variable;
```

Docblock equivalent:
```php
/**
* @AG\Generate(encryption_alias="database.table.column")
*/
private $encrypted_variable;
```

The alias used there should be added to the application's composer.json as follows:

```
Expand Down
11 changes: 6 additions & 5 deletions cli-config.php
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
<?php
require_once __DIR__ . '/vendor/autoload.php';

use Doctrine\DBAL\DriverManager;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\ORMSetup;
use Doctrine\ORM\Tools\Console\ConsoleRunner;
use Doctrine\ORM\Tools\Setup;

$paths = [ 'test/Generator/fixtures'];
$config = Setup::createAnnotationMetadataConfiguration($paths, true, null, null, false);
$entityManager = EntityManager::create([driver => 'pdo_sqlite', 'memory' => true], $config);
$paths = ['test/Generator/fixtures'];
$config = ORMSetup::createAttributeMetadataConfiguration($paths, true);
$connection = DriverManager::getConnection(['driver' => 'pdo_sqlite', 'memory' => true], $config);

return ConsoleRunner::createHelperSet($entityManager);
return ConsoleRunner::createHelperSet(new EntityManager($connection, $config));
12 changes: 5 additions & 7 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,21 @@
"composer-plugin-api": "^2.0",
"ext-bcmath": "*",
"ext-json": "*",
"doctrine/annotations": "^1.14.3",
"doctrine/collections": "^1.8.0",
"doctrine/dbal": "^3.7.2",
"doctrine/inflector": "^2.0.8",
"doctrine/orm": "^2.17.2",
"symfony/filesystem": "^5.4||^6.0",
"symfony/filesystem": "^6.0||^7.0",
"symfony/finder": "^6.0||^7.0",
"twig/twig": "^3.15.0"
},
"require-dev": {
"composer/composer": "^2.0.0",
"hostnet/phpcs-tool": "^9.0.0",
"phpspec/prophecy": "^1.17",
"phpspec/prophecy-phpunit": "^2.1",
"phpunit/phpunit": "^9.6.0"
"phpunit/phpunit": "^9.6.0",
"symfony/cache": "^6.4||^7.0"
},
"autoload": {
"psr-4": {
Expand All @@ -33,10 +34,7 @@
"psr-4": {
"Hostnet\\Component\\AccessorGenerator\\Generator\\fixtures\\Generated\\": "test/Generator/fixtures/expected/",
"Hostnet\\Component\\AccessorGenerator\\": "test/"
},
"files": [
"test/annotation_loader.php"
]
}
},
"config": {
"allow-plugins": {
Expand Down
22 changes: 0 additions & 22 deletions src/Annotation/Enumerator.php

This file was deleted.

24 changes: 0 additions & 24 deletions src/Annotation/Generate.php

This file was deleted.

40 changes: 31 additions & 9 deletions src/Attribute/Generate.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@

namespace Hostnet\Component\AccessorGenerator\Attribute;

use Doctrine\Common\Annotations\Annotation\Enum;

/**
* Activates accessor method generation for a property.
*
Expand Down Expand Up @@ -37,13 +35,20 @@ class Generate
*/
public const string VISIBILITY_PRIVATE = 'private';

private const array VALID_VISIBILITIES = [
self::VISIBILITY_NONE,
self::VISIBILITY_PUBLIC,
self::VISIBILITY_PROTECTED,
self::VISIBILITY_PRIVATE,
];

public function __construct(
/**
* Will generate a getter of the given visibility.
*
* Default: public.
*
* @Enum({"public", "protected", "private", "none"})
* @var 'public'|'protected'|'private'|'none'|null
*/
private ?string $get = null,
/**
Expand All @@ -55,7 +60,7 @@ public function __construct(
*
* Default: public.
*
* @Enum({"public", "protected", "private", "none"})
* @var 'public'|'protected'|'private'|'none'|null
*/
private ?string $set = null,
/**
Expand All @@ -64,7 +69,7 @@ public function __construct(
*
* Default: public.
*
* @Enum({"public", "protected", "private", "none"})
* @var 'public'|'protected'|'private'|'none'|null
*/
private ?string $add = null,
/**
Expand All @@ -73,7 +78,7 @@ public function __construct(
*
* Default: public.
*
* @Enum({"public", "protected", "private", "none"})
* @var 'public'|'protected'|'private'|'none'|null
*/
private ?string $remove = null,
/**
Expand All @@ -82,7 +87,7 @@ public function __construct(
*
* Default: public.
*
* @Enum({"public", "protected", "private", "none"})
* @var 'public'|'protected'|'private'|'none'
*/
private readonly string $is = self::VISIBILITY_PUBLIC,
/**
Expand Down Expand Up @@ -124,6 +129,25 @@ public function __construct(
*/
private readonly ?string $encryption_alias = null,
) {
self::validateVisibility($get, 'get');
self::validateVisibility($set, 'set');
self::validateVisibility($add, 'add');
self::validateVisibility($remove, 'remove');
self::validateVisibility($is, 'is');
}

/**
* @throws \DomainException if $visibility is not one of "public", "protected", "private", "none" or null
*/
private static function validateVisibility(?string $visibility, string $param_name): void
{
if (null !== $visibility && !\in_array($visibility, self::VALID_VISIBILITIES, true)) {
throw new \DomainException(sprintf(
'Invalid value "%s" for Generate::$%s, must be one of "public", "protected", "private", "none".',
$visibility,
$param_name
));
}
}

public function getGet(): ?string
Expand Down Expand Up @@ -201,8 +225,6 @@ public static function getMostLimitedVisibility(...$requirements): string

/**
* Sets the given visibility to all accessors if they are not explicitly defined.
*
* @param string $visibility
*/
public function setDefaultVisibility(string $visibility): void
{
Expand Down
10 changes: 0 additions & 10 deletions src/Collection/ConstCollectionInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -126,32 +126,24 @@ public function next();

/**
* Returns true if the predicate is true for at least one element, false otherwise.
*
* @param \Closure $predicate
*/
public function exists(\Closure $predicate): bool;

/**
* Returns all the elements of this collection that satisfy the given predicate.
* The order of the elements is preserved.
*
* @param \Closure $predicate
*/
public function filter(\Closure $predicate): Collection;

/**
* Returns true if the given predicate is satisfied by all elements in this
* collection, false otherwise.
*
* @param \Closure $predicate
*/
public function forAll(\Closure $predicate): bool;

/**
* Applies the given function to each element in the collection and returns
* a new collection with the elements returned by the function.
*
* @param \Closure $func
*/
public function map(\Closure $func): Collection;

Expand All @@ -163,8 +155,6 @@ public function map(\Closure $func): Collection;
* the predicate returned TRUE, the second returned element contains the
* collection of elements where the predicate returned FALSE.
*
* @param \Closure $predicate
*
* @return Collection[]
*/
public function partition(\Closure $predicate): array;
Expand Down
2 changes: 0 additions & 2 deletions src/Collection/ImmutableCollection.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,6 @@ class ImmutableCollection implements Collection, ConstCollectionInterface, Selec

/**
* Wrap a collection to make it immutable.
*
* @param Collection $collection
*/
public function __construct(Collection $collection)
{
Expand Down
Loading
Loading