Craft CMS プラグインの作法(Matrixフィールド内にSuperTableフィールドがある場合の新規ブロック追加)

番外編。

Matrixフィールド内にSuperTableフィールドをレイアウトしている場合、プラグインから新規ブロックを追加するのが、結構わかりにくいです。

'sampleMatrix'フィールドに、'sampleBlock'というブロックがあり、そのブロックに'superTableField'というSuperTableフィールドがあるとします。
$matrix["new1"] = [
'type' => 'sampleBlock',
'enabled' => true,
'fields' => [
'textField' => 'abcdefg',
'numField' => 123456,
'superTableField' => [
'new1' => [
'type' => 0,
'enabled' => true,
'fields' => [
'columnOne' => 'sample one',
'columnTwo' => 'sample two',
],
],
],
],
];
$entry->setContentFromPost(array('sampleMatrix' => $matrix));
$success = craft()->entries->saveEntry($entry);
本当は、こう書きたいところですが、これではエラーになります…。
問題は、ブロック内のsuperTableFieldのtypeに設定するブロックタイプIDが決定していない点にあります。

ということで、ブロックタイプIDを取得するメソッドを作ってみます。
public function getSuperTableFieldId($ownerId, $matrixFieldHandle, $blockHandle, $tableFieldName) {
$criteria = craft()->elements->getCriteria(ElementType::MatrixBlock);
$criteria->ownerId = (int)$ownerId;
$criteria->type = $blockHandle;
$criteria->fieldId = (int)craft()->fields->getFieldByHandle($matrixFieldHandle)->id;
$blocks = $criteria->find();
if (!empty($blocks)) {
$blockTypes = craft()->superTable->getBlockTypesByFieldId($blocks[0]->$tableFieldName->fieldId);
if (!empty($blockTypes)) {
return $blockTypes[0]->id;
}
}
return false;
}
ただし、このメソッドはentryにmatrixブロックが1つ以上、存在する状態でないと機能しません。

以上を踏まえて、作成したメソッドを利用して新規ブロック追加をしてみます。
// 一旦superTableFieldは空にしておく
$matrix["new1"] = [
'type' => 'sampleBlock',
'enabled' => true,
'fields' => [
'textField' => 'abcdefg',
'numField' => 123456,
'superTableField' => [],
],
],
];

$entry->setContentFromPost(array('sampleMatrix' => $matrix));
// ブロックを追加するために、一旦保存
$success = craft()->entries->saveEntry($entry);

// superTableFieldを追加
$table["new1"] = [
'type' => $this->getSuperTableFieldId($entry->id, 'sampleMatrix', 'sampleBlock', 'superTableField'),
'enabled' => true,
'fields' => [
'columnOne' => 'sample one',
'columnTwo' => 'sample two',
],
];
$matrix['new1']['fields'][] = $table;

$entry->setContentFromPost(array('sampleMatrix' => $matrix));
$success = craft()->entries->saveEntry($entry);

一旦saveEntry()を実行してブロックを保存していますが、ブロックだけ更新するような場合は、MatrixServiceのsaveBlock()でも良いと思います。ただ、エントリーの他のフィールドも一緒に更新する場合は、saveEntry()でまとめて保存してしまったほうが良い気もするので、お好みで。

Craft CMS プラグインの作法(メール関連)

Craft CMSの設定ページでメールテンプレートを編集できますが、そのテンプレートを追加したい場合の方法。

1)プラグイン本体に、registerEmailMessages()を書く。配列に記述するのはテンプレートのキー名。
public function registerEmailMessages() {
return array(
'template_one',
'template_two',
);
}


2)プラグインのtranslationsフォルダにja.phpやen.phpを作成して、各言語毎のデフォルトテンプレートを定義する。
return array(
'template_one_heading' => 'hogehogeされた時',
'template_one_subject' => 'メール件名',
'template_one_body' => "Dear {{ user.username }}¥n¥n" . "本文.¥n¥n",
'template_two_heading' => 'hogehogeされた時',
'template_two_subject' => 'メール件名',
'template_two_body' => "Hello, {{ user.username }}¥n¥n" . "本文.¥n¥n",
);
※Craft CMSの設定ページでテンプレートを編集すると、データベースに保存されます。

