Skip to content

Make convert services #604

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 31 commits into from
Closed

Make convert services #604

wants to merge 31 commits into from

Conversation

ghost
Copy link

@ghost ghost commented May 12, 2020

Branch? master
Bug fix? no
New feature? - yes
Deprecations? - no
Tickets - no
License MIT
Doc PR - in progress

TODOs:

  • Maybe bring in more refactoring from @TomasVotruba
  • Fix/finish checking of Kernel.php for 5.1 recipe code
  • Clear cache after or recommend the user does
  • If there is no App\Kernel class, we can't continue. Or, at least, we would need to use a different type-hint in the config files.

@ghost ghost marked this pull request as draft May 12, 2020 16:50
Copy link
Member

@weaverryan weaverryan left a comment

Choose a reason for hiding this comment

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

This is pretty insane. I love it! Let's see if we can tighten up a few things. But mostly, the tests are critical here, and you've covered them nicely.

Copy link
Member

@weaverryan weaverryan left a comment

Choose a reason for hiding this comment

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

Some comments! Very impressive result! The tweaks are for readability on this complex feature.

Thanks!

if (null === $invalid && ', 0' === $priority) {
$priority = null;
$innerName = ', null' === $innerName ? null : $innerName;
}
Copy link
Member

Choose a reason for hiding this comment

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

I think we are going to have a few more places where we need to intelligently generate methods like this. We could possibly create a private method for it... but I'm not sure if that would be easy. This is just really ugly logic... especially if we repeat it in multiple places.

@ghost
Copy link
Author

ghost commented Jun 1, 2020

I don't understand why my last test is failing.

@weaverryan
Copy link
Member

weaverryan commented Jun 12, 2020

I've checked the core YamlFileParser, and we're missing support for these service options:

  • parent
  • synthetic
  • lazy
  • abstract
  • file
  • properties
  • bind

These should be added to the switch-case statement inside PhpServicesCreator::convertServiceOptionsToNodes. Some will be really easy - I think lazy and synthetic are just true/false values, so they could be added to the same case as shared/public/exclude, etc

Other than that, I'm very happy with this PR!

Also, tests should pass once symfony/recipes#785 is merged

@TomasVotruba
Copy link

What is missing here?

I'm using this class out in the wild to convert configs in my projects, so I can give some practical feedback

$this->addLineStmt('$parameters = $configurator->parameters();', true);

