--- /dev/null
+<?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;
+ }
+}
--- /dev/null
+<?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();
+ }
+}
--- /dev/null
+<?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;
+ } // */
+
+}
--- /dev/null
+<?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:
+ }
+ }
+}
--- /dev/null
+<?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>
--- /dev/null
+-- Installation mysql script
\ No newline at end of file
--- /dev/null
+-- Un installation mysql script
\ No newline at end of file
--- /dev/null
+{* 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>
--- /dev/null
+<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>
--- /dev/null
+<?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
--- /dev/null
+<?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);
+}
--- /dev/null
+<?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>