開発(PHP):リソースを複製(3系)
リソースを複製するには、DocumentManager::duplicate
メソッドを使用します。
- ※ Evolution CMSの3系に対応し、1系には対応していません。
- ※ 配下の子孫リソースも含めて複製されます。
- ※ 公開ステータスは非公開として複製されます。
- ※ 公開開始・終了日時はリセット(空白)で複製されます。
- ※ エイリアスはリソース名を元に自動的に割り当てし直され、複製元のエイリアスは引き継がれません。
グローバル設定のエイリアスの重複許可を有効にしても、影響しません。 - ※ 「OnBeforeDocDuplicate」「OnDocDuplicate」のイベントを発火しますが、加えて作成が含まれるため「OnBeforeDocFormSave」「OnDocFormSave」のイベントも発火します。
構文
戻り値 = DocumentManager::duplicate(オプション);
引数名 | 型 | 初期値 | 説明 | |
---|---|---|---|---|
第一引数 必須 |
設定 | array | オプションを連想配列で指定。id キーは必須で、複製するリソースのIDを指定。parent キーは複製先のリソースIDを指定、未指定は複製元と同じ親リソース。 |
戻り値
複製したリソースの情報を返します。
リソース変数のみで、テンプレート変数は含まれません。
サンプルコード
DocumentManager::duplicate(['id' => 13]);
不便さを軽減させたい場合
DocumentManager::duplicate
メソッドはリソースを複製するうえで非常に便利なメソッドですが、作成時のイベント「OnBeforeDocFormSave」「OnDocFormSave」が発火したり、エイリアスが維持されないなど少々不便や不具合といった部分があります。
そこで次のようにLaravelのモデルで直接処理することで、そういった不便さを軽減させることができます。
関数定義
PHP
/**
* リソースを複製
* @param int|string $id 複製するリソースID
* @param array $opts オプション
* @return int 複製されたリソースIDを返す
*/
function duplicateResource($targetId, $opts = []) {
// リソース情報を取得
$docObj = \EvolutionCMS\Models\SiteContent::query()->find((int)$targetId);
$docObj->tv->pluck('value', 'name');
$doc = $docObj->toArray();
/**
* オプション
* @property int parent 複製先の親要素
* @property bool events イベントを発火するかどうか
* @property bool keepAlias 元のエイリアスを維持するかどうか
* @property bool keepPageTitle ページタイトルを維持するかどうか
* @property iboolnt withChildren 子孫リソースを複製するかどうか
*/
$opts = array_merge([
'parent' => $doc['parent'],
'events' => false,
'keepAlias' => false,
'keepPageTitle' => false,
'withChildren' => true
], $opts);
// 複製前のイベント発火
if ($opts['events']) {
evo()->invokeEvent('OnBeforeDocDuplicate', [
'mode' => 'new',
'id' => null,
'doc' => &$docObj
]);
}
// エイリアスの重複を許可しない場合
if (!$opts['keepAlias'] && evo()->getConfig('allow_duplicate_alias') == 0) {
if (evo()->getConfig('friendly_urls') == 0) {
$doc['alias'] = null;
} else {
$count = \EvolutionCMS\Models\SiteContent::query()->where('pagetitle', 'LIKE', '%'.$doc['pagetitle'].'_%')->count();
if ($count == 0) $count = 1;
$doc['alias'] = $doc['alias'].'_'.$count;
}
}
// ページタイトルの接尾辞付与
if (!$opts['keepPageTitle']) {
$suffix = ' '.\Lang::get('global.duplicated_el_suffix');
$count = \EvolutionCMS\Models\SiteContent::query()->where('pagetitle', 'LIKE', '%'.$doc['pagetitle'].$suffix.'%')->count();
if ($count >= 1) $suffix .= ' '.($count + 1);
$doc['pagetitle'] = $doc['pagetitle'].$suffix;
}
// 複製先の親リソースを指定
$doc['parent'] = $opts['parent'];
// テンプレート変数そのものは削除
unset($doc['tpl']);
// 非公開に設定(ページ側の表示に影響を与える可能性があるため)
$doc['published'] = 0;
// リソースを作成
$newDoc = \EvolutionCMS\Models\SiteContent::create($doc);
$newDocId = $newDoc->getKey();
// テンプレート変数を設定
foreach ($doc['template_values'] as $tvVal) {
\EvolutionCMS\Models\SiteTmplvarContentvalue::updateOrCreate([
'contentid' => $newDocId,
'tmplvarid' => $tvVal['tmplvarid']
], [
'value' => $tvVal['value']
]);
}
// 所属グループの設定
$docGroupsObj = \EvolutionCMS\Models\DocumentGroup::query()->where('document', $doc['id'])->get();
foreach ($docGroupsObj->toArray() as $docGroup) {
// idは自動付与なので削除
unset($docGroup['id']);
$docGroup['document'] = $newDocId;
\EvolutionCMS\Models\DocumentGroup::query()->insert($docGroup);
}
// 子孫リソースを複製
if ($opts['withChildren'] && $doc['isfolder']) {
$childIds = \EvolutionCMS\Models\SiteContent::select('id')->where('parent', $targetId)->get()->toArray();
$childIds = array_map(fn ($x) => $x['id'], $childIds);
foreach ($childIds as $childId) {
duplicateResource($childId, array_merge($opts, [
'parent' => $newDocId,
'keepAlias' => true,
'keepPageTitle' => true
]));
}
}
// 複製完了後のイベント発火
if ($opts['events']) {
evo()->invokeEvent('OnDocDuplicate', [
'mode' => 'new',
'id' => $newDocId
]);
}
return $newDocId;
}
使い方
構文
PHP
$result = duplicateResource( $resourceId, $options )
引数
引数名 | 型 | 説明 | |
---|---|---|---|
第一引数 必須 |
$resourceId | int | string | 複製するリソースのID。 |
第二引数 | $options | array | 各種オプション。詳しくは見出し「第二引数:$options」を参照。 |
第二引数:$options
プロパティ名 | 型 | 初期値 | 説明 |
---|---|---|---|
parent | int | 複製先の親要素。 | |
events | bool | false | イベントを発火するかどうか。true を指定すると、「OnBeforeDocDuplicate」「OnDocDuplicate」のイベントを発火する。 |
keepAlias | bool | false | 元のエイリアスを維持するかどうか。true を指定すると、複製元のエイリアスをそのまま複製したリソースに反映する。ただし true の場合、グローバル設定のallow_duplicate_alias が有効になっていることが前提となる。また、基本的に子孫リソースを対象とした内部的なオプションであるため、任意として使用されることはない。 |
keepPageTitle | bool | false | ページタイトルを維持するかどうか。true を指定すると、複製元のページタイトルをそのまま複製したリソースに反映する。基本的に子孫リソースを対象とした内部的なオプションであるため、任意として使用されることはない。 |
withChildren | bool | true | 子孫リソースを複製するかどうか。false を指定すると、複製されない。 |
戻り値
複製したリソースのIDを返します。
子孫要素が含まれていても複製した最初の親リソースのみを返します。
サンプルコード
PHP
// リソースID「3」を複製
duplicateResource(3);
// 子孫要素を含まない
duplicateResource(3, [
'withChildren' => false
]);