Skip to content
Snippets Groups Projects
  • View options
  • View options
  • Activity

    • All activity
    • Comments only
    • History only
    • Newest first
    • Oldest first
    • colemanw changed the description
    • colemanw changed title from Proposal: Create stub extension for civicrm core + all components to Proposal: Create stub extensions for civicrm core + all components
    • totten
      Owner

      If I'm reading correctly, you're suggesting that we keep the Components basically as-is but provide the facade of Extension-style management (so that they can participate in the dependency-graph). This gives some management benefits without the technical cost of reorganizing the code or changing the lifecycle of the MySQL data/entities. Very interesting.

      There are important differences between Components and Module-Extensions -- you might summarize the difference as "lightweight activation" vs "heavyweight activation". Compare:

      • For Components (lightweight activation - supported by large system):
        • Most artifacts (PHP classes, MySQL schema, default data, Smarty templates, APIv3 entities, HTTP routes) are always registered (regardless of whether the Component is active).
        • When activating/deactivating a Component, you do not require a script to setup system-level artifacts. You just change a lightweight setting.
        • The activation is tracked as a Setting (enable_components). This means that every Domain stores a separate list of Components. It also means that civicrm.settings.php can statically or dynamically compute the list of components.
      • For Module-Extensions (heavyweight activation - combing several smaller systems):
        • Most artifacts (PHP classes, MySQL schema, default data, Smarty templates, APIv3 entities, HTTP routes) are only registered if the extension is active.
        • When activating/deactivating a Module-Extension, you must run a script to setup system-level artifacts.
        • The activation is tracked via civicrm_extension. This is a system-wide table.

      Some questions and gut feelings:

      1. Extracting civigrant was hard because it was changing the lifecycle+activation for so many artifacts.
      2. Is it important to allow enable_components to vary per-domain or to be customized in civicrm.settings.php? I doubt it. But it's really a question for multisite users.
      3. If we want to treat Components as a special kind of Extension (for dependency-management purposes), then we should no longer support enable_components as a Setting.
        • I'm OK with some limited facade for 80%-compatibility, but functionality will be lost -- no per-domain and no $civicrm_setting. My brain would explode if two Domains could have different perspectives on the "extension dependency graph".
      4. Would the extension name civicrm convey "Common/Shared/Base/Core" or "Default/Overarching/Profile"? I think that's an important distinction. If they're blended into one name, then you get a cyclic dependency (civicrm depends on search_kit, and search_kit depends on civicrm ==> What?!) Based on the current pseudo-extension civicrm, I would use civicrm for "Common/Shared/Base/Core" and develop a separate construct for "Default/Overarching/Profile".
      5. There are a few ways to do stub extensions for each component. My gut says that a "Component-Extension" approach would give us the more wiggle-room for weird edge-cases, and a "Module-Extension" approach would encourage more unplanned/incremental/drive-by patches. But that's just a gut feeling.
        <!-- COMPONENT-EXTENSION: Components are a type of extension -->
        <extension key="civievent" type="component">
          <name>CiviEvent</name>
          <component>CiviEvent</component>
          <!-- Tip: CRM_Extension_Manager_Component will manage enable/disable. -->
        
        <!-- MODULE-EXTENSION: Components are empty module-extensions w/common lifecycle -->
        <extension key="civievent" type="module">
          <name>CiviEvent</name>
          <upgrader>CRM_Extension_Upgrader_Component</upgrader>
        
        <!-- MODULE-EXTENSION: Components are empty module-extensions w/common lifecycle -->
        <extension key="civievent" type="module">
          <name>CiviEvent</name>
          <mixins>
            <mixin>component@1.0.0</mixin>
          </mixin>
      Edited by totten
    • colemanw
      Owner

      Thanks @totten, you articulated the differences between components and extensions well. To your questions/comments:

      1. I think the lessons from CiviGrant were that
        1. The hardest part was migrating the sql installer and structural data (option groups, etc).
        2. Moving (most of) the php code was straightforward.
        3. But some of it wasn't (particularly code that expects to be tied to a component, like reports and advanced search panes).
        4. Therefore, a gradual code migration is best (I'm taking inspiration here from @eileen's approach of creating hidden extensions that you can drag-n-drop php classes into from core at a leisurely pace).
        5. The easiest part was creating a stub extension. That's why I think this is a good place to start, and still a good thing to do even if we never get around to migrating all components into self-contained extensions.
      2. Oof you blindsided me with the "per-domain" component activation. I had no idea that was a thing, but my hot take is that it's unnecessary. Given the "heavy" nature of components (they're really always there whether you enable them or not) I see no benefit to disabling them per-domain. IMO we just need to take it into account during the migration process and be sure to turn on a component-extension if the corresponding component was enabled on any domain.
      3. Agreed, the setting should be axed, the multi-domain functionality lost to the ages, and a facade could help the transition.
      4. I'm not sure I understand your point about cyclic dependencies. It would be redundant to declare any extension as dependent on civicrm (like declaring a Wordpress plugin as dependent on Wordpress). But I think making CiviCRM dependant on search_kit is useful (and part of the motivation for this proposal).
      5. As clever as it would be to add an extension type=component I worry that might be overcomplicating things (as that new type would need special support throughout the ExtensionManager system), and I also think it's steering us slightly in the wrong direction. I think the end goal should be to turn every component into a fully self-contained module extension. Sure, we might never fully achieve that goal, but it's IMO the right direction to aim for. And hey, we did it once and survived the ordeal (and even learned a few things along the way), so it's not a totally unrealistic goal.
      Edited by colemanw
    • cividesk
      Developer

      If I am reading correctly, you are suggesting creating a 'fake' civicrm core extension to indicate that SearchKit is a required dependency of core.

      It seems to me this is already implemented, but the other way around, as the info.xml for SearchKit states:

      <?xml version="1.0"?>
      <extension key="org.civicrm.search_kit" type="module">
        <file>search_kit</file>
        <name>SearchKit</name>
      [...]
        <tags>
          <tag>mgmt:required</tag>
        </tags>
      [...]

      This seems to fully address 'Motivation 1' as described above.

      'Motivation 2' seems to stem from the same need but related to an individual component rather than core. So you would need to express that an extension is required for a certain component of CiviCRM.

      Could we use the same paradigm, and add other mgmt tags that would indicate this (ex: mgmt:required_civievent). These extensions would then automatically be installed when the corresponding component is enabled.

    • colemanw
      Owner

      Thanks @cividesk you're correct about motivation 1. I've edited the issue description to reflect the fact that it's been solved and isn't relevant to this issue anymore. The second motivation was actually to be able to package Afforms and SearchKit displays within components, which I think is the best rationale for this proposal. I think what you're talking about would also be a benefit we'd get for free, which is that extensions would finally be able to declare dependencies on components, e.g. <requires><ext>civievent</ext></requires>. I've added that as motivation 3. Another reason for going down this path is that it will be the start of a slow transition away from components entirely (I've put that as motivation 4).

    • colemanw changed the description
    • colemanw
      Owner

      Here is a PR to add the extensions: https://github.com/civicrm/civicrm-core/pull/26036

    • A deleted user added has-pull-request label
    • totten mentioned in issue #3089 (closed)
      • jensschuppe

        First of all, moving more and more Core code into extensions seems a very good thing.

        Unfortunately, we just discovered this after a class naming collision occurred when updating to CiviCRM 5.63 with our extension systopia/de.systopia.campaign (Campaign Manager) installed.

        I guess we're way too late to the party for another round of finding unique names for Core component extensions ...

        Seems there will be much more "reserved" namespaces with Core moving functionality into extensions. Will there be documentation about that?

        Also, please consider making those additions public a bit more noisily, e. g. in a special dev-digest or by informing maintainers of things in Universe, which I think Campaign Manager has long been part of.

      • totten
        Owner

        Ooooh, the collision is on CRM_Campaign_ExtensionUtil because both extensions declare <civix><namespace>CRM/Campaign</namespace></civix>.

        One could soften the error a little bit by putting a guard around the class declaration, e.g.

        if (!class_exists('CRM_Campaign_ExtensionUtil')) { 
          class CRM_Campaign_ExtensionUtil { ... }
        }

        That would prevent hard-crashes. (I'd be +1 on updating the template and core-ext so that the problem-scenario is recoverable.) But realistically, one ext or the other needs to change the <namespace> and then search/replace the use statements.

        -use CRM_Campaign_ExtensionUtil as E;
        +use CRM_CampaignManager_ExtensionUtil as E;

        (I don't think there are any other clashes. In theory, CRM_Campaign_Upgrader could be a conflict-point, but I don't think it's likely since all the civi_* stubs are using a special <upgrader>CRM_Extension_Upgrader_Component</upgrader>.)

      • totten
        Owner

        I mean... if we really wanted drop-in compat with the published versions of de.systopia.campaign, then one could:

        • Update civix to support an XML flag to override this particular name:
          <civix>
            <utilClass>CRM_Campaign_OtherExtensionUtil</utilClass>
          </civix>
        • Add this flag to ext/civi_*/info.xml and regen ext/civi_*/*.php.
          • (AFAICS, the civi_* aren't using the E::* helpers... probably because they're stub-extensions...)
        Edited by totten
      • jensschuppe

        See https://github.com/systopia/de.systopia.campaign/pull/111 for a starting point on renaming our namespace.

      • Please register or sign in to reply
    • **** closed