class SalesforceMappingCommands in Salesforce Suite 8.3
Same name and namespace in other branches
- 8.4 modules/salesforce_mapping/src/Commands/SalesforceMappingCommands.php \Drupal\salesforce_mapping\Commands\SalesforceMappingCommands
- 5.0.x modules/salesforce_mapping/src/Commands/SalesforceMappingCommands.php \Drupal\salesforce_mapping\Commands\SalesforceMappingCommands
A Drush commandfile.
In addition to this file, you need a drush.services.yml in root of your module, and a composer.json file that provides the name of the services file to use.
See these files for an example of injecting Drupal services:
- http://cgit.drupalcode.org/devel/tree/src/Commands/DevelCommands.php
- http://cgit.drupalcode.org/devel/tree/drush.services.yml
Hierarchy
- class \Drupal\salesforce\Commands\SalesforceCommandsBase extends \Drush\Commands\DrushCommands
- class \Drupal\salesforce_mapping\Commands\SalesforceMappingCommandsBase
- class \Drupal\salesforce_mapping\Commands\SalesforceMappingCommands
- class \Drupal\salesforce_mapping\Commands\SalesforceMappingCommandsBase
Expanded class hierarchy of SalesforceMappingCommands
1 string reference to 'SalesforceMappingCommands'
- drush.services.yml in modules/
salesforce_mapping/ drush.services.yml - modules/salesforce_mapping/drush.services.yml
1 service uses SalesforceMappingCommands
- salesforce_mapping.commands in modules/
salesforce_mapping/ drush.services.yml - \Drupal\salesforce_mapping\Commands\SalesforceMappingCommands
File
- modules/
salesforce_mapping/ src/ Commands/ SalesforceMappingCommands.php, line 25
Namespace
Drupal\salesforce_mapping\CommandsView source
class SalesforceMappingCommands extends SalesforceMappingCommandsBase {
protected $salesforceConfig;
protected $database;
/**
* SalesforceMappingCommands constructor.
*
* @param \Drupal\salesforce\Rest\RestClient $client
* The salesforce.client service.
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $etm
* The entity_type.manager service.
* @param \Drupal\Core\Config\ConfigFactory $configFactory
* The config.factory service.
* @param \Drupal\Core\Database\Connection $database
* The database service.
*
* @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
* @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
*/
public function __construct(RestClient $client, EntityTypeManagerInterface $etm, ConfigFactory $configFactory, Connection $database) {
parent::__construct($client, $etm);
$this->database = $database;
$this->salesforceConfig = $configFactory
->get('salesforce.settings');
}
/**
* Get a limit argument interactively.
*
* @hook interact salesforce_mapping:prune-revisions
*/
public function interactPrune(Input $input, Output $output) {
if ($input
->getArgument('limit')) {
return;
}
$config_limit = $this->salesforceConfig
->get('limit_mapped_object_revisions');
// These 2 lines give different results:
while (TRUE) {
if (!($limit = $this
->io()
->ask('Enter a revision limit (integer). All revisions beyond this limit will be deleted, oldest first', $config_limit))) {
throw new UserAbortException();
}
elseif ($limit > 0) {
$input
->setArgument('limit', $limit);
return;
}
else {
$this
->logger()
->error('A positive integer limit is required.');
}
}
}
/**
* Delete old revisions of Mapped Objects, based on revision limit settings.
*
* Useful if you have recently changed settings, or if you have just updated
* to a version with prune support.
*
* @param int $limit
* If $limit is not specified,
* salesforce.settings.limit_mapped_object_revisions is used.
*
* @command salesforce_mapping:prune-revisions
* @aliases sfprune,sf-prune-revisions
*/
public function pruneRevisions($limit) {
$revision_table = $this->etm
->getDefinition('salesforce_mapped_object')
->getRevisionTable();
$ids = $this->database
->select($revision_table, 'r')
->fields('r', [
'id',
])
->having('COUNT(r.id) > ' . $limit)
->groupBy('r.id')
->execute()
->fetchCol();
if (empty($ids)) {
$this
->logger()
->warning(dt("No Mapped Objects with more than !limit revision(s). No action taken.", [
'!limit' => $limit,
]));
return;
}
$this
->logger()
->info(dt('Found !count mapped objects with excessive revisions. Will prune to revision(s) each. This may take a while.', [
'!count' => count($ids),
'!limit' => $limit,
]));
$total = count($ids);
$i = 0;
$buckets = ceil($total / 20);
if ($buckets == 0) {
$buckets = 1;
}
foreach ($ids as $id) {
if ($i++ % $buckets == 0) {
$this
->logger()
->info(dt("Pruned !i of !total records.", [
'!i' => $i,
'!total' => $total,
]));
}
/** @var \Drupal\salesforce_mapping\Entity\MappedObject $mapped_object */
$mapped_object = $this->mappedObjectStorage
->load($id);
$mapped_object
->pruneRevisions($this->mappedObjectStorage);
}
}
/**
* Interactively gather a salesforce mapping name.
*
* @hook interact salesforce_mapping:purge-drupal
*/
public function interactPurgeDrupal(Input $input, Output $output) {
return $this
->interactMapping($input, $output, 'Choose a Salesforce mapping', 'Purge All');
}
/**
* Interactively gather a salesforce mapping name.
*
* @hook interact salesforce_mapping:purge-salesforce
*/
public function interactPurgeSalesforce(Input $input, Output $output) {
return $this
->interactMapping($input, $output, 'Choose a Salesforce mapping', 'Purge All');
}
/**
* Interactively gather a salesforce mapping name.
*
* @hook interact salesforce_mapping:purge-mapping
*/
public function interactPurgeMapping(Input $input, Output $output) {
return $this
->interactMapping($input, $output, 'Choose a Salesforce mapping', 'Purge All');
}
/**
* Interactively gather a salesforce mapping name.
*
* @hook interact salesforce_mapping:purge-all
*/
public function interactPurgeAll(Input $input, Output $output) {
return $this
->interactMapping($input, $output, 'Choose a Salesforce mapping', 'Purge All');
}
/**
* Clean up Mapped Objects referencing missing Drupal entities.
*
* @param string $name
* Id of the salesforce mapping whose mapped objects should be purged.
*
* @command salesforce_mapping:purge-drupal
* @aliases sfpd,sf-purge-drupal
*/
public function purgeDrupal($name) {
$mapped_obj_table = $this->etm
->getDefinition('salesforce_mapped_object')
->getBaseTable();
$query = $this->database
->select($mapped_obj_table, 'm')
->fields('m', [
'drupal_entity__target_type',
])
->distinct();
if ($name && strtoupper($name) != 'ALL') {
$query
->condition('salesforce_mapping', $name);
}
$entity_type_ids = $query
->execute()
->fetchCol();
if (empty($entity_type_ids)) {
$this
->logger()
->info('No orphaned mapped objects found by Drupal entities.');
return;
}
foreach ($entity_type_ids as $et_id) {
$query = $this->database
->select($mapped_obj_table, 'm')
->fields('m', [
'id',
]);
$query
->condition('drupal_entity__target_type', $et_id);
$entity_type = $this->etm
->getDefinition($et_id);
if ($entity_type) {
$id_key = $entity_type
->getKey('id');
$query
->addJoin("LEFT", $entity_type
->getBaseTable(), 'et', "et.{$id_key} = m.drupal_entity__target_id_int");
$query
->isNull("et.{$id_key}");
}
$mapped_obj_ids = $query
->execute()
->fetchCol();
if (empty($mapped_obj_ids)) {
$this
->logger()
->info('No orphaned mapped objects found for ' . $et_id . '.');
continue;
}
$this
->purgeConfirmAndDelete($mapped_obj_ids, 'entity type: ' . $et_id);
}
}
/**
* Helper to confirm before destructive operation.
*/
protected function purgeConfirmAndDelete(array $object_ids, $extra = '') {
if (empty($object_ids)) {
return;
}
$message = 'Delete ' . count($object_ids) . ' orphaned mapped objects';
if ($extra) {
$message .= ' for ' . $extra;
}
$message .= '?';
if (!$this
->io()
->confirm($message)) {
return;
}
// Still have to *load* entities in order to delete them. **UGH**.
$mapped_objs = $this->mappedObjectStorage
->loadMultiple($object_ids);
$this->mappedObjectStorage
->delete($mapped_objs);
}
/**
* Helper to gather object types by prefix.
*/
protected function objectTypesByPrefix() {
$ret = [];
$describe = $this->client
->objects();
foreach ($describe as $object) {
$ret[$object['keyPrefix']] = $object;
}
return $ret;
}
/**
* Clean up Mapped Objects by deleting records referencing missing records.
*
* @param string $name
* Id of the salesforce mapping whose mapped objects should be purged.
*
* @command salesforce_mapping:purge-salesforce
* @aliases sfpsf,sf-purge-salesforce
*/
public function purgeSalesforce($name) {
$object_types = $this
->objectTypesByPrefix();
$mapped_obj_table = $this->etm
->getDefinition('salesforce_mapped_object')
->getBaseTable();
$query = $this->database
->select($mapped_obj_table, 'm');
$query
->addExpression('distinct substr(salesforce_id, 1, 3)');
if ($name && strtoupper($name) != 'ALL') {
$query
->condition('salesforce_mapping', $name);
}
$sfid_prefixes = $query
->execute()
->fetchCol();
foreach ($sfid_prefixes as $prefix) {
if (empty($object_types[$prefix]['name'])) {
$query = $this->database
->select($mapped_obj_table, 'm')
->fields('m', [
'salesforce_id',
'id',
]);
$query
->condition('salesforce_id', $prefix . '%', 'LIKE');
$mapped_obj_ids = $query
->execute()
->fetchAllKeyed();
if (empty($mapped_obj_ids)) {
continue;
}
$this
->logger()
->warning(dt('Unknown object type for Salesforce ID prefix !prefix', [
'!prefix' => $prefix,
]));
$this
->purgeConfirmAndDelete($mapped_obj_ids, 'prefix ' . $prefix);
continue;
}
$query = $this->database
->select($mapped_obj_table, 'm')
->fields('m', [
'salesforce_id',
'id',
]);
if ($name && strtoupper($name) != 'ALL') {
$query
->condition('salesforce_mapping', $name);
}
else {
$query
->condition('salesforce_id', $prefix . '%', 'LIKE');
}
$sfids = $query
->execute()
->fetchAllKeyed();
$to_delete = $sfids;
// SOQL queries are limited to 4000-characters in where statements.
// Chunkify in case we have more than ~200 sfids.
foreach (array_chunk($sfids, 200, TRUE) as $chunk) {
$soql_query = new SelectQuery($object_types[$prefix]['name']);
$soql_query->fields[] = 'Id';
$soql_query
->addCondition('Id', array_keys($chunk));
$results = $this->client
->query($soql_query);
foreach ($results
->records() as $record) {
unset($to_delete[(string) $record
->id()]);
}
}
if (empty($to_delete)) {
$this
->logger()
->info(dt('No orphaned mapped objects found for SObject type !type', [
'!type' => $object_types[$prefix]['name'],
]));
continue;
}
$this
->purgeConfirmAndDelete(array_values($to_delete), 'SObject type *' . $object_types[$prefix]['name'] . '*');
}
}
/**
* Clean up Mapped Objects by deleting records referencing missing Mappings.
*
* @param string $name
* Mapping id.
*
* @command sf:purge-mapping
* @aliases sfpmap,sf-purge-mapping
*/
public function purgeMapping($name) {
$mapped_obj_table = $this->etm
->getDefinition('salesforce_mapped_object')
->getBaseTable();
$query = $this->database
->select($mapped_obj_table, 'm')
->fields('m', [
'salesforce_mapping',
])
->distinct();
if ($name && strtoupper($name) != 'ALL') {
$query
->condition('salesforce_mapping', $name);
}
$mapping_ids = $query
->execute()
->fetchCol();
if (empty($entity_type_ids)) {
$this
->logger()
->info('No orphaned mapped objects found by mapping.');
return;
}
foreach ($mapping_ids as $mapping_id) {
$mapping = $this->mappingStorage
->load($mapping_id);
// If mapping loads successsfully, we assume the mapped object is OK.
if ($mapping) {
continue;
}
$query = $this->database
->select($mapped_obj_table, 'm')
->fields('m', [
'id',
]);
$query
->condition('salesforce_mapping', $mapping_id);
$mapped_obj_ids = $query
->distinct()
->execute()
->fetchCol();
$this
->purgeConfirmAndDelete($mapped_obj_ids, 'missing mapping: ' . $mapping_id);
}
}
/**
* Clean up Mapped Objects table.
*
* Clean by deleting any records which reference missing Mappings, Entities,
* or Salesforce records.
*
* @param string $name
* Id of the salesforce mapping whose mapped objects should be purged.
*
* @command salesforce_mapping:purge-all
* @aliases sfpall,sf-purge-all
*/
public function purgeAll($name) {
$this
->purgeDrupal($name);
$this
->purgeSalesforce($name);
$this
->purgeMapping($name);
}
}
Members
Name | Modifiers | Type | Description | Overrides |
---|---|---|---|---|
SalesforceCommandsBase:: |
protected | property | The Salesforce client. | |
SalesforceCommandsBase:: |
protected | property | The entity type manager. | |
SalesforceCommandsBase:: |
protected | function | Collect a salesforce object name, and set it to "object" argument. | |
SalesforceMappingCommands:: |
protected | property | ||
SalesforceMappingCommands:: |
protected | property | ||
SalesforceMappingCommands:: |
public | function | Get a limit argument interactively. | |
SalesforceMappingCommands:: |
public | function | Interactively gather a salesforce mapping name. | |
SalesforceMappingCommands:: |
public | function | Interactively gather a salesforce mapping name. | |
SalesforceMappingCommands:: |
public | function | Interactively gather a salesforce mapping name. | |
SalesforceMappingCommands:: |
public | function | Interactively gather a salesforce mapping name. | |
SalesforceMappingCommands:: |
protected | function | Helper to gather object types by prefix. | |
SalesforceMappingCommands:: |
public | function | Delete old revisions of Mapped Objects, based on revision limit settings. | |
SalesforceMappingCommands:: |
public | function | Clean up Mapped Objects table. | |
SalesforceMappingCommands:: |
protected | function | Helper to confirm before destructive operation. | |
SalesforceMappingCommands:: |
public | function | Clean up Mapped Objects referencing missing Drupal entities. | |
SalesforceMappingCommands:: |
public | function | Clean up Mapped Objects by deleting records referencing missing Mappings. | |
SalesforceMappingCommands:: |
public | function | Clean up Mapped Objects by deleting records referencing missing records. | |
SalesforceMappingCommands:: |
public | function |
SalesforceMappingCommands constructor. Overrides SalesforceMappingCommandsBase:: |
|
SalesforceMappingCommandsBase:: |
protected | property | Mapped Object storage handler. | |
SalesforceMappingCommandsBase:: |
protected | property | Salesforce Mapping storage handler. | |
SalesforceMappingCommandsBase:: |
protected | function | Helper method to collect the choice from user, given a set of options. | |
SalesforceMappingCommandsBase:: |
protected | function | Given a mapping name (and optional direction), get an array of mappings. | |
SalesforceMappingCommandsBase:: |
protected | function | Given a mappin gname, get an array of matching pull mappings. | |
SalesforceMappingCommandsBase:: |
protected | function | Given a mapping name, get an array of matching push mappings. | |
SalesforceMappingCommandsBase:: |
protected | function | Collect a salesforce mapping interactively. | |
SalesforceMappingCommandsBase:: |
protected | function | Collect a salesforce mapping name, and set it to a "name" argument. | |
SalesforceMappingCommandsBase:: |
protected | function | Collect a salesforce mapping name, and set it to a "name" argument. | |
SalesforceMappingCommandsBase:: |
protected | function |
Pass-through helper to add appropriate formatters for a query result. Overrides SalesforceCommandsBase:: |