foreach ($parameters as $parameterName => $value) {
$this->addLineStmt(sprintf(

Choose a reason for hiding this comment

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

Actually, all these sprintf(%variable, %call, %args) should not be string, but a node.

Using string in a node as Name, while it is MethodCall or Assing is like writing PHP in one big string.

Copy link
Member

Choose a reason for hiding this comment

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

That's 100% true. I think, at some point (and I think it was quite pragmatic) @archeoprog took some shortcuts, where writing string code was simpler than using the Nodes. In this case (causeI just tried it), it's easy until the argument part, which has a lot of complex logic attached to it - specifically the $this->toString() method.

So I don't think it's worth the work to refactor the internals of the class, though you do have a perfectly valid point.

Copy link

@TomasVotruba TomasVotruba Jul 10, 2020

Choose a reason for hiding this comment

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

It makes sense as 1st draft with lack of knowledge of php-parser, I'm 👍 for that.

Just now it would deserve using nodes correctly. As this sprintf magic disables php-parser printer features. Basically printer is now written manually here, which cluters the code and makes it very hard to read and extend. It's too much to think about on every line, instead of extending php-parser printer on 1 place :) (I'm super lazy btw)

E.g. this is how you add indentation to all fluent method calls:

https://github.com/migrify/migrify/pull/45/files#diff-3079c82962d6f72f03af70c687388891R17

Copy link
Author

Choose a reason for hiding this comment

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

Actually, all these sprintf(%variable, %call, %args) should not be string, but a node.

Using string in a node as Name, while it is MethodCall or Assing is like writing PHP in one big string.

That's exactly what I wanted to do with Name, it's a little "hack" reserved for the content of the Closure because the use of nodes proved to be, at this level, a waste of time, very tedious where the manipulation of strings was much simpler. But this is only my personal vision of complexity and now that you have a few sorting algorithms as a basis, feel free to adapt for your project and see what happens with the nodes. I'm sure @weaverryan would be interested to see the result :)

Copy link
Author

@ghost ghost Jul 10, 2020

Choose a reason for hiding this comment

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

Yeah, it was my first project with the library. I tried a refactoring with nodes. Even without knowing well, the Dump system allows to get nodes corresponding to php instructions so I had this help :)

In spite of that, I couldn't find the interest to continue, surely it would have been necessary to start again from the beginning, impossible for me.

Choose a reason for hiding this comment

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

Got you. It makes sense 👍

I look forward to your final version.

@weaverryan
Copy link
Member

@TomasVotruba!

Ah, super happy to hear you're already using this! The only missing piece is that we really need to convert services_*.yaml all at once - meaning we need to detect (for example) services_test.yaml and put it into the new services.php file. The reason is that, with the 5.1 recipe, once services.yaml is gone, the other services_{env}.yaml files won't be loaded - https://github.com/symfony/recipes/blob/c6de7cf8f54b10a7e4b54729368433fe35fcae0a/symfony/framework-bundle/5.1/src/Kernel.php#L19

So, we need to do that last step - I'm working on it now.

jean and others added 13 commits July 10, 2020 11:31
What we really want to know is whether the new services.php file is being read
and that it at least has basic functionality. This test now proves that the
controller and FakeService are registered correctly and that autowiring works.
When we're looping over the service config keys, they are not really "methods",
they are service config keys. This clarifies that. Then, set determine the
method *based* from that key.

This is super minor, but it makes the code read more accurately: we are looping
over the config keys and THEN determining the php "method" based on that.
…to the data provider

The data provider should, ideally, pass all the info the tests needs directly. So,
let's directly tell the test case if the container should be compared or not
@TomasVotruba
Copy link

TomasVotruba commented Jul 10, 2020

Btw, this is the PR with all XML to PHP stuff: https://github.com/migrify/migrify/pull/39
I try to refer it with every change I make, so there is just one source to study.


Use of @migrify tool in practise:

@ghost
Copy link
Author

ghost commented Jul 10, 2020

@TomasVotruba

Looks great, i think you should offering an improvment of php parser documentation.
I noticed your big contribution to this library.

In fact, it might be good to present a little bit of the theoretical aspect of code analysis, beyond the library itself. Or maybe, very simply, redirect to documentation, tutorials on this aspect of development.
I didn't learn computer science in school, I realized a lot of theoretical gaps while using it. This is a personal testimony :)

Of course, I imagine your time is precious, it's just a suggestion :)

@TomasVotruba
Copy link

TomasVotruba commented Jul 10, 2020

@archeoprog I'm way to expert for nodes now to be able to write intro documentation :D = only I'd find it useful, nobody else.

I didn't learn computer science in school, I realized a lot of theoretical gaps while using it.

School or knowledge is irelevant here.

I actually haven't studied computer science either, I studied psychology. Docs might be useful, but it would basically 1:1 copy the source. I just looked at the php-parser code and tests and copied the behavior, until I got it right.

The main thing is not documentation, or package code design, but the motivation. If you want to learn AST and nodes just for this single command, it doesn't last long. My motivation is to allow refactoring of any PHP code to modern codebase to every PHP developer in the world without any knowledge at 1 click.


If you feel you'll find a purpose in this, go deep dive to php-parser. It's worth the time and frustration :) soon you'll see PHP code as Matrix code 😉

@weaverryan
Copy link
Member

@TomasVotruba I've just ported your code over... at least how it looked about 1 hour ago. I know it won't be as clean as your final product, but I'm very happy with it and it's improved several important things that you mentioned. So, thanks again :). I've included links back to the migrify project, of course.