3)サービス等から、テンプレート名をキーにして、送信する。配列で渡すのはテンプレートで使用するデータ。
craft()->email->sendEmailByKey($user, 'template_one', array(
'user' => $user,
'entry' => $entry,
));

Craft CMS プラグインの作法(セクション関連)

Craft CMSのプラグインを書くときの作法

スラッグでセクションを取得する


URLのslugでセクションからエントリーを1件取得する方法。
$criteria = craft()->elements->getCriteria(ElementType::Entry);
$criteria->section = 'sampleSection';
$criteria->slug = 'test-slug';
$entry = $criteria->first();

sampleSectionのsampleTagsフィールドでタグ検索した結果を取得する


$criteria->searchを使います。twigで記述した場合
{% set entries = craft.entries.section('sampleSection').search('sampleTags:test') %}
と等価です。
$criteria          = craft()->elements->getCriteria(ElementType::Entry);
$criteria->section = "sampleSection";
$criteria->search = "sampleTags:test";
$entries = $criteria->find();

新規にセクションを作成する


プラグインでセクションの新規エントリーを保存する方法。
$currentUser = craft()->userSession->getUser();
$section = craft()->sections->getSectionByHandle('sampleSection');
$section->getEntryTypes();
$entry = new EntryModel();
$entry->sectionId = $section->id;
$entry->enabled = true;
$entry->authorId = $currentUser->id;
// ToDo : セクションのフィールドを埋める
$success = craft()->entries->saveEntry($entry);

セクションのSuper Tableフィールドを更新する


new1,new2,new3…のインデックスを持った配列を設定します。新規作成時、更新時どちらも同じ方法です。
$field = craft()->fields->getFieldByHandle("sampleSuperTableField");
$blockTypes = craft()->superTable->getBlockTypesByFieldId($field->id);
$blockType = $blockTypes[0];
$superTableData = array();

$tableValues = array(
'new1' => array(
'sampleTextField' => 'foobar',
'sampleAssetFileField' => $assets,
),
'new2' => array(
'sampleTextField' => 'foobar',
'sampleAssetFileField' => $assets,
),
);

foreach($tableValues as $key => $value) {
$superTableData[$key] = array(
'type' => $blockType->id,
'enabled' => true,
'fields' => $value,
);
}
$entry->setContentFromPost(array("sampleSuperTableField" => $superTableData));

$success = craft()->entries->saveEntry($entry);

アセットフィールドの更新


アセットフィールドはIDの配列なので、そのように設定します。タグフィールドやカテゴリフィールドも基本的に同じです。
$entry->getContent()->setAttributes(array(
"sampleAssetField" => array($assetModel->id),
));
$success = craft()->entries->saveEntry($entry);


Razer Tiamat 7.1 (v1) イヤーパッドを交換

Razer Tiamat 7.1 (V1) のイヤーパッドが加水分解でボロボロになってしまったので交換しました。ほぼ毎日使っている(仕事の時も通話用に使っている)ので、痛むのが早いです。

amazonで探すと、Tiamat 7.1用のイヤーパッドはノーブランド品が、かなり多く出品されているので、とりあえず適当に選んでみました。

Tiamat 7.1のイヤーパッドは樹脂製のピンで固定するようになっているんですが、購入したイヤーパッドはピンを通す穴が無いので、自分で開ける必要があります。ドライバーセットのキリで、適当に穴を開けて取り付け。

純正のイヤーパッドと比べると、若干小ぶりでスポンジの量が多くパンパンですが、装着感はあまり変わらないので良しとします。

GMYLE スマートコンセントの設定(IFTTT編)

ということで、IFTTTのレシピも作りました。

Maker Channelでwebhookを有効にして、トリガーをwebhookに、thatにはSmartlifeのturn-onとturn-offを設定しています。

ASUSモニターの電源を切るレシピ



win10にインストールしているGit Bashでcurlを叩いてみます("your-key"には自分のキーを入れます)。
$ curl -X POST https://maker.ifttt.com/trigger/asus-off/with/key/your-key
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 48 100 48 0 0 48 0 0:00:01 0:00:01 --:--:-- 38
Congratulations! You've fired the asus-off event

だいたい、3〜5秒後に電源がOFFになりました。

これをタスクスケジューラーを使って、スリープから復帰時に実行すればいいわけです。
ですが、一旦、電源OFFにしてONにする必要があり、トータル10秒くらいかかりそうなので…

やめました。