4 use Civi\Test\CiviEnvBuilder\CallbackStep
;
5 use Civi\Test\CiviEnvBuilder\CoreSchemaStep
;
6 use Civi\Test\CiviEnvBuilder\ExtensionsStep
;
7 use Civi\Test\CiviEnvBuilder\SqlFileStep
;
8 use Civi\Test\CiviEnvBuilder\SqlStep
;
9 use Civi\Test\CiviEnvBuilder\StepInterface
;
13 * Class CiviEnvBuilder
15 * Provides a fluent interface for tracking a set of steps.
16 * By computing and storing a signature for the list steps, we can
17 * determine whether to (a) do nothing with the list or (b)
18 * reapply all the steps.
20 class CiviEnvBuilder
{
27 * A digest of the values in $steps.
29 private $targetSignature = NULL;
31 public function __construct($name) {
35 public function addStep(StepInterface
$step) {
36 $this->targetSignature
= NULL;
37 $this->steps
[] = $step;
41 public function callback($callback, $signature = NULL) {
42 return $this->addStep(new CallbackStep($callback, $signature));
46 * Generate the core SQL tables.
48 * @return \Civi\Test\CiviEnvBuilder
50 public function coreSchema() {
51 return $this->addStep(new CoreSchemaStep());
54 public function sql($sql) {
55 return $this->addStep(new SqlStep($sql));
58 public function sqlFile($file) {
59 return $this->addStep(new SqlFileStep($file));
63 * Require that an extension be installed.
65 * @param string|array $names
66 * One or more extension names. You may use a wildcard '*'.
67 * @return CiviEnvBuilder
69 public function install($names) {
70 return $this->addStep(new ExtensionsStep('install', $names));
74 * Require an extension be installed (identified by its directory).
77 * The current test directory. We'll search for info.xml to
78 * see what this extension is.
79 * @return CiviEnvBuilder
80 * @throws \CRM_Extension_Exception_ParseException
82 public function installMe($dir) {
83 return $this->addStep(new ExtensionsStep('install', $this->whoAmI($dir)));
87 * Require an extension be uninstalled.
89 * @param string|array $names
90 * One or more extension names. You may use a wildcard '*'.
91 * @return CiviEnvBuilder
93 public function uninstall($names) {
94 return $this->addStep(new ExtensionsStep('uninstall', $names));
98 * Require an extension be uninstalled (identified by its directory).
101 * The current test directory. We'll search for info.xml to
102 * see what this extension is.
103 * @return CiviEnvBuilder
104 * @throws \CRM_Extension_Exception_ParseException
106 public function uninstallMe($dir) {
107 return $this->addStep(new ExtensionsStep('uninstall', $this->whoAmI($dir)));
110 protected function assertValid() {
111 foreach ($this->steps
as $step) {
112 if (!$step->isValid()) {
113 throw new RuntimeException("Found invalid step: " . var_dump($step, 1));
121 protected function getTargetSignature() {
122 if ($this->targetSignature
=== NULL) {
124 foreach ($this->steps
as $step) {
125 $buf .= $step->getSig();
127 $this->targetSignature
= md5($buf);
130 return $this->targetSignature
;
136 protected function getSavedSignature() {
137 $liveSchemaRev = NULL;
138 $pdo = \Civi\Test
::pdo();
139 $pdoStmt = $pdo->query(sprintf(
140 "SELECT rev FROM %s.civitest_revs WHERE name = %s",
141 \Civi\Test
::dsn('database'),
142 $pdo->quote($this->name
)
144 foreach ($pdoStmt as $row) {
145 $liveSchemaRev = $row['rev'];
147 return $liveSchemaRev;
151 * @param $newSignature
153 protected function setSavedSignature($newSignature) {
154 $pdo = \Civi\Test
::pdo();
156 'INSERT INTO %s.civitest_revs (name,rev) VALUES (%s,%s) '
157 . 'ON DUPLICATE KEY UPDATE rev = %s;',
158 \Civi\Test
::dsn('database'),
159 $pdo->quote($this->name
),
160 $pdo->quote($newSignature),
161 $pdo->quote($newSignature)
164 if (\Civi\Test
::execute($query) === FALSE) {
165 throw new RuntimeException("Failed to flag schema version: $query");
170 * Determine if there's been a change in the preferred configuration.
171 * If the preferred-configuration matches the last test, keep it. Otherwise,
172 * destroy and recreate.
175 * Forcibly execute the build, even if the configuration hasn't changed.
176 * This will slow-down the tests, but it may be appropriate for some very sloppy
178 * @return CiviEnvBuilder
180 public function apply($force = FALSE) {
181 return \Civi\Test
::asPreInstall(function() use ($force) {
182 $dbName = \Civi\Test
::dsn('database');
183 $query = "USE {$dbName};"
184 . "CREATE TABLE IF NOT EXISTS civitest_revs (name VARCHAR(64) PRIMARY KEY, rev VARCHAR(64));";
186 if (\Civi\Test
::execute($query) === FALSE) {
187 throw new \
RuntimeException("Failed to flag schema version: $query");
190 $this->assertValid();
192 if (!$force && $this->getSavedSignature() === $this->getTargetSignature()) {
195 foreach ($this->steps
as $step) {
198 $this->setSavedSignature($this->getTargetSignature());
206 * @throws \CRM_Extension_Exception_ParseException
208 protected function whoAmI($dir) {
209 while ($dir && dirname($dir) !== $dir && !file_exists("$dir/info.xml")) {
210 $dir = dirname($dir);
212 if (file_exists("$dir/info.xml")) {
213 $info = \CRM_Extension_Info
::loadFromFile("$dir/info.xml");