Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Promote DocBlock to native types #128

Merged
merged 9 commits into from
May 27, 2021
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 composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"laminas/laminas-servicemanager": "<3.6.0"
},
"require-dev": {
"ext-intl": "*",
"doctrine/annotations": "^1.12.0",
"laminas/laminas-captcha": "^2.10.0",
"laminas/laminas-coding-standard": "^2.2.1",
Expand Down
16 changes: 14 additions & 2 deletions docs/book/migration/v2-to-v3.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,27 @@ laminas-form v3 makes a number of changes that may affect your application. This
document details those changes, and provides suggestions on how to update your
application to work with v3.

## Native types

laminas-form v3 promoted `@param` and `@return` annotations of non-mixed types to
the corresponding function signatures. This change should affect only highly customized
element, fieldset or form classes.
If you need to automate native types promotion, [PHP-CS-Fixer](https://github.com/FriendsOfPHP/PHP-CS-Fixer)
can help you with this command:

```console
$ php-cs-fixer fix --rules=phpdoc_to_param_type,phpdoc_to_return_type --allow-risky=yes path/to/my/custom/forms/
```

Comment on lines +7 to +18
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Slamdunk
Thank you! 😃

## Using doctrine/annotations now instead of laminas/laminas-code

Since laminas-code dropped support for annotation parsing with v4, laminas-form
switched to doctrine/annotations for annotation parsing. For most users, this will
not have any side effects, however, you must ensure that you install
doctrine/annotations with at least version 1.12.0:

```bash
composer require doctrine/annotations
```console
$ composer require doctrine/annotations
```

## Support for PHP8 Attributes
Expand Down
13 changes: 3 additions & 10 deletions psalm-baseline.xml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@
</DuplicateArrayKey>
</file>
<file src="src/Element/Collection.php">
<ImplementedParamTypeMismatch occurrences="1">
<code>$object</code>
</ImplementedParamTypeMismatch>
<MoreSpecificImplementedParamType occurrences="1">
<code>$object</code>
</MoreSpecificImplementedParamType>
Expand Down Expand Up @@ -63,11 +66,6 @@
<code>formRow</code>
</UndefinedMagicMethod>
</file>
<file src="src/View/Helper/FormDateTimeSelect.php">
<ImplementedParamTypeMismatch occurrences="1">
<code>$timeType</code>
</ImplementedParamTypeMismatch>
</file>
<file src="src/View/Helper/FormRow.php">
<InvalidArgument occurrences="1">
<code>$element</code>
Expand All @@ -91,11 +89,6 @@
<code>null</code>
</NullArgument>
</file>
<file src="test/FormTest.php">
<NullArgument occurrences="1">
<code>null</code>
</NullArgument>
</file>
<file src="test/View/Helper/FormButtonTest.php">
<InvalidArgument occurrences="1">
<code>$element</code>
Expand Down
8 changes: 2 additions & 6 deletions src/Annotation/AbstractAnnotationsListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,9 @@ abstract class AbstractAnnotationsListener extends AbstractListenerAggregate
/**
* Attempt to discover a name set via annotation
*
* @param EventInterface $e
* @return false|string
*/
public function handleNameAnnotation($e)
public function handleNameAnnotation(EventInterface $e)
{
$annotations = $e->getParam('annotations');
assert($annotations instanceof AnnotationCollection);
Expand All @@ -47,11 +46,8 @@ public function handleNameAnnotation($e)

/**
* Discover the fallback name via reflection
*
* @param EventInterface $e
* @return string
*/
public function discoverFallbackName($e)
public function discoverFallbackName(EventInterface $e): string
{
$reflection = $e->getParam('reflection');
if ($reflection instanceof ReflectionClass) {
Expand Down
67 changes: 23 additions & 44 deletions src/Annotation/AbstractBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,8 @@ public function setFormFactory(Factory $formFactory)

/**
* Set event manager instance
*
* @return void
*/
public function setEventManager(EventManagerInterface $eventManager)
public function setEventManager(EventManagerInterface $eventManager): void
{
$eventManager->setIdentifiers([
self::class,
Expand All @@ -74,10 +72,8 @@ public function setEventManager(EventManagerInterface $eventManager)
* Retrieve form factory
*
* Lazy-loads the default form factory if none is currently set.
*
* @return Factory
*/
public function getFormFactory()
public function getFormFactory(): Factory
{
if ($this->formFactory) {
return $this->formFactory;
Expand All @@ -89,10 +85,8 @@ public function getFormFactory()

/**
* Get event manager
*
* @return EventManagerInterface
*/
public function getEventManager()
public function getEventManager(): EventManagerInterface
{
if (null === $this->eventManager) {
$this->setEventManager(new EventManager());
Expand All @@ -105,9 +99,8 @@ public function getEventManager()
*
* @param string|object $entity Either an instance or a valid class name for an entity
* @throws Exception\InvalidArgumentException If $entity is not an object or class name.
* @return ArrayObject
*/
public function getFormSpecification($entity)
public function getFormSpecification($entity): ArrayObject
{
if (! is_object($entity)) {
if (
Expand Down Expand Up @@ -149,9 +142,8 @@ abstract protected function getFormSpecificationInternal($entity): array;
* Create a form from an object.
*
* @param string|object $entity
* @return FormInterface
*/
public function createForm($entity)
public function createForm($entity): FormInterface
{
$formSpec = ArrayUtils::iteratorToArray($this->getFormSpecification($entity));
$formFactory = $this->getFormFactory();
Expand All @@ -160,27 +152,24 @@ public function createForm($entity)

/**
* Get the entity used to construct the form.
*
* @return object
*/
public function getEntity()
public function getEntity(): object
{
return $this->entity;
}

/**
* Configure the form specification from annotations
*
* @param AnnotationCollection $annotations
* @param ReflectionClass $reflection
* @param ArrayObject $formSpec
* @param ArrayObject $filterSpec
* @return void
* @triggers discoverName
* @triggers configureForm
*/
protected function configureForm($annotations, $reflection, $formSpec, $filterSpec)
{
protected function configureForm(
AnnotationCollection $annotations,
ReflectionClass $reflection,
ArrayObject $formSpec,
ArrayObject $filterSpec
): void {
$name = $this->discoverName($annotations, $reflection);
$formSpec['name'] = $name;
$formSpec['attributes'] = [];
Expand All @@ -201,17 +190,16 @@ protected function configureForm($annotations, $reflection, $formSpec, $filterSp
/**
* Configure an element from annotations
*
* @param AnnotationCollection $annotations
* @param ReflectionProperty $reflection
* @param ArrayObject $formSpec
* @param ArrayObject $filterSpec
* @return void
* @triggers checkForExclude
* @triggers discoverName
* @triggers configureElement
*/
protected function configureElement($annotations, $reflection, $formSpec, $filterSpec)
{
protected function configureElement(
AnnotationCollection $annotations,
ReflectionProperty $reflection,
ArrayObject $formSpec,
ArrayObject $filterSpec
): void {
// If the element is marked as exclude, return early
if ($this->checkForExclude($annotations)) {
return;
Expand Down Expand Up @@ -271,31 +259,23 @@ protected function configureElement($annotations, $reflection, $formSpec, $filte
}

/**
* @param bool $preserveDefinedOrder
* @return $this
*/
public function setPreserveDefinedOrder($preserveDefinedOrder)
public function setPreserveDefinedOrder(bool $preserveDefinedOrder)
{
$this->preserveDefinedOrder = (bool) $preserveDefinedOrder;
$this->preserveDefinedOrder = $preserveDefinedOrder;
return $this;
}

/**
* @return bool
*/
public function preserveDefinedOrder()
public function preserveDefinedOrder(): bool
{
return $this->preserveDefinedOrder;
}

/**
* Discover the name of the given form or element
*
* @param AnnotationCollection $annotations
* @param Reflector $reflection
* @return string
*/
protected function discoverName($annotations, $reflection)
protected function discoverName(AnnotationCollection $annotations, Reflector $reflection): string
{
$event = new Event();
$event->setName(__FUNCTION__);
Expand All @@ -320,10 +300,9 @@ static function ($r) {
/**
* Determine if an element is marked to exclude from the definitions
*
* @param AnnotationCollection $annotations
* @return true|false
*/
protected function checkForExclude($annotations)
protected function checkForExclude(AnnotationCollection $annotations): bool
{
$event = new Event();
$event->setName(__FUNCTION__);
Expand Down
13 changes: 5 additions & 8 deletions src/Annotation/BuilderAbstractFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,9 @@ class BuilderAbstractFactory implements AbstractFactoryInterface
/**
* @param string $requestedName
* @param null|array $options
* @return AnnotationBuilder
* @throws ServiceNotCreatedException For invalid listener configuration.
*/
public function __invoke(ContainerInterface $container, $requestedName, ?array $options = null)
public function __invoke(ContainerInterface $container, $requestedName, ?array $options = null): AbstractBuilder
{
// resolve aliases used in laminas servicemanager
if (isset($this->aliases[$requestedName])) {
Expand All @@ -53,9 +52,8 @@ public function __invoke(ContainerInterface $container, $requestedName, ?array $

/**
* @param string $requestedName
* @return bool
*/
public function canCreate(ContainerInterface $container, $requestedName)
public function canCreate(ContainerInterface $container, $requestedName): bool
{
return isset($this->aliases[$requestedName]) || is_subclass_of($requestedName, AbstractBuilder::class);
}
Expand All @@ -73,7 +71,7 @@ public function canCreate(ContainerInterface $container, $requestedName)
*
* @return array
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PHP Code Sniffer keeps @return array notation to let be more specific if the developer is willing to be so

*/
private function marshalConfig(ContainerInterface $container)
private function marshalConfig(ContainerInterface $container): array
{
if (! $container->has('config')) {
return [];
Expand All @@ -95,10 +93,9 @@ private function marshalConfig(ContainerInterface $container)
* - otherwise attaches it to the event manager
*
* @param array $config
* @return void
* @throws ServiceNotCreatedException If any listener is not an event listener aggregate.
*/
private function injectListeners(array $config, EventManagerInterface $events, ContainerInterface $container)
private function injectListeners(array $config, EventManagerInterface $events, ContainerInterface $container): void
{
if (! isset($config['listeners'])) {
return;
Expand All @@ -120,7 +117,7 @@ private function injectListeners(array $config, EventManagerInterface $events, C
*
* Also injects the factory with the InputFilterManager if present.
*/
private function injectFactory(Factory $factory, ContainerInterface $container)
private function injectFactory(Factory $factory, ContainerInterface $container): void
{
$factory->setFormElementManager($container->get('FormElementManager'));

Expand Down
Loading