-
-
Notifications
You must be signed in to change notification settings - Fork 825
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
Scan for classes based on the PHP interface (WorkflowMessageInterface, ExampleDataInterface) #23854
Conversation
(Standard links)
|
7da39b9
to
9936dce
Compare
This seems cool. What about |
7c24407
to
3ac5c0f
Compare
We discussed this a bit more the other day. Outcome: It should basically use a copy of I'm going to split out the hook/event auto-subscriber stuff as a separate PR because (1) this PR is already big enough and (2) the hook/event stuff needs some work to address a phpunit issue. |
@totten I think this might need to be against the rc as we actually need to get something into 5.51 to handle this functionality for import parsers to fix extensions to work with it |
In terms of the code - it looks pretty good - I am going to test it out against the rc in our WMF config later today |
OK, it should be easy for me to rebase to 5.51-rc. As it currently stands, I'm a bit more comfortable with the |
3ac5c0f
to
0bfd76b
Compare
…interface-php test. * The interface-php test registers an instance of WorkflowMessageInterface. * The list of WorkflowMessageInterface's is stored in the 'long' cache. * When you enable/disable an extension, it should clear WorkflowMessage list (and other things). * Before this patch, interface-php's `LifecycleTest` is inconsistent: it passes with `testLifecycleWithSubprocesses()` and fails with `testLifecycleWithLocalFunctions()`. * After this patch, interface-php's `LifecycleTest` is consistent: it passes with both `testLifecycleWithSubprocesses()` and `testLifecycleWithLocalFunctions()`. * The problem - while executing `testLifecycleWithLocalFunctions()`, it evidentally uses `Arraycache` as the backend -- and thus skips the flushes. However, I cannot fathom why one would want to clear-caches for SQL+memcache+redis but keep them for Arraycache.
hmm conflict.... |
0bfd76b
to
652a831
Compare
would it be a cleaner up-merge if we pulled in that commit? |
This works in my testing, allowing loading of templates from extensions with the mixin. Per above it might be cleaner to port the conflicting patches in - but I'm also OK merging as is |
By including civicrm/civicrm-core#23854 in the deploy we can then remove from a civi-hack-patch whereby we were putting these templates in core. Note that this should be no change on current master. With the latest Civi to go out it should pass tests without us needing https://gerrit.wikimedia.org/r/c/wikimedia/fundraising/crm/civicrm/+/801440 as these files will be loaded from the extension using the very latest upstream code Bug: T309250 Change-Id: Ie9094feaf20a5b0b5e5a40628756dc4c5ce94f43
Overview
Class-scanning allows one to write a class and have it recognized automatically (without any other explicit declarations). There are some existing class-scanners in core; this branch expands that. It is an alternative to #23848. It specifically scans for PHP classes based on the PHP interfaces.
(There should be at least 1 test-failure in the current draft. So far, I have been focused on running the integration-tests rather than
r-run
. Posting for a more complete test-run.)Before
There is some precedent for class/interface-based scanning:
civicrm-core
for implementations ofWorkflowMessageInterface
.civicrm-core
for implementations ofExampleDataInterface
.HookInterface
or Symfony'sEventDispatcherInterface
.However, each of these has a different scanner with slightly different quirks.
After
The PR provides a generic scanning mechanism. Additionally, it updates existing code to use the generic scanner for specific interfaces (
WorkflowMessageInterface
,ExampleDataInterface
).Technical Details: Generic mechanism
The helper,
Civi\Core\ClassScanner::get(...)
, finds matching classes.Each extension can define classes that implement the interface, eg
The scanner requires a general opt-in (per extension). It should be safe for most extensions to opt-in, as it is designed to match existing code-conventions. However, the scanner requirements are slightly stricter. (For example, all PHP files in
./CRM
or./Civi
must define eponymous PHP classes. If you have any script-files in those folders, they could be mis-fired by the scanner.) The opt-in requirement ensures that existing extensions will continue to work.The typical opt-in should go through
info.xml
:Alternatively, as a last resort (if you need to support an uncommon file-layout), there is an experimental hook:
Technical Details: Specific interfaces
WorkflowMessageInterface
(in addition to scanning the previous core folders).ExampleDataInterface
(in addition to scanning the previous core folders).It scans the extensions for classes that implement(*This was included in the original draft. It generally works in practice, but it needs work to address an edge-case in phpunit testing, and it should be updated to support Symfony-style subscribers.)HookInterface
(in addition to the previous BAO).FAQ
Q: What about Doctrine annotations? What about PHP attributes? What about YAML files? Should we register components with these?
They all have nice properties. But they all create dependency-hell. PHP interfaces are simple, inspect-able, and compatible with all supported environments.
Q: What are the performance characteristics? How will adapt to large source-trees?
There are a couple expenses to look out for: the cost of walking the source-tree, and the cumulative size of the class-list. There are some guard-rails that should keep each of these moderate:
scan-classes@1.0
. It does not scan external PHP libraries or CMS plugins../CRM
and./Civi
). It ignores other folders (like./vendor
,./templates
, or./css
).CRM
andCivi
namespaces. (Other interfaces are ignored.)WorkflowMessageInterface
with a list of matching classes. When enumeratingWorkflowMessageInterface
, it will load this list. It doesn't load the full class-list.)There are limits, of course. If you define an interface that is both very broad (eg used in a huge number of classes) and very active (eg used in most page-loads), then the cumulative effect would a huge number of class-loads during a most page-loads. So... don't do that.