CRM_Core_CodeGen_Reflection::needsUpdate() - Imitate DAO's check
authorTim Otten <totten@civicrm.org>
Thu, 28 Jul 2016 22:49:36 +0000 (15:49 -0700)
committerTim Otten <totten@civicrm.org>
Thu, 28 Jul 2016 23:12:25 +0000 (16:12 -0700)
The old check was prone to false-positives if you make unrelated changes in
`CRM/Core/CodeGen/*` and false-negatives when some hacks the underlying
file.  It's now more diligent.

CRM/Core/CodeGen/BaseTask.php
CRM/Core/CodeGen/DAO.php
CRM/Core/CodeGen/Reflection.php

index 73bf72a5d7ac656027fde5e2cd936eab0dc2cae7..83fcf1a410d0fec65851bcf1fe97add512ebe6c3 100644 (file)
@@ -57,4 +57,30 @@ abstract class CRM_Core_CodeGen_BaseTask implements CRM_Core_CodeGen_ITask {
     }
   }
 
+  /**
+   * Determine if two snippets of PHP code are approximately equivalent.
+   *
+   * This includes exceptions to equivalence for (a) whitespace and (b)
+   * the token "GenCodeChecksum".
+   *
+   * This is useful for determining if someone has manually mucked with
+   * one the files. However, it's not perfect -- because whitespace changes
+   * are not detected. Hence, it's good to use in combination with another
+   * heuristic.
+   *
+   * @param $actual
+   * @param $expected
+   * @return bool
+   */
+  protected function isApproxPhpMatch($actual, $expected) {
+    $actual = preg_replace(';\(GenCodeChecksum:([a-zA-Z0-9]+)\);', '', $actual);
+    $actual = preg_replace(';[ \r\n\t];', '', $actual);
+
+    $expected = preg_replace(';\(GenCodeChecksum:([a-zA-Z0-9]+)\);', '',
+      $expected);
+    $expected = preg_replace(';[ \r\n\t];', '', $expected);
+
+    return $actual === $expected;
+  }
+
 }
index 632f3479c7793ef7a77d9598626ebd5d2df6bf64..503ba3eb240c0812df837375000ff3a10b541b08 100644 (file)
@@ -34,21 +34,13 @@ class CRM_Core_CodeGen_DAO extends CRM_Core_CodeGen_BaseTask {
       return TRUE;
     }
 
-    // Has the table metadata changed since the DAO was generated?
     if ($this->getTableChecksum() !== self::extractRegex($this->getAbsFileName(), ';\(GenCodeChecksum:([a-zA-Z0-9]+)\);')) {
       return TRUE;
     }
 
-    // Has someone messed with the logic of the DAO?
-    // Compare suggested+actual code (modulo whitespace).
-    $stripped['actual'] = file_get_contents($this->getAbsFileName());
-    $stripped['expect'] = $this->getRaw();
-
-    foreach (array('actual', 'expect') as $key) {
-      $stripped[$key] = preg_replace(';\(GenCodeChecksum:([a-zA-Z0-9]+)\);', '', $stripped[$key]);
-      $stripped[$key] = preg_replace(';[ \r\n\t];', '', $stripped[$key]);
-    }
-    return $stripped['actual'] !== $stripped['expect'];
+    return !$this->isApproxPhpMatch(
+      file_get_contents($this->getAbsFileName()),
+      $this->getRaw());
   }
 
   public function run() {
index f47c8a07410970f398937da91a5813f697675618..8741e2a0cd23af647b6248fe8767207661e2010c 100644 (file)
@@ -7,6 +7,11 @@ class CRM_Core_CodeGen_Reflection extends CRM_Core_CodeGen_BaseTask {
 
   protected $checksum;
 
+  /**
+   * @var string
+   */
+  private $raw;
+
   /**
    * @return bool
    *   TRUE if an update is needed.
@@ -15,17 +20,40 @@ class CRM_Core_CodeGen_Reflection extends CRM_Core_CodeGen_BaseTask {
     if (!file_exists($this->getAbsFileName())) {
       return TRUE;
     }
-    return $this->getChecksum() !== self::extractRegex($this->getAbsFileName(), ';\(GenCodeChecksum:([a-z0-9]+)\);');
+
+    if ($this->getSchemaChecksum() !== self::extractRegex($this->getAbsFileName(), ';\(GenCodeChecksum:([a-zA-Z0-9]+)\);')) {
+      return TRUE;
+    }
+
+    return !$this->isApproxPhpMatch(
+      file_get_contents($this->getAbsFileName()),
+      $this->getRaw());
   }
 
+
   public function run() {
     echo "Generating table list\n";
     $template = new CRM_Core_CodeGen_Util_Template('php');
     $template->assign('tables', $this->tables);
-    $template->assign('genCodeChecksum', $this->getChecksum());
+    $template->assign('genCodeChecksum', $this->getSchemaChecksum());
     $template->run('listAll.tpl', $this->getAbsFileName());
   }
 
+  /**
+   * Generate the raw PHP code for the data file.
+   *
+   * @return string
+   */
+  public function getRaw() {
+    if (!$this->raw) {
+      $template = new CRM_Core_CodeGen_Util_Template('php');
+      $template->assign('tables', $this->tables);
+      $template->assign('genCodeChecksum', 'NEW');
+      $this->raw = $template->fetch('listAll.tpl');
+    }
+    return $this->raw;
+  }
+
   /**
    * @return string
    */
@@ -33,11 +61,11 @@ class CRM_Core_CodeGen_Reflection extends CRM_Core_CodeGen_BaseTask {
     return $this->config->CoreDAOCodePath . "AllCoreTables.data.php";
   }
 
-  protected function getChecksum() {
+  protected function getSchemaChecksum() {
     if (!$this->checksum) {
       CRM_Utils_Array::flatten($this->tables, $flat);
       ksort($flat);
-      $this->checksum = md5($this->config->getSourceDigest() . json_encode($flat));
+      $this->checksum = md5(json_encode($flat));
     }
     return $this->checksum;
   }