フィールドコレクション内のフィールドの保存に問題があります。これが私がすることです:私はノードを持っていて、そのフィールドの1つはフィールドコレクションです。収集されたフィールドの1つはオーディオファイルで、他の3つは説明、ビットレート、期間です。つまり次のようになります。
Node
ユーザーに、ノード編集でオーディオファイルをアップロードしてから、getId3ライブラリを使用して、presaveのビットレートフィールドと期間フィールドにプログラムで入力することを望んでいました。しかし、presaveでビットレートと期間を設定して、node_saveがそれらをdbに保存するのを待つことはできないようです。以下は、ビットレートと継続時間の両方を正常に設定するが、DBには何も保存しないコードの一部です。
require_once('sites/all/libraries/getid3/getid3/getid3.php');
function mymodule_node_presave($node)
{
$wrapper = entity_metadata_wrapper('node', $node);
// Initialize getID3 engine
$getID3 = new getID3;
foreach($wrapper->field_song_with_params as $i => $value)
{
//getting file info
$mp3FileInfo = $wrapper->field_song_with_params[$i]->field_mp3->value();
$id3_fileinfo = $getID3->analyze(drupal_realpath($mp3FileInfo['uri']));
//setting duration and bitrate
$wrapper->field_song_with_params[$i]->field_mp3_duration->set($id3_fileinfo['playtime_string']);
$wrapper->field_song_with_params[$i]->field_mp3_bitrate->set($id3_fileinfo['bitrate']);
}unset($i);
//$wrapper->save(); Calling this results in a fatal connectivity error
}
それで、私は何を間違っているのですか、それを正しく設定するにはどうすればよいですか?
更新:それに約3日間費やした後、私はそれを理解しました。ここでコードを提供します。フィールドコレクションのフィールドを自動的に更新することで別の不運なことに対処できる可能性がありますが、フィールドコレクションを処理するための「適切な」方法がないようです(または少なくとも私は知りません)。コードは不完全です、警告されます。しかし、それは機能します。
1)最初に、フォーム送信時に呼び出されるハンドラーを追加します。呼ばれる特定のタイプのノードでのみハンドラが必要です article_song フィールドコレクションフィールドが含まれています。
function mymodule_form_article_song_node_form_alter(&$form, &$form_state, $form_id)
{
$form['#submit'][] = 'my_audio_file_properties_submit_handler';
}
2)それから嫌悪感があります。コメントは多いので、ここでは詳しく説明しません。 field_song_with_params フィールドコレクションフィールドの名前です。 field_mp3 アップロードされた音声ファイルを保持する収集フィールドです。 field_mp3_duration そして field_mp3_bitrate それぞれ期間とビットレートを含む収集フィールドです。
function my_audio_file_properties_submit_handler(&$form, &$form_state)
{
// Initialize getID3 engine
$getID3 = new getID3;
// here is how audio file field collection looks like on form
$song_field_collection_on_form = $form['field_song_with_params'][LANGUAGE_NONE];
//for every audio file and its params do the following:
foreach($song_field_collection_on_form as $i => $song_collected_fields)
{
//need to check that $i is a real index of a FieldCollection entity.
//Something belonging to $song_field_collection_on_form is not necessarily a FieldCollection
//there are other properties there like #theme and so on.
if(is_array($song_collected_fields) &&
array_key_exists('#entity_type', $song_collected_fields) &&
$song_collected_fields['#entity_type'] == 'field_collection_item')
{
//Getting file id value
$file_id = $song_collected_fields['field_mp3'][LANGUAGE_NONE][0]['fid']['#value'];
//if it is something meaningful (yeah it can be something crazy)
if($file_id != 0)
{
//load file properties from db
$file_info = file_load($file_id);
$id3_fileinfo = $getID3->analyze(drupal_realpath($file_info->uri));
// here is an FieldCollection entity at $form_state that
// needs to be updated in order to tell drupal that value
// should persist to db.
// Normally people use something like form_set_value
// http://api.drupal.org/api/drupal/includes!form.inc/function/form_set_value/7
// but to work with it a value must be somewhere in a nested array
// and in this case a value is in a FieldCollection Entity
// that in its turn is in a nested array
$song_field_entity_in_form_state = $form_state
['values']
['field_song_with_params']
[LANGUAGE_NONE]
[$i]
['entity'];
//setting duration
$song_field_entity_in_form_state->field_mp3_duration[LANGUAGE_NONE][0]['value'] = $id3_fileinfo['playtime_string'];
//setting bitrate
$song_field_entity_in_form_state->field_mp3_bitrate[LANGUAGE_NONE][0]['value'] = $id3_fileinfo['bitrate'];
}
}
}
}
フィールドコレクションアイテムの削除/作成/変更の例を示す良い投稿は、ここにあります。
http://rajanmayekar.com/blog/programmatically-creating-deleting-modifying-field-collection-item-node
私は実際にこれを自分で実装する必要があり、それは少し異なっていました。これは、ノードの挿入/更新時にプログラムでフィールドコレクション項目を追加する方法です。ただし、アイテムを更新するロジックはありません。これにより、アイテムが作成されるだけです。
/**
* Implements hook_entity_insert().
*
* We use this hook as it's called later than node_insert().
*/
function HOOK_entity_insert($node, $type) {
module_field_collection_stuff($node, $type);
}
/**
* Implements hook_entity_update().
*/
function HOOK_entity_update($node, $type) {
module_field_collection_stuff($node, $type);
}
/**
* Do your magic
*/
function module_field_collection_stuff($node, $type) {
if ($type != 'node' || $node->type != 'my_content_type') {
return;
}
// Create a dummy node so we can update the real node without
// triggering all the node fields hooks.
$update = new stdClass();
$update->nid = $node->nid;
$update->type = $node->type;
$update->status = $node->status;
$update->language = $node->language;
$values['field_name'] = 'field_collection_field';
$values['field_item_first'][LANGUAGE_NONE][0]['value'] = 'value';
$values['field_item_second'][LANGUAGE_NONE][0]['value'] = 'second';
// Create new field collection item.
$field_collection_item = entity_create('field_collection_item', $values);
// Attach it to the node
$field_collection_item->setHostEntity('node', $update, LANGUAGE_NONE, true);
// Save field-collection item, without trigger the nodes own save.
// This is because you might want to insert multiple field collection items.
$field_collection_item->save(TRUE);
// Update the fields.
field_attach_presave('node', $update);
field_attach_update('node', $update);
}
$ wrapper-> save()の呼び出しは、最初にユーザー1に切り替えた場合に機能します。
// switch to user 1 to update field_collection_item
global $user;
$original_user = $user;
$old_state = drupal_save_session(FALSE);
$user = user_load(1);
$wrapper->save();
// be sure to switch back to the original user
$user = $original_user;
drupal_save_session($old_state);
ユーザー切り替えコードは、Views Bulk Operationsの機能リクエスト https://drupal.org/node/1334088#comment-5870512 からのものです。
これは、フィールドコレクションの更新に何らかの権限の問題があることを示していますが、その方法で整理することはできません。
if (isset($profile->field_childrens_info[LANGUAGE_NONE][$i])) {
// update
$fc_item = reset(entity_load('field_collection_item', array($profile->field_childrens_info[LANGUAGE_NONE][$i]['value'])));
}
ここであなたを助けることができるかどうかわかりませんが、ノードを更新します(新しいフィールドコレクションを追加します)
$mynode = node_load(25);
$field_collection_item = entity_create('field_collection_item', array('field_name' => 'field_joinedmembers'));
$field_collection_item->setHostEntity('node', $mynode);
$field_collection_item->field_members_name[LANGUAGE_NONE][]['uid'] = $user->uid;
$field_collection_item->field_initiative[LANGUAGE_NONE][]['nid'] = arg(2);
$field_collection_item->save();
これは、保存する前にfield_collectionを更新する方法に関する元の質問に回答するための私の貢献です(フォームフックで提案された手法の使用は避けてください)。
ノードにアタッチされたフィールドコレクションがあり、コレクションの1つのフィールドを更新したいと思っていました。これは、hook_field_collection_item_presave(FieldCollectionItemEntity $ field_collection_item)を呼び出すことで実現できます。
function mymodule_field_collection_item_presave(FieldCollectionItemEntity $ field_collection_item){$ field_collection_item-> field_addr [LANGUAGE_NONE] ['0'] = "XXX"; }
以下のコードを使用して、項目IDごとにフィールドコレクションの詳細を保存/更新できます
<?PHP
global $user;
$field_collection_item = entity_load('field_collection_item', array($value));
$field_collection_item[$value]->field_members_name[LANGUAGE_NONE][]['uid'] = $user->uid;
$field_collection_item[$value]->field_initiative[LANGUAGE_NONE][]['nid'] = arg(2);
$field_collection_item[$value]->save();
?>