mirror of
https://codeberg.org/artfulrobot/contactcats.git
synced 2025-06-27 00:57:19 +02:00
Rewrite sync to use new features
This commit is contained in:
parent
b0983603e5
commit
16f2b6235d
7 changed files with 502 additions and 365 deletions
|
@ -2,12 +2,8 @@
|
|||
namespace Civi\Api4\Action\ContactCategory;
|
||||
|
||||
use Civi;
|
||||
use Civi\Api4\Activity;
|
||||
use Civi\Api4\Generic\Result;
|
||||
use Civi\Api4\Group;
|
||||
use Civi\Api4\OptionValue;
|
||||
use Civi\Api4\Setting;
|
||||
use CRM_Core_DAO;
|
||||
use Civi\ContactCats\Processor;
|
||||
|
||||
/**
|
||||
* Sync the data
|
||||
|
@ -28,145 +24,24 @@ class Sync extends \Civi\Api4\Generic\AbstractAction {
|
|||
public function _run(Result $result) {
|
||||
ini_set('memory_limit', '256M');
|
||||
Civi::log()->debug('Begin', ['=start' => 'ContactCatSync', '=timed' => 1]);
|
||||
// this does not unserialize $settings = Civi::settings()->get('contact_categories');
|
||||
$settings = Setting::get(FALSE)
|
||||
->addSelect('contact_categories')
|
||||
->execute()->first()['value'] ?? NULL;
|
||||
if (empty($settings['groupIDs'])) {
|
||||
throw new \API_Exception('Unconfigured');
|
||||
}
|
||||
if (!$this->force && time() < $settings['updateAfter']) {
|
||||
// not needed yet.
|
||||
Civi::log()->debug("Skipping because not due until " . date('H:i j M Y', $settings['updateAfter']), ['=' => 'pop']);
|
||||
return;
|
||||
}
|
||||
// Ensure we're definitely dealing with integer Group IDs.
|
||||
array_walk($settings['groupIDs'], fn (&$groupID) => $groupID = (int) $groupID);
|
||||
|
||||
// Load category names
|
||||
$catNames = OptionValue::get(FALSE)
|
||||
->addWhere('option_group_id:name', '=', 'contact_categories')
|
||||
->addSelect('value', 'label')
|
||||
->execute()->indexBy('value')->column('label');
|
||||
|
||||
$groups = Group::get(FALSE)
|
||||
->addWhere('id', 'IN', $settings['groupIDs'])
|
||||
->execute()->indexBy('id')->getArrayCopy();
|
||||
|
||||
$smartGroups = [];
|
||||
foreach ($groups as $groupID => $group) {
|
||||
if (!empty($group['saved_search_id'])) {
|
||||
$smartGroups[] = $groupID;
|
||||
}
|
||||
}
|
||||
if ($smartGroups) {
|
||||
Civi::log()->debug('Refreshing smart groups', ['=' => 'timed,start', 'groups' => $smartGroups]);
|
||||
\CRM_Contact_BAO_GroupContactCache::loadAll($smartGroups);
|
||||
Civi::log()->debug('', ['=' => 'pop']);
|
||||
}
|
||||
|
||||
Civi::log()->debug('Resetting table', ['=' => 'start,timed']);
|
||||
// clear out temp space.
|
||||
CRM_Core_DAO::executeQuery("UPDATE civicrm_contact_category SET next_category = 0;")->free();
|
||||
// ensure we have all our contacts covered.
|
||||
CRM_Core_DAO::executeQuery(<<<SQL
|
||||
INSERT IGNORE INTO civicrm_contact_category
|
||||
SELECT id, id contact_id, 0 as category, 0 next_category
|
||||
FROM civicrm_contact
|
||||
SQL)->free();
|
||||
Civi::log()->debug('', ['=' => 'pop']);
|
||||
|
||||
foreach ($settings['groupIDs'] as $groupID) {
|
||||
if ($groupID == 0) {
|
||||
// The default 'group' isn't a ... group.
|
||||
continue;
|
||||
}
|
||||
if (!$groups[$groupID]) {
|
||||
Civi::log()->warning("Group $groupID no longer exists.");
|
||||
continue;
|
||||
}
|
||||
// Put unclaimed contacts in this group into this category.
|
||||
$isSmart = !empty($groups[$groupID]['saved_search_id']);
|
||||
Civi::log()->debug($groups[$groupID]['title'] . ($isSmart ? '(smart)' : ''), ['=' => 'timed', '=start' => "group$groupID"]);
|
||||
$table = $isSmart ? 'civicrm_group_contact_cache' : 'civicrm_group_contact';
|
||||
$statusWhere = $isSmart ? '' : 'AND gc.status = "Added"';
|
||||
$sql = <<<SQL
|
||||
UPDATE civicrm_contact_category cc
|
||||
INNER JOIN $table gc ON gc.contact_id = cc.id AND group_id = $groupID $statusWhere
|
||||
SET next_category = $groupID
|
||||
WHERE next_category = 0
|
||||
SQL;
|
||||
CRM_Core_DAO::executeQuery($sql)->free();
|
||||
Civi::log()->debug('', ['=' => 'pop']);
|
||||
}
|
||||
|
||||
Civi::log()->debug("Calculate changes", ['=' => 'timed', '=start' => "changes"]);
|
||||
$changes = CRM_Core_DAO::executeQuery(<<<SQL
|
||||
SELECT id, category, next_category
|
||||
FROM civicrm_contact_category
|
||||
WHERE next_category <> category
|
||||
ORDER BY category, next_category
|
||||
SQL);
|
||||
$lastChange = [0, 0];
|
||||
$batch = [];
|
||||
$n = 0;
|
||||
$writeBatch = function() use (&$lastChange, &$batch, $catNames) {
|
||||
if (empty($batch)) {
|
||||
if (!$this->force) {
|
||||
$nextRun = Civi::settings()->get('contactcats_next_run') ?? 0;
|
||||
if (time() < $nextRun) {
|
||||
// not needed yet.
|
||||
Civi::log()->debug("Skipping because not due until " . date('H:i j M Y', $nextRun), ['=' => 'pop']);
|
||||
return;
|
||||
}
|
||||
$oldCategoryId = (int) ($lastChange[0] ?? 0);
|
||||
$newCategoryId = (int) ($lastChange[1] ?? 0);
|
||||
// Create activity on the first contact
|
||||
$a = Activity::create(FALSE)
|
||||
->addValue('target_contact_id', $batch[0])
|
||||
->addValue('activity_type_id:name', 'changed_contact_category')
|
||||
->addValue('source_contact_id', \CRM_Core_BAO_Domain::getDomain()->contact_id)
|
||||
->addValue('status_id:name', 'Completed')
|
||||
->addValue('subject', $catNames[$oldCategoryId] . ' → ' . $catNames[$newCategoryId])
|
||||
->execute()->first();
|
||||
$activityID = (int) $a['id'];
|
||||
// Join activity to all relevant contacts
|
||||
CRM_Core_DAO::executeQuery("INSERT INTO civicrm_activity_contact (contact_id, activity_id, record_type_id)
|
||||
SELECT id contact_id, $activityID activity_id, 3 record_type_id
|
||||
FROM civicrm_contact_category cc
|
||||
WHERE cc.category = $oldCategoryId
|
||||
AND cc.next_category = $newCategoryId
|
||||
AND contact_id <> $batch[0]
|
||||
")->free();
|
||||
Civi::log()->debug(count($batch) . " changes: " . $catNames[$lastChange[0] ?? 0] . ' → ' . $catNames[$lastChange[1] ?? 0]);
|
||||
};
|
||||
while ($changes->fetch()) {
|
||||
$n++;
|
||||
if ($lastChange[0] !== $changes->category || $lastChange[1] !== $changes->next_category) {
|
||||
$writeBatch();
|
||||
$lastChange = [$changes->category, $changes->next_category];
|
||||
$batch = [];
|
||||
}
|
||||
$batch[] = $changes->id;
|
||||
}
|
||||
$changes->free();
|
||||
$writeBatch();
|
||||
Civi::log()->debug('Apply changes', ['=change' => 'applyChanges', '=timed' => 1]);
|
||||
|
||||
CRM_Core_DAO::executeQuery("UPDATE civicrm_contact_category
|
||||
SET category = next_category WHERE category <> next_category")->free();
|
||||
Civi::log()->debug('', ['=pop' => 1]);
|
||||
|
||||
$summary = CRM_Core_DAO::executeQuery("SELECT next_category, count(*) from civicrm_contact_category group by next_category")->fetchAll();
|
||||
$summary['changes'] = $n;
|
||||
$_ = memory_get_peak_usage(TRUE);
|
||||
$summary['memory_use'] = @round($_ / pow(1024, ($i = floor(log($_, 1024)))), 2) . ' ' . ['b', 'kb', 'mb', 'gb', 'tb', 'pb'][$i];
|
||||
$result->exchangeArray($summary);
|
||||
$processor = new Processor();
|
||||
$result->exchangeArray($processor->run());
|
||||
|
||||
// Limit to running every 24 hours; we actually want it to be stable within one day.
|
||||
// Schedule for 3am to avoid busy times and DST.
|
||||
$settings['updateAfter'] = strtotime('tomorrow + 180 minutes');
|
||||
Setting::set(FALSE)
|
||||
->addValue('contact_categories', $settings)
|
||||
->execute();
|
||||
|
||||
Civi::log()->debug("Complete. Scheduling next run after " . date('H:i j M Y', $settings['updateAfter']), ['=' => 'set']);
|
||||
|
||||
$nextRun = strtotime('tomorrow + 180 minutes');
|
||||
Civi::settings()->set('contactcats_next_run', $nextRun);
|
||||
Civi::settings()->set('contactcats_last_run', time());
|
||||
Civi::log()->debug("Complete. Scheduling next run after " . date('H:i j M Y', $nextRun), ['=' => 'set']);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue