Skip to content
This repository has been archived by the owner on Aug 1, 2021. It is now read-only.

Simplify SQL and translation pipeline changes #9

Merged
merged 22 commits into from
May 15, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
d2672ca
Simplify SQL and translation pipeline changes
monishdeb Feb 13, 2018
e85d19e
Add CRM_Core_CodeGen_Schema code to InstallSchema.civi-setup.php
monishdeb Feb 15, 2018
1b022b1
use SQL content rather then filename to populate mysql data
monishdeb Feb 15, 2018
f347d6d
AvailableTables - Quiet
totten Feb 15, 2018
eff38f6
InstallSchema - Fix path reference. Display more fine-grained messages.
totten Feb 15, 2018
552d0aa
FileUtil - Fix createTempDir()
totten Feb 15, 2018
e75c2bc
Template.php - Multiple fixes
totten Feb 15, 2018
bf76ef6
DbUtil - Fix misnamed param. Throw error when running unsupported mode.
totten Feb 15, 2018
463b730
SmartyUtil - Ensure that {ts}/ts() is available
totten Feb 16, 2018
fa0824b
UninstallSettingsFile - Tweak error message
totten Feb 16, 2018
7bd6d16
DbUtil - Remove extra newlines from log
totten Feb 16, 2018
b5734ec
Combine InstallSchema, AvailableTables
totten Feb 16, 2018
f64d492
InstallSchema - Convert from "listener" (closure) to "subscriber" (OO…
totten Feb 16, 2018
87e3bf6
reorder install plugins and other minor fixes
monishdeb Feb 19, 2018
09106d6
additional fixes
monishdeb Feb 20, 2018
6ed179f
SchemaGenerator, InstallSchema - More consistent log output
totten Feb 20, 2018
0d8c119
InstallSchema - Allow `ts()` to work without booting `CRM_Core_DAO`
totten Feb 20, 2018
66da8e8
multilingual fix
monishdeb Feb 23, 2018
4f0315a
additional fixes
monishdeb Apr 25, 2018
c3bed33
SchemaGenerator::generateSample - Use the full version
totten May 15, 2018
839da8f
InstallSchema - Split `generateSample()`. Preserve old behavior.
totten May 15, 2018
a109dda
SchemaGenerator - Simplify code-style for calling civicrm_navigation.tpl
totten May 15, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion plugins/init/Drupal.civi-setup.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
\Civi\Setup::dispatcher()
->addListener('civi.setup.checkAuthorized', function (\Civi\Setup\Event\CheckAuthorizedEvent $e) {
$model = $e->getModel();
if ($model->cms !== 'Drupal') {
if ($model->cms !== 'Drupal' || !function_exists('user_access')) {
return;
}

Expand Down
103 changes: 75 additions & 28 deletions plugins/installDatabase/InstallSchema.civi-setup.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,36 @@
exit("Installation plugins must only be loaded by the installer.\n");
}

\Civi\Setup::dispatcher()
->addListener('civi.setup.checkRequirements', function (\Civi\Setup\Event\CheckRequirementsEvent $e) {
class InstallSchemaPlugin implements \Symfony\Component\EventDispatcher\EventSubscriberInterface {

public static function getSubscribedEvents() {
return [
'civi.setup.checkRequirements' => [
['checkXmlFiles', 0],
['checkSqlFiles', 0],
],
'civi.setup.installDatabase' => [
['installDatabase', 0]
],
];
}

public function checkXmlFiles(\Civi\Setup\Event\CheckRequirementsEvent $e) {
$m = $e->getModel();
$files = array(
'xmlMissing' => implode(DIRECTORY_SEPARATOR, [$m->srcPath, 'xml']),
'xmlSchemaMissing' => implode(DIRECTORY_SEPARATOR, [$m->srcPath, 'xml', 'schema', 'Schema.xml']),
'xmlVersionMissing' => implode(DIRECTORY_SEPARATOR, [$m->srcPath, 'xml', 'version.xml']),
);

foreach ($files as $key => $file) {
if (!file_exists($file)) {
$e->addError('system', $key, "Schema file is missing: \"$file\"");
}
}
}

public function checkSqlFiles(\Civi\Setup\Event\CheckRequirementsEvent $e) {
\Civi\Setup::log()->info(sprintf('[%s] Handle %s', basename(__FILE__), 'checkRequirements'));
$seedLanguage = $e->getModel()->lang;
$sqlPath = $e->getModel()->srcPath . DIRECTORY_SEPARATOR . 'sql';
Expand All @@ -25,44 +53,63 @@
return;
}

$files = array(
$sqlPath . DIRECTORY_SEPARATOR . "civicrm_data.{$seedLanguage}.mysql",
$sqlPath . DIRECTORY_SEPARATOR . "civicrm_acl.{$seedLanguage}.mysql",
);

foreach ($files as $file) {
if (!file_exists($file)) {
$e->addError('system', 'langMissing', "Language schema file is missing: \"$file\"");
return;
}
if (!file_exists($e->getModel()->settingsPath)) {
$e->addError('system', 'settingsPath', sprintf('The CiviCRM setting file is missing.'));
}

$e->addInfo('system', 'lang', "Language $seedLanguage is allowed.");
});
}

\Civi\Setup::dispatcher()
->addListener('civi.setup.installDatabase', function (\Civi\Setup\Event\InstallDatabaseEvent $e) {
public function installDatabase(\Civi\Setup\Event\InstallDatabaseEvent $e) {
\Civi\Setup::log()->info(sprintf('[%s] Install database schema', basename(__FILE__)));

$model = $e->getModel();

$sqlPath = $model->srcPath . DIRECTORY_SEPARATOR . 'sql';
$spec = $this->loadSpecification($model->srcPath);

\Civi\Setup\DbUtil::sourceSQL($model->db, $sqlPath . DIRECTORY_SEPARATOR . 'civicrm.mysql');
$conn = \Civi\Setup\DbUtil::connect($model->db);
\CRM_Core_I18n::$SQL_ESCAPER = function($text) use ($conn) {
return $conn->escape_string($text);
};

\Civi\Setup::log()->info(sprintf('[%s] Load basic tables', basename(__FILE__)));
\Civi\Setup\DbUtil::sourceSQL($model->db, \Civi\Setup\SchemaGenerator::generateCreateSql($model->srcPath, $spec->database, $spec->tables));

$seedLanguage = $model->lang;
if (!empty($model->loadGenerated)) {
\Civi\Setup\DbUtil::sourceSQL($model->db, $sqlPath . DIRECTORY_SEPARATOR . 'civicrm_generated.mysql', TRUE);
\Civi\Setup::log()->info(sprintf('[%s] Load sample data', basename(__FILE__)));
// At time of writing, `generateSampleData()` is not yet a full replacement for `civicrm_generated.mysql`.
\Civi\Setup\DbUtil::sourceSQL($model->db, file_get_contents($sqlPath . DIRECTORY_SEPARATOR . 'civicrm_generated.mysql'));
// \Civi\Setup\DbUtil::sourceSQL($model->db, \Civi\Setup\SchemaGenerator::generateSampleData($model->srcPath));
}
else {
$seedLanguage = $model->lang;
if ($seedLanguage && $seedLanguage !== 'en_US') {
\Civi\Setup\DbUtil::sourceSQL($model->db, $sqlPath . DIRECTORY_SEPARATOR . "civicrm_data.{$seedLanguage}.mysql");
\Civi\Setup\DbUtil::sourceSQL($model->db, $sqlPath . DIRECTORY_SEPARATOR . "civicrm_acl.{$seedLanguage}.mysql");
}
else {
\Civi\Setup\DbUtil::sourceSQL($model->db, $sqlPath . DIRECTORY_SEPARATOR . 'civicrm_data.mysql');
\Civi\Setup\DbUtil::sourceSQL($model->db, $sqlPath . DIRECTORY_SEPARATOR . 'civicrm_acl.mysql');
}
elseif ($seedLanguage) {
global $tsLocale;
$tsLocale = $seedLanguage;
\Civi\Setup::log()->info(sprintf('[%s] Load basic data', basename(__FILE__)));
\Civi\Setup\DbUtil::sourceSQL($model->db, \Civi\Setup\SchemaGenerator::generateBasicData($model->srcPath));
}

});
require_once $model->settingsPath;
\Civi\Core\Container::boot(TRUE);

\CRM_Core_I18n::$SQL_ESCAPER = NULL;
}

/**
* @param string $srcPath
* @return \CRM_Core_CodeGen_Specification
*/
protected function loadSpecification($srcPath) {
$schemaFile = implode(DIRECTORY_SEPARATOR, [$srcPath, 'xml', 'schema', 'Schema.xml']);
$versionFile = implode(DIRECTORY_SEPARATOR, [$srcPath, 'xml', 'version.xml']);
$xmlBuilt = \CRM_Core_CodeGen_Util_Xml::parse($versionFile);
$buildVersion = preg_replace('/^(\d{1,2}\.\d{1,2})\.(\d{1,2}|\w{4,7})$/i', '$1', $xmlBuilt->version_no);
$specification = new \CRM_Core_CodeGen_Specification();
$specification->parse($schemaFile, $buildVersion, FALSE);
return $specification;
}

}

\Civi\Setup::dispatcher()->addSubscriber(new InstallSchemaPlugin());
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
$file = $e->getModel()->settingsPath;
if (file_exists($file)) {
if (!\Civi\Setup\FileUtil::isDeletable($file)) {
throw new \Exception("Cannot remove $file");
throw new \Exception("Cannot remove \"$file\". Please check permissions on the file and directory.");
}
unlink($file);
}
Expand Down
44 changes: 23 additions & 21 deletions src/Setup/DbUtil.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
namespace Civi\Setup;

use Civi\Setup\Exception\SqlException;
use Civi\Setup\Template;

class DbUtil {

Expand Down Expand Up @@ -29,7 +30,7 @@ public static function encodeDsn($db) {
return sprintf('mysql://%s:%s@%s/%s',
$db['username'],
$db['password'],
self::encodeHostPort($db['host'], $db['port']),
$db['server'],

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

won't this cause people with non standard ports to have issues? or is $db['server'] defined further up

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@seamuslee001 yes its defined up where parseDsn(...) will return the db creds, among which the server attribute will be first encoded with host and port information. See here

$db['database']
);
}
Expand Down Expand Up @@ -96,17 +97,17 @@ public static function encodeHostPort($host, $port) {

/**
* @param array $db
* @param string $fileName
* @param string $SQLcontent
* @param bool $lineMode
* What does this mean? Seems weird.
*/
public static function sourceSQL($db, $fileName, $lineMode = FALSE) {
public static function sourceSQL($db, $SQLcontent, $lineMode = FALSE) {
$conn = self::connect($db);

$conn->query('SET NAMES utf8');

if (!$lineMode) {
$string = file_get_contents($fileName);
$string = $SQLcontent;

// change \r\n to fix windows issues
$string = str_replace("\r\n", "\n", $string);
Expand All @@ -132,23 +133,24 @@ public static function sourceSQL($db, $fileName, $lineMode = FALSE) {
}
}
else {
$fd = fopen($fileName, "r");
while ($string = fgets($fd)) {
$string = preg_replace("/^#[^\n]*$/m", "\n", $string);
$string = preg_replace("/^(--[^-]).*/m", "\n", $string);

$string = trim($string);
if (!empty($string)) {
if ($result = $conn->query($string)) {
if (is_object($result)) {
mysqli_free_result($result);
}
}
else {
throw new SqlException("Cannot execute $string: " . mysqli_error($conn));
}
}
}
throw new \RuntimeException("Not implemented: lineMode");
// $fd = fopen($SQLcontent, "r");
// while ($string = fgets($fd)) {
// $string = preg_replace("/^#[^\n]*$/m", "\n", $string);
// $string = preg_replace("/^(--[^-]).*/m", "\n", $string);
//
// $string = trim($string);
// if (!empty($string)) {
// if ($result = $conn->query($string)) {
// if (is_object($result)) {
// mysqli_free_result($result);
// }
// }
// else {
// throw new SqlException("Cannot execute $string: " . mysqli_error($conn));
// }
// }
// }
}
}

Expand Down
12 changes: 12 additions & 0 deletions src/Setup/FileUtil.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,16 @@ public static function isDeletable($path) {
return is_writable(dirname($path));
}

/**
* @param $prefix
*
* @return string
*/
public static function createTempDir($prefix) {
$newTempDir = tempnam(sys_get_temp_dir(), $prefix) . '.d';
mkdir($newTempDir, 0755, TRUE);

return $newTempDir;
}

}
92 changes: 92 additions & 0 deletions src/Setup/SchemaGenerator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
<?php
namespace Civi\Setup;

use Civi\Setup\Template;

class SchemaGenerator {

/**
* Return translated SQL content using tpl, mainly contain SQL codes on table CREATE/DROP
*
* @param string $srcPath
* @param array $database
* @param array $tables
* @return string
*/
public static function generateCreateSql($srcPath, $database, $tables) {
$template = new Template($srcPath, 'sql');

$template->assign('database', $database);
$template->assign('tables', $tables);
$dropOrder = array_reverse(array_keys($tables));
$template->assign('dropOrder', $dropOrder);
$template->assign('mysql', 'modern');

return $template->getContent('schema.tpl');
}

/**
* Generate an example set of data, including the basic data as well
* as some example records/entities (e.g. case-types, membership types).
*
* @param string $srcPath
*
* @return string
*/
public static function generateSampleData($srcPath) {
$versionFile = implode(DIRECTORY_SEPARATOR, [$srcPath, 'xml', 'version.xml']);
$xml = \CRM_Core_CodeGen_Util_Xml::parse($versionFile);

$template = new Template($srcPath, 'sql');
$template->assign('db_version', $xml->version_no);

// If you're going to use the full data generator...
// "DROP TABLE IF EXISTS zipcodes"
// .... file_get_contents($sqlPath . DIRECTORY_SEPARATOR . 'zipcodes.mysql')...

$sections = [
'civicrm_country.tpl',
'civicrm_state_province.tpl',
'civicrm_currency.tpl',
'civicrm_data.tpl',
'civicrm_acl.tpl',
'civicrm_sample.tpl',
'case_sample.tpl',
'civicrm_version_sql.tpl',
'civicrm_navigation.tpl',
];

// DROP TABLE IF EXISTS zipcodes;

return $template->getConcatContent($sections);
}

/**
* Generate a minimalist set of basic data, such as
* common option-values and countries.
*
* @param string $srcPath
*
* @return string
* SQL
*/
public static function generateBasicData($srcPath) {
$versionFile = implode(DIRECTORY_SEPARATOR, [$srcPath, 'xml', 'version.xml']);
$xml = \CRM_Core_CodeGen_Util_Xml::parse($versionFile);

$template = new Template($srcPath, 'sql');
$template->assign('db_version', $xml->version_no);

$sections = [
'civicrm_country.tpl',
'civicrm_state_province.tpl',
'civicrm_currency.tpl',
'civicrm_data.tpl',
'civicrm_acl.tpl',
'civicrm_version_sql.tpl',
'civicrm_navigation.tpl',
];
return $template->getConcatContent($sections);
}

}
33 changes: 33 additions & 0 deletions src/Setup/SmartyUtil.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php
namespace Civi\Setup;

class SmartyUtil {

/**
* Create a Smarty instance.
*
* @return \Smarty
*/
public static function createSmarty($srcPath) {
require_once 'CRM/Core/I18n.php';

$packagePath = implode(DIRECTORY_SEPARATOR, [$srcPath, 'packages']);
require_once $packagePath . DIRECTORY_SEPARATOR . 'Smarty' . DIRECTORY_SEPARATOR . 'Smarty.class.php';

$smarty = new \Smarty();
$smarty->template_dir = implode(DIRECTORY_SEPARATOR, [$srcPath, 'xml', 'templates']);
$smarty->plugins_dir = [
implode(DIRECTORY_SEPARATOR, [$packagePath, 'Smarty', 'plugins']),
implode(DIRECTORY_SEPARATOR, [$srcPath, 'CRM', 'Core', 'Smarty', 'plugins']),
];
$smarty->compile_dir = \Civi\Setup\FileUtil::createTempDir('templates_c');
$smarty->clear_all_cache();

// CRM-5308 / CRM-3507 - we need {localize} to work in the templates
require_once implode(DIRECTORY_SEPARATOR, [$srcPath, 'CRM', 'Core', 'Smarty', 'plugins', 'block.localize.php']);
$smarty->register_block('localize', 'smarty_block_localize');

return $smarty;
}

}
Loading