Concrete CMS エクスプレスの重複データ一の削除

そこで、夜間にCron処理を行い、重複データを自動削除できるJobプログラムを開発しました。
Concrete CMSのエクスプレスはユニークデータ指定ができない
PIXTAで販売しているイラストの紹介を、Concrete CMSのエクスプレス機能を活用して行っています。販売登録時には、以前紹介したエクスプレス一括CSV登録プログラムを使用しています。しかし、誤って重複登録をしてしまうことがあり、これはConcrete CMSのエクスプレス機能にユニークな属性を指定できないことが原因です。
重複登録による大きな影響はありませんが、販売数量と表示数量が一致しない状況は気になってしまいます。そこで、夜間に自動で重複データを削除するCron処理を行うJobプログラムを開発しました。
Concrete CMS ジョブ紹介:CleanupDuplicateEntries
CleanupDuplicateEntries
は、Concrete CMS の Express エンティティにおいて、属性 illust_no
の値が重複しているエントリを検出し、最初の1件を残して重複を自動的に削除するジョブです。
以前に開発して紹介しているConcrete CMS エクスプレスデータベースのデータ一括削除の応用ですので、理論的な理解を深めるにはそちらも御覧ください。
特徴
-
対象の Express エンティティ(この例では
illust
)からすべてのエントリを取得 -
illust_no
の値でグルーピングし、重複しているグループを判定(illust_noはユニーク値であることが前提) -
各グループ内の先頭エントリを残し、残りを削除
-
Doctrine ORM を使って効率的にデータを操作
-
Concrete CMS の管理画面からジョブとして手動実行可能
現在の課題
-
バックグラウンド処理に未対応:大量データを扱う場合、PHP の実行時間制限やタイムアウトにより処理が完了しない可能性があります。
-
バッチ処理未実装:一括処理のため、データ量が多いとページの応答性が低下することがあります。
このジョブは、Express エンティティにおける重複データのクリーンアップを簡便に行いたいユーザー向けのシンプルで効果的なツールです。データが比較的少ない環境では即戦力となるでしょう。
Jobへの登録
主な用途は夜間のCron処理になると思いますので、この機能をJobに登録しました。
実行プログラム cleanup_duplicate_entries.php
<?php
namespace Concrete\Package\CleanupDuplicateEntries\Job;
use Concrete\Core\Job\Job;
use Concrete\Core\Express\EntryList;
use Concrete\Core\Entity\Express\Entry;
use Doctrine\ORM\EntityManagerInterface;
class CleanupDuplicateEntries extends Job
{
public function getJobName()
{
return t("Cleanup Duplicate illust_no Entries");
}
public function getJobDescription()
{
return t("Finds and deletes duplicate illust_no entries, keeping only the first one.");
}
public function run()
{
// Expressエンティティと属性のハンドル
$entityHandle = 'illust';
$attributeHandle = 'illust_no';
// Expressエンティティ取得
$express = \Core::make('express');
$entity = $express->getObjectByHandle($entityHandle);
if (!$entity) {
return t("Error: Express entity '{$entityHandle}' not found.");
}
// 全エントリ取得
$entryList = new EntryList($entity);
$entryList->ignorePermissions();
$entryList->sortByDateAdded('asc');
$entries = $entryList->getResults();
// illust_no でグループ化
$map = [];
foreach ($entries as $entry) {
$illustNo = $entry->getAttribute($attributeHandle);
if (!$illustNo) {
continue; // 空の値は無視
}
if (!isset($map[$illustNo])) {
$map[$illustNo] = [];
}
$map[$illustNo][] = $entry;
}
// 重複エントリを削除(最初の1件を除く)
$em = \Core::make(EntityManagerInterface::class);
$deleted = 0;
foreach ($map as $illustNo => $entryGroup) {
if (count($entryGroup) > 1) {
array_shift($entryGroup); // 最初の1件は残す
foreach ($entryGroup as $entry) {
$found = $em->find(Entry::class, $entry->getID());
if ($found) {
$em->remove($found);
$deleted++;
}
}
}
}
// 削除を確定
$em->flush();
return "{$deleted} duplicate entries deleted.";
}
}
controller.php
<?php
namespace Concrete\Package\CleanupDuplicateEntries;
use Concrete\Core\Package\Package;
use Concrete\Core\Job\Job;
class Controller extends Package
{
protected $pkgHandle = 'cleanup_duplicate_entries';
protected $appVersionRequired = '8.5.0';
protected $pkgVersion = '1.0.0';
public function getPackageName()
{
return t('Cleanup Duplicate Entries');
}
public function getPackageDescription()
{
return t('エクスプレスの重複データを削除する');
}
public function install()
{
$pkg = parent::install();
Job::installByPackage('cleanup_duplicate_entries', $pkg);
}
}
ダウンロードとインストール手順
以下のリンクからファイルをダウンロードし、解凍後に packages
ディレクトリ内へ配置してください。
その後、システム設定 → Concreteの拡張 → Cleanup Duplicate Entriesのインストール を実行すると、Jobに登録され、いつでも使用可能 になります。
主な使用は、Cron処理になると思いますので、Job画面よりCron用のurlを取得して実行してください。
当然ですが、$entityHandleと$attributeHandleは、ご自身の環境に適した内容に変更してください。
また、$attributeHandleはユニークな属性である必要があります。
動作確認はConcrete CMS 8.5.19のみで行っており、他のバージョンでの動作は未確認です。
なお、本プログラムの使用により不具合が発生した場合でも、自己責任となることをご了承ください。
本処理ではバッチ処理やバックグラウンド処理が実装されていないため、実行時にブラウザーの表示が停止する可能性があります。
そのため、運用時は夜間のCron処理を利用することをおすすめします。
なお、大量の重複データ処理については試験していませんが、タイムアウトエラーが発生する可能性が高いと考えられます。
本稿の題材のイラスト紹介ページは、以下のリンクからご覧いただけます。エクスプレスデータベースに登録したPIXTAの画像URLを使用し、画像を表示できるようにしました。