1. 12 Jul, 2019 1 commit
  2. 11 Jul, 2019 1 commit
  3. 21 Jun, 2019 1 commit
  4. 18 Jun, 2019 1 commit
  5. 15 Jun, 2019 1 commit
    • totten's avatar
      CRM-18792 - CRM_Core_Theme - Add helper for loading CSS files from themes · d89d2545
      totten authored
      CRM-18792 - CRM_Core_Resources - Load civicrm.css through theme system
      
      CRM-18792 - Rename `CRM_Core_Theme` to `\Civi\Core\Theme`
      
      CRM-18792 - Civi\Core\Theme - Remove statics
      
      WIP
      
      CRM_Core_Resources::addCoreStyles - Revert change
      
      CRM-18792 - addStyleFile - Always pass through to theme. Support fallback.
      
      Rename `Civi\Core\Theme` to `Civi\Core\Themes`
      
      The class manages a list of themes -- not just a single theme.
      
      CRM-18792 - Add org.civicrm.demotheme
      
      CRM-18792 - Add uncommitted test files (`Civi\Core\Themes`)
      
      CRM-18792 - Fix regression in CRM_Core_ResourceTest
      
      CRM-18792 - Theme naming - Use prefix '_' for hidden themes
      
      This cleans up a few things:
      
       * Previously, there was a special case for using FALLBACK in `search_order`.
       * If you're creating a multitheme extension, you may want to define a base theme
         (which is extended by the others). Previously, you were required to show this
         base theme as a user-selectable option. Now, it can be hidden.
       * There was a bug where `resolveUrl()` would sometimes call the wrong callback.
         (It used resolver for `$active` instead of `$themeKey`.)
      
      CRM-18792 - Themes - File overrides and excludes should use same naming
      
      Previously, when using `addStyleFile($cssExt,$css$file)`, the file overrides
      and exlcudes would combine them differently e.g.
      
       * For `addStyleFile('civicrm','css/bootstrap.css')`
         * Override `css/bootstrap.css`
         * Exclude `civicrm:css/bootstrap.css`
       * For `('org.foo.bar','css/bang.css')`
         * Override `org.foo.bar-css/bang.css`
         * Exclude `org.foo.bar:css/bang.css`
      
      Now, they use the same notation:
      
       * For `addStyleFile('civicrm','css/bootstrap.css')`
         * Override `css/bootstrap.css`
         * Exclude `css/bootstrap.css`
       * For `('org.foo.bar','css/bang.css')`
         * Override `org.foo.bar-css/bang.css`
         * Exclude `org.foo.bar-css/bang.css`
      
      "Display Preferences" - Add the `theme_backend` and `theme_frontend` settings
      
      hook_civicrm_activeTheme - Allow extensions and CMS modules to choose active theme
      
      CRM_Utils_Hook::themes() - Tweak docblock
      
      Civi\Core\Themes - Move cache from `short` to `long`
      
      Remove tools/extensions/org.civicrm.demotheme
      
      Fix merge ahem errors
      d89d2545
  6. 26 Apr, 2019 2 commits
  7. 09 Apr, 2019 1 commit
    • totten's avatar
      (REF) CRM_Core_Resources - Move hook declaration from addCoreResources() to Container.php · f22fb451
      totten authored
      tldr: It's easier to declare `hook_civicrm_buildAsset` listeners at a high-level.
      
      Asset building can use two modes -- production mode writes a static file to
      disk when it's being reference.  Debug mode just generates a URL for a
      web-service (which in turn dynamically renders the content in a separate
      page-view).
      
      If the only mode were production mode, then the code would be on pretty
      solid ground.  We could even simplify things a lot by changing the
      AssetBuilder contract to replace the hooks with callbacks, as in:
      
      ```php
      Civi::service('asset_builder')->getUrl('crm-menu.css', function() {
        return '...the css code...';
      });
      ```
      
      Why have a hook?  Because hooks are generally context-free and
      always-available.  If we use debug-mode (or if we add a feature to warm-up
      the caches during deployment), then we'll want to fire that hook from a
      different context (e.g.  web-service or CLI), and the hook-listener needs to
      be available in those other contexts.
      
      It would be nice if we could declare hooks generally without needing to edit
      the `Container.php` mega-file (e.g.  maybe some kind of annotation).  But,
      for the moment, I think this is the best spot that we have in `civicrm-core`
      for ensuring that hook listeners are fully/consistently registered.
      f22fb451
  8. 06 Apr, 2019 1 commit
  9. 29 Mar, 2019 1 commit
  10. 28 Nov, 2018 1 commit
    • totten's avatar
      (#217) PrevNext - More conservative transition (5.7=>5.8=>5.9) · f76de01c
      totten authored
      This revision sets up more conservative transition process for adopting PrevNext drivers.
      
      Before
      ------
      
      * 5.7.x - Hard-coded to SQL driver.
      * 5.8.x - Allow setting to pick driver. If left as `default`, then choose best-available (based on configured services).
      
      After
      ------
      
      * 5.7.x - Hard-coded to SQL driver.
      * 5.8.x - Allow setting to pick driver. If left as `default`, then use SQL driver.
      * 5.9.x - Allow setting to pick driver. If left as `default`, then choose best-available (based on configured services).
      
      This essentially mitigates the risk that bugs in the new Redis driver cause regreessions for sites already running Redis.
      f76de01c
  11. 27 Nov, 2018 2 commits
  12. 18 Oct, 2018 1 commit
  13. 28 Sep, 2018 1 commit
    • totten's avatar
      Register "short" and "long" cache services · 90cdaa0e
      totten authored
      Overview
      --------
      
      This is an improvement for developer-experience when working with caches.
      It reduces the amount of boilerplate required for core-code or
      extension-code in a typical caching use-case.
      
      Before
      ------
      
      * To use a short-lived/latency-optimized cache (e.g. Redis or PHP array),
        you can work with the default cache instance (`Civi::cache('default')`.
      * To use a long-lived/durability-optimized cache (e.g. Redis or SQL), there is no
        simple way or code. You must [register a custom cache service](https://docs.civicrm.org/dev/en/latest/framework/cache/#example-named-service).
      
      After
      -----
      
      * All the above remains true. Additionally, you can request the `short` or `long` cache service.
      * To use a short-lived/latency-optimized cache, you can use `Civi::cache('short')`. (`short` and `default` are synonmyms.)
      * To use a long-lived/durability-optimized cache, you can use use `Civi::cache('long')`.
      
      Comments
      --------
      
      * After this is approved, we should update the [dev docs for caching](https://docs.civicrm.org/dev/en/latest/framework/cache/).
      * There's a bike-sheddy argument about the naming. I'd be willing to rename if there was a strong reason, but I don't really think
        there is a strong reason. This naming convention provides a simple dichotomy of `short` vs `long`.
      90cdaa0e
  14. 24 Jul, 2018 1 commit
  15. 20 Jul, 2018 1 commit
  16. 05 Jul, 2018 1 commit
    • totten's avatar
      Change default for CIVICRM_CONTAINER_CACHE to simplify admin/developer experience · 5497e016
      totten authored
      In discussion of cache-related PRs for Civi 5.3, there were a few
      reports/issues from developers observing `ServiceNotFoundException`.  This
      is because there's not much awareness about how service-definitions are
      cached.  It shouldn't be a significant issue for production systems running
      vanilla code, but for admins and developers (who juggle patches/branches),
      it can cause confusion/support-issues/false-failures.  This PR aims to
      reduce those.
      
      (This is a follow-up/substitute for #12401.)
      
      Before
      ------
      * The default value of `CIVICRM_CONTAINER_CACHE` is `always`.
      
      After
      -----
      * The default value of `CIVICRM_CONTAINER_CACHE` is `auto`.
      
      Technical Details
      -----------------
      The Symfony container essentially stores a list of "services".  In some
      Symfony-based apps, building the list of services can be time consuming, so
      it's common to cache this.
      
      In Civi, this cache physically appears as
      `files/civicrm/templates_c/CachedCiviContainer.*.php`.  The constant
      `CIVICRM_CONTAINER_CACHE` determines how Civi manages the cache.  There are
      three available policies:
      
      * `never`: This means we never use the cache.  You never have to worry about
        staleness.  But it means we have to fire `hook_civicrm_container` on every
        page-request, and we go through any container-compilation tasks.
        This would have the fewest support-issues for devs and advanced admins.
      
      * `always`: This means we always use whatever is in the cache.  It never
        (automatically) rebuilds the cache or checks freshness...  if you make
        change, then you must flush the cache explicitly.  This should be the
        fastest in production.
      
      * `auto`: This means we typically use the cache (avoiding
        hooks/recompilation), but it has to `stat()` a half-dozen files to check
        the modification time.  (To wit: if the timestamp on
        `Civi/Core/Container.php` changes, then we discard the cache.)
      
      Since performance is a consideration, I did some light benchmarking on my
      laptop (fetching a basic public Civi page 100 times across 3 threads).
      
      https://gist.github.com/totten/ec4bffd723afb7967aec56a3040b9ca3
      
      In these results, the `never` policy appears to be ~15-20ms slower than
      `auto` or `always`. `auto` is only ~2ms slower than `always`.
      
      The other consideration is accuracy -- `auto` will usually re-compile if you
      make a change, but there are some edge-cases where you must still flush
      manually.  (In particular -- when you first implement
      `hook_civicrm_container` in a new extension, it might not be aware of the
      new extension.  And extensions need to call `$container->addResource()`.)
      
      However, overall, `auto` is a pretty good compromise that's almost as fast
      you can get and works out-of-the-box for many dev/admin scenarios.
      5497e016
  17. 02 Jul, 2018 1 commit
    • totten's avatar
      (#174) Forms/Sessions - Store state via Civi::cache('session') · 19707a63
      totten authored
      Overview
      ----------------------------------------
      
      When using forms based on CiviQuickForm (specifically `CRM_Core_Controller`), `CRM_Core_Session`
      stores form-state via `CRM_Core_BAO_Cache::storeSessionToCache` and `::restoreSessionFromCache`,
      which in turn calls `CRM_Core_BAO_Cache::setItem()` and `::getItem()`.
      
      However, using `CRM_Core_BAO_Cache::setItem()` and `::getItem()` means that all session state
      **must** be written to MySQL.  For #174, we seek the **option** to store via
      Redis/Memcache.
      
      Before
      ----------------------------------------
      
      * (a) Form/session state is always stored via `CRM_Core_BAO_Cache::setItem()` and `civicrm_cache` table.
      * (b) To ensure that old sessions are periodically purged, there is special purpose logic that accesses `civicrm_cache`
        (roughly `delete where group_name=Sessions and  created_date < now()-ttl`).
      * (c) On Memcache/Redis-enabled systems, the cache server functions as an extra tier. The DB provides canonical storage for form/session state.
      
      After
      ----------------------------------------
      
      * (a) Form/session state is stored via `CRM_Utils_CacheInterface`.
          * On a typical server, this defaults to `CRM_Utils_Cache_SqlGroup` and `civicrm_cache` table.
      * (b) To ensure that old sessions are periodically purged, the call to `CRM_Utils_CacheInterface::set()` specifies a TTL.
          * It is the responsibility of the cache driver to handle TTLs. With #12360, TTL's are supported in `ArrayCache`, `SqlGroup`, and `Redis`.
      * (c) On Memcache/Redis-enabled systems, the cache server provides canonical storage for form/session state.
      19707a63
  18. 18 Jun, 2018 2 commits
  19. 22 Sep, 2017 1 commit
  20. 20 Sep, 2017 1 commit
    • totten's avatar
      CRM-21179 - visual-bundle.js - Generate custom build of dc.js · 64fe847e
      totten authored
      This defines an asset named `visual-bundle.js`.  It creates a custom build
      of `dc.js` + `crossfilter.js` + `d3.js` which loads all the services into
      the namespace `CRM.visual.{foo}`, which allows it to coexist with other
      copies of the library.
      64fe847e
  21. 10 Sep, 2017 1 commit
  22. 06 Sep, 2017 2 commits
  23. 03 Aug, 2017 3 commits
  24. 20 Jun, 2017 1 commit
    • bgm's avatar
      CRM-16395: Installation with localized default settings (4) (#10518) · ece6501c
      bgm authored
      CRM-16395: Installation with localized default settings
      
      This makes it possible to have a file in "civicrm/l10n/xx_YY/settings.default.json" with default settings that correspond to the locale during installation (ex: default country, currency, date formats, etc).
      ece6501c
  25. 17 Jun, 2017 2 commits
  26. 14 Apr, 2017 5 commits
  27. 11 Apr, 2017 1 commit
    • totten's avatar
      CRM-19813 - Only dispatch through EventDispatcher after booting · 4d8e83b6
      totten authored
      After merging #9949, some screens (like the contact-result list or "View
      Contact") reported warnings like:
      
      ```
      Notice: Undefined index: in CRM_Core_BAO_Country::countryLimit() (line 90 of /home/foo/buildkit/build/dmaster/sites/all/modules/civicrm/CRM/Core/BAO/Country.php).
      Notice: Undefined index: in CRM_Core_BAO_Country::provinceLimit() (line 62 of /home/foo/buildkit/build/dmaster/sites/all/modules/civicrm/CRM/Core/BAO/Country.php).
      ```
      
      Bisecting the git history revealed that it stemmed from switching
      `hook_civicrm_entityTypes` to go through EventDispatcher.
      
      https://github.com/civicrm/civicrm-core/pull/9949/commits/fb1d9ad2f5116245ba3488a26f8e0b065f328006#diff-8869a8f3c6318eb0580ce2aa04b713bfL1835
      
      This hook is apparently similar to `hook_civicrm_container` in that both
      fires pre-boot.  If we attempt to dispatch it through the container in a
      pre-boot environment, something initializes incorrectly.
      
      This change proposes a general rule:
       * If you fire a hook before the container or EventDispatcher is available...
       * Then don't try to use the container or EventDispatcher.
      4d8e83b6
  28. 30 Mar, 2017 2 commits
    • totten's avatar
      CRM-19813 - CRM_Utils_Hook - Cleanup existing dual-emit events · c73e3098
      totten authored
      There are a handful of events which have been dual-emitted by explicitly
      calling both the dispatcher and Hook::invoke().  The dispatcher now calls
      Hook::invoke automatically (if applicable), so we can omit that.
      c73e3098
    • totten's avatar
      CRM-19813 - GenericHookEvent - Bridge between Symfony Events and hooks · 762dc04d
      totten authored
      The GenericHookEvent is used to expose all traditional hooks to the Symfony
      EventDispatcher.
      
      The traditional notation for a hook is based on a function signature:
      
        function hook_civicrm_foo($bar, &$whiz, &$bang);
      
      Symfony Events are based on a class with properties and methods.  This
      requires some kind of mapping.
      
      Symfony Events has two conventions which might be used to support that
      mapping.  One might implement event classes for every hook, or one might use
      the `GenericEvent`.  This design-decision comes with a basic trade-off
      between size (total #files, #classes, #SLOC) and IDE assistance
      (docs/autocomplete):
      
       * `GenericEvent` has smaller size and less boiler-plate, but it also
         provides little IDE assistance.
       * Custom event classes provide more IDE assistance, but they also
         inflate the size (with lots of boilerplate).
      
      This patch implements `GenericHookEvent`, which is conceptually similar to
      `GenericEvent`, but it has a few modifications:
      
       * The `__get()` function returns references, which makes it easier to
         alter data.
       * The `getHookValues()` function returns an ordered list of hook arguments.
      
      The approach of `GenericEvent` / `GenericHookEvent` seems like a reasonable
      balance -- it starts out with little boilerplate, but we can incrementally
      introduce subclasses.  The subclasses can:
      
       * Use docblocks for IDE support
       * Use declared properties for IDE support (though you may need to customize
         the constructor, etal).
       * Add semantic/businessy functions.
       * Override the `__get()` / `__set()` functions to be provide
         different getter/setter behavior.
      762dc04d