Skip to content

Commit

Permalink
Propagate elements over background jobs
Browse files Browse the repository at this point in the history
Resolves #4064
  • Loading branch information
brandonkelly committed Mar 28, 2019
1 parent 3df530e commit 9e7d6c5
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 14 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG-v3.2.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,12 @@ This update introduces a few changes in behavior to be aware of:
- Added `craft\web\Request::getIsLoginRequest()` and `craft\console\Request::getIsLoginRequest()`.

### Changed
- Craft now propagates elements over background jobs, speeding up the initial element save request. ([#4064](https://github.com/craftcms/cms/issues/4064))
- Renamed `craft\helpers\ArrayHelper::filterByValue()` to `where()`.
- Anonymous/offline/Control Panel access validation now takes place from `craft\web\Controller::beforeAction()` rather than `craft\web\Application::handleRequest()`, giving controllers a chance to do things like set CORS headers before a `ForbiddenHttpException` or `ServiceUnavailableHttpException` is thrown. ([#4008](https://github.com/craftcms/cms/issues/4008))
- Controllers can now set `$allowAnonymous` to a combination of bitwise integers `self::ALLOW_ANONYMOUS_LIVE` and `self::ALLOW_ANONYMOUS_OFFLINE`, or an array of action ID/bitwise integer pairs, to define whether their actions should be accessible anonymously even when the system is offline.
- `craft\queue\jobs\PropagateElements` no longer needs to be configured with a `siteId`, and no longer propagates elements to sites if they were updated in the target site more recently than the source site.
- `craft\services\Elements::propagateElement()` now has a `$siteElement` argument.

### Deprecated
- Deprecated `craft\helpers\ArrayHelper::filterByValue()`. Use `where()` instead.
Expand Down
26 changes: 23 additions & 3 deletions src/queue/jobs/PropagateElements.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
use craft\db\QueryAbortedException;
use craft\elements\db\ElementQuery;
use craft\helpers\App;
use craft\helpers\ArrayHelper;
use craft\helpers\ElementHelper;
use craft\queue\BaseJob;

/**
Expand All @@ -37,7 +39,9 @@ class PropagateElements extends BaseJob
public $criteria;

/**
* @var int|int[] The site ID(s) that the elements should be propagated to
* @var int|int[]|null The site ID(s) that the elements should be propagated to
*
* If this is `null`, then elements will be propagated to all supported sites, except the one they were queried in.
*/
public $siteId;

Expand Down Expand Up @@ -68,14 +72,30 @@ public function execute($queue)
$totalElements = $query->count();
$currentElement = 0;

$elementsService = Craft::$app->getElements();

try {
foreach ($query->each() as $element) {
$this->setProgress($queue, $currentElement++ / $totalElements);

/** @var Element $element */
$element->setScenario(Element::SCENARIO_ESSENTIALS);
foreach ((array)$this->siteId as $siteId) {
Craft::$app->getElements()->propagateElement($element, $siteId);

if ($this->siteId) {
$siteIds = (array)$this->siteId;
} else {
$siteIds = ArrayHelper::getColumn(ElementHelper::supportedSitesForElement($element), 'siteId');
}

foreach ($siteIds as $siteId) {
if ($siteId != $element->siteId) {
// Make sure the site element wasn't updated more recently than the main one
/** @var Element $siteElement */
$siteElement = $elementsService->getElementById($element->id, $class, $siteId);
if ($siteElement === null || $siteElement->dateUpdated < $element->dateUpdated) {
$elementsService->propagateElement($element, $siteId, $siteElement);
}
}
}
}
} catch (QueryAbortedException $e) {
Expand Down
31 changes: 20 additions & 11 deletions src/services/Elements.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
use craft\helpers\ElementHelper;
use craft\helpers\StringHelper;
use craft\queue\jobs\FindAndReplace;
use craft\queue\jobs\PropagateElements;
use craft\queue\jobs\UpdateElementSlugsAndUris;
use craft\records\Element as ElementRecord;
use craft\records\Element_SiteSettings as Element_SiteSettingsRecord;
Expand Down Expand Up @@ -524,12 +525,18 @@ public function saveElement(ElementInterface $element, bool $runValidation = tru

// Update the element across the other sites?
if ($propagate && $element::isLocalized() && Craft::$app->getIsMultiSite()) {
foreach ($supportedSites as $siteInfo) {
// Skip the master site
if ($siteInfo['siteId'] != $element->siteId) {
$this->_propagateElement($element, $isNewElement, $siteInfo);
}
}
Craft::$app->getQueue()->push(new PropagateElements([
'elementType' => get_class($element),
'criteria' => [
'id' => $element->id,
'siteId' => $element->siteId,
'status' => null,
'enabledForSite' => false,
],
'description' => $element::hasTitles()
? Craft::t('app', 'Propagating {title}', ['title' => $element->title])
: null,
]));
}

$transaction->commit();
Expand Down Expand Up @@ -1480,9 +1487,11 @@ public function eagerLoadElements(string $elementType, array $elements, $with)
*
* @param ElementInterface $element The element to propagate
* @param int $siteId The site ID that the element should be propagated to
* @param ElementInterface|null $siteElement The element loaded for the propagated site (only pass this if you
* already had a reason to load it)
* @throws Exception if the element couldn't be propagated
*/
public function propagateElement(ElementInterface $element, int $siteId)
public function propagateElement(ElementInterface $element, int $siteId, ElementInterface $siteElement = null)
{
/** @var Element $element */
$isNewElement = !$element->id;
Expand All @@ -1499,7 +1508,7 @@ public function propagateElement(ElementInterface $element, int $siteId)
throw new Exception('Attempting to propagate an element to an unsupported site.');
}

$this->_propagateElement($element, $isNewElement, $siteInfo);
$this->_propagateElement($element, $isNewElement, $siteInfo, $siteElement);
}

// Private Methods
Expand All @@ -1511,14 +1520,14 @@ public function propagateElement(ElementInterface $element, int $siteId)
* @param ElementInterface $element
* @param bool $isNewElement
* @param array $siteInfo
* @param ElementInterface|null $siteElement The element loaded for the propagated site
* @throws Exception if the element couldn't be propagated
*/
private function _propagateElement(ElementInterface $element, bool $isNewElement, array $siteInfo)
private function _propagateElement(ElementInterface $element, bool $isNewElement, array $siteInfo, ElementInterface $siteElement = null)
{
/** @var Element $element */
// Try to fetch the element in this site
$siteElement = null;
if (!$isNewElement) {
if ($siteElement === null && !$isNewElement) {
$siteElement = $this->getElementById($element->id, get_class($element), $siteInfo['siteId']);
}

Expand Down

0 comments on commit 9e7d6c5

Please sign in to comment.