エンティティページからentity_typeおよびentity_idを取得するにはどうすればよいですか?


9

一部のページ(パス)は1つのエンティティを表しています。例えば:

  • これらのパスにあるページは、1つのノードエンティティを表します。entity_id(nid)はXXです。
    • / node / xx
    • / node / xx / delete
    • / node / xx / edit
  • このパスのページは、1つの検索サーバーエンティティ(検索APIモジュールで定義)を表し、entity_id(machine_name)は「apache_solr」です。
    • / admin / config / search / search_api / server / apache_solr

現在のフックまたは関数がそれを渡さない場合、このエンティティ(idおよびtype)に関する基本データをどのようにロードしますか?

現在のエンティティを取得する標準的な方法は明らかに使用すること menu_get_object($entity_type,$position_of_id_in_url)です。ただし、これは1つのエンティティタイプのみをコーディングしていることを前提としています。エンティティタイプをプログラムで記述する必要があり、さらに悪いことに、このエンティティが使用するエンティティIDのURL位置を調査してハードコーディングする必要があります。 。

これまでに見つけることができる最も近いのは、ページの基になるシステムURI(例:)を取得してから、この提案のようなものにsubstr(request_uri(),strlen($base_path))基づいて怪しいスイッチリストを記述し、サイトがこれまでに持っていると思われるすべての考えられるエンティティについてケースを推測し、ハードコーディングします。 。しかし、それよりももっと良いものがあるに違いありませんよね?

コアからの一般的な解決策が最善ですが、ctools(ページマネージャー、コンテキストなど)、Entity APIDevelなどの一般的なモジュールに依存する回答も受け入れます。

私の当面の必要性は、hook_field_widget_form()(適切な構成とモジュールを使用して)フィールド化可能なエンティティタイプにアタッチできるウィジェット用の編集フォームです。したがって、一般的な解決策が最善ですが、この関数内またはフォームでのみ機能する狭い答えも受け入れます(エンティティタイプに固有のIDおよびデータは$ formに埋め込まれているように見えますが、エンティティにキー入力されています特定の方法で入力するので、$ formから取り出すのは、鶏と卵の問題のようです)。

------------編集------------------

一部の人々は単純な一般的な問題を理解するのが難しいようです。これが別の使用例です(別の別の関連する問題が私が直面しています)。いくつかのエンティティーをリストするビューがあるとします。このビューは、ノードページやユーザープロファイル(またはその両方)などの1つのエンティティを表すことができるページのブロック/ペインとして配置されます。ビューのデータを読み取り、結果を確認するフックを設定しました(foreach $view->result as...)。それがhook_views_pre_renderだとしましょう、つまり$ viewオブジェクトだけを持っているということです。ビューの結果の行にページと同じエンティティIDとエンティティタイプがある場合、何かを実行したい(たとえば、行を削除したり、フィールドデータを変更したりする)。ビューの結果からこのデータを抽出するためのロジックがあるので、必要なのは、生成されているページのentity_typeとentity_idを検索して比較することだけです。そのデータはDrupalのどこかにあります。そうでなければ、Drupalはこのビューをロードする必要があることを理解できなかったでしょう。それで、それがあなたがいるフックまたは関数に渡されないとき、どうやってそれを得るのですか?


paul-mが指摘したように、「エンティティページ」とは何ですか?
Letharion 2012

[ここに正しいDrupalの用語を挿入]が表し、1つのエンティティのパス上にあるDrupalサイトのブラウザ(または「ウェブページ」、おそらく「パス」がよりDrupalの用語です)でレンダリングされたhttp配信HTMLドキュメントを意味します。たとえば、/ node / xx / delete / node / xx / editと同様に、/ node / xxはID xxの1つのノードエンティティを「表す」、/ admin / config / search / search_api / server / apache_solrはsearch_apiで定義された検索サーバーエンティティを表しますマシン名が 'apache_solr'のモジュール
user56reinstatemonica8

回答:


4

Drupal Coreでは、これを行うことはできません。そのような機能を追加するための関連する問題はここにあります

コア自体は常に2つの引数を渡します。

function($entity, $entity_type)

1年以上続いているDrupalコアディベートの1つですが、簡単な質問ですが、その問題に関連するためには、$ entityオブジェクトをすでに持っている必要があります。$ entityオブジェクトを取得することをどのように提案していますか?一般的な方法はありますか?
user56reinstatemonica8

