-
-
Notifications
You must be signed in to change notification settings - Fork 817
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
ManagedEntities - Allow targeted reconciliation. Add hook parameter. Simplify logic. #22959
Conversation
(Standard links)
|
1c87c15
to
21c278e
Compare
@@ -70,8 +72,7 @@ protected function writeRecord($item) { | |||
$isChanged('is_dashlet') || | |||
(!empty($meta['is_dashlet']) && $isChanged('title')) | |||
) { | |||
// FIXME: more targeted reconciliation | |||
\CRM_Core_ManagedEntities::singleton()->reconcile(); | |||
\CRM_Core_ManagedEntities::singleton()->reconcile(E::LONG_NAME); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@totten this FIXME has been staring me down for a long time. Finally fixed!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Woot! That should help performance when editing afforms!
fb664e0
to
6dacf3a
Compare
@totten the prerequisite PR has been merged and I've rebased this one, so it's just the one commit now. |
jenkins, test this please |
So I did a reading on the code before-patch and after-patch, and I agree this looks better. Just to verbalize... it appears to me (and this is post-hoc rationalization) that
IMHO, the planner/todo-list approach is better than the 3-stage approach. eg I like that the planner is more function-y -- you get more ways to test+inspect the todo-list without modifying the DB. It may also be more amenable to re-sorting based on a dependency-graph. This PR definitely makes it easier to read. On There is a fair amount of test-coverage in On the general conceptual level, I'm inclined toward merging. On a more concrete QA level, there are also several smaller places where it twiddles types+names (eg DAO=>array) which I haven't really looked at. (I'm optimistic because those are mostly internal and because there's test-coverage. But I didn't have the general picture when I first skimmed them, and I should probably give them another read with this better sense of context.) |
@totten thanks for taking the time to get your head round this, I think you summed it up well, and I think you're right the before state of the class is transitional, and this PR basically completes the transition. |
I also agree with the analysis - I think the intent of the transitional refactor was a step towards the plan & then do approach |
… module Reconciling a single module (e.g. Afform) is more efficient. Further refactoring of ManagedEntities for code simplification and efficiency. Instead of fetching Managed records 3 times (for enabled, disabled and missing modules), now they are fetched only once and sorted into the correct category.
6dacf3a
to
a7db555
Compare
foreach ($declarations as $name => &$declare) { | ||
if (!array_key_exists('name', $declare)) { | ||
$declare['name'] = $name; | ||
protected function setDeclarations(array $declarations, $moduleName = NULL) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Non-blocker/General observation) There's a tension around the lifecycle of $declarations
, which has behavioral and stylistic dimensions:
- (Behaviorally) Are
$declarations
ephemeral things (loaded+destroyed each time you useManagedEntities
) or are they retained for a while (re-used in multiple calls toManagedEntities
)? How long should they live in memory? - (Stylistically) Do we prefer to use more stateless design (eg
cleanupDeclarations(array):array
) or more stateful design (egsetDeclarations(array,string): void
)?
A couple thoughtlets that stand out to me:
- There are two
public
operations relying on this data (reconcile()
+revert()
). Both of them rebuild the$declarations
before doing their work. This behavior seems reasonable to me (though maybe that belief merits inspection). In any case, it appears consistent before+after patch. - AFAICS, the
$moduleName
is never actually passed in tosetDeclarations()
. I was concerned it would mean some subtle corruption of$this->declarations
. But it doesn't matter - b/creconcile()
+revert()
will rebuild$this->declarations
whenever they're called. - It seems to me that (following the other changes) there's now less need to store data in
$this
. In the older design, it retained$this->declarations
so that eachreconcileFooModules()
could do a pass through the list -- in the newer design, the planner does a single pass over$declarations
.
Anyway, this comment has as many questions as answers, and these don't have to be resolved now. The relevant methods are protected function
s in a de-facto final class
, so we can continue to revise based on other analysis or discussion.
@totten I've rebased this PR to include your suggestion about variable/function names, made |
@colemanw OK, cool. I'm flagging it "merge ready". I should give it some |
Did some light
Promoting to "merge on pass". |
Thanks @totten. Here's a followup because I realized that |
if (!array_key_exists('name', $declare)) { | ||
$declare['name'] = $name; | ||
protected function setDeclarations(array $declarations, $moduleName = NULL) { | ||
$this->declarations = []; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@totten I have been pushing in the direction of ephemeral. A few versions ago I hit some bugs caused by them hanging around from one reconcile to the next and they were solved by the addition of this line.
I would be happy to push it further in that direction and make them local variables passed between functions instead of class variables.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I assume that's a reference to #23243... Commented over there. Pushed up a little more test-coverage here. Expanded description to highlight changes to two interfaces ( Still |
This is a follow-up/correction for civicrm#22959 (circa 5.50.alpha1; specifically fdc67a7). The prior revision had updated the behavior of `mgd-php`, so it should have also updated the version-number.
Overview
Makes the ManagedEntity reconcile process more efficient and the code easier to read & understand.
Makes saving or reverting an Afform faster by only reconciling managed entities from that one module.
Before
CRM_Core_ManagedEntities->reconcile()
reconciles entities in all modules.hook_managed(&$entities)
enumerates entities in all modules.After
CRM_Core_ManagedEntities->reconcile($modules = NULL)
can optionally be limited to specific modules.hook_managed(&$entities, $modules = NULL)
can optionally limit lookups to specific modules.All core extensions now support
hook_managed
with the$modules
filter. Existing implementations ofhook_managed
are not required to abide by$modules
, but doing so will improve performance. Example:Technical Details
The
CRM_Core_ManagedEntities
class has been around for a while and gathered a bit of cruft in that time.I found the code quite difficult to read and understand, as it was fetching and re-fetching records, sorting them and dividing them by module but ultimately discarding those divisions. Some records were getting processed twice. Here's what I did:
reconcile()
function now accepts a$moduleName
param that will reconcile a single module, which fixes a fixme in Afform.