Skip to content
This repository has been archived by the owner on Oct 24, 2024. It is now read-only.

CRM-13331 re-apply email send once fix but in a way more true to origina... #2

Open
wants to merge 82 commits into
base: 4.2-master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
82 commits
Select commit Hold shift + click to select a range
c13cf1d
Confirmed 4.3 CRM-11998 Add font family, font size and color buttons …
torrance Mar 1, 2013
ac886ea
Partial 4.3 CRM-11180 change log not showing for over 50 contacts
eileenmcnaughton Oct 29, 2012
4d18926
Proposed CRM-11801 configurable Authorize'net receipts
eileenmcnaughton Jan 31, 2013
7e06051
Proposed (not in core) allow cancel of duff subscriptions
eileenmcnaughton Jan 31, 2013
44061e3
Proposed CRM-11966 Html_purifier module incompatibility
eileenmcnaughton Feb 25, 2013
781d68f
Proposed 4.3 CRM-12023 basic version of regions
eileenmcnaughton Mar 6, 2013
4d329fe
Proposed Create opt-out exemption token NOT IN CORE
eileenmcnaughton Apr 9, 2013
2b91397
Proposed CRM-10571 add smarty style modifiers
eileenmcnaughton Jul 23, 2012
e2dcc31
Proposed CRM-10806 increase batch field update limit from 9 to 25
eileenmcnaughton Oct 18, 2012
217201a
Proposed (no JIRA) Allow remote pdfs in receipts
eileenmcnaughton Apr 24, 2013
eedeba1
Proposed (not submitted) fix for reports that are munted after upgrade
eileenmcnaughton Apr 15, 2013
96695a5
Proposed allow recurring installations against pledges
eileenmcnaughton Jan 24, 2013
59bf444
Experimental CRM-12108 Add Authorize.net 2 ipn file
eileenmcnaughton Apr 30, 2013
57fb872
Experimental CRM 12108 add Paypal2 IPN code
eileenmcnaughton Mar 13, 2013
4299964
Custom language for ABA. May not be required in 4.3 if word replaceme…
eileenmcnaughton Oct 17, 2012
12bfbcf
Confirmed CRM-10573 relationship date search + Proposed CRM-12619 - R…
eileenmcnaughton May 15, 2013
f3d16fa
4.4 CRM-12659 - Add Phone as a potential field to pledge detail report
eileenmcnaughton May 19, 2013
5f5f689
CRM-11331 action links on page 2 not working
eileenmcnaughton May 14, 2013
2820077
CRM-12715 fix merge on multi-record entities
eileenmcnaughton May 30, 2013
58e7f5f
CRM-12715 backport multiple fields query fix on JOIN
eileenmcnaughton Jun 4, 2013
19a282f
CRM-12750 upgrade smarty to 2.6.27
eileenmcnaughton Jun 7, 2013
fff705b
fix on relationship search for inactive
eileenmcnaughton Jun 24, 2013
3a93c59
CRM-12715 remove extraneous line from backport
eileenmcnaughton Jun 25, 2013
24c32b8
enotice fix
eileenmcnaughton Jul 2, 2013
1b8e7db
CRM-13059 fix relationship killing query
eileenmcnaughton Jul 16, 2013
f3fd813
CRM-13074 - Failure on CMS user deletes contribution
eileenmcnaughton Jul 18, 2013
7719f25
CRM-12108 noticed type on 'skipDefault' was wrong
eileenmcnaughton Jul 30, 2013
79a31b6
CRM-12108 noticed api.contribution_recur.frequency_interval needs to …
eileenmcnaughton Jul 30, 2013
587355b
CRM-12108 noticed api.contribution_recur.start_date needs to be set o…
eileenmcnaughton Jul 30, 2013
fd574cf
4.3 backport of payment processor api
eileenmcnaughton Jul 30, 2013
311d70a
backport contribution page api
eileenmcnaughton Jul 30, 2013
ef27fe0
backport 4.4. exception class
eileenmcnaughton Jul 30, 2013
b3cf304
CRM-12108 IPN refactor to be testable (possible to redo IPNs outside …
eileenmcnaughton Jul 31, 2013
00e8757
CRM-12679 Fix Paypal Express Recurring IPN not working ...
eileenmcnaughton Jul 30, 2013
47ddfd4
CRM-13162 make table for disabled relationships show the same fields …
eileenmcnaughton Aug 6, 2013
47d626e
CRM-13201 add alterTemplateFile hook
eileenmcnaughton Aug 11, 2013
591d237
fuzion ipn logging -create notification log if not exists
eileenmcnaughton Aug 12, 2013
ba7dce0
CRM-12715 fixes to backport
eileenmcnaughton Aug 13, 2013
35a5bbc
CRM-13201, fixed profile search
kurund Aug 14, 2013
7affae8
Fix apiv3 wrapper
eileenmcnaughton Jul 28, 2013
bb24e6f
CRM-13016 api wrapper needs to deal with non-array results (getcount …
eileenmcnaughton Jul 30, 2013
23086d5
fix port of exception class
eileenmcnaughton Aug 19, 2013
cb3d6c3
Backport of fix on backoffice credit card memberships using default p…
eileenmcnaughton Aug 19, 2013
bdfc5c2
Result from CRM_Utils_Hook::pre not saved in CRM_Core_BAO_Phone
nganivet Aug 12, 2013
958a558
CRM-12036: Uninstall extension
nganivet Aug 12, 2013
1da3026
add ipn logging to A.net
eileenmcnaughton Aug 19, 2013
1be8026
add more debugging when receipt is sent
eileenmcnaughton Aug 19, 2013
ca42c86
change paypal to a.net
eileenmcnaughton Aug 19, 2013
46d596f
CRM-13273 - is_email_receipt setting on recurring contribution should…
eileenmcnaughton Aug 22, 2013
4c6ac76
4.4 version of pledge detail report includes campaign data & currency +
eileenmcnaughton Aug 22, 2013
e265570
Backport of report statistic fix
eileenmcnaughton Aug 22, 2013
4f94d67
CRM-13275 Pledge detail report not showing paid amount for cancelled,
eileenmcnaughton Aug 22, 2013
d289307
CRM-13275 fix stats to show total count by currency & grand total
eileenmcnaughton Aug 22, 2013
dadbe1a
CRM-13034 premium price not being enforced
eileenmcnaughton Aug 23, 2013
598d680
4.4 Backport Add config setting to disable mandatory tokens check in …
antrik Aug 24, 2013
c031a84
test fix on api_v3_ContributionTest.testCompleteTransaction api_v3_Co…
eileenmcnaughton Aug 28, 2013
9de0821
CRM-13294 fix membership to support IN format on contact_id
eileenmcnaughton Aug 28, 2013
ea7fdd7
Add Options to Membership search to print labels & send letters
eileenmcnaughton Aug 28, 2013
642b022
CRM-13296 alter backport for 4.2
eileenmcnaughton Aug 28, 2013
10b411e
CRM-13296 alter backport for 4.2 (another)
eileenmcnaughton Aug 28, 2013
0b25718
backport of 4.4 return property handling
eileenmcnaughton Aug 29, 2013
3464172
Changes to group contact cache behaviour that worked on AUG to fix pe…
eileenmcnaughton Aug 29, 2013
527cd87
CRM-13296 fix token hook
eileenmcnaughton Aug 29, 2013
ae92481
CRM-13331 - limited approach to preventing double click to double-send
eileenmcnaughton Sep 3, 2013
812c923
CRM-13332 print to error log if eWay hits an error
eileenmcnaughton Sep 3, 2013
4f62ab3
CRM-13331 turns out crmaccordian has been renamed in 4.4
eileenmcnaughton Sep 3, 2013
fa5419c
CRM-9493 only adjust main group contact cache rebuild fn
eileenmcnaughton Sep 3, 2013
d147358
remove extra setting from backport of optional token
eileenmcnaughton Sep 4, 2013
820f43d
update contact api return handling from 4.4
eileenmcnaughton Sep 5, 2013
11e62d6
CRM-13372 truncate description string before passing to paypal
eileenmcnaughton Sep 11, 2013
7946e27
CRM-13379 js, contribution form - generalise button double submit pr…
eileenmcnaughton Sep 16, 2013
8603e0a
CRM-13397 js.common also backport js ts function, other changes are o…
eileenmcnaughton Sep 16, 2013
c2cad2a
emailProcessor add details about the account that failed
eileenmcnaughton Sep 16, 2013
dd4ae37
Profile_form add error logging on rollback so transactions rollbacks …
eileenmcnaughton Sep 16, 2013
199f9e7
CRM-13402 error handling, prevent loop if mysql server has 'gone away'
eileenmcnaughton Sep 16, 2013
2ddee1a
character tweak in log msg
eileenmcnaughton Sep 16, 2013
adabd96
CRM-13426 Fatal error on search that includes a smart group crea…
eileenmcnaughton Sep 20, 2013
6b959cd
CRM-13460 - Add is_numeric checks and test coverage
Sep 27, 2013
823bbc3
Revert "CRM-13379 js, contribution form - generalise button double s…
eileenmcnaughton Oct 8, 2013
37ceb34
Revert "CRM-13331 - limited approach to preventing double click to do…
eileenmcnaughton Oct 8, 2013
896fa45
CRM-13331 re-apply email send once fix but in a way more true to orig…
eileenmcnaughton Oct 15, 2013
92385dd
CRM-13397 dont allow contribution pages to submit more than once
eileenmcnaughton Oct 15, 2013
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CRM/Admin/Form/Preferences/Mailing.php
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,13 @@ function preProcess() {
'weight' => 7,
'description' => NULL,
),
'disable_mandatory_tokens_check' =>
array(
'html_type' => 'checkbox',
'title' => ts('Disable check for mandatory tokens'),
'weight' => 9,
'description' => ts('Don\'t check for presence of mandatory tokens (domain address; unsubscribe/opt-out) before sending mailings. WARNING: Mandatory tokens are a safe-guard which facilitate compliance with the US CAN-SPAM Act. They should only be disabled if your organization adopts other mechanisms for compliance or if your organization is not subject to CAN-SPAM.'),
),
),
);

Expand Down
10 changes: 8 additions & 2 deletions CRM/Contact/BAO/GroupContactCache.php
Original file line number Diff line number Diff line change
Expand Up @@ -336,15 +336,21 @@ static function load(&$group, $fresh = FALSE) {

$groupIDs = array($groupID);
self::remove($groupIDs);

$tempTable = 'civicrm_temp_group_contact_cache' . rand(0,2000);
foreach (array($sql, $sqlB) as $selectSql) {
if (!$selectSql) {
continue;
}
$insertSql = "INSERT IGNORE INTO civicrm_group_contact_cache (group_id,contact_id) ($selectSql);";
$insertSql = "CREATE TEMPORARY TABLE $tempTable ($selectSql);";
$processed = TRUE; // FIXME
$result = CRM_Core_DAO::executeQuery($insertSql);
CRM_Core_DAO::executeQuery(
"INSERT IGNORE INTO civicrm_group_contact_cache (contact_id, group_id)
SELECT DISTINCT $idName , group_id FROM $tempTable
");
CRM_Core_DAO::executeQuery(" DROP TABLE $tempTable");
}

self::updateCacheTime($groupIDs, $processed);

if ($group->children) {
Expand Down
130 changes: 106 additions & 24 deletions CRM/Contact/BAO/Query.php
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,17 @@ class CRM_Contact_BAO_Query {
* so we can skip the other
*/
protected $_rangeCache = array();
/**
* Set to true when $this->relationship is run to avoid adding twice
* @var Boolean
*/
protected $_relationshipValuesAdded = FALSE;

/**
* Set to the name of the temp table if one has been created
* @var String
*/
static $_relationshipTempTable = NULL;
/**
* class constructor which also does all the work
*
Expand Down Expand Up @@ -1456,15 +1466,16 @@ function whereClauseSingle(&$values) {
return;

case 'relation_type_id':
$this->relationship($values);
return;

case 'relation_start_date_high':
case 'relation_start_date_low':
case 'relation_end_date_high':
case 'relation_end_date_low':
case 'relation_target_name':
// since this case is handled with the above
return;

case 'relation_status':
// since this case is handled with the above
case 'relation_date_low':
case 'relation_date_high':
$this->relationship($values);
$this->_relationshipValuesAdded = TRUE;
return;

case 'task_status_id':
Expand Down Expand Up @@ -1509,7 +1520,6 @@ function whereClause() {
$this->includeContactIds();
if (!empty($this->_params)) {
$activity = FALSE;

foreach (array_keys($this->_params) as $id) {
if (!CRM_Utils_Array::value(0, $this->_params[$id])) {
continue;
Expand Down Expand Up @@ -2260,8 +2270,15 @@ static function fromClause(&$tables, $inner = NULL, $right = NULL, $primaryLocat

case 'civicrm_relationship':
if (self::$_relType == 'reciprocal') {
$from .= " $side JOIN civicrm_relationship ON (civicrm_relationship.contact_id_b = contact_a.id OR civicrm_relationship.contact_id_a = contact_a.id)";
$from .= " $side JOIN civicrm_contact contact_b ON (civicrm_relationship.contact_id_a = contact_b.id OR civicrm_relationship.contact_id_b = contact_b.id)";
if(self::$_relationshipTempTable) {
// we have a temptable to join on
$tbl = self::$_relationshipTempTable;
$from .= " INNER JOIN {$tbl} civicrm_relationship ON civicrm_relationship.contact_id = contact_a.id";
}
else {
$from .= " $side JOIN civicrm_relationship ON (civicrm_relationship.contact_id_b = contact_a.id OR civicrm_relationship.contact_id_a = contact_a.id)";
$from .= " $side JOIN civicrm_contact contact_b ON (civicrm_relationship.contact_id_a = contact_b.id OR civicrm_relationship.contact_id_b = contact_b.id)";
}
}
elseif (self::$_relType == 'b') {
$from .= " $side JOIN civicrm_relationship ON (civicrm_relationship.contact_id_b = contact_a.id )";
Expand Down Expand Up @@ -3435,7 +3452,9 @@ function task(&$values) {
*/
function relationship(&$values) {
list($name, $op, $value, $grouping, $wildcard) = $values;

if($this->_relationshipValuesAdded){
return;
}
// also get values array for relation_target_name
// for relatinship search we always do wildcard
$targetName = $this->getWhereValues('relation_target_name', $grouping);
Expand Down Expand Up @@ -3465,21 +3484,32 @@ function relationship(&$values) {
$params = array('id' => $rel[0]);
$rTypeValues = array();
$rType = CRM_Contact_BAO_RelationshipType::retrieve($params, $rTypeValues);
if (!$rType) {
return;
}

if ($rTypeValues['name_a_b'] == $rTypeValues['name_b_a']) {
// if we don't know which end of the relationship we are dealing with we'll create a temp table
//@todo unless we are dealing with a target group
self::$_relType = 'reciprocal';
}

if ($nameClause) {
$this->_where[$grouping][] = "( contact_b.sort_name $nameClause AND contact_b.id != contact_a.id )";
// if we are creating a temp table we build our own where for the relationship table
if(self::$_relType == 'reciprocal' && empty($targetGroup)) {
$where = array();
self::$_relationshipTempTable = $relationshipTempTable = 'civicrm_temp_rel' . rand(0,99999);
if($nameClause) {
$where[$grouping][] = " sort_name $nameClause ";
}
}
else {
$where = &$this->_where;
if ($nameClause) {
$where[$grouping][] = "( contact_b.sort_name $nameClause AND contact_b.id != contact_a.id )";
}
}


$relTypeInd = CRM_Contact_BAO_Relationship::getContactRelationshipType(NULL, 'null', NULL, 'Individual');
$relTypeOrg = CRM_Contact_BAO_Relationship::getContactRelationshipType(NULL, 'null', NULL, 'Organization');
$relTypeHou = CRM_Contact_BAO_Relationship::getContactRelationshipType(NULL, 'null', NULL, 'Household');

$allRelationshipType = array();
$allRelationshipType = array_merge($relTypeInd, $relTypeOrg);
$allRelationshipType = array_merge($allRelationshipType, $relTypeHou);
Expand All @@ -3488,7 +3518,6 @@ function relationship(&$values) {
$this->_qill[$grouping][] = "$allRelationshipType[$value] $name";
}


//check to see if the target contact is in specified group
if ($targetGroup) {
//add contacts from static groups
Expand Down Expand Up @@ -3521,27 +3550,80 @@ function relationship(&$values) {
//check for active, inactive and all relation status
$today = date('Ymd');
if ($relStatus[2] == 0) {
$this->_where[$grouping][] = "(
$where[$grouping][] = "(
civicrm_relationship.is_active = 1 AND
( civicrm_relationship.end_date IS NULL OR civicrm_relationship.end_date >= {$today} ) AND
( civicrm_relationship.start_date IS NULL OR civicrm_relationship.start_date <= {$today} )
)";
$this->_qill[$grouping][] = ts('Relationship - Active');
$this->_qill[$grouping][] = ts('Relationship - Active and Current');
}
elseif ($relStatus[2] == 1) {
$this->_where[$grouping][] = "(
$where[$grouping][] = "(
civicrm_relationship.is_active = 0 OR
civicrm_relationship.end_date < {$today} OR
civicrm_relationship.start_date > {$today}
)";
$this->_qill[$grouping][] = ts('Relationship - Inactive');
$this->_qill[$grouping][] = ts('Relationship - Inactive or not Current');
}

$this->_where[$grouping][] = 'civicrm_relationship.relationship_type_id = ' . $rel[0];
$this->addRelationshipDateClauses($grouping, $where);
if(!empty($rType) && isset($rType->id)){
$where[$grouping][] = 'civicrm_relationship.relationship_type_id = ' . $rType->id;
}
$this->_tables['civicrm_relationship'] = $this->_whereTables['civicrm_relationship'] = 1;
$this->_useDistinct = TRUE;
$this->_relationshipValuesAdded = TRUE;
// it could be a or b, using an OR creates an unindexed join - better to create a temp table &
// join on that,
// @todo creating a temp table could be expanded to group filter
// as even creating a temp table of all relationships is much much more efficient than
// an OR in the join
if($relationshipTempTable) {
$whereClause = ' WHERE ' . implode(' AND ', $where[$grouping]);
$sql = "
CREATE TEMPORARY TABLE {$relationshipTempTable}
(SELECT contact_id_b as contact_id, civicrm_relationship.id
FROM civicrm_relationship
INNER JOIN civicrm_contact c ON civicrm_relationship.contact_id_a = c.id
$whereClause )
UNION
(SELECT contact_id_a as contact_id, civicrm_relationship.id
FROM civicrm_relationship
INNER JOIN civicrm_contact c ON civicrm_relationship.contact_id_b = c.id
$whereClause )
";
CRM_Core_DAO::executeQuery($sql);
}

}
/**
* Add start & end date criteria in
* @param string $grouping
* @param array $where = array to add where clauses to, in case you are generating a temp table
* not the main query.
*/
function addRelationshipDateClauses($grouping, &$where){
$dateValues = array();
$dateTypes = array(
'start_date',
'end_date',
);

foreach ($dateTypes as $dateField){
$dateValueLow = $this->getWhereValues('relation_'. $dateField .'_low', $grouping);
$dateValueHigh= $this->getWhereValues('relation_'. $dateField .'_high', $grouping);
if(!empty($dateValueLow)){
$date = date('Ymd', strtotime($dateValueLow[2]));
$where[$grouping][] = "civicrm_relationship.$dateField >= $date";
$this->_qill[$grouping][] = ($dateField == 'end_date' ? ts('Relationship Ended on or After') : ts('Relationship Recorded Start Date On or Before')) . " " . CRM_Utils_Date::customFormat($date);
}
if(!empty($dateValueHigh)){
$date = date('Ymd', strtotime($dateValueHigh[2]));
$where[$grouping][] = "civicrm_relationship.$dateField <= $date";
$this->_qill[$grouping][] = ( $dateField == 'end_date' ? ts('Relationship Ended on or Before') : ts('Relationship Recorded Start Date On or After')) . " " . CRM_Utils_Date::customFormat($date);
}
}
}
/**
* default set of return properties
*
Expand Down Expand Up @@ -3733,7 +3815,7 @@ static function apiQuery($params = NULL,
* @param boolean $count is this a count only query ?
* @param boolean $includeContactIds should we include contact ids?
* @param boolean $sortByChar if true returns the distinct array of first characters for search results
* @param boolean $groupContacts if true, use a single mysql group_concat statement to get the contact ids
* @param boolean $groupContacts if true, return only the contact ids
* @param boolean $returnQuery should we return the query as a string
* @param string $additionalWhereClause if the caller wants to further restrict the search (used for components)
* @param string $additionalFromClause should be clause with proper joins, effective to reduce where clause load.
Expand Down
4 changes: 3 additions & 1 deletion CRM/Contact/Form/Search/Criteria.php
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ static function location(&$form) {
// Build location criteria based on _submitValues if
// available; otherwise, use $form->_formValues.
$formValues = $form->_submitValues;

if (empty($formValues) && !empty($form->_formValues)) {
$formValues = $form->_formValues;
}
Expand Down Expand Up @@ -436,6 +436,8 @@ function relationship(&$form) {
array('id' => 'relation_target_group', 'multiple' => 'multiple', 'title' => ts('- select -'))
);
}
CRM_Core_Form_Date::buildDateRange($form, 'relation_start_date', 1, '_low', '_high', ts('From:'), FALSE, FALSE);
CRM_Core_Form_Date::buildDateRange($form, 'relation_end_date', 1, '_low', '_high', ts('From:'), FALSE, FALSE);

// add all the custom searchable fields
$relationship = array('Relationship');
Expand Down
30 changes: 15 additions & 15 deletions CRM/Contact/Form/Search/Custom/ActivitySearch.php
Original file line number Diff line number Diff line change
Expand Up @@ -145,11 +145,11 @@ function templateFile() {
* Construct the search query
*/
function all($offset = 0, $rowcount = 0, $sort = NULL,
$includeContactIDs = FALSE, $onlyIDs = FALSE
$includeContactIDs = FALSE, $justIDs = FALSE
) {

// SELECT clause must include contact_id as an alias for civicrm_contact.id
if ($onlyIDs) {
if ($justIDs) {
$select = 'contact_a.id as contact_id';
}
else {
Expand Down Expand Up @@ -195,7 +195,7 @@ function all($offset = 0, $rowcount = 0, $sort = NULL,
$sql = " SELECT $select FROM $from $where ";

//no need to add order when only contact Ids.
if (!$onlyIDs) {
if (!$justIDs) {
// Define ORDER BY for query in $sort, with default value
if (!empty($sort)) {
if (is_string($sort)) {
Expand Down Expand Up @@ -226,19 +226,19 @@ function alterRow(&$row) {
function from() {
return "
civicrm_contact contact_a
JOIN civicrm_activity activity
JOIN civicrm_activity activity
ON contact_a.id = activity.source_contact_id
JOIN civicrm_option_value ov1
JOIN civicrm_option_value ov1
ON activity.activity_type_id = ov1.value AND ov1.option_group_id = 2
JOIN civicrm_option_value ov2
JOIN civicrm_option_value ov2
ON activity.status_id = ov2.value AND ov2.option_group_id = {$this->_groupId}
JOIN civicrm_contact contact_b
JOIN civicrm_contact contact_b
ON activity.source_contact_id = contact_b.id
LEFT JOIN civicrm_case_activity cca
LEFT JOIN civicrm_case_activity cca
ON activity.id = cca.activity_id
LEFT JOIN civicrm_activity_assignment assignment
LEFT JOIN civicrm_activity_assignment assignment
ON activity.id = assignment.activity_id
LEFT JOIN civicrm_contact contact_c
LEFT JOIN civicrm_contact contact_c
ON assignment.assignee_contact_id = contact_c.id ";
}

Expand All @@ -254,8 +254,8 @@ function where($includeContactIDs = FALSE) {
if (!empty($contactname)) {
$dao = new CRM_Core_DAO();
$contactname = $dao->escape($contactname);
$clauses[] = "(contact_a.sort_name LIKE '%{$contactname}%' OR
contact_b.sort_name LIKE '%{$contactname}%' OR
$clauses[] = "(contact_a.sort_name LIKE '%{$contactname}%' OR
contact_b.sort_name LIKE '%{$contactname}%' OR
contact_c.display_name LIKE '%{$contactname}%')";
}

Expand Down Expand Up @@ -316,9 +316,9 @@ function where($includeContactIDs = FALSE) {
return implode(' AND ', $clauses);
}

/*
* Functions below generally don't need to be modified
*/
/*
* Functions below generally don't need to be modified
*/
function count() {
$sql = $this->all();

Expand Down
Loading