Comments (7)
Sounds like an OK idea, TBH (same for validators).
Note that some of these require external dependencies, and cannot really be safely used as attributes.
from laminas-filter.
Just as a proof of concept, perhaps this could be an interesting implementation:
namespace Laminas\Filter;
use ReflectionAttribute;
use ReflectionClass;
use function class_exists;
use function is_object;
final class AnnotatedObjectFilter implements FilterInterface
{
public function filter(mixed $object): mixed
{
if (! is_object($object)) {
return $object;
}
$className = $object::class;
if (! class_exists($className)) {
return $object;
}
$reflectionClass = new ReflectionClass($className);
$properties = $reflectionClass->getProperties();
foreach ($properties as $property) {
$attributes = $property->getAttributes(
name: FilterInterface::class,
flags: ReflectionAttribute::IS_INSTANCEOF,
);
foreach ($attributes as $attribute) {
$filter = $attribute->newInstance();
$value = $filter->filter($property->getValue($object));
$property->setValue($object, $value);
}
}
return $object;
}
}
from laminas-filter.
@delolmo
Your implementation ignores external dependencies of filters. The filter plugin manager must be used to retrieve a filter, as the manager resolves the dependencies and also the alias names of filters:
laminas-filter/src/FilterPluginManager.php
Lines 20 to 30 in b986ac1
More on this topic can be found in the documentation of laminas-servicemanager: Plugin Managers
from laminas-filter.
What about something like this then? I am sure there are better ways to do it, just trying to contribute something here. Let me know if there is something else I need to take into account.
use Laminas\ServiceManager\ServiceManager;
use ReflectionAttribute;
use ReflectionClass;
use function is_object;
final class AnnotatedObject implements Filter
{
/** @var FilterPluginManager|null */
protected $plugins;
/**
* Get plugin manager instance
*
* @return FilterPluginManager
*/
public function getPluginManager()
{
$plugins = $this->plugins;
if (! $plugins instanceof FilterPluginManager) {
$plugins = new FilterPluginManager(new ServiceManager());
$this->setPluginManager($plugins);
}
return $plugins;
}
public function filter(mixed $value): mixed
{
if (! is_object($value)) {
return $value;
}
$reflectionClass = new ReflectionClass($value);
$properties = $reflectionClass->getProperties();
foreach ($properties as $property) {
$attributes = $property->getAttributes(
name: Filter::class,
flags: ReflectionAttribute::IS_INSTANCEOF,
);
foreach ($attributes as $attribute) {
$filter = $this->plugin(
name: $attribute->getName(),
options: $attribute->getArguments()
);
/** @var mixed $origValue */
$origValue = $property->getValue($value);
/** @var mixed $newValue */
$newValue = $filter->filter($origValue);
$property->setValue($value, $newValue);
}
}
return $value;
}
/**
* Retrieve a filter plugin by name
*
* @param string $name
* @return FilterInterface|callable(mixed): mixed
*/
public function plugin($name, array $options = [])
{
$plugins = $this->getPluginManager();
return $plugins->get($name, $options);
}
/**
* Set plugin manager instance
*
* @return self
*/
public function setPluginManager(FilterPluginManager $plugins)
{
$this->plugins = $plugins;
return $this;
}
}
from laminas-filter.
Maybe we find a way that it is somehow related to laminas-form as well, we do have Filters and Validators there as well and afair there are attributes.
But Overall I like the idea.
from laminas-filter.
I was revisiting this topic and I think the idea still is as an interesting one. Would you like to revisit it?
I have been thinking about what you said about laminas-form, but laminas-filter and laminas-validator should work in a standalone manner, shouldn't they? Perhaps we can move towards implementing the feature in filters and validators and then try to use this new feature in the laminas-form library.
Should I open a PR with my AnnotatedObject
implementation?
from laminas-filter.
I think a PR would be very welcome.
However, you might want to have a look into #118 first and maybe wait some time until we decided on how we want to proceed with this library (esp. the option passing via __construct
).
@froschdesign I am not sure if we need the filter plugin manager. Attributes are not annotations which can be invalid.
Not every filter can be an attribute either, so those filters which can be used as attributes are not allowed to have external dependencies anyways, as these cannot be resolved via the attribute notation.
I am not 100% sure if we should actually have this in-place as (at least I) do not see a real use-case for this (besides the very limited functionality provided by @delolmo).
One of my concerns are, that one has to have a mixed
property and just by adding attributes, no static analyzer will understand what value is in those properties.
If we provide plugins for analyzers, that might work with analyzers but there is no way of actually verifying that the object has already applied filters or not and thus static analyzers will have a tough time.
That is why I do not use filters outside of forms (in which I can just pass array
).
I'd rather have something like:
final class CreateNewBookDto extends Dto
{
/**
* @param non-empty-string $author
* @param uppercase-string $title
*/
public function __construct(public readonly string $author, public readonly string $title)
{
}
}
With having StringTrim
being applied prior instantiating the class.
This provides proper types without having mixed
somewhere.
But thats most probably a personal thing and there might be projects and developers who are not that strict when it comes to their types. I would never pass any code review in our company with that but thats just because I have other expectations.
from laminas-filter.
Related Issues (20)
- [RFC]: Removal of `UriNormalizer` HOT 2
- v3 Docs: Improve documentation on change to final everywhere
- Test failure with OpenSSL 3.0 HOT 1
- RenameUpload filter breaks UploadFile validator HOT 1
- PHP 8.1 support HOT 3
- Non-string scalar types produce a fatal error with StripNewlines HOT 6
- Hydration of object attached to form with unfiltered values on submission HOT 1
- Is `DateTimeFormatter` filter missed in documentation? HOT 1
- Removal of `container-interop/container-interop`
- Problem with FileInput HOT 1
- Dependency Dashboard
- Declaration of Laminas\Filter\FilterPluginManager::get($name, ?array $options = NULL) must be compatible with Laminas\ServiceManager\AbstractPluginManager::get($name, $options = Array, $usePeeringServiceManagers = true) HOT 10
- Action Required: Fix Renovate Configuration HOT 3
- [RFC]: Deprecate Compression Adapters Lzf, Rar and Snappy HOT 1
- Remove Deprecated Compression Adapters HOT 1
- Remove Deprecated Encryption & Decryption Filters HOT 1
- `Boolean` filter should also accept `int-mask<self::CONSTANTS>` via `__construct`
- Check for an instance of the `DateTimeInterface` instead of `DateTime` in `DateTimeFormatter` HOT 4
- ToString filter missing? HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from laminas-filter.