if (!array_key_exists($cfID, $this->_cfIDs)) {
$this->_cfIDs[$cfID] = array();
}
+ // Set wildcard value based on "and/or" selection
+ foreach ($this->_params as $key => $param) {
+ if ($param[0] == $value[0] . '_operator') {
+ $value[4] = $param[2] == 'or';
+ break;
+ }
+ }
$this->_cfIDs[$cfID][] = $value;
}
foreach ($fields['values'] as $field => $info) {
if (!empty($info['options']) || !empty($info['pseudoconstant']) || !empty($info['option_group_id'])) {
$options[$field] = $entity;
+ // Hack for when search field doesn't match db field - e.g. "country" instead of "country_id"
if (substr($field, -3) == '_id') {
$options[substr($field, 0, -3)] = $entity;
}
}
+ elseif (!empty($info['data_type']) && in_array($info['data_type'], array('StateProvince', 'Country'))) {
+ $options[$field] = $entity;
+ }
elseif (in_array(substr($field, 0, 3), array('is_', 'do_')) || CRM_Utils_Array::value('data_type', $info) == 'Boolean') {
$options[$field] = 'yesno';
if ($entity != 'contact') {
'style'
);
- if ($displayStyle === 'Tab with table' && $this->_multiRecordDisplay != 'single') {
+ if ($this->_multiRecordDisplay != 'single') {
$id = "custom_{$this->_groupId}";
$this->ajaxResponse['tabCount'] = CRM_Contact_BAO_Contact::getCountComponent($id, $this->_contactId, $groupTree[$this->_groupId]['table_name']);
+ }
+
+ if ($displayStyle === 'Tab with table' && $this->_multiRecordDisplay != 'single') {
$ctype = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact',
$this->_contactId,
'contact_type'
* @param CRM_Core_Form $qf form object (reference)
* @param string $elementName name of the custom field
* @param $fieldId
- * @param boolean $inactiveNeeded
+ * @param boolean $inactiveNeeded -deprecated
* @param bool $useRequired
* @param boolean $search true if used for search else false
* @param string $label label for custom field
$label = NULL
) {
$field = self::getFieldObject($fieldId);
+ $widget = $field->html_type;
// Custom field HTML should indicate group+field name
$groupName = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_CustomGroup', $field->custom_group_id);
$field->attributes .= $dataCrmCustomAttr;
// Fixed for Issue CRM-2183
- if ($field->html_type == 'TextArea' && $search) {
- $field->html_type = 'Text';
+ if ($widget == 'TextArea' && $search) {
+ $widget = 'Text';
+ }
+
+ if ($widget == 'Select State/Province' || $widget == 'Select Country') {
+ $qf->_stateCountryMap[$widget == 'Select Country' ? 'country' : 'state_province'][] = $elementName;
}
$placeholder = $search ? ts('- any -') : ($useRequired ? ts('- select -') : ts('- none -'));
// FIXME: Why are select state/country separate widget types?
- if (in_array($field->html_type, array('Select', 'Multi-Select', 'Select State/Province', 'Multi-Select State/Province', 'Select Country', 'Multi-Select Country'))) {
+ $isSelect = (in_array($widget, array('Select', 'Multi-Select', 'Select State/Province', 'Multi-Select State/Province', 'Select Country', 'Multi-Select Country', 'AdvMulti-Select', 'CheckBox', 'Radio')));
+
+ if ($isSelect) {
+ $options = CRM_Utils_Array::value('values', civicrm_api3('contact', 'getoptions', array('field' => "custom_$fieldId", 'context' => $search ? 'search' : 'create'), array()));
+
+ // Consolidate widget types to simplify the below switch statement
+ if ($search || ($widget !== 'AdvMulti-Select' && strpos($widget, 'Select') !== FALSE)) {
+ $widget = 'Select';
+ }
$selectAttributes = array(
'data-crm-custom' => $dataCrmCustomVal,
'class' => 'crm-select2',
);
- if (strpos($field->html_type, 'Multi') === 0) {
+ // Search field is always multi-select
+ if ($search || strpos($field->html_type, 'Multi') !== FALSE) {
+ $selectAttributes['class'] .= ' huge';
$selectAttributes['multiple'] = 'multiple';
+ $selectAttributes['placeholder'] = $placeholder;
+ }
+ // Add data for popup link. Normally this is handled by CRM_Core_Form->addSelect
+ if ($field->option_group_id && !$search && $widget == 'Select' && CRM_Core_Permission::check('administer CiviCRM')) {
+ $selectAttributes += array(
+ 'data-api-entity' => 'contact', // FIXME: This works because the getoptions api isn't picky about custom fields, but it's WRONG
+ 'data-api-field' => 'custom_' . $field->id,
+ 'data-option-edit-path' => 'civicrm/admin/options/' . CRM_Core_DAO::getFieldValue('CRM_Core_DAO_OptionGroup', $field->option_group_id),
+ );
}
- }
- // Add data so popup link. Normally this is handled by CRM_Core_Form->addSelect
- if ($field->option_group_id && !$search && in_array($field->html_type, array('Select', 'Multi-Select')) && CRM_Core_Permission::check('administer CiviCRM')) {
- $selectAttributes += array(
- 'data-api-entity' => 'contact', // FIXME: This works because the getoptions api isn't picky about custom fields, but it's WRONG
- 'data-api-field' => 'custom_' . $field->id,
- 'data-option-edit-path' => 'civicrm/admin/options/' . CRM_Core_DAO::getFieldValue('CRM_Core_DAO_OptionGroup', $field->option_group_id),
- );
}
if (!isset($label)) {
* at some point in time we might want to split the below into small functions
**/
- switch ($field->html_type) {
+ switch ($widget) {
case 'Text':
+ case 'Link':
if ($field->is_search_range && $search) {
$qf->add('text', $elementName . '_from', $label . ' ' . ts('From'), $field->attributes);
$qf->add('text', $elementName . '_to', ts('To'), $field->attributes);
}
else {
- $element = &$qf->add(strtolower($field->html_type), $elementName, $label,
+ $element = &$qf->add('text', $elementName, $label,
$field->attributes,
$useRequired && !$search
);
if ($field->text_length) {
$attributes .= ' maxlength=' . $field->text_length;
}
- $element = &$qf->add(strtolower($field->html_type),
+ $element = &$qf->add('textarea',
$elementName,
$label,
$attributes,
case 'Radio':
$choice = array();
- if ($field->data_type != 'Boolean') {
- $customOption = CRM_Core_BAO_CustomOption::valuesByID($field->id,
- $field->option_group_id
- );
- foreach ($customOption as $v => $l) {
- $choice[] = $qf->createElement('radio', NULL, '', $l, (string)$v, $field->attributes);
- }
- $group = $qf->addGroup($choice, $elementName, $label);
- }
- else {
- $choice[] = $qf->createElement('radio', NULL, '', ts('Yes'), '1', $field->attributes);
- $choice[] = $qf->createElement('radio', NULL, '', ts('No'), '0', $field->attributes);
- $group = $qf->addGroup($choice, $elementName, $label);
+ foreach ($options as $v => $l) {
+ $choice[] = $qf->createElement('radio', NULL, '', $l, (string)$v, $field->attributes);
}
+ $group = $qf->addGroup($choice, $elementName, $label);
if ($useRequired && !$search) {
$qf->addRule($elementName, ts('%1 is a required field.', array(1 => $label)), 'required');
}
}
break;
+ // For all select elements
case 'Select':
- $selectOption = CRM_Core_BAO_CustomOption::valuesByID($field->id,
- $field->option_group_id
- );
-
- $qf->add('select', $elementName, $label,
- array('' => $placeholder) + $selectOption,
- $useRequired && !$search,
- $selectAttributes
- );
- break;
+ if (empty($selectAttributes['multiple'])) {
+ $options = array('' => $placeholder) + $options;
+ }
+ $qf->add('select', $elementName, $label, $options, $useRequired && !$search, $selectAttributes);
- //added for select multiple
+ // Add and/or option for fields that store multiple values
+ if ($search && self::isSerialized($field)) {
- case 'AdvMulti-Select':
- $selectOption = CRM_Core_BAO_CustomOption::valuesByID($field->id,
- $field->option_group_id
- );
- if ($search &&
- count($selectOption) > 1
- ) {
- $selectOption['CiviCRM_OP_OR'] = ts('Select to match ANY; unselect to match ALL');
+ $operators = array(
+ $qf->createElement('radio', NULL, '', ts('Any'), 'or', array('title' => ts('Results may contain any of the selected options'))),
+ $qf->createElement('radio', NULL, '', ts('All'), 'and', array('title' => ts('Results must have all of the selected options'))),
+ );
+ $qf->addGroup($operators, $elementName . '_operator');
+ $qf->setDefaults(array($elementName . '_operator' => 'or'));
}
+ break;
+ case 'AdvMulti-Select':
$include =& $qf->addElement(
'advmultiselect',
$elementName,
- $label, $selectOption,
+ $label, $options,
array(
'size' => 5,
'style' => '',
}
break;
- case 'Multi-Select':
- $selectOption = CRM_Core_BAO_CustomOption::valuesByID($field->id,
- $field->option_group_id
- );
- if ($search &&
- count($selectOption) > 1
- ) {
- $selectOption['CiviCRM_OP_OR'] = ts('Select to match ANY; unselect to match ALL');
- }
- $qf->addElement('select', $elementName, $label, $selectOption, $selectAttributes);
-
- if ($useRequired && !$search) {
- $qf->addRule($elementName, ts('%1 is a required field.', array(1 => $label)), 'required');
- }
- break;
-
case 'CheckBox':
- $customOption = CRM_Core_BAO_CustomOption::valuesByID($field->id,
- $field->option_group_id
- );
$check = array();
- foreach ($customOption as $v => $l) {
+ foreach ($options as $v => $l) {
$check[] = &$qf->addElement('advcheckbox', $v, NULL, $l, array('data-crm-custom' => $dataCrmCustomVal));
}
- if ($search &&
- count($check) > 1
- ) {
- $check[] = &$qf->addElement('advcheckbox', 'CiviCRM_OP_OR', NULL, ts('Check to match ANY; uncheck to match ALL'), array('data-crm-custom' => $dataCrmCustomVal));
- }
$qf->addGroup($check, $elementName, $label);
if ($useRequired && !$search) {
$qf->addRule($elementName, ts('%1 is a required field.', array(1 => $label)), 'required');
$qf->addUploadElement($elementName);
break;
- case 'Select State/Province':
- //Add State
- $stateOption = array('' => $placeholder) + CRM_Core_PseudoConstant::stateProvince();
- $qf->add('select', $elementName, $label, $stateOption,
- $useRequired && !$search,
- $selectAttributes
- );
- $qf->_stateCountryMap['state_province'][] = $elementName;
- break;
-
- case 'Multi-Select State/Province':
- //Add Multi-select State/Province
- $stateOption = CRM_Core_PseudoConstant::stateProvince();
-
- $qf->addElement('select', $elementName, $label, $stateOption, $selectAttributes);
- if ($useRequired && !$search) {
- $qf->addRule($elementName, ts('%1 is a required field.', array(1 => $label)), 'required');
- }
- break;
-
- case 'Select Country':
- //Add Country
- $countryOption = array('' => $placeholder) + CRM_Core_PseudoConstant::country();
- $qf->add('select', $elementName, $label, $countryOption,
- $useRequired && !$search,
- $selectAttributes
- );
- $qf->_stateCountryMap['country'][] = $elementName;
- break;
-
- case 'Multi-Select Country':
- //Add Country
- $countryOption = CRM_Core_PseudoConstant::country();
- $qf->addElement('select', $elementName, $label, $countryOption, $selectAttributes);
- if ($useRequired && !$search) {
- $qf->addRule($elementName, ts('%1 is a required field.', array(1 => $label)), 'required');
- }
- break;
-
case 'RichTextEditor':
$attributes = array('rows' => $field->note_rows, 'cols' => $field->note_columns, 'data-crm-custom' => $dataCrmCustomVal);
if ($field->text_length) {
$attributes += array(
'entity' => 'option_value',
'placeholder' => $placeholder,
+ 'multiple' => $search,
'api' => array(
'params' => array('option_group_id' => $field->option_group_id),
),
$qf->addRule($elementName . '_from', ts('%1 From must be an integer (whole number).', array(1 => $label)), 'integer');
$qf->addRule($elementName . '_to', ts('%1 To must be an integer (whole number).', array(1 => $label)), 'integer');
}
- else {
+ elseif ($widget == 'Text') {
$qf->addRule($elementName, ts('%1 must be an integer (whole number).', array(1 => $label)), 'integer');
}
break;
$qf->addRule($elementName . '_from', ts('%1 From must be a number (with or without decimal point).', array(1 => $label)), 'numeric');
$qf->addRule($elementName . '_to', ts('%1 To must be a number (with or without decimal point).', array(1 => $label)), 'numeric');
}
- else {
+ elseif ($widget == 'Text') {
$qf->addRule($elementName, ts('%1 must be a number (with or without decimal point).', array(1 => $label)), 'numeric');
}
break;
$qf->addRule($elementName . '_from', ts('%1 From must in proper money format. (decimal point/comma/space is allowed).', array(1 => $label)), 'money');
$qf->addRule($elementName . '_to', ts('%1 To must in proper money format. (decimal point/comma/space is allowed).', array(1 => $label)), 'money');
}
- else {
+ elseif ($widget == 'Text') {
$qf->addRule($elementName, ts('%1 must be in proper money format. (decimal point/comma/space is allowed).', array(1 => $label)), 'money');
}
break;
case 'Link':
- $qf->add(
- 'text',
- $elementName,
- $label,
- array(
- 'onfocus' => "if (!this.value) { this.value='http://';} else return false",
- 'onblur' => "if ( this.value == 'http://') { this.value='';} else return false",
- 'data-crm-custom' => $dataCrmCustomVal,
- ),
- $useRequired && !$search
- );
+ $element->setAttribute('onfocus', "if (!this.value) {this.value='http://';}");
+ $element->setAttribute('onblur', "if (this.value == 'http://') {this.value='';}");
+ $element->setAttribute('class', "url");
$qf->addRule($elementName, ts('Enter a valid Website.'), 'wikiURL');
break;
}
$v = array();
$p = array();
foreach ($checkedData as $key => $val) {
- if ($key === 'CiviCRM_OP_OR') {
- continue;
- }
-
if ($html_type == 'CheckBox') {
if ($val) {
$p[] = $key;
return $isMultipleWithGid;
}
+
+ /**
+ * Does this field store a serialized string?
+ * @param CRM_Core_DAO_CustomField|array $field
+ * @return bool
+ */
+ static function isSerialized($field) {
+ // Fields retrieved via api are an array, or from the dao are an object. We'll accept either.
+ $field = (array) $field;
+ // FIXME: Currently the only way to know if data is serialized is by looking at the html_type. It would be cleaner to decouple this.
+ return ($field['html_type'] == 'CheckBox' || strpos($field['html_type'], 'Multi') !== FALSE);
+ }
}
if (!isset($group['fields'])) {
continue;
}
- $groupId = CRM_Utils_Array::value('id', $group);
foreach ($group['fields'] as $field) {
if (CRM_Utils_Array::value('element_value', $field) !== NULL) {
$value = $field['element_value'];
continue;
}
- $fieldId = $field['id'];
if (!empty($field['element_name'])) {
$elementName = $field['element_name'];
}
foreach ($values as $tuple) {
list($name, $op, $value, $grouping, $wildcard) = $tuple;
- // fix $value here to escape sql injection attacks
$field = $this->_fields[$id];
- $qillValue = CRM_Core_BAO_CustomField::getDisplayValue($value, $id, $this->_options);
+ $fieldName = "{$field['table_name']}.{$field['column_name']}";
+
+ // Autocomplete comes back as a string not an array
+ if ($field['data_type'] == 'String' && $field['html_type'] == 'Autocomplete-Select' && $op == '=') {
+ $value = explode(',', $value);
+ }
+
+ // Handle multi-select search for any data type
+ if (is_array($value) && !$field['is_search_range']) {
+ $isSerialized = CRM_Core_BAO_CustomField::isSerialized($field);
+ $wildcard = $isSerialized ? $wildcard : TRUE;
+ $options = CRM_Utils_Array::value('values', civicrm_api3('contact', 'getoptions', array('field' => $name, 'context' => 'search'), array()));
+ $qillValue = '';
+ $sqlOP = $wildcard ? ' OR ' : ' AND ';
+ $sqlValue = array();
+ foreach ($value as $num => &$v) {
+ $sep = count($value) > (1 + $num) ? ', ' : (' ' . ($wildcard ? ts('OR') : ts('AND')) . ' ');
+ $qillValue .= ($num ? $sep : '') . $options[$v];
+ $v = CRM_Core_DAO::escapeString($v);
+ if ($isSerialized) {
+ $sqlValue[] = "( $fieldName like '%" . CRM_Core_DAO::VALUE_SEPARATOR . $v . CRM_Core_DAO::VALUE_SEPARATOR . "%' ) ";
+ }
+ else {
+ $v = "'$v'";
+ }
+ }
+ if (!$isSerialized) {
+ $sqlValue = array("$fieldName IN (" . implode(',', $value) . ")");
+ }
+ $this->_where[$grouping][] = ' ( ' . implode($sqlOP, $sqlValue) . ' ) ';
+ $this->_qill[$grouping][] = "$field[label] $op $qillValue";
+ continue;
+ }
+
+ // fix $value here to escape sql injection attacks
if (!is_array($value)) {
$value = CRM_Core_DAO::escapeString(trim($value));
}
- $fieldName = "{$field['table_name']}.{$field['column_name']}";
+ $qillValue = CRM_Core_BAO_CustomField::getDisplayValue($value, $id, $this->_options);
+
switch ($field['data_type']) {
case 'String':
$sql = "$fieldName";
- // if we are coming in from listings,
- // for checkboxes the value is already in the right format and is NOT an array
- if (is_array($value)) {
-
- //ignoring $op value for checkbox and multi select
- $sqlValue = array();
- $sqlOP = ' AND ';
- $sqlOPlabel = ts('match ALL');
- if ($field['html_type'] == 'CheckBox') {
- foreach ($value as $k => $v) {
- if ($v) {
- if ($k == 'CiviCRM_OP_OR') {
- $sqlOP = ' OR ';
- $sqlOPlabel = ts('match ANY');
- continue;
- }
-
- $sqlValue[] = "( $sql like '%" . CRM_Core_DAO::VALUE_SEPARATOR . $k . CRM_Core_DAO::VALUE_SEPARATOR . "%' ) ";
- }
- }
- //if user check only 'CiviCRM_OP_OR' check box
- //of custom checkbox field, then ignore this field.
- if (!empty($sqlValue)) {
- $this->_where[$grouping][] = ' ( ' . implode($sqlOP, $sqlValue) . ' ) ';
- $this->_qill[$grouping][] = "{$field['label']} $op $qillValue ( $sqlOPlabel )";
- }
- // for multi select
- }
- else {
- foreach ($value as $k => $v) {
- if ($v == 'CiviCRM_OP_OR') {
- $sqlOP = ' OR ';
- $sqlOPlabel = ts('match ANY');
- continue;
- }
- $v = CRM_Core_DAO::escapeString($v);
- $sqlValue[] = "( $sql like '%" . CRM_Core_DAO::VALUE_SEPARATOR . $v . CRM_Core_DAO::VALUE_SEPARATOR . "%' ) ";
- }
- //if user select only 'CiviCRM_OP_OR' value
- //of custom multi select field, then ignore this field.
- if (!empty($sqlValue)) {
- $this->_where[$grouping][] = ' ( ' . implode($sqlOP, $sqlValue) . ' ) ';
- $this->_qill[$grouping][] = "$field[label] $op $qillValue ( $sqlOPlabel )";
- }
- }
+
+ if ($field['is_search_range'] && is_array($value)) {
+ $this->searchRange($field['id'],
+ $field['label'],
+ $field['data_type'],
+ $fieldName,
+ $value,
+ $grouping
+ );
}
else {
- if ($field['is_search_range'] && is_array($value)) {
- $this->searchRange($field['id'],
- $field['label'],
- $field['data_type'],
- $fieldName,
- $value,
- $grouping
- );
- }
- else {
- if (in_array($field['html_type'], array('Select', 'Radio', 'Autocomplete-Select'))) {
- $wildcard = FALSE;
- $val = CRM_Utils_Type::escape($value, 'String');
- }
- else {
- $val = CRM_Utils_Type::escape($strtolower(trim($value)), 'String');
- }
-
- if ($wildcard) {
- $val = $strtolower(CRM_Core_DAO::escapeString($val));
- $val = "%$val%";
- $op = 'LIKE';
- }
-
- //FIX for custom data query fired against no value(NULL/NOT NULL)
- $this->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause($sql, $op, $val, $field['data_type']);
- $this->_qill[$grouping][] = "$field[label] $op $qillValue";
+ $val = CRM_Utils_Type::escape($strtolower(trim($value)), 'String');
+
+ if ($wildcard) {
+ $val = $strtolower(CRM_Core_DAO::escapeString($val));
+ $val = "%$val%";
+ $op = 'LIKE';
}
+
+ //FIX for custom data query fired against no value(NULL/NOT NULL)
+ $this->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause($sql, $op, $val, $field['data_type']);
+ $this->_qill[$grouping][] = "$field[label] $op $qillValue";
}
- continue;
+ break;
case 'ContactReference':
$label = $value ? CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $value, 'sort_name') : '';
$this->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause($fieldName, $op, $value, 'String');
$this->_qill[$grouping][] = $field['label'] . " $op $label";
- continue;
+ break;
case 'Int':
if ($field['is_search_range'] && is_array($value)) {
$this->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause($fieldName, $op, $value, 'Integer');
$this->_qill[$grouping][] = $field['label'] . " $op $value";
}
- continue;
+ break;
case 'Boolean':
if (strtolower($value) == 'yes' || strtolower($value) == strtolower(ts('Yes'))) {
$this->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause($fieldName, $op, $value, 'Integer');
$value = $value ? ts('Yes') : ts('No');
$this->_qill[$grouping][] = $field['label'] . " {$op} {$value}";
- continue;
+ break;
case 'Link':
$this->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause($fieldName, $op, $value, 'String');
$this->_qill[$grouping][] = $field['label'] . " $op $value";
- continue;
+ break;
case 'Float':
if ($field['is_search_range'] && is_array($value)) {
$this->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause($fieldName, $op, $value, 'Float');
$this->_qill[$grouping][] = $field['label'] . " {$op} {$value}";
}
- continue;
+ break;
case 'Money':
if ($field['is_search_range'] && is_array($value)) {
$this->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause($fieldName, $op, $value, 'Float');
$this->_qill[$grouping][] = $field['label'] . " {$op} {$value}";
}
- continue;
+ break;
case 'Memo':
$this->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause($fieldName, $op, $value, 'String');
$this->_qill[$grouping][] = "$field[label] $op $value";
- continue;
+ break;
case 'Date':
$fromValue = CRM_Utils_Array::value('from', $value);
$this->_qill[$grouping][] = $field['label'] . ' <= ' . CRM_Utils_Date::customFormat($toDate);
}
}
- continue;
+ break;
case 'StateProvince':
case 'Country':
- if (!is_array($value)) {
- $this->_where[$grouping][] = "$fieldName {$op} " . CRM_Utils_Type::escape($value, 'Int');
- $this->_qill[$grouping][] = $field['label'] . " {$op} {$qillValue}";
- }
- else {
- $sqlOP = ' AND ';
- $sqlOPlabel = ts('match ALL');
- foreach ($value as $k => $v) {
- if ($v == 'CiviCRM_OP_OR') {
- $sqlOP = ' OR ';
- $sqlOPlabel = ts('match ANY');
- continue;
- }
- $sqlValue[] = "( $fieldName like '%" . CRM_Core_DAO::VALUE_SEPARATOR . $v . CRM_Core_DAO::VALUE_SEPARATOR . "%' ) ";
- }
-
- //if user select only 'CiviCRM_OP_OR' value
- //of custom multi select field, then ignore this field.
- if (!empty($sqlValue)) {
- $this->_where[$grouping][] = " ( " . implode($sqlOP, $sqlValue) . " ) ";
- $this->_qill[$grouping][] = "$field[label] $op $qillValue ( $sqlOPlabel )";
- }
- }
- continue;
+ $this->_where[$grouping][] = "$fieldName {$op} " . CRM_Utils_Type::escape($value, 'Int');
+ $this->_qill[$grouping][] = $field['label'] . " {$op} {$qillValue}";
+ break;
case 'File':
if ( $op == 'IS NULL' || $op == 'IS NOT NULL' || $op == 'IS EMPTY' || $op == 'IS NOT EMPTY' ) {
$this->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause($fieldName, $op);
$this->_qill[$grouping][] = $field['label'] . " {$op} ";
}
- continue;
+ break;
}
}
}
}
/**
+ * Build a nested array from hierarchical tags. Supports infinite levels of nesting.
* @param null $usedFor
* @param bool $excludeHidden
*/
function buildTree($usedFor = NULL, $excludeHidden = FALSE) {
- $sql = "SELECT civicrm_tag.id, civicrm_tag.parent_id,civicrm_tag.name FROM civicrm_tag ";
+ $sql = "SELECT id, parent_id, name, description FROM civicrm_tag";
$whereClause = array();
if ($usedFor) {
$dao = CRM_Core_DAO::executeQuery($sql, CRM_Core_DAO::$_nullArray, TRUE, NULL, FALSE, FALSE);
- $orphan = array();
+ $refs = array();
while ($dao->fetch()) {
+ $thisref = &$refs[$dao->id];
+
+ $thisref['parent_id'] = $dao->parent_id;
+ $thisref['name'] = $dao->name;
+ $thisref['description'] = $dao->description;
+
if (!$dao->parent_id) {
- $this->tree[$dao->id]['name'] = $dao->name;
+ $this->tree[$dao->id] = &$thisref;
}
else {
- if (array_key_exists($dao->parent_id, $this->tree)) {
- $parent = &$this->tree[$dao->parent_id];
- if (!isset($this->tree[$dao->parent_id]['children'])) {
- $this->tree[$dao->parent_id]['children'] = array();
- }
- }
- else {
- //3rd level tag
- if (!array_key_exists($dao->parent_id, $orphan)) {
- $orphan[$dao->parent_id] = array('children' => array());
- }
- $parent = &$orphan[$dao->parent_id];
- }
- $parent['children'][$dao->id] = array('name' => $dao->name);
+ $refs[$dao->parent_id]['children'][$dao->id] = &$thisref;
}
}
- if (sizeof($orphan)) {
- //hang the 3rd level lists at the right place
- foreach ($this->tree as & $level1) {
- if (!isset($level1['children'])) {
- continue;
- }
- foreach ($level1['children'] as $key => & $level2) {
- if (array_key_exists($key, $orphan)) {
- $level2['children'] = $orphan[$key]['children'];
- }
- }
- }
- }
}
/**
foreach ($this->_fields as $name => $field) {
if ((substr($name, 0, 6) == 'custom') && !empty($field['is_search_range'])) {
- $from = CRM_Utils_Request::retrieve($name . '_from', 'String',
- $this, FALSE, NULL, 'REQUEST'
- );
- $to = CRM_Utils_Request::retrieve($name . '_to', 'String',
- $this, FALSE, NULL, 'REQUEST'
- );
+ $from = CRM_Utils_Request::retrieve($name . '_from', 'String', $this);
+ $to = CRM_Utils_Request::retrieve($name . '_to', 'String', $this);
$value = array();
if ($from && $to) {
$value['from'] = $from;
if (!is_array($value)) {
$value = trim($value);
}
+ $operator = CRM_Utils_Request::retrieve($name . '_operator', 'String', $this);
+ if ($operator) {
+ $this->_params[$name . '_operator'] = $operator;
+ }
$this->_params[$name] = $this->_fields[$name]['value'] = $value;
}
}
* @return bool
*/
public function isRedirectSupported() {
- return (ini_get('open_basedir') == '') && (ini_get('safe_mode') == 'Off' || ini_get('safe_mode') === FALSE);
+ return (ini_get('open_basedir') == '') && (ini_get('safe_mode') == 'Off' || ini_get('safe_mode') == '' || ini_get('safe_mode') === FALSE);
}
}
--- /dev/null
+<?php
+namespace Civi\CiUtil;
+
+class Arrays {
+ static function collect($arr, $col) {
+ $r = array();
+ foreach ($arr as $k => $item) {
+ $r[$k] = $item[$col];
+ }
+ return $r;
+ }
+}
\ No newline at end of file
--- /dev/null
+<?php
+namespace Civi\CiUtil\Command;
+
+class AntagonistCommand {
+ static function main($argv) {
+ if (count($argv) != 3) {
+ print "usage: {$argv[0]} <TargetTest::testFunc> </path/to/suite>\n";
+ exit(1);
+ }
+ list ($program, $target, $suite) = $argv;
+
+ $candidateTests = \Civi\CiUtil\PHPUnitScanner::findTestsByPath(array($suite));
+// $candidateTests = array(
+// array('class' => 'CRM_Core_RegionTest', 'method' => 'testBlank'),
+// array('class' => 'CRM_Core_RegionTest', 'method' => 'testDefault'),
+// array('class' => 'CRM_Core_RegionTest', 'method' => 'testOverride'),
+// array('class' => 'CRM_Core_RegionTest', 'method' => 'testAllTypes'),
+// );
+ $antagonist = self::findAntagonist($target, $candidateTests);
+ if ($antagonist) {
+ print_r(array('found an antagonist' => $antagonist));
+ }
+ else {
+ print_r(array('found no antagonists'));
+ }
+ }
+
+ /**
+ * @param string $target e.g. "MyTest::testFoo"
+ * @param array $candidateTests list of strings (e.g. "MyTest::testFoo")
+ * @return array|null array contains keys:
+ * - antagonist: array
+ * - file: string
+ * - class: string
+ * - method: string
+ * - expectedResults: array
+ * - actualResults: array
+ */
+ static function findAntagonist($target, $candidateTests) {
+ //$phpUnit = new \Civi\CiUtil\EnvTestRunner('./scripts/phpunit', 'EnvTests');
+ $phpUnit = new \Civi\CiUtil\EnvTestRunner('phpunit', 'tests/phpunit/EnvTests.php');
+ $expectedResults = $phpUnit->run(array($target));
+ print_r(array('$expectedResults' => $expectedResults));
+
+ foreach ($candidateTests as $candidateTest) {
+ $candidateTestName = $candidateTest['class'] . '::' . $candidateTest['method'];
+ if ($candidateTestName == $target) {
+ continue;
+ }
+ $actualResults = $phpUnit->run(array(
+ $candidateTestName,
+ $target,
+ ));
+ print_r(array('$actualResults' => $actualResults));
+ foreach ($expectedResults as $testName => $expectedResult) {
+ if ($actualResults[$testName] != $expectedResult) {
+ return array(
+ 'antagonist' => $candidateTest,
+ 'expectedResults' => $expectedResults,
+ 'actualResults' => $actualResults,
+ );
+ }
+ }
+ }
+ return NULL;
+ }
+}
\ No newline at end of file
--- /dev/null
+<?php
+namespace Civi\CiUtil\Command;
+
+class CompareCommand {
+ static function main($argv) {
+ if (empty($argv[1])) {
+ echo "summary: Compares the output of different test runs\n";
+ echo "usage: phpunit-compare <json-file1> [<json-file2>...]\n";
+ exit(1);
+ }
+
+
+ $suites = array(); // array('file' => string, 'results' => array)
+ for ($i = 1; $i < count($argv); $i++) {
+ $suites[$i] = array(
+ 'file' => $argv[$i],
+ 'results' => \Civi\CiUtil\PHPUnitParser::parseJsonResults(file_get_contents($argv[$i]))
+ );
+ }
+
+ $tests = array(); // array(string $name)
+ foreach ($suites as $suiteName => $suite) {
+ $tests = array_unique(array_merge(
+ $tests,
+ array_keys($suite['results'])
+ ));
+ }
+ sort($tests);
+
+ $printer = new \Civi\CiUtil\ComparisonPrinter(\Civi\CiUtil\Arrays::collect($suites, 'file'));
+ foreach ($tests as $test) {
+ $values = array();
+ foreach ($suites as $suiteName => $suite) {
+ $values[] = isset($suite['results'][$test]) ? $suite['results'][$test] : 'MISSING';
+ }
+
+ if (count(array_unique($values)) > 1) {
+ $printer->printRow($test, $values);
+ }
+ }
+ }
+}
--- /dev/null
+<?php
+namespace Civi\CiUtil\Command;
+
+class LsCommand {
+ static function main($argv) {
+ $paths = $argv;
+ array_shift($paths);
+ foreach (\Civi\CiUtil\PHPUnitScanner::findTestsByPath($paths) as $test) {
+ printf("%s %s %s\n", $test['file'], $test['class'], $test['method']);
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+<?php
+namespace Civi\CiUtil;
+
+class ComparisonPrinter {
+ var $headers;
+ var $hasHeader = FALSE;
+
+ function __construct($headers) {
+ $this->headers = $headers;
+ }
+
+ function printHeader() {
+ if ($this->hasHeader) {
+ return;
+ }
+
+ ## LEGEND
+ print "LEGEND\n";
+ $i = 1;
+ foreach ($this->headers as $header) {
+ printf("% 2d: %s\n", $i, $header);
+ $i++;
+ }
+ print "\n";
+
+ ## HEADER
+ printf("%-90s ", 'TEST NAME');
+ $i = 1;
+ foreach ($this->headers as $header) {
+ printf("%-10d ", $i);
+ $i++;
+ }
+ print "\n";
+
+ $this->hasHeader = TRUE;
+ }
+
+ function printRow($test, $values) {
+ $this->printHeader();
+ printf("%-90s ", $test);
+ foreach ($values as $value) {
+ printf("%-10s ", $value);
+ }
+ print "\n";
+ }
+}
\ No newline at end of file
--- /dev/null
+<?php
+namespace Civi\CiUtil;
+
+/**
+ * Parse phpunit result files
+ */
+class EnvTestRunner {
+ protected $phpunit;
+ protected $envTestSuite;
+
+ function __construct($phpunit = "phpunit", $envTestSuite = 'EnvTests') {
+ $this->phpunit = $phpunit;
+ $this->envTestSuite = $envTestSuite;
+ }
+
+ /**
+ * @param array $tests
+ * @return array (string $testName => string $status)
+ */
+ public function run($tests) {
+ $envTests = implode(' ', $tests);
+ $jsonFile = tempnam(sys_get_temp_dir(), 'phpunit-json-');
+ unlink($jsonFile);
+ $command = "env PHPUNIT_TESTS=\"$envTests\" {$this->phpunit} --log-json $jsonFile {$this->envTestSuite}";
+ echo "Running [$command]\n";
+ system($command);
+ $results = PHPUnitParser::parseJsonResults(file_get_contents($jsonFile));
+ unlink($jsonFile);
+ return $results;
+ }
+}
\ No newline at end of file
--- /dev/null
+<?php
+namespace Civi\CiUtil;
+
+/**
+ * Parse phpunit result files
+ */
+class PHPUnitParser {
+ /**
+ * @param string $content phpunit streaming JSON
+ * @return array(string "$class::$func" => $status)
+ */
+ protected static function parseJsonStream($content) {
+ $content = '['
+ . strtr($content, array("}{" => "},{"))
+ . ']';
+ return json_decode($content, TRUE);
+ }
+
+ /**
+ * @param string $content json stream
+ * @return array (string $testName => string $status)
+ */
+ public static function parseJsonResults($content) {
+ $records = self::parseJsonStream($content);
+ $results = array();
+ foreach ($records as $r) {
+ if ($r['event'] == 'test') {
+ $results[$r['test']] = $r['status'];
+ }
+ }
+ return $results;
+ }
+
+}
\ No newline at end of file
--- /dev/null
+<?php
+namespace Civi\CiUtil;
+use Symfony\Component\Finder\Finder;
+
+/**
+ * Search for PHPUnit test cases
+ */
+class PHPUnitScanner {
+ /**
+ * @return array<string> class names
+ */
+ static function _findTestClasses($path) {
+// print_r(array(
+// 'loading' => $path,
+// get_included_files()
+// ));
+
+ $origClasses = get_declared_classes();
+ require_once $path;
+ $newClasses = get_declared_classes();
+
+ return preg_grep('/Test$/', array_diff(
+ $newClasses,
+ $origClasses
+ ));
+ }
+
+ /**
+ * @return array (string $file => string $class)
+ */
+ static function findTestClasses($paths) {
+ $testClasses = array();
+ $finder = new Finder();
+
+ foreach ($paths as $path) {
+ if (is_dir($path)) {
+ foreach ($finder->files()->in($paths)->name('*Test.php') as $file) {
+ $testClass = self::_findTestClasses((string) $file);
+ if (count($testClass) == 1) {
+ $testClasses[(string) $file] = array_shift($testClass);
+ }
+ elseif (count($testClass) > 1) {
+ throw new \Exception("Too many classes in $file");
+ }
+ else {
+ throw new \Exception("Too few classes in $file");
+ }
+ }
+ }
+ elseif (is_file($path)) {
+ $testClass = self::_findTestClasses($path);
+ if (count($testClass) == 1) {
+ $testClasses[$path] = array_shift($testClass);
+ }
+ elseif (count($testClass) > 1) {
+ throw new \Exception("Too many classes in $path");
+ }
+ else {
+ throw new \Exception("Too few classes in $path");
+ }
+ }
+ }
+
+ return $testClasses;
+ }
+
+ /**
+ * @param array $testClasses
+ * @return array each element is an array with keys:
+ * - file: string
+ * - class: string
+ * - method: string
+ */
+ static function findTestsByPath($paths) {
+ $r = array();
+ $testClasses = self::findTestClasses($paths);
+ foreach ($testClasses as $testFile => $testClass) {
+ $clazz = new \ReflectionClass($testClass);
+ foreach ($clazz->getMethods() as $method) {
+ if (preg_match('/^test/', $method->name)) {
+ $r[] = array(
+ 'file' => $testFile,
+ 'class' => $testClass,
+ 'method' => $method->name
+ );
+ }
+ }
+ }
+ return $r;
+ }
+}
\ No newline at end of file
#crm-container input.submit-link {
color: #285286;
- background-color: transparent;
+ background: none transparent;
border: none;
cursor: pointer;
- cursor: hand;
margin: 0em -0.5em 0em -0.5em;
+ text-shadow: none;
}
.crm-container .underline-effect {
opacity: .7;
position: relative;
top: 2px;
+ padding: 0;
}
div.crm-accordion-header a.helpicon {
}
};
+ $scope.isValidName = function(name) {
+ return !name || name.match(/^[a-zA-Z0-9_]+$/);
+ };
+
$scope.getWorkflowName = function(activitySet) {
var result = 'Unknown';
_.each($scope.workflows, function(value, key) {
name="caseTypeName"
ng-model="caseType.name"
ng-disabled="locks.caseTypeName"
- ng-pattern="/^[a-zA-Z0-9_]+$/"
required
class="big crm-form-text"/>
<a crm-ui-lock binding="locks.caseTypeName"></a>
+ <div ng-show="!isValidName(caseType.name)">
+ <em>WARNING: The case type name includes deprecated characters.</em>
+ </div>
<div ng-show="caseType.id && !locks.caseTypeName">
<em>WARNING: If any external files or programs reference the old "Name", then they must be updated manually.</em>
</div>
{/foreach}
{/foreach}
<div id="case_custom_edit"></div>
-
-{*currently delete is available only for tab custom data*}
-{if $groupId}
-<script type="text/javascript">
- {literal}
- function hideStatus(valueID, groupID) {
- cj('#statusmessg_' + groupID + '_' + valueID).hide( );
- }
-
- function showDelete(valueID, elementID, groupID, contactID) {
- var confirmMsg = '{/literal}{ts escape='js'}Are you sure you want to delete this record?{/ts}{literal} <a href="#" onclick="deleteCustomValue( ' + valueID + ',\'' + elementID + '\',' + groupID + ',' + contactID + ' ); return false;" style="text-decoration: underline;">{/literal}{ts escape='js'}Yes{/ts}{literal}</a> <a href="#" onclick="hideStatus( ' + valueID + ', ' + groupID + ' ); return false;" style="text-decoration: underline;">{/literal}{ts escape='js'}No{/ts}{literal}</a>';
- cj('tr#statusmessg_' + groupID + '_' + valueID).show( ).children().find('span').html( confirmMsg );
- }
-
- function deleteCustomValue( valueID, elementID, groupID, contactID ) {
- var postUrl = {/literal}"{crmURL p='civicrm/ajax/customvalue' h=0 }"{literal};
- var request = cj.ajax({
- type: "POST",
- data: "valueID=" + valueID + "&groupID=" + groupID +"&contactId=" + contactID + "&key={/literal}{crmKey name='civicrm/ajax/customvalue'}{literal}",
- url: postUrl,
- success: function(html){
- cj('#'+ elementID).hide();
- hideStatus(valueID, groupID);
- var element = cj( '.ui-tabs-nav #tab_custom_' + groupID + ' a' );
- cj(element).html(cj(element).attr('title') + ' ('+ html+') ');
- }
- });
- CRM.status({success: '{/literal}{ts escape="js"}Record Deleted{/ts}{literal}'}, request);
- }
- {/literal}
-</script>
-{/if}
-
<script type="text/javascript" >
CRM.$(function($) {
+ var $form = $("#{/literal}{$form.formName}{literal}");
var action = "{/literal}{$action}{literal}";
$('.crm-accordion-body').each( function() {
return true;
});
{/literal}{/if}{literal}
+
+ // Handle delete of multi-record custom data
+ $form.on('click', '.crm-custom-value-del', function(e) {
+ e.preventDefault();
+ var $el = $(this),
+ msg = '{/literal}{ts escape="js"}The record will be deleted immediately. This action cannot be undone.{/ts}{literal}';
+ CRM.confirm({title: $el.attr('title'), message: msg})
+ .on('crmConfirm:yes', function() {
+ var url = CRM.url('civicrm/ajax/customvalue');
+ var request = $.post(url, $el.data('post'));
+ CRM.status({success: '{/literal}{ts escape="js"}Record Deleted{/ts}{literal}'}, request);
+ var addClass = '.add-more-link-' + $el.data('post').groupID;
+ $el.closest('div.crm-custom-accordion').remove();
+ $('div' + addClass).last().show();
+ });
+ });
});
</script>
+--------------------------------------------------------------------+
*}
-<script type="text/javascript">var showTab = Array();</script>
{foreach from=$groupTree item=cd_edit key=group_id}
{if $cd_edit.is_multiple eq 1}
{assign var=tableID value=$cd_edit.table_id}
{assign var=divName value=$group_id|cat:"_$tableID"}
<div></div>
- <div id="{$cd_edit.name|cat:'_$divName'}"
+ <div
class="crm-accordion-wrapper crm-custom-accordion {if $cd_edit.collapse_display and !$skipTitle}collapsed{/if}">
{else}
<div id="{$cd_edit.name}"
{if $cd_edit.is_multiple eq 1}
{if $cd_edit.table_id}
<table class="no-border">
- <tr id="statusmessg_{$group_id|cat:"_$tableID"}" class="hiddenElement">
- <td><span class="success-status"></span></td>
- </tr>
<tr>
- <div class="crm-submit-buttons">
- <a href="#"
- onclick="showDelete( {$tableID}, '{$cd_edit.name}_{$group_id|cat:"_$tableID"}', {$group_id}, {$contactId} ); return false;"
- class="button delete-button" title="{ts 1=$cv_edit.title}Delete this %1 record{/ts}">
- <span><div class="icon delete-icon"></div>{ts}Delete{/ts}</span>
- </a>
- </div>
+ <a href="#" class="crm-hover-button crm-custom-value-del" title="{ts 1=$cd_edit.title}Delete %1{/ts}"
+ data-post='{ldelim}"valueID": "{$tableID}", "groupID": "{$group_id}", "contactId": "{$contactId}", "key": "{crmKey name='civicrm/ajax/customvalue'}"{rdelim}'>
+ <span class="icon delete-icon"></span> {ts}Delete{/ts}
+ </a>
<!-- crm-submit-buttons -->
</tr>
</table>
{/foreach}
{include file="CRM/common/customData.tpl"}
- <script type="text/javascript">
- {literal}
-
- function hideStatus(valueID, groupID) {
- cj('#statusmessg_' + groupID + '_' + valueID).hide();
- }
-
- function showDelete(valueID, elementID, groupID, contactID) {
- var confirmMsg = '{/literal}{ts escape='js'}Are you sure you want to delete this record?{/ts}{literal} <a href="#" onclick="deleteCustomValue( ' + valueID + ',\'' + elementID + '\',' + groupID + ',' + contactID + ' ); return false;" style="text-decoration: underline;">{/literal}{ts escape='js'}Yes{/ts}{literal}</a> <a href="#" onclick="hideStatus( ' + valueID + ', ' + groupID + ' ); return false;" style="text-decoration: underline;">{/literal}{ts escape='js'}No{/ts}{literal}</a>';
- cj('tr#statusmessg_' + groupID + '_' + valueID).show().children().find('span').html(confirmMsg);
- }
-
- function deleteCustomValue(valueID, elementID, groupID, contactID) {
- var postUrl = {/literal}"{crmURL p='civicrm/ajax/customvalue' h=0 }"{literal},
- request = cj.ajax({
- type: "POST",
- data: "valueID=" + valueID + "&groupID=" + groupID + "&contactId=" + contactID + "&key={/literal}{crmKey name='civicrm/ajax/customvalue'}{literal}",
- url: postUrl,
- success: function (html) {
- cj('#' + elementID).hide();
- hideStatus(valueID, groupID);
- var element = cj('.ui-tabs-nav #tab_custom_' + groupID + ' a');
- cj(element).html(cj(element).attr('title') + ' (' + html + ') ');
- }
- });
- CRM.status({success: '{/literal}{ts escape="js"}Record Deleted{/ts}{literal}'}, request);
- }
-
- {/literal}
- </script>
{include file="CRM/Form/attachmentjs.tpl"}
{include file="CRM/common/formButtons.tpl" location="top" buttonStyle="width:80px; text-align:center;"}
</div>
<div class="crm-submit-buttons reset-advanced-search">
- <a href="{crmURL p='civicrm/contact/search/advanced' q='reset=1'}" id="resetAdvancedSearch" class="button" style="width:70px; text-align:center;"><span>{ts}Reset Form{/ts}</span></a>
+ <a href="{crmURL p='civicrm/contact/search/advanced' q='reset=1'}" id="resetAdvancedSearch" class="crm-hover-button" title="{ts}Clear all search criteria{/ts}">
+ <span class="icon ui-icon-circle-close"></span>
+ {ts}Reset Form{/ts}
+ </a>
</div>
</td>
</tr>
<div class="messages help">{$cd_edit.help_post}</div>
{/if}
{if $cd_edit.is_multiple and ( ( $cd_edit.max_multiple eq '' ) or ( $cd_edit.max_multiple > 0 and $cd_edit.max_multiple > $cgCount ) ) }
- <div id="add-more-link-{$cgCount}" class="add-more-link-{$group_id}-{$cgCount}"><a href="#" onclick="CRM.buildCustomData('{$cd_edit.extends}',{if $cd_edit.subtype}'{$cd_edit.subtype}'{else}'{$cd_edit.extends_entity_column_id}'{/if}, '', {$cgCount}, {$group_id}, true ); return false;">{ts 1=$cd_edit.title}Add another %1 record{/ts}</a></div>
+ <div id="add-more-link-{$cgCount}" class="add-more-link-{$group_id} add-more-link-{$group_id}-{$cgCount}">
+ <a href="#" class="crm-hover-button" onclick="CRM.buildCustomData('{$cd_edit.extends}',{if $cd_edit.subtype}'{$cd_edit.subtype}'{else}'{$cd_edit.extends_entity_column_id}'{/if}, '', {$cgCount}, {$group_id}, true ); return false;">
+ <span class="icon ui-icon-circle-plus"></span>
+ {ts 1=$cd_edit.title}Another %1 record{/ts}
+ </a>
+ </div>
{/if}
{else}
{foreach from=$groupTree item=cd_edit key=group_id name=custom_sets}
<div class="custom-group custom-group-{$cd_edit.name} crm-accordion-wrapper {if $cd_edit.collapse_display and !$skipTitle}collapsed{/if}">
{if !$skipTitle}
<div class="crm-accordion-header">
- {$cd_edit.title}
+ {$cd_edit.title} {$cgCount}
</div><!-- /.crm-accordion-header -->
{/if}
<div class="crm-accordion-body">
<em>{ts 1=$cd_edit.title}Click "Edit Contact" to add more %1 records{/ts}</em>
</div>
{else}
- <div id="add-more-link-{$cgCount}"><a href="#" onclick="CRM.buildCustomData('{$cd_edit.extends}',{if $cd_edit.subtype}'{$cd_edit.subtype}'{else}'{$cd_edit.extends_entity_column_id}'{/if}, '', {$cgCount}, {$group_id}, true ); return false;">{ts 1=$cd_edit.title}Add another %1 record{/ts}</a></div>
+ <div id="add-more-link-{$cgCount}">
+ <a href="#" class="crm-hover-button" onclick="CRM.buildCustomData('{$cd_edit.extends}',{if $cd_edit.subtype}'{$cd_edit.subtype}'{else}'{$cd_edit.extends_entity_column_id}'{/if}, '', {$cgCount}, {$group_id}, true ); return false;">
+ <span class="icon ui-icon-circle-plus"></span>
+ {ts 1=$cd_edit.title}Another %1 record{/ts}
+ </a>
+ </div>
{/if}
{/if}
{/if}
--- /dev/null
+{*
+ +--------------------------------------------------------------------+
+ | CiviCRM version 4.5 |
+ +--------------------------------------------------------------------+
+ | Copyright CiviCRM LLC (c) 2004-2014 |
+ +--------------------------------------------------------------------+
+ | This file is a part of CiviCRM. |
+ | |
+ | CiviCRM is free software; you can copy, modify, and distribute it |
+ | under the terms of the GNU Affero General Public License |
+ | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
+ | |
+ | CiviCRM is distributed in the hope that it will be useful, but |
+ | WITHOUT ANY WARRANTY; without even the implied warranty of |
+ | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
+ | See the GNU Affero General Public License for more details. |
+ | |
+ | You should have received a copy of the GNU Affero General Public |
+ | License and the CiviCRM Licensing Exception along |
+ | with this program; if not, contact CiviCRM LLC |
+ | at info[AT]civicrm[DOT]org. If you have questions about the |
+ | GNU Affero General Public License or the licensing of CiviCRM, |
+ | see the CiviCRM license FAQ at http://civicrm.org/licensing |
+ +--------------------------------------------------------------------+
+*}
+{literal}
+ <script type="text/javascript">
+ CRM.$(function($) {
+ function showHideOperator() {
+ var val = $(this).val();
+ $(this).siblings("span.crm-multivalue-search-op").toggle(!!(val && val.length > 1));
+ }
+ $("span.crm-multivalue-search-op").siblings('select')
+ .off('.crmMultiValue')
+ .on('change.crmMultiValue', showHideOperator)
+ .each(showHideOperator);
+ });
+ </script>
+{/literal}
<div class="crm-accordion-body">
<table class="form-layout-compressed">
{foreach from=$cd_edit.fields item=element key=field_id}
- {assign var="element_name" value='custom_'|cat:$field_id}
- {if $element.options_per_line != 0}
- <tr>
- <td class="label">{$form.$element_name.label}</td>
- <td>
- {assign var="count" value="1"}
- {strip}
- <table class="form-layout-compressed">
- <tr>
- {* sort by fails for option per line. Added a variable to iterate through the element array*}
- {assign var="index" value="1"}
- {foreach name=outer key=key item=item from=$form.$element_name}
- {if $index < 10} {* Hack to skip QF field properties that are not checkbox elements. *}
- {assign var="index" value=`$index+1`}
- {else}
- {if $element.html_type EQ 'CheckBox' AND $smarty.foreach.outer.last EQ 1} {* Put 'match ANY / match ALL' checkbox in separate row. *}
- </tr>
- <tr>
- <td class="op-checkbox" colspan="{$element.options_per_line}" style="padding-top: 0px;">{$form.$element_name.$key.html}</td>
- {else}
- <td class="labels font-light">{$form.$element_name.$key.html}</td>
- {if $count EQ $element.options_per_line}
- </tr>
- <tr>
- {assign var="count" value="1"}
- {else}
- {assign var="count" value=`$count+1`}
- {/if}
- {/if}
- {/if}
- {/foreach}
- </tr>
- </table>
- {/strip}
- </td>
- </tr>
- {else}
{assign var="type" value=`$element.html_type`}
{assign var="element_name" value='custom_'|cat:$field_id}
+ {assign var="operator_name" value='custom_'|cat:$field_id|cat:'_operator'}
{if $element.is_search_range}
{assign var="element_name_from" value=$element_name|cat:"_from"}
{assign var="element_name_to" value=$element_name|cat:"_to"}
{elseif $element.skip_calendar NEQ true }
{include file="CRM/common/jcalendar.tpl" elementName=$element_name}
{/if}
+ {if !empty($form.$operator_name)}
+ <span class="crm-multivalue-search-op" for="{$element_name}">{$form.$operator_name.html}</span>
+ {assign var="add_multivalue_js" value=true}
+ {/if}
{/if}
{if $element.html_type eq 'Autocomplete-Select'}
{if $element.data_type eq 'ContactReference'}
{/if}
</td>
</tr>
- {/if}
{/foreach}
</table>
</div><!-- /.crm-accordion-body -->
</div><!-- /.crm-accordion-wrapper -->
{/foreach}
+ {if !empty($add_multivalue_js)}
+ {include file="CRM/Custom/Form/MultiValueSearch.js.tpl"}
+ {/if}
{/if}
*}
{* Custom Data view mode*}
{assign var="showEdit" value=1}
+{assign var="rowCount" value=1}
{foreach from=$viewCustomData item=customValues key=customGroupId}
{foreach from=$customValues item=cd_edit key=cvID}
{if $multiRecordDisplay neq 'single'}
<div class="crm-accordion-wrapper {if $cd_edit.collapse_display eq 0 or $skipTitle} {else}collapsed{/if}">
{if !$skipTitle}
<div class="crm-accordion-header">
- {$cd_edit.title}
+ {$cd_edit.title} {$rowCount}
</div>
{/if}
<div class="crm-accordion-body">
{if $groupId and $cvID and $editCustomData}
<div class="crm-submit-buttons">
- <a href="#"
- onclick="showDelete( {$cvID}, '{$cd_edit.name}_{$index}', {$customGroupId}, {$contactId} ); return false;"
- class="button delete-button" title="{ts 1=$cd_edit.title}Delete this %1 record{/ts}">
- <span><div class="icon delete-icon"></div>{ts}Delete{/ts}</span>
+ <a href="#" class="crm-hover-button crm-custom-value-del"
+ data-post='{ldelim}"valueID": "{$cvID}", "groupID": "{$customGroupId}", "contactId": "{$contactId}", "key": "{crmKey name='civicrm/ajax/customvalue'}"{rdelim}'
+ title="{ts 1=$cd_edit.title|cat:" `$rowCount`"}Delete %1{/ts}">
+ <span class="icon delete-icon"></span> {ts}Delete{/ts}
</a>
</div>
{/if}
</tr>
</table>
{/foreach}
+ {assign var="rowCount" value=$rowCount+1}
</div>
<!-- end of body -->
<div class="clear"></div>
{if $groupId}
<script type="text/javascript">
{literal}
- function hideStatus(valueID, groupID) {
- cj('#statusmessg_' + groupID + '_' + valueID).hide();
- }
- function showDelete(valueID, elementID, groupID, contactID) {
- var confirmMsg = '{/literal}{ts escape='js'}Are you sure you want to delete this record?{/ts}{literal} <a href="#" onclick="deleteCustomValue( ' + valueID + ',\'' + elementID + '\',' + groupID + ',' + contactID + ' ); return false;" style="text-decoration: underline;">{/literal}{ts escape='js'}Yes{/ts}{literal}</a> <a href="#" onclick="hideStatus( ' + valueID + ', ' + groupID + ' ); return false;" style="text-decoration: underline;">{/literal}{ts escape='js'}No{/ts}{literal}</a>';
- cj('tr#statusmessg_' + groupID + '_' + valueID).show().children().find('span').html(confirmMsg);
- }
- function deleteCustomValue(valueID, elementID, groupID, contactID) {
- var postUrl = {/literal}"{crmURL p='civicrm/ajax/customvalue' h=0 }"{literal},
- request = cj.ajax({
- type: "POST",
- data: "valueID=" + valueID + "&groupID=" + groupID + "&contactId=" + contactID + "&key={/literal}{crmKey name='civicrm/ajax/customvalue'}{literal}",
- url: postUrl,
- success: function (html) {
- cj('#' + elementID).hide();
- hideStatus(valueID, groupID);
- var element = cj('.ui-tabs-nav #tab_custom_' + groupID + ' a');
- cj(element).html(cj(element).attr('title') + ' (' + html + ') ');
- }
+ CRM.$(function($) {
+ // Handle delete of multi-record custom data
+ $('#crm-container')
+ .off('.customValueDel')
+ .on('click.customValueDel', '.crm-custom-value-del', function(e) {
+ e.preventDefault();
+ var $el = $(this),
+ msg = '{/literal}{ts escape="js"}The record will be deleted immediately. This action cannot be undone.{/ts}{literal}';
+ CRM.confirm({title: $el.attr('title'), message: msg})
+ .on('crmConfirm:yes', function() {
+ var url = CRM.url('civicrm/ajax/customvalue');
+ var request = $.post(url, $el.data('post'))
+ .done(CRM.refreshParent($el));
+ CRM.status({success: '{/literal}{ts escape="js"}Record Deleted{/ts}{literal}'}, request);
+ });
+ });
});
- CRM.status({success: '{/literal}{ts escape="js"}Record Deleted{/ts}{literal}'}, request);
- }
{/literal}
</script>
{/if}
{continue}
{/if}
{assign var=n value=$field.name}
+ {assign var="operator_name" value=$n|cat:'_operator'}
{if $field.is_search_range}
{assign var=from value=$field.name|cat:'_from'}
{assign var=to value=$field.name|cat:'_to'}
{$form.$to.label} {include file="CRM/common/jcalendar.tpl" elementName=$to}</td>
</tr>
{/if}
- {elseif $field.options_per_line}
- <tr>
- <td class="option-label">{$form.$n.label}</td>
- <td>
- {assign var="count" value="1"}
- {strip}
- <table class="form-layout-compressed">
- <tr>
- {* sort by fails for option per line. Added a variable to iterate through the element array*}
- {assign var="index" value="1"}
- {foreach name=outer key=key item=item from=$form.$n}
- {if $index < 10} {* Hack to skip QF field properties that are not checkbox elements. *}
- {assign var="index" value=`$index+1`}
- {else}
- {if $field.html_type EQ 'CheckBox' AND $smarty.foreach.outer.last EQ 1} {* Put 'match ANY / match ALL' checkbox in separate row. *}
- </tr>
- <tr>
- <td class="op-checkbox" colspan="{$field.options_per_line}" style="padding-top: 0px;">{$form.$n.$key.html}</td>
- {else}
- <td class="labels font-light">{$form.$n.$key.html}</td>
- {if $count EQ $field.options_per_line}
- </tr>
- <tr>
- {assign var="count" value="1"}
- {else}
- {assign var="count" value=`$count+1`}
- {/if}
- {/if}
- {/if}
- {/foreach}
- </tr>
- </table>
- {/strip}
- </td>
- </tr>
{else}
<tr>
<td class="label">
{else}
{$form.$n.html}
{/if}
- {if $field.html_type eq 'Autocomplete-Select'}
- {if $field.data_type eq 'ContactReference'}
- {include file="CRM/Custom/Form/ContactReference.tpl" element_name = $n}
- {/if}
+ {if $field.html_type eq 'Autocomplete-Select' and $field.data_type eq 'ContactReference'}
+ {include file="CRM/Custom/Form/ContactReference.tpl" element_name = $n}
+ {/if}
+ {if !empty($form.$operator_name)}
+ <span class="crm-multivalue-search-op" for="{$n}">{$form.$operator_name.html}</span>
+ {assign var="add_multivalue_js" value=true}
{/if}
</td>
{/if}
});
</script>
{/literal}
+
+{if !empty($add_multivalue_js)}
+ {include file="CRM/Custom/Form/MultiValueSearch.js.tpl"}
+{/if}
#tagtree .highlighted > label {
background-color: #FEFD7B;
}
+ #tagtree .helpicon ins {
+ display: none;
+ }
+ #tagtree ins.jstree-icon {
+ cursor: pointer;
+ }
</style>
<script type="text/javascript">
(function($, _){{/literal}
//load js tree.
$("#tagtree").jstree({
- "plugins" : ["themes", "html_data"],
- "themes": {"url": CRM.config.resourceBase + 'packages/jquery/plugins/jstree/themes/default/style.css'}
+ plugins : ["themes", "html_data"],
+ themes: {
+ "theme": 'classic',
+ "dots": false,
+ "icons": false,
+ "url": CRM.config.resourceBase + 'packages/jquery/plugins/jstree/themes/classic/style.css'
+ }
});
{/literal}
<div id="Tag" class="view-content">
<h3>{if !$hideContext}{ts}Tags{/ts}{/if}</h3>
<div id="tagtree">
- <ul class="tree">
- {foreach from=$tree item="node" key="id"}
- <li id="tag_{$id}">
- {if ! $node.children}<input name="tagList[{$id}]" id="check_{$id}" type="checkbox" {if $tagged[$id]}checked="checked"{/if}/>{/if}
- {if $node.children}<input name="tagList[{$id}]" id="check_{$id}" type="checkbox" {if $tagged[$id]}checked="checked"{/if}/>{/if}
- {if $node.children} <span class="hit"></span> {/if} <label for="check_{$id}" id="tagLabel_{$id}">{$node.name}</label>
- {if $node.children}
- <ul>
- {foreach from=$node.children item="subnode" key="subid"}
- <li id="tag_{$subid}">
- <input id="check_{$subid}" name="tagList[{$subid}]" type="checkbox" {if $tagged[$subid]}checked="checked"{/if}/>
- {if $subnode.children} <span class="hit"></span> {/if} <label for="check_{$subid}" id="tagLabel_{$subid}">{$subnode.name}</label>
- {if $subnode.children}
- <ul>
- {foreach from=$subnode.children item="subsubnode" key="subsubid"}
- <li id="tag_{$subsubid}">
- <input id="check_{$subsubid}" name="tagList[{$subsubid}]" type="checkbox" {if $tagged[$subsubid]}checked="checked"{/if}/>
- <label for="check_{$subsubid}" id="tagLabel_{$subsubid}">{$subsubnode.name}</label>
- </li>
- {/foreach}
- </ul>
- {/if}
- </li>
- {/foreach}
- </ul>
- {/if}
- </li>
- {/foreach}
- </ul>
+ {include file="CRM/Tag/Form/Tagtree.tpl"}
</div>
<br />
{include file="CRM/common/Tagset.tpl"}
--- /dev/null
+{*
+ +--------------------------------------------------------------------+
+ | CiviCRM version 4.5 |
+ +--------------------------------------------------------------------+
+ | Copyright CiviCRM LLC (c) 2004-2014 |
+ +--------------------------------------------------------------------+
+ | This file is a part of CiviCRM. |
+ | |
+ | CiviCRM is free software; you can copy, modify, and distribute it |
+ | under the terms of the GNU Affero General Public License |
+ | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
+ | |
+ | CiviCRM is distributed in the hope that it will be useful, but |
+ | WITHOUT ANY WARRANTY; without even the implied warranty of |
+ | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
+ | See the GNU Affero General Public License for more details. |
+ | |
+ | You should have received a copy of the GNU Affero General Public |
+ | License and the CiviCRM Licensing Exception along |
+ | with this program; if not, contact CiviCRM LLC |
+ | at info[AT]civicrm[DOT]org. If you have questions about the |
+ | GNU Affero General Public License or the licensing of CiviCRM, |
+ | see the CiviCRM license FAQ at http://civicrm.org/licensing |
+ +--------------------------------------------------------------------+
+*}
+
+{htxt id=$id}
+ {crmAPI var='result' entity='tag' action='getsingle' return="description" id=$id}
+ {$result.description}
+{/htxt}
--- /dev/null
+{*
+ +--------------------------------------------------------------------+
+ | CiviCRM version 4.5 |
+ +--------------------------------------------------------------------+
+ | Copyright CiviCRM LLC (c) 2004-2014 |
+ +--------------------------------------------------------------------+
+ | This file is a part of CiviCRM. |
+ | |
+ | CiviCRM is free software; you can copy, modify, and distribute it |
+ | under the terms of the GNU Affero General Public License |
+ | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
+ | |
+ | CiviCRM is distributed in the hope that it will be useful, but |
+ | WITHOUT ANY WARRANTY; without even the implied warranty of |
+ | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
+ | See the GNU Affero General Public License for more details. |
+ | |
+ | You should have received a copy of the GNU Affero General Public |
+ | License and the CiviCRM Licensing Exception along |
+ | with this program; if not, contact CiviCRM LLC |
+ | at info[AT]civicrm[DOT]org. If you have questions about the |
+ | GNU Affero General Public License or the licensing of CiviCRM, |
+ | see the CiviCRM license FAQ at http://civicrm.org/licensing |
+ +--------------------------------------------------------------------+
+*}
+{* This tpl runs recursively to build each level of the tag tree *}
+<ul>
+ {foreach from=$tree item="node" key="id"}
+ <li id="tag_{$id}">
+ <input name="tagList[{$id}]" id="check_{$id}" type="checkbox" {if $tagged[$id]}checked="checked"{/if}/>
+ <label for="check_{$id}" id="tagLabel_{$id}">
+ {$node.name}
+ {if $node.description}{help id=$id title=$node.name file="CRM/Tag/Form/Tagtree"}{/if}
+ </label>
+ {if $node.children}
+ {* Recurse... *}
+ {include file="CRM/Tag/Form/Tagtree.tpl" tree=$node.children}
+ {/if}
+ </li>
+ {/foreach}
+</ul>
*/
require_once 'CiviTest/CiviSeleniumTestCase.php';
-require_once 'WebTest/Event/AddEventTest.php';
/**
* Class WebTest_Event_PCPAddTest
/**
* Class WebTest_Import_SavedMapping
*/
-class WebTest_Import_SavedMapping extends ImportCiviSeleniumTestCase {
+class WebTest_Import_SavedMappingTest extends ImportCiviSeleniumTestCase {
protected function setUp() {
parent::setUp();
$this->webtestVerifyTabularData($expected);
}
+ function testStandaloneGiftMembership() {
+
+ $this->webtestLogin();
+
+ // create contact
+ $firstName = substr(sha1(rand()), 0, 7);
+ $this->webtestAddContact($firstName, "Memberson", "Memberson{$firstName}@memberson.name");
+ $contactName = "Memberson, $firstName";
+
+ $giftMemberfirstName = substr(sha1(rand()), 0, 7);
+ $this->webtestAddContact($giftMemberfirstName, "Memberson", "Memberson{$giftMemberfirstName}@memberson.name");
+ $giftMembercontactName = "Memberson, $giftMemberfirstName";
+
+ // add membership type
+ $membershipTypes = $this->webtestAddMembershipType();
+
+ // now add membership
+ $this->openCiviPage("member/add", "reset=1&action=add&context=standalone", "_qf_Membership_upload");
+
+ // select contact
+ $this->webtestFillAutocomplete($firstName);
+
+ // fill in Membership Organization
+ $this->select("membership_type_id[0]", "label={$membershipTypes['member_of_contact']}");
+
+ // select membership type
+ $this->select("membership_type_id[1]", "label={$membershipTypes['membership_type']}");
+
+ // fill in Source
+ $this->type("source", "Membership StandaloneAddTest Webtest");
+
+ // fill in Start Date
+ $this->webtestFillDate('start_date');
+
+ // add softcredit details
+ $totalAmount = 100;
+ $financialType = 'Donation';
+ $this->clickLink('is_different_contribution_contact','total_amount',FALSE);
+
+ $this->select('soft_credit_type_id', 'Gift');
+ $this->select2('soft_credit_contact_id', $giftMembercontactName);
+ $this->select('financial_type_id','Donation');
+ $this->type('total_amount', $totalAmount);
+ $this->select('payment_instrument_id', 'Check');
+ $this->select('contribution_status_id', 'Completed');
+
+ $this->click("_qf_Membership_upload");
+
+ //View Membership
+ $this->waitForElementPresent("xpath=//div[@id='memberships']//table//tbody/tr[1]/td[9]/span/a[text()='View']");
+ $this->click("xpath=//div[@id='memberships']//table/tbody/tr[1]/td[9]/span/a[text()='View']");
+ $this->waitForElementPresent("_qf_MembershipView_cancel-bottom");
+
+ // verify soft credit data
+ $expected = array(
+ '1' => $giftMemberfirstName.' Memberson',
+ '2' => $totalAmount,
+ '3' => 'Gift',
+ '4' => 'Donation',
+ '6' => 'Completed',
+ );
+
+ foreach($expected as $key => $value) {
+ $this->verifyText("xpath=//div[@class='crm-accordion-wrapper']//table/tbody//tr/td[$key]", $value);
+ }
+
+ }
+
function testStandaloneMemberOverrideAdd() {
$this->webtestLogin();
--- /dev/null
+#!/bin/bash
+####################################################################
+function show_help() {
+ echo "Jeanine Matthews - Divergent Hunter"
+ echo "summary: Execute test suite in multiple ways and compare results"
+ echo "usage: env [var1=... var2=...] $0 [--bundled-full|--bf] [--bundled-indiv|--bi] [--standalone-full|--sf] [--standalone-indiv|--si] [--compare]"
+ echo "Optional variables:"
+ echo " - CIVI: Path to Civi installation [$CIVI]"
+ echo " - PHP: Path to PHP binary [$PHP]"
+ echo " - PHPUNIT: Path to phpunit binary [$PHPUNIT]"
+ echo " - TESTCLASS: PHP class name for the test case/suite [$TESTCLASS]"
+ echo " - TESTPATH: Path for the test file/directory (Note: MUST match TESTCLASS) [$TESTPATH]"
+ echo " - OUTDIR: Folder to which outputs are written [$OUTDIR]"
+}
+
+function reset_dir() {
+ [ -d "$1" ] && rm -rf "$1"
+ mkdir -p "$1"
+}
+
+####################################################################
+## Env
+export PHP=${PHP:-php}
+export PHPUNIT=${PHPUNIT:-phpunit}
+export TESTCLASS=${TESTCLASS:-api_v3_AllTests}
+export TESTPATH=${TESTPATH:-tests/phpunit/api/v3}
+export CIVI=$(realpath "${CIVI:-.}")
+export OUTDIR=$(realpath "${OUTDIR:-output}")
+
+####################################################################
+## Main
+if [ -z "$1" ];then
+ show_help
+ exit 1
+fi
+
+while [ -n "$1" ]; do
+ OPTION="$1"
+ shift
+
+ case "$OPTION" in
+ --bundled-full|--bf)
+ echo "[[ Prepare $OUTDIR/bundled-full ]]"
+
+ [ -d "packages/PHPUnit.bak" ] && mv "packages/PHPUnit.bak" "packages/PHPUnit"
+ if [ ! -d "$CIVI/packages/PHPUnit" ]; then
+ echo "Missing $CIVI/packages/PHPUnit"
+ exit 2
+ fi
+
+ reset_dir "$OUTDIR/bundled-full"
+
+ pushd "$CIVI/tools"
+ $PHP ./scripts/phpunit --tap --log-json "$OUTDIR/bundled-full/all.json" "$TESTCLASS"
+ popd
+ ;;
+
+ --bundled-indiv|--bi)
+ echo "[[ Prepare $OUTDIR/bundled-indiv ]]"
+
+ [ -d "packages/PHPUnit.bak" ] && mv "packages/PHPUnit.bak" "packages/PHPUnit"
+ if [ ! -d "$CIVI/packages/PHPUnit" ]; then
+ echo "Missing $CIVI/packages/PHPUnit"
+ exit 2
+ fi
+
+ reset_dir "$OUTDIR/bundled-indiv"
+
+ pushd "$CIVI/tools"
+ ./scripts/phpunit-indiv --civi --test-dir "../$TESTPATH" --json-dir "$OUTDIR/bundled-indiv"
+ popd
+
+ cat "$OUTDIR"/bundled-indiv/*-*.json > "$OUTDIR/bundled-indiv/all.json"
+ ;;
+
+ --standalone-full|--sf)
+ echo "[[ Prepare $OUTDIR/standalone-full ]]"
+ reset_dir "$OUTDIR/standalone-full"
+
+ pushd "$CIVI"
+ [ -d "packages/PHPUnit" ] && mv "packages/PHPUnit" "packages/PHPUnit.bak"
+ $PHP $(which $PHPUNIT) --tap --log-json "$OUTDIR/standalone-full/all.json" "$TESTPATH"
+ [ -d "packages/PHPUnit.bak" ] && mv "packages/PHPUnit.bak" "packages/PHPUnit"
+ popd
+ ;;
+
+ --standalone-indiv|--si)
+ echo "[[ Prepare $OUTDIR/standalone-indiv ]]"
+ reset_dir "$OUTDIR/standalone-indiv"
+
+ pushd "$CIVI"
+ [ -d "packages/PHPUnit" ] && mv "packages/PHPUnit" "packages/PHPUnit.bak"
+ ./tools/scripts/phpunit-indiv --test-dir "$TESTPATH" --json-dir "$OUTDIR/standalone-indiv"
+ [ -d "packages/PHPUnit.bak" ] && mv "packages/PHPUnit.bak" "packages/PHPUnit"
+ popd
+
+ cat "$OUTDIR"/standalone-indiv/*-*.json > "$OUTDIR/standalone-indiv/all.json"
+ ;;
+
+ --compare)
+ echo "[[ Compare all results in $OUTDIR ]]"
+ phpunit-compare "$OUTDIR"/*/all.json
+ ;;
+ esac
+done
--- /dev/null
+#!/usr/bin/env php
+<?php
+require_once dirname(dirname(__DIR__)) . '/tests/phpunit/CiviTest/bootstrap.php';
+\Civi\CiUtil\Command\AntagonistCommand::main($argv);
--- /dev/null
+#!/usr/bin/env php
+<?php
+require_once dirname(dirname(__DIR__)) . '/tests/phpunit/CiviTest/bootstrap.php';
+\Civi\CiUtil\Command\CompareCommand::main($argv);
--- /dev/null
+#!/bin/bash
+function absdirname() {
+ pushd $(dirname $0) >> /dev/null
+ pwd
+ popd >> /dev/null
+}
+
+BINDIR=$(absdirname "$0")
+PHP=${PHP:-php}
+PHPUNIT=${PHPUNIT:-phpunit}
+MODE=standalone
+XMLDIR=
+JSONDIR=
+
+while [ -n "$1" ]; do
+ ARG="$1"
+ shift
+
+ case "$ARG" in
+ --civi)
+ MODE=civi
+ ;;
+ --test-dir)
+ TESTSUITE="$1"
+ shift
+ ;;
+ --json-dir)
+ JSONDIR="$1"
+ [ ! -d "$JSONDIR" ] && mkdir -p "$JSONDIR"
+ shift
+ ;;
+ --xml-dir)
+ XMLDIR="$1"
+ [ ! -d "$XMLDIR" ] && mkdir -p "$XMLDIR"
+ shift
+ ;;
+ *)
+ echo "unrecognized option: $ARG"
+ ;;
+ esac
+done
+
+
+if [ -z "$TESTSUITE" ]; then
+ echo "summary: Executes all tests in a suite (individually)"
+ echo "usage: $0 --test-dir <dir> [--json-dir <dir>] [--xml-dir <dir>] [--civi]"
+ exit 1
+fi
+
+
+#phpunit-ls "$TESTSUITE"
+$BINDIR/phpunit-ls "$TESTSUITE" | while read FILE CLASS METHOD ; do
+ PHPUNITARGS="--tap"
+ if [ -n "$JSONDIR" ]; then
+ PHPUNITARGS="$PHPUNITARGS --log-json $JSONDIR/$CLASS-$METHOD.json"
+ fi
+ if [ -n "$XMLDIR" ]; then
+ PHPUNITARGS="$PHPUNITARGS --log-junit $XMLDIR/$CLASS-$METHOD.xml"
+ fi
+
+
+ if [ "$MODE" == "civi" ]; then
+ $PHP ./scripts/phpunit $PHPUNITARGS --filter $METHOD'( with.*)?$' "$CLASS"
+ fi
+ if [ "$MODE" == "standalone" ]; then
+ $PHP $(which $PHPUNIT) $PHPUNITARGS --filter $METHOD'( with.*)?$' "$FILE"
+ fi
+done
--- /dev/null
+#!/usr/bin/env php
+<?php
+require_once dirname(dirname(__DIR__)) . '/tests/phpunit/CiviTest/bootstrap.php';
+error_reporting(E_ALL);
+\Civi\CiUtil\Command\LsCommand::main($argv);
\ No newline at end of file
+++ /dev/null
-#!/bin/bash
-
-SELF=$(cd $(dirname $0); pwd -P)/$(basename $0)
-
-case $1 in
-
- stable-3.4)
-
- echo
- echo §§§§§§§§§§§§§§§§§§§§ EXECUTING TESTS FOR STABLE
- echo
-
- echo
- echo §§§§§§§§§§§§§§§§§§§§ Updating Selenium tests repository
- echo
- cd /var/www/drupal6.dev.civicrm.org/public/sites/devel.drupal6.tests.dev.civicrm.org/modules/civicrm/
- find . -name *~ -delete
- svn up
- echo §§§§§§§§§§§§§§§§§§§§ ...done.
-
- echo
- echo §§§§§§§§§§§§§§§§§§§§ Resetting Selenium tests database and template files
- echo
- rm -rf /tmp/templates_c/
- cd /var/www/drupal6.dev.civicrm.org/public/sites/devel.drupal6.tests.dev.civicrm.org/modules/civicrm/bin
- ./setup.sh
- rm -rf /var/www/drupal6.dev.civicrm.org/public/sites/devel.drupal6.tests.dev.civicrm.org/files/civicrm/
- chmod -R 777 /var/www/drupal6.dev.civicrm.org/public/sites/devel.drupal6.tests.dev.civicrm.org/files/
-
- echo §§§§§§§§§§§§§§§§§§§§ ...done.
- echo
-
- CODE_DIR="/home/tests/stable-suite"
-
- echo
- echo §§§§§§§§§§§§§§§§§§§§ Running test suite
- echo
-
- rm -rf /tmp/templates_c/
-
- for testName in api_v2 api_v3 CRM WebTest; do
- cd $CODE_DIR/tools
- scripts/phpunit --tap --log-junit tests/reports/logfile.$testName.xml -u tests -ptests -h localhost ${testName}_AllTests
- cd $CODE_DIR/tools/scripts/
-
- echo
- echo §§§§§§§§§§§§§§§§§§§§ Generating test results.
- echo
- phing $testName
- echo §§§§§§§§§§§§§§§§§§§§ All finished.
- done
-
- ;;
-
- stable)
-
- echo
- echo §§§§§§§§§§§§§§§§§§§§ EXECUTING TESTS FOR TRUNK
- echo
-
- echo
- echo §§§§§§§§§§§§§§§§§§§§ Updating test suite repository
- echo
- cd /var/www/drupal7.dev.civicrm.org/public/sites/stable.drupal7.tests.dev.civicrm.org/modules/civicrm/
- find . -name *~ -delete
- svn up
- echo §§§§§§§§§§§§§§§§§§§§ ...done.
-
- echo
- echo §§§§§§§§§§§§§§§§§§§§ Resetting Selenium tests database and template files
- echo
- rm -rf /tmp/templates_c/
- cd /var/www/drupal7.dev.civicrm.org/public/sites/stable.drupal7.tests.dev.civicrm.org/modules/civicrm/bin
- ./setup.sh
-
- echo §§§§§§§§§§§§§§§§§§§§ ...done.
-
- rm -rf /var/www/drupal7.dev.civicrm.org/public/sites/stable.drupal7.tests.dev.civicrm.org/files/civicrm/
- chmod -R 777 /var/www/drupal7.dev.civicrm.org/public/sites/stable.drupal7.tests.dev.civicrm.org/files/
-
- CODE_DIR="/home/tests/stable-suite"
-
- echo
- echo §§§§§§§§§§§§§§§§§§§§ Running test suite
- echo
-
-# for testName in api_v3; do
-# for testName in WebTest; do
-# for testName in api_v3 CRM; do
- for testName in api_v3 CRM WebTest; do
-# for testName in CRM; do
- cd $CODE_DIR/tools
-
- rm -rf /tmp/templates_c/
-
- #reset the db before running webtest
- if [ $testName == WebTest ] ; then
- echo
- echo ============== reloading db for Webtest ===============================
- echo
- /var/www/drupal7.dev.civicrm.org/public/sites/stable.drupal7.tests.dev.civicrm.org/modules/civicrm/bin/setup.sh
- fi
-
- scripts/phpunit --tap --log-junit tests/reports/logfile.$testName.xml -u tests -ptests -bstable_drupal7_tests_dev_civicrm -h localhost ${testName}_AllTests
- cd $CODE_DIR/tools/scripts/
-
- echo
- echo §§§§§§§§§§§§§§§§§§§§ Generating test results.
- echo
- phing $testName
- echo §§§§§§§§§§§§§§§§§§§§ All finished.
- done
-
- ;;
-
- trunk)
-
- echo
- echo §§§§§§§§§§§§§§§§§§§§ EXECUTING TESTS FOR TRUNK
- echo
-
- echo
- echo §§§§§§§§§§§§§§§§§§§§ Updating test suite repository
- echo
- cd /var/www/drupal7.dev.civicrm.org/public/sites/devel.drupal7.tests.dev.civicrm.org/modules/civicrm/
- find . -name *~ -delete
- svn up
- echo §§§§§§§§§§§§§§§§§§§§ ...done.
-
- echo
- echo §§§§§§§§§§§§§§§§§§§§ Resetting Selenium tests database and template files
- echo
- rm -rf /tmp/templates_c/
- cd /var/www/drupal7.dev.civicrm.org/public/sites/devel.drupal7.tests.dev.civicrm.org/modules/civicrm/bin
- ./setup.sh
-
- echo §§§§§§§§§§§§§§§§§§§§ ...done.
-
- rm -rf /var/www/drupal7.dev.civicrm.org/public/sites/devel.drupal7.tests.dev.civicrm.org/files/civicrm/
- chmod -R 777 /var/www/drupal7.dev.civicrm.org/public/sites/devel.drupal7.tests.dev.civicrm.org/files/
-
- CODE_DIR="/home/tests/devel-suite"
-
- echo
- echo §§§§§§§§§§§§§§§§§§§§ Running test suite
- echo
-
-# for testName in api_v3; do
-# for testName in WebTest; do
-# for testName in api_v2 api_v3 CRM; do
- for testName in api_v3 CRM WebTest; do
-# for testName in CRM; do
- cd $CODE_DIR/tools
-
- rm -rf /tmp/templates_c/
-
- #reset the db before running webtest
- if [ $testName == WebTest ] ; then
- echo
- echo ============== reloading db for Webtest ===============================
- echo
- /var/www/drupal7.dev.civicrm.org/public/sites/devel.drupal7.tests.dev.civicrm.org/modules/civicrm/bin/setup.sh
- fi
-
- scripts/phpunit --tap --log-junit tests/reports/logfile.$testName.xml -u tests -ptests -bdevel_drupal7_tests_dev_civicrm -h localhost ${testName}_AllTests
- cd $CODE_DIR/tools/scripts/
-
- echo
- echo §§§§§§§§§§§§§§§§§§§§ Generating test results.
- echo
- phing $testName
- echo §§§§§§§§§§§§§§§§§§§§ All finished.
- done
-
- ;;
-
- *)
- $SELF trunk
- ;;
-esac