From e7e176259f89af7fdda0a2940171d313f98f678f Mon Sep 17 00:00:00 2001 From: Tim Otten Date: Mon, 1 Jul 2019 16:58:58 -0700 Subject: [PATCH] Migrate CivicrmHelper::parseUrl() to CRM_Utils_System_Drupal8::parseUrl(). Resolve dep order. This fixes a bug which manifests during CLI installation. It corrects a dependency issue by migrating an install-critical function from `civicrm-drupal-8` to `civicrm-core`. Before ------ Consider this sequence from `cv core:install` docs. (For simplicity/legibility, the example is minimalist.) ``` $ cv core:install --cms-base-url=http://example.com/ $ drush -y en civicrm ``` The first step crashes. Partial console output: ``` [bknix-dfl:~/bknix/build/d8prj-re] cv core:install -f --cms-base-url=http://d8prj-re.bknix:8001 -m 'settings.userFrameworkResourceURL=[cms.root]/libraries/civicrm' -v Found code for civicrm-core in /Users/myuser/bknix/build/d8prj-re/vendor/civicrm/civicrm-core Found code for civicrm-setup in /Users/myuser/bknix/build/d8prj-re/vendor/civicrm/civicrm-setup Found existing civicrm.settings.php in /Users/myuser/bknix/build/d8prj-re/web/sites/default Removing civicrm.settings.php from /Users/myuser/bknix/build/d8prj-re/web/sites/default Creating civicrm.settings.php in /Users/myuser/bknix/build/d8prj-re/web/sites/default Found existing civicrm_* database tables in d8prjrecms_rwlck Removing civicrm_* database tables in d8prjrecms_rwlck Creating civicrm_* database tables in d8prjrecms_rwlck [Symfony\Component\Debug\Exception\FatalThrowableError] Class 'Drupal\civicrm\CivicrmHelper' not found Exception trace: () at /Users/myuser/bknix/build/d8prj-re/vendor/civicrm/civicrm-core/CRM/Utils/System/Drupal8.php:303 CRM_Utils_System_Drupal8->url() at /Users/myuser/bknix/build/d8prj-re/vendor/civicrm/civicrm-core/CRM/Utils/System.php:295 CRM_Utils_System::url() at /Users/myuser/bknix/build/d8prj-re/vendor/civicrm/civicrm-core/CRM/Core/Menu.php:581 CRM_Core_Menu::buildBreadcrumb() at /Users/myuser/bknix/build/d8prj-re/vendor/civicrm/civicrm-core/CRM/Core/Menu.php:281 CRM_Core_Menu::build() at /Users/myuser/bknix/build/d8prj-re/vendor/civicrm/civicrm-core/CRM/Core/Menu.php:308 CRM_Core_Menu::store() at /Users/myuser/bknix/build/d8prj-re/vendor/civicrm/civicrm-core/CRM/Core/Invoke.php:373 CRM_Core_Invoke::rebuildMenuAndCaches() at /Users/myuser/bknix/build/d8prj-re/vendor/civicrm/civicrm-core/api/v3/System.php:49 civicrm_api3_system_flush() at /Users/myuser/bknix/build/d8prj-re/vendor/civicrm/civicrm-core/Civi/API/Provider/MagicFunctionProvider.php:101 Civi\API\Provider\MagicFunctionProvider->invoke() at /Users/myuser/bknix/build/d8prj-re/vendor/civicrm/civicrm-core/Civi/API/Kernel.php:168 Civi\API\Kernel->runRequest() at /Users/myuser/bknix/build/d8prj-re/vendor/civicrm/civicrm-core/Civi/API/Kernel.php:99 Civi\API\Kernel->runSafe() at /Users/myuser/bknix/build/d8prj-re/vendor/civicrm/civicrm-core/api/api.php:23 civicrm_api() at /Users/myuser/bknix/build/d8prj-re/vendor/civicrm/civicrm-core/Civi/Core/DatabaseInitializer.php:50 Civi\Core\DatabaseInitializer::initialize() at /Users/myuser/bknix/build/d8prj-re/vendor/symfony/event-dispatcher/EventDispatcher.php:212 Symfony\Component\EventDispatcher\EventDispatcher->doDispatch() at /Users/myuser/bknix/build/d8prj-re/vendor/symfony/event-dispatcher/EventDispatcher.php:44 Symfony\Component\EventDispatcher\EventDispatcher->dispatch() at /Users/myuser/bknix/build/d8prj-re/vendor/civicrm/civicrm-core/Civi/Core/CiviEventDispatcher.php:47 Civi\Core\CiviEventDispatcher->dispatch() at /Users/myuser/bknix/build/d8prj-re/vendor/civicrm/civicrm-core/CRM/Core/Config.php:572 CRM_Core_Config->handleFirstRun() at /Users/myuser/bknix/build/d8prj-re/vendor/civicrm/civicrm-core/CRM/Core/Config.php:128 CRM_Core_Config::singleton() at /Users/myuser/bknix/build/d8prj-re/vendor/civicrm/civicrm-core/packages/DB/DataObject.php:2304 DB_DataObject->_connect() at /Users/myuser/bknix/build/d8prj-re/vendor/civicrm/civicrm-core/CRM/Core/DAO.php:474 CRM_Core_DAO->initialize() at /Users/myuser/bknix/build/d8prj-re/vendor/civicrm/civicrm-core/CRM/Core/DAO.php:126 CRM_Core_DAO->__construct() at /Users/myuser/bknix/build/d8prj-re/vendor/civicrm/civicrm-core/CRM/Core/DAO.php:1488 CRM_Core_DAO::singleValueQuery() at /Users/myuser/bknix/build/d8prj-re/vendor/civicrm/civicrm-core/CRM/Utils/SQL.php:67 CRM_Utils_SQL::getSqlModes() at /Users/myuser/bknix/build/d8prj-re/vendor/civicrm/civicrm-core/CRM/Core/DAO.php:168 CRM_Core_DAO::init() at /Users/myuser/bknix/build/d8prj-re/vendor/civicrm/civicrm-core/Civi/Core/Container.php:494 Civi\Core\Container::boot() at /Users/myuser/bknix/build/d8prj-re/vendor/civicrm/civicrm-setup/plugins/installDatabase/InstallSchema.civi-setup.php:94 InstallSchemaPlugin->installDatabase() at /Users/myuser/bknix/build/d8prj-re/vendor/symfony/event-dispatcher/EventDispatcher.php:212 ... ``` In English: towards the end of the `core:install`, it boots up Civi for the first time, which causes a general system flush, a menu rebuild, and some calls to `url()` and `CivirmHelper`. But the `civicrm-drupal-8` module isn't online yet, so `CivicrmHelper` isn't isn't available yet. After ----- That crash does not happen. The install routine is able to run with or without `civicrm-drupal-8` active. Technical Details ----------------- This is one of two changes. (The first adds the function to `civicrm-core`; the second removes it from `civicrm-drupal-8`.) You might wonder: Will this be a flip-floppy problem? Perhaps there's some dataflow through `drupal/core`and `civicrm-drupal-8/src/Routing/Routes.php` where the new call to `CRM_Core_Config::singleton()->userSystem->parseUrl()` cannot be processed because `civicrm-core` isn't available yet? This hypothetical can be dispensed by reading `src/Routing/Routes.php` (either old code or new code). The function already begins with `\Drupal::service('civicrm')->initialize();`, which boots all the core Civi services (like `CRM_Core_Config::singleton()->userSystem`). The system is already online before the relevant code is called. --- CRM/Utils/System/Drupal8.php | 46 +++++++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/CRM/Utils/System/Drupal8.php b/CRM/Utils/System/Drupal8.php index 76b9580125..2d305e9e54 100644 --- a/CRM/Utils/System/Drupal8.php +++ b/CRM/Utils/System/Drupal8.php @@ -303,7 +303,7 @@ class CRM_Utils_System_Drupal8 extends CRM_Utils_System_DrupalBase { $config = CRM_Core_Config::singleton(); $base = $absolute ? $config->userFrameworkBaseURL : 'internal:/'; - $url = \Drupal\civicrm\CivicrmHelper::parseURL("{$path}?{$query}"); + $url = $this->parseURL("{$path}?{$query}"); // Not all links that CiviCRM generates are Drupal routes, so we use the weaker ::fromUri method. try { @@ -668,6 +668,50 @@ class CRM_Utils_System_Drupal8 extends CRM_Utils_System_DrupalBase { return \Drupal::languageManager()->getCurrentLanguage()->getId(); } + /** + * Helper function to extract path, query and route name from Civicrm URLs. + * + * For example, 'civicrm/contact/view?reset=1&cid=66' will be returned as: + * + * @code + * array( + * 'path' => 'civicrm/contact/view', + * 'route' => 'civicrm.civicrm_contact_view', + * 'query' => array('reset' => '1', 'cid' => '66'), + * ); + * @endcode + * + * @param string $url + * The url to parse. + * + * @return string[] + * The parsed url parts, containing 'path', 'route' and 'query'. + */ + public function parseUrl($url) { + $processed = ['path' => '', 'route_name' => '', 'query' => []]; + + // Remove leading '/' if it exists. + $url = ltrim($url, '/'); + + // Separate out the url into its path and query components. + $url = parse_url($url); + if (empty($url['path'])) { + return $processed; + } + $processed['path'] = $url['path']; + + // Create a route name by replacing the forward slashes in the path with + // underscores, civicrm/contact/search => civicrm.civicrm_contact_search. + $processed['route_name'] = 'civicrm.' . implode('_', explode('/', $url['path'])); + + // Turn the query string (if it exists) into an associative array. + if (!empty($url['query'])) { + parse_str($url['query'], $processed['query']); + } + + return $processed; + } + /** * Append Drupal8 js to coreResourcesList. * -- 2.25.1