1
$ entityオブジェクトを取得する方法がある場合、醜いが実用的なハックを使用して、drupal.org / node / 1042822#comment-5134730にリンクし、問題を解決することができます。しかし、最初に$ entityオブジェクトが必要です...
user56reinstatemonica8

4

この問題を解決する最も簡単な方法は、を実装することhook_entity_load()です。

function MODULE_entity_load($entities, $entity_type) {
  foreach ($entities as $entity) {
    $entity->entity_type = $entity_type;
  }
}

次に、によって返されるオブジェクトにmenu_get_object()は、entity_typeがバインドされます。


4

モジュールToken Filter(D7バージョン)でこれとして機能するものを見つけました:

  // Attempt to fetch the entity that is being viewed via a backtrace to the
  // field_attach_view($entity_type, $entity) function and parameters §if found.
    $backtrace = debug_backtrace();
    foreach ($backtrace as $caller) {
      if ($caller['function'] == 'field_attach_view') {
        $entity_type = $caller['args'][0];
        $entity = $caller['args'][2];
        // do stuff with entity
        break;
      }  
    } 

かなり賢いです-$ entity_typeと$ entity($ entityの代わりに$ entity_idも機能します)を含む関数が呼び出される前に発生しているはずの関数を見つけ出し、それが見つかるまでバックトレースオブジェクトを調べます。

トークンフィルターはフィールド処理モジュールであるため、その関数はfield_attach_view()の呼び出し後に常に呼び出されることがわかります。field_attach_viewの優れた汎用的な代替手段があるかどうかはわかりませんが、一般的なアプローチは機能しているようで、バックトレースデバッグコード(以前は壊れていたリンクが修正されています)をポイントにドロップすることで、特定のケースのケース固有の候補を常に見つけることができますエンティティを取得する必要があるコード内で、何が利用できるかを確認します(その後、ロジックがチェックされ、常に存在することを確認するためのテストが行​​われます)。


1
素敵なハック、本当に便利
Clive

1
素晴らしいという理由だけで賛成投票してください。地獄のようにハッキーですが、素晴らしいです。
tobynew 2017

同じ理由で反対投票:地獄のようにハッキー。
エリックモランド

1

次の例は、パスごとにエンティティとエンティティタイプを取得するために機能します。

/**
 * Get the entity and entity-type by path.
 *
 * @param string $path
 *   The path to the entity page.
 * @return array|boolean
 *   Contains the entity and the entity-type or false if entity or type could
 *   not be determinded.
 */
function custom_module_get_entity_and_entity_type_by_path($path) {
  $item = menu_get_item($_GET['internal_path']);
  if (empty($item['access']) || empty($item['page_arguments'][0]) || empty($item['load_functions'])) {
    return FALSE;
  }

  $entity = $item['page_arguments'][0];

  // Get entity-type.
  $load_function = reset($item['load_functions']);
  $entity_types = entity_get_info();
  dpm($entity_types);
  $entity_type = '';
  foreach ($entity_types as $type => $type_definition) {
    if ($load_function == $type_definition['load hook']) {
      // When the load_function from menu_get_item matches "load hook" of the
      // entity type definition, then the entity_type was found.
      $entity_type = $type;
      break;
    }
  }
  if (!$entity_type) {
    return FALSE;
  }

  return array('entity' => $entity, 'entity_type' => $entity_type);
}

0

これは役に立ちますか?

function entity_by_path($path) {
    $router_item = menu_get_item($path);

    $ent_sug_array = array();
    foreach ($router_item['map'] as $key => $value) {
        if(is_object($value) && isset($value->type)) {
           $ent_sug_array[$key] =  $value;
        }
    }

    $ent_sug = false;
    if(count($ent_sug_array) > 1) {
        $lf_sug = false;
        if(isset($router_item['load_functions'])) {
            if(count($router_item['load_functions']) == 1) {
                reset($router_item['load_functions']);
                $lf_sug = key($router_item['load_functions']);
            }
        }
        if($lf_sug !== false) {
            $ent_sug = is_object($router_item['map'][$lg_sug] && isset($router_item['map'][$lg_sug]->type)) ? $router_item['map'][$lg_sug] : $ent_sug;
        }
    } elseif(count($ent_sug_array) == 1) {
        $ent_sug = reset($ent_sug_array);
    }

    if(!empty($ent_sug)) {
        $bundle = $ent_sug->type;
        $ent_type = method_exists($ent_sug, 'entityType') ? $ent_sug->entityType() : false; //eck case
        if(empty($ent_type)) {
            $aclass = get_class($ent_sug);
            if($aclass == 'stdClass') {
                //node, user, core entity case
                if(isset($router_item['load_functions'])) {
                    $lf = reset($router_item['load_functions']);
                    $ei = entity_get_info();
                    foreach ($ei as $key => $value) {
                        if(empty('load hook'))
                            continue;
                        if($lf == $value['load hook']) {
                            $ent_type = $key;
                            break;
                        }
                    }
                }
            }else{
                //custom entity case
                $ent_type = $aclass;
            }
        }

        return array('entity'=>$ent_sug, 'type'=>$ent_type, 'bundle'=>$bundle);
    }

    return false;
}

