#29521 - Skeleton structure generated using civix tool.
authorManoj K <manoj.k@zyxware.com>
Fri, 5 Sep 2014 12:47:09 +0000 (18:17 +0530)
committerManoj K <manoj.k@zyxware.com>
Fri, 5 Sep 2014 12:47:09 +0000 (18:17 +0530)
12 files changed:
CRM/Wci/Form/CreateWidget.php [new file with mode: 0644]
CRM/Wci/Page/WCIDashboard.php [new file with mode: 0644]
CRM/Wci/Upgrader.php [new file with mode: 0644]
CRM/Wci/Upgrader/Base.php [new file with mode: 0644]
info.xml [new file with mode: 0644]
sql/install.sql [new file with mode: 0644]
sql/uninstall.sql [new file with mode: 0644]
templates/CRM/Wci/Form/CreateWidget.tpl [new file with mode: 0644]
templates/CRM/Wci/Page/WCIDashboard.tpl [new file with mode: 0644]
wci.civix.php [new file with mode: 0644]
wci.php [new file with mode: 0644]
xml/Menu/wci.xml [new file with mode: 0644]

diff --git a/CRM/Wci/Form/CreateWidget.php b/CRM/Wci/Form/CreateWidget.php
new file mode 100644 (file)
index 0000000..98a6ec4
--- /dev/null
@@ -0,0 +1,76 @@
+<?php
+
+require_once 'CRM/Core/Form.php';
+
+/**
+ * Form controller class
+ *
+ * @see http://wiki.civicrm.org/confluence/display/CRMDOC43/QuickForm+Reference
+ */
+class CRM_Wci_Form_CreateWidget extends CRM_Core_Form {
+  function buildQuickForm() {
+
+    // add form elements
+    $this->add(
+      'select', // field type
+      'favorite_color', // field name
+      'Favorite Color', // field label
+      $this->getColorOptions(), // list of options
+      true // is required
+    );
+    $this->addButtons(array(
+      array(
+        'type' => 'submit',
+        'name' => ts('Submit'),
+        'isDefault' => TRUE,
+      ),
+    ));
+
+    // export form elements
+    $this->assign('elementNames', $this->getRenderableElementNames());
+    parent::buildQuickForm();
+  }
+
+  function postProcess() {
+    $values = $this->exportValues();
+    $options = $this->getColorOptions();
+    CRM_Core_Session::setStatus(ts('You picked color "%1"', array(
+      1 => $options[$values['favorite_color']]
+    )));
+    parent::postProcess();
+  }
+
+  function getColorOptions() {
+    $options = array(
+      '' => ts('- select -'),
+      '#f00' => ts('Red'),
+      '#0f0' => ts('Green'),
+      '#00f' => ts('Blue'),
+      '#f0f' => ts('Purple'),
+    );
+    foreach (array('1','2','3','4','5','6','7','8','9','a','b','c','d','e') as $f) {
+      $options["#{$f}{$f}{$f}"] = ts('Grey (%1)', array(1 => $f));
+    }
+    return $options;
+  }
+
+  /**
+   * Get the fields/elements defined in this form.
+   *
+   * @return array (string)
+   */
+  function getRenderableElementNames() {
+    // The _elements list includes some items which should not be
+    // auto-rendered in the loop -- such as "qfKey" and "buttons".  These
+    // items don't have labels.  We'll identify renderable by filtering on
+    // the 'label'.
+    $elementNames = array();
+    foreach ($this->_elements as $element) {
+      $label = $element->getLabel();
+      if (!empty($label)) {
+        $elementNames[] = $element->getName();
+      }
+    }
+    return $elementNames;
+  }
+}
diff --git a/CRM/Wci/Page/WCIDashboard.php b/CRM/Wci/Page/WCIDashboard.php
new file mode 100644 (file)
index 0000000..2aab981
--- /dev/null
@@ -0,0 +1,15 @@
+<?php
+
+require_once 'CRM/Core/Page.php';
+
+class CRM_Wci_Page_WCIDashboard extends CRM_Core_Page {
+  function run() {
+    // Example: Set the page-title dynamically; alternatively, declare a static title in xml/Menu/*.xml
+    CRM_Utils_System::setTitle(ts('WCIDashboard'));
+
+    // Example: Assign a variable for use in a template
+    $this->assign('currentTime', date('Y-m-d H:i:s'));
+
+    parent::run();
+  }
+}
diff --git a/CRM/Wci/Upgrader.php b/CRM/Wci/Upgrader.php
new file mode 100644 (file)
index 0000000..a0afc6b
--- /dev/null
@@ -0,0 +1,115 @@
+<?php
+
+/**
+ * Collection of upgrade steps
+ */
+class CRM_Wci_Upgrader extends CRM_Wci_Upgrader_Base {
+
+  // By convention, functions that look like "function upgrade_NNNN()" are
+  // upgrade tasks. They are executed in order (like Drupal's hook_update_N).
+
+  /**
+   * Example: Run an external SQL script when the module is installed
+   */
+  public function install() {
+    $this->executeSqlFile('sql/install.sql');
+  }
+
+  /**
+   * Example: Run an external SQL script when the module is uninstalled
+   */
+  public function uninstall() {
+   $this->executeSqlFile('sql/uninstall.sql');
+  }
+
+  /**
+   * Example: Run a simple query when a module is enabled
+   *
+  public function enable() {
+    CRM_Core_DAO::executeQuery('UPDATE foo SET is_active = 1 WHERE bar = "whiz"');
+  }
+
+  /**
+   * Example: Run a simple query when a module is disabled
+   *
+  public function disable() {
+    CRM_Core_DAO::executeQuery('UPDATE foo SET is_active = 0 WHERE bar = "whiz"');
+  }
+
+  /**
+   * Example: Run a couple simple queries
+   *
+   * @return TRUE on success
+   * @throws Exception
+   *
+  public function upgrade_4200() {
+    $this->ctx->log->info('Applying update 4200');
+    CRM_Core_DAO::executeQuery('UPDATE foo SET bar = "whiz"');
+    CRM_Core_DAO::executeQuery('DELETE FROM bang WHERE willy = wonka(2)');
+    return TRUE;
+  } // */
+
+
+  /**
+   * Example: Run an external SQL script
+   *
+   * @return TRUE on success
+   * @throws Exception
+  public function upgrade_4201() {
+    $this->ctx->log->info('Applying update 4201');
+    // this path is relative to the extension base dir
+    $this->executeSqlFile('sql/upgrade_4201.sql');
+    return TRUE;
+  } // */
+
+
+  /**
+   * Example: Run a slow upgrade process by breaking it up into smaller chunk
+   *
+   * @return TRUE on success
+   * @throws Exception
+  public function upgrade_4202() {
+    $this->ctx->log->info('Planning update 4202'); // PEAR Log interface
+
+    $this->addTask(ts('Process first step'), 'processPart1', $arg1, $arg2);
+    $this->addTask(ts('Process second step'), 'processPart2', $arg3, $arg4);
+    $this->addTask(ts('Process second step'), 'processPart3', $arg5);
+    return TRUE;
+  }
+  public function processPart1($arg1, $arg2) { sleep(10); return TRUE; }
+  public function processPart2($arg3, $arg4) { sleep(10); return TRUE; }
+  public function processPart3($arg5) { sleep(10); return TRUE; }
+  // */
+
+
+  /**
+   * Example: Run an upgrade with a query that touches many (potentially
+   * millions) of records by breaking it up into smaller chunks.
+   *
+   * @return TRUE on success
+   * @throws Exception
+  public function upgrade_4203() {
+    $this->ctx->log->info('Planning update 4203'); // PEAR Log interface
+
+    $minId = CRM_Core_DAO::singleValueQuery('SELECT coalesce(min(id),0) FROM civicrm_contribution');
+    $maxId = CRM_Core_DAO::singleValueQuery('SELECT coalesce(max(id),0) FROM civicrm_contribution');
+    for ($startId = $minId; $startId <= $maxId; $startId += self::BATCH_SIZE) {
+      $endId = $startId + self::BATCH_SIZE - 1;
+      $title = ts('Upgrade Batch (%1 => %2)', array(
+        1 => $startId,
+        2 => $endId,
+      ));
+      $sql = '
+        UPDATE civicrm_contribution SET foobar = whiz(wonky()+wanker)
+        WHERE id BETWEEN %1 and %2
+      ';
+      $params = array(
+        1 => array($startId, 'Integer'),
+        2 => array($endId, 'Integer'),
+      );
+      $this->addTask($title, 'executeSql', $sql, $params);
+    }
+    return TRUE;
+  } // */
+
+}
diff --git a/CRM/Wci/Upgrader/Base.php b/CRM/Wci/Upgrader/Base.php
new file mode 100644 (file)
index 0000000..fa1544b
--- /dev/null
@@ -0,0 +1,298 @@
+<?php
+
+// AUTO-GENERATED FILE -- Civix may overwrite any changes made to this file
+
+/**
+ * Base class which provides helpers to execute upgrade logic
+ */
+class CRM_Wci_Upgrader_Base {
+
+  /**
+   * @var varies, subclass of htis
+   */
+  static $instance;
+
+  /**
+   * @var CRM_Queue_TaskContext
+   */
+  protected $ctx;
+
+  /**
+   * @var string, eg 'com.example.myextension'
+   */
+  protected $extensionName;
+
+  /**
+   * @var string, full path to the extension's source tree
+   */
+  protected $extensionDir;
+
+  /**
+   * @var array(revisionNumber) sorted numerically
+   */
+  private $revisions;
+
+  /**
+   * Obtain a refernece to the active upgrade handler
+   */
+  static public function instance() {
+    if (! self::$instance) {
+      // FIXME auto-generate
+      self::$instance = new CRM_Wci_Upgrader(
+        'civicrm-wci',
+        realpath(__DIR__ .'/../../../')
+      );
+    }
+    return self::$instance;
+  }
+
+  /**
+   * Adapter that lets you add normal (non-static) member functions to the queue.
+   *
+   * Note: Each upgrader instance should only be associated with one
+   * task-context; otherwise, this will be non-reentrant.
+   *
+   * @code
+   * CRM_Wci_Upgrader_Base::_queueAdapter($ctx, 'methodName', 'arg1', 'arg2');
+   * @endcode
+   */
+  static public function _queueAdapter() {
+    $instance = self::instance();
+    $args = func_get_args();
+    $instance->ctx = array_shift($args);
+    $instance->queue = $instance->ctx->queue;
+    $method = array_shift($args);
+    return call_user_func_array(array($instance, $method), $args);
+  }
+
+  public function __construct($extensionName, $extensionDir) {
+    $this->extensionName = $extensionName;
+    $this->extensionDir = $extensionDir;
+  }
+
+  // ******** Task helpers ********
+
+  /**
+   * Run a CustomData file
+   *
+   * @param string $relativePath the CustomData XML file path (relative to this extension's dir)
+   * @return bool
+   */
+  public function executeCustomDataFile($relativePath) {
+    $xml_file = $this->extensionDir . '/' . $relativePath;
+    return $this->executeCustomDataFileByAbsPath($xml_file);
+  }
+
+  /**
+   * Run a CustomData file
+   *
+   * @param string $xml_file  the CustomData XML file path (absolute path)
+   * @return bool
+   */
+  protected static function executeCustomDataFileByAbsPath($xml_file) {
+    require_once 'CRM/Utils/Migrate/Import.php';
+    $import = new CRM_Utils_Migrate_Import();
+    $import->run($xml_file);
+    return TRUE;
+  }
+
+  /**
+   * Run a SQL file
+   *
+   * @param string $relativePath the SQL file path (relative to this extension's dir)
+   * @return bool
+   */
+  public function executeSqlFile($relativePath) {
+    CRM_Utils_File::sourceSQLFile(
+      CIVICRM_DSN,
+      $this->extensionDir . '/' . $relativePath
+    );
+    return TRUE;
+  }
+
+  /**
+   * Run one SQL query
+   *
+   * This is just a wrapper for CRM_Core_DAO::executeSql, but it
+   * provides syntatic sugar for queueing several tasks that
+   * run different queries
+   */
+  public function executeSql($query, $params = array()) {
+    // FIXME verify that we raise an exception on error
+    CRM_Core_DAO::executeSql($query, $params);
+    return TRUE;
+  }
+
+  /**
+   * Syntatic sugar for enqueuing a task which calls a function
+   * in this class. The task is weighted so that it is processed
+   * as part of the currently-pending revision.
+   *
+   * After passing the $funcName, you can also pass parameters that will go to
+   * the function. Note that all params must be serializable.
+   */
+  public function addTask($title) {
+    $args = func_get_args();
+    $title = array_shift($args);
+    $task = new CRM_Queue_Task(
+      array(get_class($this), '_queueAdapter'),
+      $args,
+      $title
+    );
+    return $this->queue->createItem($task, array('weight' => -1));
+  }
+
+  // ******** Revision-tracking helpers ********
+
+  /**
+   * Determine if there are any pending revisions
+   *
+   * @return bool
+   */
+  public function hasPendingRevisions() {
+    $revisions = $this->getRevisions();
+    $currentRevision = $this->getCurrentRevision();
+
+    if (empty($revisions)) {
+      return FALSE;
+    }
+    if (empty($currentRevision)) {
+      return TRUE;
+    }
+
+    return ($currentRevision < max($revisions));
+  }
+
+  /**
+   * Add any pending revisions to the queue
+   */
+  public function enqueuePendingRevisions(CRM_Queue_Queue $queue) {
+    $this->queue = $queue;
+
+    $currentRevision = $this->getCurrentRevision();
+    foreach ($this->getRevisions() as $revision) {
+      if ($revision > $currentRevision) {
+        $title = ts('Upgrade %1 to revision %2', array(
+          1 => $this->extensionName,
+          2 => $revision,
+        ));
+
+        // note: don't use addTask() because it sets weight=-1
+
+        $task = new CRM_Queue_Task(
+          array(get_class($this), '_queueAdapter'),
+          array('upgrade_' . $revision),
+          $title
+        );
+        $this->queue->createItem($task);
+
+        $task = new CRM_Queue_Task(
+          array(get_class($this), '_queueAdapter'),
+          array('setCurrentRevision', $revision),
+          $title
+        );
+        $this->queue->createItem($task);
+      }
+    }
+  }
+
+  /**
+   * Get a list of revisions
+   *
+   * @return array(revisionNumbers) sorted numerically
+   */
+  public function getRevisions() {
+    if (! is_array($this->revisions)) {
+      $this->revisions = array();
+
+      $clazz = new ReflectionClass(get_class($this));
+      $methods = $clazz->getMethods();
+      foreach ($methods as $method) {
+        if (preg_match('/^upgrade_(.*)/', $method->name, $matches)) {
+          $this->revisions[] = $matches[1];
+        }
+      }
+      sort($this->revisions, SORT_NUMERIC);
+    }
+
+    return $this->revisions;
+  }
+
+  public function getCurrentRevision() {
+    // return CRM_Core_BAO_Extension::getSchemaVersion($this->extensionName);
+    $key = $this->extensionName . ':version';
+    return CRM_Core_BAO_Setting::getItem('Extension', $key);
+  }
+
+  public function setCurrentRevision($revision) {
+    // We call this during hook_civicrm_install, but the underlying SQL
+    // UPDATE fails because the extension record hasn't been INSERTed yet.
+    // Instead, track revisions in our own namespace.
+    // CRM_Core_BAO_Extension::setSchemaVersion($this->extensionName, $revision);
+
+    $key = $this->extensionName . ':version';
+    CRM_Core_BAO_Setting::setItem($revision, 'Extension', $key);
+    return TRUE;
+  }
+
+  // ******** Hook delegates ********
+
+  public function onInstall() {
+    $files = glob($this->extensionDir . '/sql/*_install.sql');
+    if (is_array($files)) {
+      foreach ($files as $file) {
+        CRM_Utils_File::sourceSQLFile(CIVICRM_DSN, $file);
+      }
+    }
+    $files = glob($this->extensionDir . '/xml/*_install.xml');
+    if (is_array($files)) {
+      foreach ($files as $file) {
+        $this->executeCustomDataFileByAbsPath($file);
+      }
+    }
+    if (is_callable(array($this, 'install'))) {
+      $this->install();
+    }
+    $revisions = $this->getRevisions();
+    if (!empty($revisions)) {
+      $this->setCurrentRevision(max($revisions));
+    }
+  }
+
+  public function onUninstall() {
+    if (is_callable(array($this, 'uninstall'))) {
+      $this->uninstall();
+    }
+    $files = glob($this->extensionDir . '/sql/*_uninstall.sql');
+    if (is_array($files)) {
+      foreach ($files as $file) {
+        CRM_Utils_File::sourceSQLFile(CIVICRM_DSN, $file);
+      }
+    }
+    $this->setCurrentRevision(NULL);
+  }
+
+  public function onEnable() {
+    // stub for possible future use
+    if (is_callable(array($this, 'enable'))) {
+      $this->enable();
+    }
+  }
+
+  public function onDisable() {
+    // stub for possible future use
+    if (is_callable(array($this, 'disable'))) {
+      $this->disable();
+    }
+  }
+
+  public function onUpgrade($op, CRM_Queue_Queue $queue = NULL) {
+    switch($op) {
+      case 'check':
+        return array($this->hasPendingRevisions());
+      case 'enqueue':
+        return $this->enqueuePendingRevisions($queue);
+      default:
+    }
+  }
+}
diff --git a/info.xml b/info.xml
new file mode 100644 (file)
index 0000000..e6d4ea8
--- /dev/null
+++ b/info.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0"?>
+<extension key="civicrm-wci" type="module">
+  <file>wci</file>
+  <name>Widget Creation Interface</name>
+  <description>CiviCRM CMS independent Widget Creation Interface.</description>
+  <license>AGPL-3.0</license>
+  <maintainer>
+    <author>Manoj K</author>
+    <email>manoj.k@zyxware.com</email>
+  </maintainer>
+  <releaseDate>2014-09-04</releaseDate>
+  <version>1.0-alpha1</version>
+  <develStage>alpha</develStage>
+  <compatibility>
+    <ver>4.2</ver>
+  </compatibility>
+  <comments>This is a new, undeveloped module</comments>
+  <civix>
+    <namespace>CRM/Wci</namespace>
+  </civix>
+</extension>
diff --git a/sql/install.sql b/sql/install.sql
new file mode 100644 (file)
index 0000000..28ca3b9
--- /dev/null
@@ -0,0 +1 @@
+-- Installation mysql script
\ No newline at end of file
diff --git a/sql/uninstall.sql b/sql/uninstall.sql
new file mode 100644 (file)
index 0000000..59ac57f
--- /dev/null
@@ -0,0 +1 @@
+-- Un installation mysql script
\ No newline at end of file
diff --git a/templates/CRM/Wci/Form/CreateWidget.tpl b/templates/CRM/Wci/Form/CreateWidget.tpl
new file mode 100644 (file)
index 0000000..c99bb1f
--- /dev/null
@@ -0,0 +1,27 @@
+{* HEADER *}
+
+<div class="crm-submit-buttons">
+{include file="CRM/common/formButtons.tpl" location="top"}
+</div>
+
+{* FIELD EXAMPLE: OPTION 1 (AUTOMATIC LAYOUT) *}
+
+{foreach from=$elementNames item=elementName}
+  <div class="crm-section">
+    <div class="label">{$form.$elementName.label}</div>
+    <div class="content">{$form.$elementName.html}</div>
+    <div class="clear"></div>
+  </div>
+{/foreach}
+
+{* FIELD EXAMPLE: OPTION 2 (MANUAL LAYOUT)
+
+  <div>
+    <span>{$form.favorite_color.label}</span>
+    <span>{$form.favorite_color.html}</span>
+  </div>
+
+{* FOOTER *}
+<div class="crm-submit-buttons">
+{include file="CRM/common/formButtons.tpl" location="bottom"}
+</div>
diff --git a/templates/CRM/Wci/Page/WCIDashboard.tpl b/templates/CRM/Wci/Page/WCIDashboard.tpl
new file mode 100644 (file)
index 0000000..d1ab2d0
--- /dev/null
@@ -0,0 +1,7 @@
+<h3>This new page is generated by CRM/Wci/Page/WCIDashboard.php</h3>
+
+{* Example: Display a variable directly *}
+<p>The current time is {$currentTime}</p>
+
+{* Example: Display a translated string -- which happens to include a variable *}
+<p>{ts 1=$currentTime}(In your native language) The current time is %1.{/ts}</p>
diff --git a/wci.civix.php b/wci.civix.php
new file mode 100644 (file)
index 0000000..17361db
--- /dev/null
@@ -0,0 +1,278 @@
+<?php
+
+// AUTO-GENERATED FILE -- Civix may overwrite any changes made to this file
+
+/**
+ * (Delegated) Implementation of hook_civicrm_config
+ *
+ * @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_config
+ */
+function _wci_civix_civicrm_config(&$config = NULL) {
+  static $configured = FALSE;
+  if ($configured) return;
+  $configured = TRUE;
+
+  $template =& CRM_Core_Smarty::singleton();
+
+  $extRoot = dirname( __FILE__ ) . DIRECTORY_SEPARATOR;
+  $extDir = $extRoot . 'templates';
+
+  if ( is_array( $template->template_dir ) ) {
+      array_unshift( $template->template_dir, $extDir );
+  } else {
+      $template->template_dir = array( $extDir, $template->template_dir );
+  }
+
+  $include_path = $extRoot . PATH_SEPARATOR . get_include_path( );
+  set_include_path( $include_path );
+}
+
+/**
+ * (Delegated) Implementation of hook_civicrm_xmlMenu
+ *
+ * @param $files array(string)
+ * @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_xmlMenu
+ */
+function _wci_civix_civicrm_xmlMenu(&$files) {
+  foreach (_wci_civix_glob(__DIR__ . '/xml/Menu/*.xml') as $file) {
+    $files[] = $file;
+  }
+}
+
+/**
+ * Implementation of hook_civicrm_install
+ *
+ * @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_install
+ */
+function _wci_civix_civicrm_install() {
+  _wci_civix_civicrm_config();
+  if ($upgrader = _wci_civix_upgrader()) {
+    return $upgrader->onInstall();
+  }
+}
+
+/**
+ * Implementation of hook_civicrm_uninstall
+ *
+ * @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_uninstall
+ */
+function _wci_civix_civicrm_uninstall() {
+  _wci_civix_civicrm_config();
+  if ($upgrader = _wci_civix_upgrader()) {
+    return $upgrader->onUninstall();
+  }
+}
+
+/**
+ * (Delegated) Implementation of hook_civicrm_enable
+ *
+ * @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_enable
+ */
+function _wci_civix_civicrm_enable() {
+  _wci_civix_civicrm_config();
+  if ($upgrader = _wci_civix_upgrader()) {
+    if (is_callable(array($upgrader, 'onEnable'))) {
+      return $upgrader->onEnable();
+    }
+  }
+}
+
+/**
+ * (Delegated) Implementation of hook_civicrm_disable
+ *
+ * @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_disable
+ */
+function _wci_civix_civicrm_disable() {
+  _wci_civix_civicrm_config();
+  if ($upgrader = _wci_civix_upgrader()) {
+    if (is_callable(array($upgrader, 'onDisable'))) {
+      return $upgrader->onDisable();
+    }
+  }
+}
+
+/**
+ * (Delegated) Implementation of hook_civicrm_upgrade
+ *
+ * @param $op string, the type of operation being performed; 'check' or 'enqueue'
+ * @param $queue CRM_Queue_Queue, (for 'enqueue') the modifiable list of pending up upgrade tasks
+ *
+ * @return mixed  based on op. for 'check', returns array(boolean) (TRUE if upgrades are pending)
+ *                for 'enqueue', returns void
+ *
+ * @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_upgrade
+ */
+function _wci_civix_civicrm_upgrade($op, CRM_Queue_Queue $queue = NULL) {
+  if ($upgrader = _wci_civix_upgrader()) {
+    return $upgrader->onUpgrade($op, $queue);
+  }
+}
+
+/**
+ * @return CRM_Wci_Upgrader
+ */
+function _wci_civix_upgrader() {
+  if (!file_exists(__DIR__.'/CRM/Wci/Upgrader.php')) {
+    return NULL;
+  } else {
+    return CRM_Wci_Upgrader_Base::instance();
+  }
+}
+
+/**
+ * Search directory tree for files which match a glob pattern
+ *
+ * Note: Dot-directories (like "..", ".git", or ".svn") will be ignored.
+ * Note: In Civi 4.3+, delegate to CRM_Utils_File::findFiles()
+ *
+ * @param $dir string, base dir
+ * @param $pattern string, glob pattern, eg "*.txt"
+ * @return array(string)
+ */
+function _wci_civix_find_files($dir, $pattern) {
+  if (is_callable(array('CRM_Utils_File', 'findFiles'))) {
+    return CRM_Utils_File::findFiles($dir, $pattern);
+  }
+
+  $todos = array($dir);
+  $result = array();
+  while (!empty($todos)) {
+    $subdir = array_shift($todos);
+    foreach (_wci_civix_glob("$subdir/$pattern") as $match) {
+      if (!is_dir($match)) {
+        $result[] = $match;
+      }
+    }
+    if ($dh = opendir($subdir)) {
+      while (FALSE !== ($entry = readdir($dh))) {
+        $path = $subdir . DIRECTORY_SEPARATOR . $entry;
+        if ($entry{0} == '.') {
+        } elseif (is_dir($path)) {
+          $todos[] = $path;
+        }
+      }
+      closedir($dh);
+    }
+  }
+  return $result;
+}
+/**
+ * (Delegated) Implementation of hook_civicrm_managed
+ *
+ * Find any *.mgd.php files, merge their content, and return.
+ *
+ * @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_managed
+ */
+function _wci_civix_civicrm_managed(&$entities) {
+  $mgdFiles = _wci_civix_find_files(__DIR__, '*.mgd.php');
+  foreach ($mgdFiles as $file) {
+    $es = include $file;
+    foreach ($es as $e) {
+      if (empty($e['module'])) {
+        $e['module'] = 'civicrm-wci';
+      }
+      $entities[] = $e;
+    }
+  }
+}
+
+/**
+ * (Delegated) Implementation of hook_civicrm_caseTypes
+ *
+ * Find any and return any files matching "xml/case/*.xml"
+ *
+ * Note: This hook only runs in CiviCRM 4.4+.
+ *
+ * @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_caseTypes
+ */
+function _wci_civix_civicrm_caseTypes(&$caseTypes) {
+  if (!is_dir(__DIR__ . '/xml/case')) {
+    return;
+  }
+
+  foreach (_wci_civix_glob(__DIR__ . '/xml/case/*.xml') as $file) {
+    $name = preg_replace('/\.xml$/', '', basename($file));
+    if ($name != CRM_Case_XMLProcessor::mungeCaseType($name)) {
+      $errorMessage = sprintf("Case-type file name is malformed (%s vs %s)", $name, CRM_Case_XMLProcessor::mungeCaseType($name));
+      CRM_Core_Error::fatal($errorMessage);
+      // throw new CRM_Core_Exception($errorMessage);
+    }
+    $caseTypes[$name] = array(
+      'module' => 'civicrm-wci',
+      'name' => $name,
+      'file' => $file,
+    );
+  }
+}
+
+/**
+ * Glob wrapper which is guaranteed to return an array.
+ *
+ * The documentation for glob() says, "On some systems it is impossible to
+ * distinguish between empty match and an error." Anecdotally, the return
+ * result for an empty match is sometimes array() and sometimes FALSE.
+ * This wrapper provides consistency.
+ *
+ * @link http://php.net/glob
+ * @param string $pattern
+ * @return array, possibly empty
+ */
+function _wci_civix_glob($pattern) {
+  $result = glob($pattern);
+  return is_array($result) ? $result : array();
+}
+
+/**
+ * Inserts a navigation menu item at a given place in the hierarchy
+ *
+ * $menu - menu hierarchy
+ * $path - path where insertion should happen (ie. Administer/System Settings)
+ * $item - menu you need to insert (parent/child attributes will be filled for you)
+ * $parentId - used internally to recurse in the menu structure
+ */
+function _wci_civix_insert_navigation_menu(&$menu, $path, $item, $parentId = NULL) {
+  static $navId;
+
+  // If we are done going down the path, insert menu
+  if (empty($path)) {
+    if (!$navId) $navId = CRM_Core_DAO::singleValueQuery("SELECT max(id) FROM civicrm_navigation");
+    $navId ++;
+    $menu[$navId] = array (
+      'attributes' => array_merge($item, array(
+        'label'      => CRM_Utils_Array::value('name', $item),
+        'active'     => 1,
+        'parentID'   => $parentId,
+        'navID'      => $navId,
+      ))
+    );
+    return true;
+  } else {
+    // Find an recurse into the next level down
+    $found = false;
+    $path = explode('/', $path);
+    $first = array_shift($path);
+    foreach ($menu as $key => &$entry) {
+      if ($entry['attributes']['name'] == $first) {
+        if (!$entry['child']) $entry['child'] = array();
+        $found = _wci_civix_insert_navigation_menu($entry['child'], implode('/', $path), $item, $key);
+      }
+    }
+    return $found;
+  }
+}
+
+/**
+ * (Delegated) Implementation of hook_civicrm_alterSettingsFolders
+ *
+ * @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_alterSettingsFolders
+ */
+function _wci_civix_civicrm_alterSettingsFolders(&$metaDataFolders = NULL) {
+  static $configured = FALSE;
+  if ($configured) return;
+  $configured = TRUE;
+
+  $settingsDir = __DIR__ . DIRECTORY_SEPARATOR . 'settings';
+  if(is_dir($settingsDir) && !in_array($settingsDir, $metaDataFolders)) {
+    $metaDataFolders[] = $settingsDir;
+  }
+}
\ No newline at end of file
diff --git a/wci.php b/wci.php
new file mode 100644 (file)
index 0000000..c7cf938
--- /dev/null
+++ b/wci.php
@@ -0,0 +1,108 @@
+<?php
+
+require_once 'wci.civix.php';
+
+/**
+ * Implementation of hook_civicrm_config
+ *
+ * @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_config
+ */
+function wci_civicrm_config(&$config) {
+  _wci_civix_civicrm_config($config);
+}
+
+/**
+ * Implementation of hook_civicrm_xmlMenu
+ *
+ * @param $files array(string)
+ *
+ * @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_xmlMenu
+ */
+function wci_civicrm_xmlMenu(&$files) {
+  _wci_civix_civicrm_xmlMenu($files);
+}
+
+/**
+ * Implementation of hook_civicrm_install
+ *
+ * @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_install
+ */
+function wci_civicrm_install() {
+  return _wci_civix_civicrm_install();
+}
+
+/**
+ * Implementation of hook_civicrm_uninstall
+ *
+ * @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_uninstall
+ */
+function wci_civicrm_uninstall() {
+  return _wci_civix_civicrm_uninstall();
+}
+
+/**
+ * Implementation of hook_civicrm_enable
+ *
+ * @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_enable
+ */
+function wci_civicrm_enable() {
+  return _wci_civix_civicrm_enable();
+}
+
+/**
+ * Implementation of hook_civicrm_disable
+ *
+ * @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_disable
+ */
+function wci_civicrm_disable() {
+  return _wci_civix_civicrm_disable();
+}
+
+/**
+ * Implementation of hook_civicrm_upgrade
+ *
+ * @param $op string, the type of operation being performed; 'check' or 'enqueue'
+ * @param $queue CRM_Queue_Queue, (for 'enqueue') the modifiable list of pending up upgrade tasks
+ *
+ * @return mixed  based on op. for 'check', returns array(boolean) (TRUE if upgrades are pending)
+ *                for 'enqueue', returns void
+ *
+ * @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_upgrade
+ */
+function wci_civicrm_upgrade($op, CRM_Queue_Queue $queue = NULL) {
+  return _wci_civix_civicrm_upgrade($op, $queue);
+}
+
+/**
+ * Implementation of hook_civicrm_managed
+ *
+ * Generate a list of entities to create/deactivate/delete when this module
+ * is installed, disabled, uninstalled.
+ *
+ * @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_managed
+ */
+function wci_civicrm_managed(&$entities) {
+  return _wci_civix_civicrm_managed($entities);
+}
+
+/**
+ * Implementation of hook_civicrm_caseTypes
+ *
+ * Generate a list of case-types
+ *
+ * Note: This hook only runs in CiviCRM 4.4+.
+ *
+ * @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_caseTypes
+ */
+function wci_civicrm_caseTypes(&$caseTypes) {
+  _wci_civix_civicrm_caseTypes($caseTypes);
+}
+
+/**
+ * Implementation of hook_civicrm_alterSettingsFolders
+ *
+ * @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_alterSettingsFolders
+ */
+function wci_civicrm_alterSettingsFolders(&$metaDataFolders = NULL) {
+  _wci_civix_civicrm_alterSettingsFolders($metaDataFolders);
+}
diff --git a/xml/Menu/wci.xml b/xml/Menu/wci.xml
new file mode 100644 (file)
index 0000000..fe7787a
--- /dev/null
@@ -0,0 +1,15 @@
+<?xml version="1.0"?>
+<menu>
+  <item>
+    <path>civicrm/wci</path>
+    <page_callback>CRM_Wci_Page_WCIDashboard</page_callback>
+    <title>WCIDashboard</title>
+    <access_arguments>access CiviCRM</access_arguments>
+  </item>
+  <item>
+    <path>civicrm/wci/create-widget</path>
+    <page_callback>CRM_Wci_Form_CreateWidget</page_callback>
+    <title>CreateWidget</title>
+    <access_arguments>access CiviCRM</access_arguments>
+  </item>
+</menu>