Skip to content

Commit

Permalink
Merge branch 'develop' into update/use-index-hints-for-mysql-db
Browse files Browse the repository at this point in the history
  • Loading branch information
brandonkelly committed Aug 31, 2022
2 parents e6d2e6c + 3e0dd9a commit 43c9619
Show file tree
Hide file tree
Showing 38 changed files with 184 additions and 89 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ on:
- develop
- v3
pull_request:
permissions:
contents: read
concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true
Expand Down
20 changes: 20 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,25 @@
# Release Notes for Craft CMS 4

## Unreleased

### Changed
- `resave/*` commands now have a `--touch` option. When passed, elements’ `dateUpdated` timestamps will be updated as they’re resaved. ([#11849](https://github.com/craftcms/cms/discussions/11849))
- `craft\services\Elements::resaveElements()` now has a `$touch` argument.

### Fixed
- Fixed an error that could occur when upgrading to Craft 4, if any Matrix blocks contained null `sortOrder` values. ([#11843](https://github.com/craftcms/cms/issues/11843))
- Fixed a bug where image transform dimensions could be calculated incorrectly when `upscaleImages` was `false`. ([#11837](https://github.com/craftcms/cms/issues/11837))
- Fixed an error that occurred when parsing an image transform string that was missing an interlace type. ([#11834](https://github.com/craftcms/cms/pull/11834))
- Fixed a bug where element caches weren’t being invalidated during garbage collection, so hard-deleted elements could appear to still exist.

## 4.2.3 - 2022-08-26

### Changed
- If a plugin’s license key is set to an empty environment variable, its trial license key will now be stored in `.env` rather than the project config. ([#11830](https://github.com/craftcms/cms/issues/11830))

### Fixed
- Fixed a PHP error that occurred when garbage collection was run on web requests. ([#11829](https://github.com/craftcms/cms/issues/11829))

## 4.2.2 - 2022-08-23

### Added
Expand Down
2 changes: 1 addition & 1 deletion src/config/app.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
return [
'id' => 'CraftCMS',
'name' => 'Craft CMS',
'version' => '4.2.2',
'version' => '4.2.3',
'schemaVersion' => '4.0.0.9',
'minVersionRequired' => '3.7.11',
'basePath' => dirname(__DIR__), // Defines the @app alias
Expand Down
9 changes: 8 additions & 1 deletion src/console/controllers/ResaveController.php
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,12 @@ class ResaveController extends Controller
*/
public bool $updateSearchIndex = false;

/**
* @var bool Whether to update the `dateUpdated` timestamp for the elements.
* @since 4.2.4
*/
public bool $touch = false;

/**
* @var string|null The group handle(s) to save categories/tags/users from. Can be set to multiple comma-separated groups.
*/
Expand Down Expand Up @@ -162,6 +168,7 @@ public function options($actionID): array
$options[] = 'offset';
$options[] = 'limit';
$options[] = 'updateSearchIndex';
$options[] = 'touch';

switch ($actionID) {
case 'assets':
Expand Down Expand Up @@ -452,7 +459,7 @@ private function _resaveElements(ElementQueryInterface $query): int
$elementsService->on(Elements::EVENT_BEFORE_RESAVE_ELEMENT, $beforeCallback);
$elementsService->on(Elements::EVENT_AFTER_RESAVE_ELEMENT, $afterCallback);

$elementsService->resaveElements($query, true, !$this->revisions, $this->updateSearchIndex);
$elementsService->resaveElements($query, true, !$this->revisions, $this->updateSearchIndex, $this->touch);

$elementsService->off(Elements::EVENT_BEFORE_RESAVE_ELEMENT, $beforeCallback);
$elementsService->off(Elements::EVENT_AFTER_RESAVE_ELEMENT, $afterCallback);
Expand Down
4 changes: 2 additions & 2 deletions src/elements/Asset.php
Original file line number Diff line number Diff line change
Expand Up @@ -1229,7 +1229,7 @@ public function getImg(mixed $transform = null, ?array $sizes = null): ?Markup
* [email protected] 200w
* ```
*
* If you pass x-descriptors, it will be assumed that the image’s current width is the indented 1x width.
* If you pass x-descriptors, it will be assumed that the image’s current width is the `1x` width.
* So if you pass `['1x', '2x']` on an image with a 100px-wide transform applied, you will get:
*
* ```
Expand Down Expand Up @@ -2571,7 +2571,7 @@ private function _dimensions(mixed $transform = null): array
return [$this->_width, $this->_height];
}

return $transformRatio > 1 ? [$this->_width, round($this->_height / $transformRatio)] : [round($this->_width * $transformRatio), $this->_height];
return $transformRatio > 1 ? [$this->_width, round($this->_width / $transformRatio)] : [round($this->_width * $transformRatio), $this->_height];
}

[$width, $height] = Image::calculateMissingDimension($transform->width, $transform->height, $this->_width, $this->_height);
Expand Down
2 changes: 1 addition & 1 deletion src/helpers/ImageTransforms.php
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ public static function createTransformFromString(string $transformString): Image
'mode' => $matches['mode'],
'position' => $matches['position'],
'quality' => $matches['quality'] ?? null,
'interlace' => $matches['interlace'],
'interlace' => $matches['interlace'] ?? 'none',
'transformer' => ImageTransform::DEFAULT_TRANSFORMER,
]);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public function safeUp(): bool

$this->execute(<<<SQL
INSERT INTO $ownersTable ([[blockId]], [[ownerId]], [[sortOrder]])
SELECT [[id]], [[ownerId]], [[sortOrder]]
SELECT [[id]], [[ownerId]], COALESCE([[sortOrder]], 1)
FROM $blocksTable
SQL
);
Expand Down
17 changes: 13 additions & 4 deletions src/services/Elements.php
Original file line number Diff line number Diff line change
Expand Up @@ -956,11 +956,17 @@ public function updateCanonicalElement(ElementInterface $element, array $newAttr
* @param bool $skipRevisions Whether elements that are (or belong to) a revision should be skipped
* @param bool|null $updateSearchIndex Whether to update the element search index for the element
* (this will happen via a background job if this is a web request)
* @param bool $touch Whether to update the `dateUpdated` timestamps for the elements
* @throws Throwable if reasons
* @since 3.2.0
*/
public function resaveElements(ElementQueryInterface $query, bool $continueOnError = false, bool $skipRevisions = true, ?bool $updateSearchIndex = null): void
{
public function resaveElements(
ElementQueryInterface $query,
bool $continueOnError = false,
bool $skipRevisions = true,
?bool $updateSearchIndex = null,
bool $touch = false,
): void {
/** @var ElementQuery $query */
// Fire a 'beforeResaveElements' event
if ($this->hasEventHandlers(self::EVENT_BEFORE_RESAVE_ELEMENTS)) {
Expand Down Expand Up @@ -1010,7 +1016,7 @@ public function resaveElements(ElementQueryInterface $query, bool $continueOnErr

if ($e === null) {
try {
$this->_saveElementInternal($element, true, true, $updateSearchIndex);
$this->_saveElementInternal($element, true, true, $updateSearchIndex, forceTouch: $touch);
} catch (Throwable $e) {
if (!$continueOnError) {
throw $e;
Expand Down Expand Up @@ -2481,6 +2487,8 @@ public function propagateElement(ElementInterface $element, int $siteId, Element
* @param bool|null $updateSearchIndex Whether to update the element search index for the element
* (this will happen via a background job if this is a web request)
* @param array|null $supportedSites The element’s supported site info, indexed by site ID
* @param bool $forceTouch Whether to force the `dateUpdated` timestamps to be updated for the elements,
* regardless of whether they’re being resaved
* @return bool
* @throws ElementNotFoundException if $element has an invalid $id
* @throws UnsupportedSiteException if the element is being saved for a site it doesn’t support
Expand All @@ -2492,6 +2500,7 @@ private function _saveElementInternal(
bool $propagate = true,
?bool $updateSearchIndex = null,
?array $supportedSites = null,
bool $forceTouch = false,
): bool {
/** @var ElementInterface|DraftBehavior|RevisionBehavior $element */
$isNewElement = !$element->id;
Expand Down Expand Up @@ -2620,7 +2629,7 @@ private function _saveElementInternal(
if (isset($element->dateUpdated)) {
$elementRecord->dateUpdated = Db::prepareValueForDb($element->dateUpdated);
}
} elseif ($element->resaving) {
} elseif ($element->resaving && !$forceTouch) {
// Prevent ActiveRecord::prepareForDb() from changing the dateUpdated
$elementRecord->markAttributeDirty('dateUpdated');
} else {
Expand Down
58 changes: 36 additions & 22 deletions src/services/Gc.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use craft\base\BlockElementInterface;
use craft\base\ElementInterface;
use craft\config\GeneralConfig;
use craft\console\Application as ConsoleApplication;
use craft\db\Connection;
use craft\db\Query;
use craft\db\Table;
Expand Down Expand Up @@ -146,6 +147,9 @@ public function run(bool $force = false): void
$this->hardDeleteVolumes();
$this->removeEmptyTempFolders();
$this->_gcCache();

// Invalidate all element caches so any hard-deleted elements don't look like they still exist
Craft::$app->getElements()->invalidateAllCaches();
}

/**
Expand All @@ -157,7 +161,7 @@ public function hardDeleteVolumes(): void
return;
}

Console::stdout(" > deleting trashed volumes and their folders ... ");
$this->_stdout(" > deleting trashed volumes and their folders ... ");
$condition = $this->_hardDeleteCondition();

$volumes = (new Query())->select(['id'])->from([Table::VOLUMES])->where($condition)->all();
Expand All @@ -177,7 +181,7 @@ public function hardDeleteVolumes(): void
}

Volume::deleteAll(['id' => $volumeIds]);
Console::stdout("done\n", Console::FG_GREEN);
$this->_stdout("done\n", Console::FG_GREEN);
}

/**
Expand All @@ -204,7 +208,7 @@ public function hardDeleteElements(): void
}
}

Console::stdout(' > deleting trashed elements ... ');
$this->_stdout(' > deleting trashed elements ... ');

if ($normalElementTypes) {
Db::delete(Table::ELEMENTS, [
Expand Down Expand Up @@ -247,7 +251,7 @@ public function hardDeleteElements(): void
$this->db->createCommand($sql, $params)->execute();
}

Console::stdout("done\n", Console::FG_GREEN);
$this->_stdout("done\n", Console::FG_GREEN);
}

/**
Expand All @@ -268,9 +272,9 @@ public function hardDelete(array|string $tables): void
}

foreach ($tables as $table) {
Console::stdout(" > deleting trashed rows in the `$table` table ... ");
$this->_stdout(" > deleting trashed rows in the `$table` table ... ");
Db::delete($table, $condition);
Console::stdout("done\n", Console::FG_GREEN);
$this->_stdout("done\n", Console::FG_GREEN);
}
}

Expand All @@ -286,7 +290,7 @@ public function hardDelete(array|string $tables): void
public function deletePartialElements(string $elementType, string $table, string $fk): void
{
/** @var string|ElementInterface $elementType */
Console::stdout(sprintf(' > deleting partial %s data in the `%s` table ... ', $elementType::lowerDisplayName(), $table));
$this->_stdout(sprintf(' > deleting partial %s data in the `%s` table ... ', $elementType::lowerDisplayName(), $table));

$elementsTable = Table::ELEMENTS;

Expand All @@ -311,7 +315,7 @@ public function deletePartialElements(string $elementType, string $table, string
}

$this->db->createCommand($sql, ['type' => $elementType])->execute();
Console::stdout("done\n", Console::FG_GREEN);
$this->_stdout("done\n", Console::FG_GREEN);
}

private function _purgeUnsavedDrafts()
Expand All @@ -320,9 +324,9 @@ private function _purgeUnsavedDrafts()
return;
}

Console::stdout(' > purging unsaved drafts that have gone stale ... ');
$this->_stdout(' > purging unsaved drafts that have gone stale ... ');
Craft::$app->getDrafts()->purgeUnsavedDrafts();
Console::stdout("done\n", Console::FG_GREEN);
$this->_stdout("done\n", Console::FG_GREEN);
}

private function _purgePendingUsers()
Expand All @@ -331,9 +335,9 @@ private function _purgePendingUsers()
return;
}

Console::stdout(' > purging pending users with stale activation codes ... ');
$this->_stdout(' > purging pending users with stale activation codes ... ');
Craft::$app->getUsers()->purgeExpiredPendingUsers();
Console::stdout("done\n", Console::FG_GREEN);
$this->_stdout("done\n", Console::FG_GREEN);
}

/**
Expand All @@ -346,6 +350,8 @@ private function _purgePendingUsers()
*/
public function removeEmptyTempFolders(): void
{
$this->_stdout(' > removing empty temp folders ... ');

$emptyFolders = (new Query())
->from(['folders' => Table::VOLUMEFOLDERS])
->select(['folders.id', 'folders.path'])
Expand All @@ -366,6 +372,7 @@ public function removeEmptyTempFolders(): void
}

VolumeFolder::deleteAll(['id' => array_keys($emptyFolders)]);
$this->_stdout("done\n", Console::FG_GREEN);
}

/**
Expand All @@ -387,22 +394,22 @@ private function _deleteStaleSessions(): void
return;
}

Console::stdout(' > deleting stale user sessions ... ');
$this->_stdout(' > deleting stale user sessions ... ');
$interval = DateTimeHelper::secondsToInterval($this->_generalConfig->purgeStaleUserSessionDuration);
$expire = DateTimeHelper::currentUTCDateTime();
$pastTime = $expire->sub($interval);
Db::delete(Table::SESSIONS, ['<', 'dateUpdated', Db::prepareDateForDb($pastTime)]);
Console::stdout("done\n", Console::FG_GREEN);
$this->_stdout("done\n", Console::FG_GREEN);
}

/**
* Deletes any feature announcement rows that have gone stale.
*/
private function _deleteStaleAnnouncements(): void
{
Console::stdout(' > deleting stale feature announcements ... ');
$this->_stdout(' > deleting stale feature announcements ... ');
Db::delete(Table::ANNOUNCEMENTS, ['<', 'dateRead', Db::prepareDateForDb(new DateTime('7 days ago'))]);
Console::stdout("done\n", Console::FG_GREEN);
$this->_stdout("done\n", Console::FG_GREEN);
}


Expand All @@ -411,7 +418,7 @@ private function _deleteStaleAnnouncements(): void
*/
private function _deleteOrphanedDraftsAndRevisions(): void
{
Console::stdout(' > deleting orphaned drafts and revisions ... ');
$this->_stdout(' > deleting orphaned drafts and revisions ... ');

$elementsTable = Table::ELEMENTS;

Expand All @@ -436,14 +443,14 @@ private function _deleteOrphanedDraftsAndRevisions(): void
$this->db->createCommand($sql)->execute();
}

Console::stdout("done\n", Console::FG_GREEN);
$this->_stdout("done\n", Console::FG_GREEN);
}

private function _deleteOrphanedSearchIndexes(): void
{
Console::stdout(' > deleting orphaned search indexes ... ');
$this->_stdout(' > deleting orphaned search indexes ... ');
Craft::$app->getSearch()->deleteOrphanedIndexes();
Console::stdout("done\n", Console::FG_GREEN);
$this->_stdout("done\n", Console::FG_GREEN);
}

private function _gcCache(): void
Expand Down Expand Up @@ -471,15 +478,15 @@ private function _gcCache(): void
return;
}

Console::stdout(' > garbage-collecting data caches ... ');
$this->_stdout(' > garbage-collecting data caches ... ');

if ($hasForceArg) {
$cache->gc(true);
} else {
$cache->gc();
}

Console::stdout("done\n", Console::FG_GREEN);
$this->_stdout("done\n", Console::FG_GREEN);
}

/**
Expand All @@ -504,4 +511,11 @@ private function _hardDeleteCondition(?string $tableAlias = null): array

return $condition;
}

private function _stdout(string $string, ...$format): void
{
if (Craft::$app instanceof ConsoleApplication) {
Console::stdout($string, ...$format);
}
}
}
Loading

0 comments on commit 43c9619

Please sign in to comment.