1
関数は複雑でドキュメントが不足しているようで、自己説明変数ではなく、関数をよりよく理解するのに役立ちません。とにかく、menu_get_item()を使用した解決策も見つけた後、コードに何らかの形で含まれていることがわかりましたfunction custom_module_get_entity_and_entity_type_by_path()。あなたはentity_typeを見つけるためにはるかに多くのことをするので、どの場合に私の解決策は機能しませんか?
LarS 2017年

実際、私はあなたの関数の何が間違っていたか覚えていませんが、私のものを書く前に試してみました。私の場合、エンティティのバンドル、エンティティタイプ、およびエンティティキー値が必要です。この$ variables ['theme_hook_suggestions'] [] = "print __ {$形式} __ {$ ent ['type']} __ {$ ent ['bundle']} __ {$ nid} ";
Mykola Mykolayovich Dolynskyi 2017年

1
私の機能はそこになかったので問題はありませんでした。1週間前に投稿しました。バンドル名も必要です。多分それがより複雑な理由です。
LarS 2017年

:-D確かに一週間前。とにかく自分で書く前に他の解決策を試しました。はい、$ suggestion []を介して適切なエンティティページのカスタムテンプレートを検索するには、バンドル、エンティティID、エンティティタイプが必要です
Mykola Mykolayovich Dolynskyi 2017年

-1

この質問に対する本当の答えは、なぜデータが必要なのか、そして操作しているAPIレイヤーケーキのどのレイヤーであるかによって異なります。

ページのエンティティが必要な場合はそれを行うことはできません。特定のページには多くのエンティティが存在する可能性があります。(すべてのノード、コメント、分類法...はすべてエンティティーです。)

を使用している場合hook_field_widget_form()は、Field APIにフィールドを実装していて、答えはドキュメントにあります。エンティティタイプは$element['#entity_type']であり、APIを実装するフィールドは自分自身に関係するべきではないため、エンティティIDを取得できません。それと。

だから:なぜエンティティIDが必要なのですか?


$ elementに関するヒントをお寄せいただきありがとうございます。いずれかのパラメーターのキーを一覧表示するドキュメントページを表示するのは素晴らしい驚きです。フォームの対象となるエンティティタイプが$ formまたは$ instanceにない場合は、フォームのインスタンスの要素に含まれないと思います。もちろん、私はブラウザでhttp配信されたHTMLドキュメントの一般的な意味でのページを意味します。Drupalノードバンドルではなく、明らかにノードです。Relationモジュールからの関係を処理するウィジェットのエンティティIDが必要であり、関係のどのエンドポイントが「この」エンティティであるかを把握する必要があります。またはより一般的には...
user56reinstatemonica8

... 1つのエンティティのみを表す「ページ」のレンダリング中に呼び出すことができる関数。エンティティを参照するデータを出力し、処理しているデータを「ページ」のエンティティのデータと比較する必要があります。に印刷されます。
user56reinstatemonica8 2012

ああ、 " ページ "がページマネージャーページを意味していて、さまざまなパネルに多くのエンティティが存在する可能性がある場合、私は特定のエンティティのパス上のページのみを念頭に置いていました。これらは任意の数のエンティティをロードできますが、パス上にある1つのエンティティを「表現」します。
user56reinstatemonica8 2012

Relationモジュールがすでに面倒な作業
paul-m

最初のコメントで述べたように、Relationモジュールを使用しています。これにより、関係について必要なすべてのデータが得られます。その部分は結構です、それは私の問題ではありません。このパスが表すエンティティと、このフォームオブジェクト、フィールド、ウィジェットが対象とするエンティティを検索したいだけなので、エンティティに関するデータと関係に関するデータを比較できます。Drupalはすでにuriクエリパスを解析しており、そこからエンティティタイプを識別してエンティティIDを識別しているため、これを調べるだけの簡単なタスクになると思います。ただし、これを行う一般的な方法はないようです。
user56reinstatemonica8 2012
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.