web-dev-qa-db-ja.com

EntityFieldQueryを使用して特定の役割を持つすべてのユーザーを取得する

これは簡単な作業だと思いましたが、Drupalによる方法はないようです。私は EntityFieldQuery を使用する必要があることを知っている限り、APIが user_load_multiple() の条件は廃止されると述べたためです。

だから私はこれを試しました:

  $query = new EntityFieldQuery;
  $query
    ->entityCondition('entity_type', 'user')
    ->propertyCondition('rid',array(1,2,3);

  $result = $query->execute();

それでも私はこれを得ました:

PDOException:SQLSTATE [42S22]:列が見つかりません:1054不明な列 'users.rid' in 'where句':SELECT users.uid AS entity_id、:entity_type AS entity_type、NULL AS revision_id、:bundle AS bundle FROM {users} users WHERE(users.rid =:db_condition_placeholder_0); EntityFieldQuery-> execute()の配列([:db_condition_placeholder_0] => 3 [:entity_type] => user [:bundle] => user)

だから私が最初に思ったのは、users_roles- Tableなどと結合する必要があるということでしたが、が重複することになります

誰かがそれを行う方法を知っていますか?

35
Nils Riedemann

正直なところ、これを実現する方法はわかりません。 EntityFieldQueryの使用例を見つけるのは難しいです。まだ誰もこの質問に答えていないので、私も解決策に興味があります。以下が私の推測です。

覚えておくべきこと:ロールはユーザーとは別のテーブルに格納されます。それらは serController :: attachLoad を使用して追加されます。

EntityFieldQueryで使用できる3つの異なる条件があるようです。

  1. entityCondition (エンティティ固有の条件: 'entity_type'、 'bundle'、 'revision_id'または 'entity_id')
  2. fieldCondition (Field APIによって維持されるフィールドの条件)
  3. propertyCondition (エンティティプロパティの条件)

最も論理的なオプション(存在する場合)はpropertyConditionを使用することですが、ロールが serController :: attachLoad でユーザーに追加されるため、EntityFieldQueryはそれにアクセスできないと思います。 EntityFieldQueryは、hook_schema()で定義されたスキーマを使用するだけだと思います。

これは私があなたが成し遂げようとしていることは不可能であると信じさせます。回避策は、通常のクエリですべてのuidを取得することです。

Drupalへのアクセス権がないため、以下のコードが無効になっている可能性があります。誰かが間違いを編集すると確信しています。

// Use $query for readability
$query = 'SELECT DISTINCT(ur.uid) 
  FROM {users_roles} AS ur
  WHERE ur.rid IN (:rids)';
$result = db_query($query, array(':rids' => array(1,2,3)));

$uids = $result->fetchCol();

$users = user_load_multiple($uids);

EntityFieldQueryを使用して目的を達成することが可能であれば、私は啓発されます。

32
Bart

それはトリックをするべきです

  $query = new EntityFieldQuery;
  $query
    ->entityCondition('entity_type', 'user')
    ->addTag('role_filter');
  $results = $query->execute();

/**
* Implement hook_query_TAG_alter
* 
* @param QueryAlterableInterface $query
*/
function MY_MODULE_query_role_filter_alter(QueryAlterableInterface $query) {
  $query->leftJoin('users_roles', 'r', 'users.uid = r.uid');  
  $and = db_and()
            ->condition('r.rid', MY_ROLE_INT, '=');
  $query
    ->condition($and);
}
19
alf

実際にこれを行う方法があります。本質的に、EntityFieldQuery(EFQ)は、クエリ変更フックで変更できる単なるデータベースクエリです。

最も簡単な例:

function mymodule_get_users_by_rolename($rolename){
  $query = new EntityFieldQuery;
  $query->entityCondition('entity_type', 'user');
  $query->addTag('rolequery');
  $query->addMetaData('rolename', $rolename);

  return $query->execute();
}

function mymodule_query_rolequery_alter(QueryAlterableInterface $query) {
  $rolename = $query->getMetaData('rolename');

  $role_subquery = db_select("role", "role");
  $role_subquery->condition('role.name', $rolename, '=');
  $role_subquery->join('users_roles', "users_to_include", "role.rid = users_to_include.rid");
  $role_subquery->fields('users_to_include', array('uid' => 'uid'));
  $role_subquery->where('users_to_include.uid = users.uid');
  $query->exists($role_subquery);
}

ただし、これにはいくつかの小さな注意事項があり、さらにコーディングが必要になります。たとえば、EFQに存在する唯一の条件がfieldConditionである場合、users-basetableは存在しないため、ロールと単一のfieldConditionでユーザーをフェッチする場合は、 usersテーブルが結合され、結合されていない場合は手動で結合します。これは少々面倒なプロセスです。

しかし、あなたの必要性のために、これはトリックをします。 EFQクエリを手動で変更できることに気づくと、インターフェイスをクリーンでDrupalに保ちながら、非常に強力なクエリを作成するための大きなチャンスが生まれます。

質問や問題がありましたらお知らせください。

編集:実際にこれを実行するもう少しパフォーマンスの高い方法を見つけ、それに応じてコードを変更しました。

16
$user_list = array();
$roles = array('role_1', 'role_2');
$query = db_select('users_roles', 'ur');
$query->join('users', 'u', 'u.uid = ur.uid');
$query->join('role', 'r', 'r.rid = ur.rid');
$query->fields('u',array('uid'));
$query->fields('u',array('mail'));
$query->fields('u',array('name'));

$query->condition('r.name', $roles, 'IN');
$result = $query->execute();

if($result){
    foreach($result as $row ) {
        $uid = $row->uid;
        $user_list[$uid]['mail'] = $row->mail;
        $user_list[$uid]['name'] = $row->name;
        $user_list[$uid]['uid'] = $uid;
    }
}

return $user_list;
6
Dhanesh Haridas

/**
 * Get users by specific role
 */
function mymodule_get_users_by_role() {
    $role = user_role_load_by_name('rolename');
    $uids = db_select('users_roles', 'ur')
        ->fields('ur', array('uid'))
        ->condition('ur.rid', $role->rid, '=')
        ->execute()
        ->fetchCol();
    $users = user_load_multiple($uids);
}
5
ibit

たとえばfieldCondition()または別のメソッドを使用したい場合など、必要に応じて、ロールのユーザーIDを取得した後でもEntityFieldQuery()を使用できます。

上記の例で$ uids配列を使用します。

$role = user_role_load_by_name('my_role_name');
$result = db_select('users_roles', 'ur')
->fields('ur', array('uid'))
->condition('rid', $role->rid)
->execute();

foreach($result as $record) {
  $uids[] = $record->uid;
}

$query = new EntityFieldQuery();
$query->entityCondition('entity_type', 'user')
->entityCondition('entity_id', $uids, 'IN')
->execute();

EntityFieldQueryにjoinメソッドがあると、さらに便利です。

5
JUPITER

OKこれは古いものですが、次のようなことができます。

$query = new EntityFieldQuery();
$query->entityCondition('entity_type', 'user')

$roles_subquery = db_select('users_roles', 'ur');
$roles_subquery->fields('ur', array('uid'));
$roles_subquery->condition('rid', $my_role_id);

$query->propertyCondition('uid', $roles_subquery, 'IN');
4
Fabio Epifani

これは少し遅れますが、OPが求めていたものだと思います。例えばSQLなし、すべてdrupal。うまくいけば、他の人もそれが役に立つと思うでしょう。これを検索してここにたどり着きました。これが私が思いついたものです。

    /**
     * Users with role
     *
     * @param $role mixed The name or rid of the role we're wanting users to have
     * @param $active_user boolean Only return active accounts?
     *
     * @return array An array of user objects with the role
     */
    function users_with_role($role, $active_user = TRUE) {
      $uids = array();
      $users = array();
      if (is_int($role)) {
        $my_rid = $role;
      }
      else {
        $role_obj = user_role_load_by_name($role);
      }
      $result = db_select('users_roles', 'ur')
        ->fields('ur')
        ->condition('ur.rid', $role_obj->rid, '=')
        ->execute();
      foreach ($result as $record) {
        $uids[] = $record->uid;
      };
      $query = new EntityFieldQuery();
      $query->entityCondition('entity_type', 'user')
        ->propertyCondition('uid', $uids, 'IN');
      if ($active_user) {
        $query->propertyCondition('status', 1);
      }
      $entities = $query->execute();
      if (!empty($entities)) {
        $users = entity_load('user', array_keys($entities['user']));
      }
      return $users;
    }
2
Gold

これは確かに古いトピックであり、多くの良いアプローチを見つけました。

@alfによって提供されるソリューションを少し改善します。結合を使用した1つのクエリが最善のアプローチだと思うからです。ただし、関数にはパラメーターがあり、定数に依存しないことも好きです。だからここに行く:

function MY_MODULE_load_users_by_role($rid) {
  $query = new EntityFieldQuery;
  $query
    ->entityCondition('entity_type', 'user')
    ->addMetaData('account_role', user_role_load($rid))
    ->addTag('role_filter');
  $results = $query->execute();

  if (isset($results['user'])) {
    $uids = array_keys($results['user']);
    $users = entity_load('user', $uids);
  }
  else {
    $users = array();
  }

  return $users;
}

/**
 * Implement hook_query_TAG_alter
 *
 * @param QueryAlterableInterface $query
 */
function MY_MODULE_query_role_filter_alter(QueryAlterableInterface $query) {
  $rid = $query->alterMetaData['account_role']->rid;
  $query->leftJoin('users_roles', 'r', 'users.uid = r.uid');
  $and = db_and()
    ->condition('r.rid', $rid, '=');
  $query
    ->condition($and);
}
0
benelori