LoginSignup
2

More than 5 years have passed since last update.

Entity URIの小技

Posted at

はじめに

Drupal8のリリースから1年以上経ちました。機能追加アップデートなども行われますます魅力的なシステムになっていると感じます。

そのような魅力的なDrupal8ですが、今年もDrupal7でのちょっとした小ネタを説明します。。

Entity URIとは?

Drupal7からエンティティの概念が導入されました。
Drupal7の段階では完全なクラス化こそされていませんが、様々なコンテンツを共通のインターフェイスで操作するための概念が導入されています

エンティティの情報の中にはバンドル名(コンテンツタイプ)や各種コールバック関数名が記憶されています。

その情報の中に、エンティティのコンテンツが表示される際のURI情報も定義されています。

develモジュールをインストールし、Execute PHPから以下のスクリプトを実行することで確認できます。

$info = entity_get_info();
dsm($info['node']['uri callback']);

上記を実行することで、ノードでは、node_uriという関数が実行されることでURIが決定されることがわかります

リダイレクトさせたい

複雑なサイトや複数のサイトを組み合わせる場合、あるコンテンツから別のアドレスへ遷移させたいといった要件が往々にして発生します。

リダイレクト、つまり対象のコンテンツを開いた後に、ページ遷移が行われるもので以下のようなケースが考えられます。

  • マイグレーションなどの結果既存コンテンツへリダイレクトを行う
    • このような場合最も高速なWebサーバーによるリダイレクトを行います。
  • コンテンツまたはユーザー情報の条件にもとづきリダイレクトを行う
    • このような場合rules, panelsなどを利用するのがよいでしょう。

URIそのものを変えたい

さて、リダイレクトは対象のコンテンツを開いた後に遷移が行われます。
しかし、Viewsなどでコンテンツを表示する時点でURIを変えたい場合はどうでしょうか?

Viewsのフィールドの設定で書き換える

幸いDrupalにはViewsモジュールという偉大なモジュールがあります。
またそのために様々な拡張モジュールがあります。

Views Conditional(https://www.drupal.org/project/views_conditional )を利用することでシンプルな要件なら事足りることでしょう。

しかし、Entity Referenceされたコンテンツの場合はどうでしょうか?

Entity Pathを利用する

https://www.drupal.org/project/entity_path
なかなか良いモジュールでエンティティのバンドルごとに、トークンを使うことで設定できます。
しかしトークンでは条件分岐が出来ません。

例えば、リンクフィールドがあり、リンクが設定されていればリンク先を、設定されていない場合は、元のリンクを利用すると行った要件に利用できません。

カスタムモジュール化

さて、上記の流れは私が実際に経験したことで、かなり残念な気持ちになりましたので、残念な気持ちで執筆致します。。

今回の要件はこうです。

  • リンクフィールドがあり、リンクが設定されている場合書き変える
  • ついでにリンクフィールドのターゲット指定も考慮してね。
  • コンテンツが表示された時常に上記を考慮してね。(ViewsやReferenceによる埋込)
  • ログインユーザーは遷移しないでね。

事実、Entity PathモジュールはEntity URIを書き換えることで実現しています。
そちらを参考にして書いたものが以下になります。

/**
 * Entityの情報を書き換えるために利用するフックを定義します。
 * Implements hook_entity_info_alter().
 */
function your_custom_entity_info_alter(&$entity_info) {
  //今回の例ではノードのarticleタイプに仕込みます
  $entity_info['node']['bundles']['article']['uri callback'] = 'your_custom_article_uri_callback';
}

/**
 * エンティティのURIを返すコールバック関数
 */ 
function your_custom_article_uri_callback($node) {
  //field_redirectという名前のリンクフィールド
  $redirects = field_get_items('node', $node, 'field_redirect');

  //ログインユーザー及びリンクが設定されていないときは元の関数をコール
  if (!user_has_role(1) || !$redirects) {
    return node_uri($node);
  }

  $redirect = reset($redirects);
  $uri = [
    'path' => $redirect['url'], //ここでリンクフィールドのリンクが設定される
    'options' => [
    ]
  ];

  //リンクフィールドのターゲットが指定されている場合、HTML属性を設定する
  if (isset($redirect['attributes']) && isset($redirect['attributes']['target']) && $redirect['attributes']['target']) {
    $uri['options']['attributes']['target'] = $redirect['attributes']['target'];
  }
  return $uri;
}

といったように、ごくごく短いコードで実現できます。
これにより、Viewsのレンダリング方法をコンテンツにした時、Referenceでコンテンツにした時に、またはイメージフィールドのリンクをコンテンツにした時などに書き換わります。

最終的には

サイトにより色々な要件があるかと思います。これがベストという方法もありません。
条件にあったものをスマートに使いこなしていきたいものです。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2