In case it helps, here were a few tweaks I had to make - our test suites clearly have a few edge cases that the other doesn't have:

  • I tweaked PhpNodeFactory::createImportMethodCall() because the __DIR__ should only be added to the first arg of import(), not all args

  • In addAliasNode(), the $serviceValues inside the first if could be a string, which is the alias. And if it is, you need to strip off the @. This was causing $services->alias('from', service('to')) - the second argument should not be wrapped in service().

  • When handling "directory imports" (i.r. if (isset($serviceValues['resource'])) {, the exclude could be a string, not just an array. I also had to add some code so that you could chain other modifiers (e.g. ->tags()) after the load() - check out the services_load_resources_simple.php test case if you're interested - look for ->tags(), they were being left off.

  • In PhpNodeFactory::createParamValue(), the check for Array_ needs to be recursive (look inside the Array) to find other arrays and make them short. This was causing deep arrays to have things like ['foo', array('bar']] in them. I actually just went one level deeper, instead of recursing.

  • bind: I think I completely forgot support for this. It's added now, it's simple: it's a subset of arguments.

Cheers!

@ghost
Copy link
Author

ghost commented Jul 10, 2020

@TomasVotruba

Of course, motivation and go deeper is the best.
But there is already theorical aspects existing for helping us.

For this command, i wrote a lot of things as string. But yes, go deeper is on my todo list but it also depend of my future contributions :)

@TomasVotruba
Copy link

TomasVotruba commented Jul 10, 2020

@weaverryan Very nice job with integration, wow! 👏

I've just added a pile of changes: https://github.com/migrify/migrify/pull/50
I plan to get rid of spacing completelly and let coding standards handle it. It will make the whole deisgn much cleaner and lighter and won't reinvent wheel of php cs fixer/sniffers.

@TomasVotruba
Copy link

@weaverryan Btw, no need to credit with those annotation. I don't want to spam Symfony, never saw any point in these references of myself. I just connected bunch of ideas that are already out there, nothing special.

Reference in this PR as we discussus is enough.

@ghost
Copy link
Author

ghost commented Jul 10, 2020

If you have contributed, it's normal. Even if it wasn't credit regarding your components,
We should add your name and mail as an author of the new command.

@TomasVotruba
Copy link

That's my point. With Github it doesn't make sense anymore. You do git blame and see everything, everyone, everytime. If we should respect the rule, there would be over 50 @author annotations over each file :D

I just say I don't need it here 😉

@ghost
Copy link
Author

ghost commented Jul 11, 2020

There are few real contributors, giving your opinion or proposing a 10-line PR is usually easy. You didn't just give your opinion. Ryan's in charge of completing Command and the Merge. We'll see what he thinks about it :)

@weaverryan
Copy link
Member

Ha! You're on fire @TomasVotruba :)

I don't know if I'll bring over another round of changes or not. My guess based on migrify/migrify#51 is that you will have crushed the bugs that I had to fix when porting over, which would make the job much easier. The last significant change that I can think of is the cs. You mentioned:

I plan to get rid of spacing completelly and let coding standards handle it. It will make the whole deisgn much cleaner and lighter and won't reinvent wheel of php cs fixer/sniffers.

That makes sense to me too. I'll be interested to see how different your final CS is from our's and what changes would be needed to make them match again. Some things are 100% subjective, like whether or not we should have line breaks between $parameter->set() calls (e.g. https://github.com/migrify/migrify/pull/54/files#diff-96075827718f599e136fc063d29dda47)

Cheers!

@TomasVotruba
Copy link

This should be the last one to get rid of manually formating:
https://github.com/migrify/migrify/pull/54

I preserved most of the coding standards, except arrays (there are sniffs/fixer that handle it better and keep the formatting even after manual change).

I have added the breaks between set parameters back, now that's easy to handle it in the printer.

The main change was where the coding standard is applied. I do not handle it in transformation itself, but nicely sperated in the printer. It's like having a controller and template separated :).

@TomasVotruba
Copy link

Now I only plan to decouple the huge god class switch to standalone smaller classes with collector pattern. Just to tidy up the mess and lower the code complexity.

Class with 900+ lines is pain to work with. The split collectors will handle first-level keys.

The functionally remains the same. I think it's done (till first bug report). I plan to use it on my packages next week.

@TomasVotruba
Copy link

TomasVotruba commented Jul 12, 2020

@weaverryan FYI, I'm done for now with package. It's ready to be ported 👍
Let me know if you need to explain some parts.

@ghost
Copy link
Author

ghost commented Jul 13, 2020

I see that you haven't totally removed the use of Name as a "hack" to write lines.

In fact, I figured if I can't convert everything to Nodes, I'll keep this trick for most methods. In order not to disturb the eventual readers of the code.

But the new code is really beautiful, i love it!

@TomasVotruba
Copy link

TomasVotruba commented Jul 13, 2020

@archeoprog Not sure who you talk to without the @ handle :D but in case it was me...

I see that you haven't totally removed the use of Name as a "hack" to write lines.

I have actually. It should not be there at all... where is it?


(If it's for @weaverryan , ignore this message).

@TomasVotruba
Copy link

This how @migrify tool runs on @symplify configs:


@weaverryan I found a new problem that might be useful to you to know. The service() was added only in Symfony 5.1. Before the same function was called ref(). Just for better compatibility I use ref()

@ghost
Copy link
Author

ghost commented Jul 17, 2020

It was for Ryan :)

I found a new problem that might be useful to you to know. The service() was added only in Symfony 5.1. Before the same function was called ref(). Just for better compatibility I use ref()

That was my original intention but it seems that Ryan and the Symfony team prefers this feature to be available from
Symfony 5.1 only.

@TomasVotruba
Copy link

@archeoprog Ping, I think your account might have been hacked.

@ghost
Copy link
Author

ghost commented Aug 6, 2020

No, don't worry. I just want to impose my opinion as most of libraries have been doing for several weeks.

@weaverryan weaverryan closed this Nov 9, 2020
@symfony symfony deleted a comment Nov 9, 2020
@ghost
Copy link

ghost commented Nov 30, 2020

Giving up so much code for ideological reasons @weaverryan

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants