Skip to content

[PoC] [ValueExporter] extract HttpKernel/DataCollector util to its own component #18450

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

Closed
wants to merge 12 commits into from

Conversation

HeahDude
Copy link
Contributor

@HeahDude HeahDude commented Apr 5, 2016

Q A
Branch? master
Bug fix? no
New feature? yes
BC breaks? not yet (old implementation has not been removed)
Deprecations? no
Tests pass? yes
Fixed tickets #18149
License MIT
Doc PR TODO ?

@HeahDude HeahDude changed the title [ValueExporter] extract HttpKernel/DataCollector util to its own component [PoC] [ValueExporter] extract HttpKernel/DataCollector util to its own component Apr 5, 2016
@nicolas-grekas
Copy link
Member

Since master is in features freeze, and also since I really think VarDumper has almost all the required bits, I suggest not working on this right now.

@HeahDude HeahDude force-pushed the component/value-exporter branch from 5d237ae to 0e4dbe2 Compare April 5, 2016 18:06
@HeahDude
Copy link
Contributor Author

HeahDude commented Apr 5, 2016

@nicolas-grekas Thank you for your feedback, I understand.

But currently, I really need it as it is proposed in that PR, to avoid requiring symfony/http-kernel for the ValueExporter only and to add it some flexibility.

Anyone can feel free to use, reuse that code for other implementation/work or when it will be the time to bring it in core.

I think I will maintain this branch for the time being. Thanks.

@HeahDude HeahDude force-pushed the component/value-exporter branch 2 times, most recently from 608f750 to 0028027 Compare April 6, 2016 11:38
*
* @var FormatterInterface[]
*/
protected $formatters = array();
Copy link
Member

Choose a reason for hiding this comment

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

any new property should be private

@HeahDude HeahDude force-pushed the component/value-exporter branch from 0028027 to 1afcb8b Compare April 7, 2016 08:41
return sprintf("array(\n%s%s\n)", $indent, implode(sprintf(",\n%s", $indent), $a));
}
// Not an array, test each formatter
foreach ($this->formatters as $formatter) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@stof So here I should use a getter ?

I've pushed some minor changes just now on that class, differences can be seen in the tests.

In fact, I've first tried to use the VarDumper component, but the ValueExporter looks more like var_export to me, not var_dump. So I took example on the architecture of the var dumper wrapper and kept the light weight of the original ValueExporter class, since it does not need cloners, we just want the type here not a deep profile.
I guess if it should replace the logic in many place in the core among the DataCollector profile, this method will be called many time each request. dump has a more specific usage imo.
So I get I'm gonna use that component as is to handle assertion messages (logs and exceptions) in the bundle I'm working on but I can close that PR if you think it's off topic.

Does this make sense to you ?

In any case I really appreciate your review. Thanks.

@HeahDude HeahDude force-pushed the component/value-exporter branch 4 times, most recently from ef747a3 to 20a9b46 Compare April 9, 2016 12:25
@HeahDude
Copy link
Contributor Author

HeahDude commented Apr 9, 2016

Little update here:

  • addressed @stof comment about formatters property in AbstractValueExporter,
  • added an abstract ExpandedFormatter to use expanded exports (exporting nested values).
  • added TraversableToStringFormatter extending the new ExpandedFormatter.
    (this formatter is not added by default)

See the tests for basic usage.

@HeahDude
Copy link
Contributor Author

Changelog: added EntityToStringFormatter.

@HeahDude HeahDude force-pushed the component/value-exporter branch from 1bb7e7a to 9f2ab95 Compare April 20, 2016 15:55
@HeahDude HeahDude force-pushed the component/value-exporter branch 2 times, most recently from 08d6b76 to eb65886 Compare April 21, 2016 17:50
@HeahDude HeahDude force-pushed the component/value-exporter branch from eb65886 to 6e4b7e9 Compare April 23, 2016 06:37
@HeahDude HeahDude force-pushed the component/value-exporter branch from 6e4b7e9 to ab119f0 Compare April 23, 2016 06:48
@HeahDude
Copy link
Contributor Author

HeahDude commented Apr 23, 2016

Changelog:

  • eb1a34d added a priority handling for formatters.
    Using either AbstractValueExporter::__construct($formatter, $_...)
    or ValueExporter::addFormatters(array $formatters).
  • 0e066a1 made ExpandedFormatter a trait for formatters needing recursive export.
  • 677c3c2 fixed an issue with the class name resolution in the InvalidFormatterException message.
  • 8f63b07 added support for FQCN formatters registration instead of passing instances.
  • a83684c added support for objects implementing __toString().
  • ab119f0 tweaked the CallableToStringFormatter.

How-to

So now to register formatters, you can pass either an FQCN or an array with an FQCN and a priority as you would do for listener method:

<?php

use App\ValueExporter\Formatter\CustomValueToStringFormatter;
use App\ValueExporter\Formatter\OverrideValueToStringFormatter;
use Symfony\Component\ValueExporter\Exporter\ValueToStringExporter;
use Symfony\Component\ValueExporter\ValueExporter;

ValueExporter::addFormatters(array(
    CustomValueToStringFormatter::class,
    array(OverrideValueToStringFormatter::class, 10),
));

// or using variadic argument of the constructor
ValueExporter::setExporter(new ValueToStringExporter(
    array(CustomValueToStringFormatter::class, 100),
    OverrideValueToStringFormatter::class,
));

Also note that priorities are handled in AbstractValueExporter holding three private arrays:

  • $formatters => array($formatterFqcn => (int) $priority, ...)
  • $sortedFormatters => array($formatterInstance, ...)
  • $cachedFormatters => array($formatterFqcn => $formatterInstance, ...)

It means that you can change the priority of a formatter in runtime:

<?php

use App\ValueExporter\Formatter\ValueToStringFormatter;
use Symfony\Component\ValueExporter\ValueExporter;

$value = // ...

echo to_string($value); // default

ValueExporter::addFormatters(array(
    array(ValueToStringFormatter::class, 10),
));

echo to_string($value); // use new formatter

ValueExporter::addFormatters(array(
    array(ValueToStringFormatter::class, -1),
));

echo to_string($value); // use formatter with a new priority

Question

Do you think I should allow to use the same formatter class multiple times as discussed in #18482? (ping @iltar :)

I don't feel it is coherent here.

I would really appreciate any one giving it a quick review or thought, I think I just need to add some other tests for better covering the priority handling.

Besides that, I believe this pseudo-component is now flexible and stable enough, so I can start using it in my work on #18411 (ref #18403).

Thanks to anyone giving a look at this experimental PR :)

@HeahDude HeahDude force-pushed the component/value-exporter branch from 856cdb2 to 5d73a2f Compare April 23, 2016 07:18
@HeahDude HeahDude force-pushed the component/value-exporter branch from 5d73a2f to 826e8fb Compare April 23, 2016 07:20
if (is_array($formatter)) {
$priority = (int) $formatter[1];
$formatter = $formatter[0];
} else {
Copy link
Contributor

Choose a reason for hiding this comment

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

You could actually do some unpacking here list($formatter, $priority) = $formatter;. I don't really think the int cast is necessary

@linaori
Copy link
Contributor

linaori commented Apr 23, 2016

I don't think it makes sense to use the same formatter class multiple times I think. If it doesn't support it on prio 10, it won't support it on anything lower either.

@HeahDude
Copy link
Contributor Author

@iltar thank you for your review :), however I don't really understand your last sentence:

If it doesn't support it on prio 10, it won't support it on anything lower either.

Thanks again, the style can still change, but I'd really like to stabilise the functional part for now.

Cheers

@linaori
Copy link
Contributor

linaori commented Apr 23, 2016

If you have something hooking in on 2 priorities, let's say 10 and 20 and on 20 it doesn't trigger anything, why would it trigger something on 10? There won't be a difference in triggering both or only 1

@HeahDude
Copy link
Contributor Author

Ok I got you, you just argue in my way: one class -> one call to support => one way to support.

Having the same class with two instances and different configurations, returning a different result when calling support makes no sens to me.

That's why I was suggesting unique class in your PR (at least for argument value resolvers).

Also I used this implementation, because I think they may be use cases for changing a priority at runtime to help debugging a particular value. Because when you need a specific overhead in supports you may want to move it to the latest after using it.

@linaori
Copy link
Contributor

linaori commented Apr 23, 2016

Yeah so in this PR it makes no sense because once support is declined, it won't ever return anything else. However, in my PR the difference is that there is no supports and everything is supported.

In your case I think it's best to make them unique or add a warning/exception if added twice.

@HeahDude
Copy link
Contributor Author

Isn't that what happens with ArgumentValueResolverInterface::supports and Encoder::supportsEncoding from serializer? That's why I was thinking of a parameter to test unique classes.

namespace Symfony\Component\ValueExporter\Formatter;

/**
* Returns a string representation of a DateTimeInterface instance.
Copy link
Contributor

Choose a reason for hiding this comment

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

Phpdocs looks like copypasted

@HeahDude HeahDude closed this Aug 24, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants