it-swarm.asia

باستخدام OR مع EntityFieldQuery

لم أكن في حاجة أبدًا إلى القيام بذلك قبل اليوم ، ولكن لا يبدو أنه يمكنك إجراء OR استعلامات مع EntityFieldQuery ، منذ db_or يستخدم لاستعلامات مختارة.

سيصل مثال إلى جميع الكيانات التي تحتوي على حقل تاريخ حيث تكون القيمة فارغة أو بعد اليوم.

هل أفقد شيئًا أو خدعة أم أن هذا ببساطة غير مدعوم؟

26
googletorp

لقد رأيت حل هذه المشكلة . الفكرة هي استخدام addTag() في الاستعلام وتنفيذ hook_query_TAG_alter() ، حيث يكون لديك كائن SelectQuery جيد جدًا.

22
Michael

يمكنك عمل فئة فرعية EntityFieldQuery وتجاوز بعض الطرق.

تتم إضافة الشروط التي تمت إضافتها إلى كائن من الفئة EntityFieldQuery (على سبيل المثال ، شرط خاصية) إلى مصفوفة.

  public function propertyCondition($column, $value, $operator = NULL) {
    // The '!=' operator is deprecated in favour of the '<>' operator since the
    // latter is ANSI SQL compatible.
    if ($operator == '!=') {
      $operator = '<>';
    }
    $this->propertyConditions[] = array(
      'column' => $column, 
      'value' => $value, 
      'operator' => $operator,
    );
    return $this;
  }

عند إنشاء الاستعلام ، يتم استخدام هذا الصفيف في حلقة مشابهة للحلقة التالية (الرمز موجود في EntityFieldQuery :: propertyQuery () ):

foreach ($this->propertyConditions as $property_condition) {
  $this->addCondition($select_query, "$base_table." . $property_condition['column'], $property_condition);
}

يحتوي $select_query على القيمة التي تم إرجاعها من استدعاء إلى db_select().

12
kiamlaluno

لا يمكنك أن أخشى ، ORs غير مدعومة أصلاً من فئة EntityFieldQuery.

قد تكون إحدى الطرق لإضافة علامة إلى الاستعلام باستخدام ->addTag() ، ثم تنفيذ hook_query_TAG_alter() لتغيير البنية الداخلية للاستعلام يدويًا للاستعلامات تحتوي على تلك العلامة.

من خلال القيام بذلك ، سوف تكون قادرًا على تكرار الشروط الحالية وإجراء التعديلات اللازمة لإضافة منطق OR. إنها ليست طريقة جميلة للقيام بذلك ؛ يمكنك العثور على مثال هنا .

5
Clive

لا حاجة لتقسيم الاستعلامات إلى 2 ودمجها أو أي شيء من هذا القبيل. تحتاج فقط إلى تغيير الاستعلام

خذ بعين الاعتبار السيناريو: كان لدي نوعان من الكيانات بأسماء الأجهزة: عبارات tincan و tincan_agents

5 حقول مرجعية للكيان على الكيان

4 منها حقول مرجعية منتظمة للكيان والخامس (tincan_object) هو حقل مرجعي من نوع متعدد الكيانات ، يشير كل حقل مرجعي إلى كيانات من نوع "وكيل".

يمكن أن يشير الحقل المرجعي tincan_object إلى الوكلاء والأنشطة (نوع كيان ثالث). لدى الوكيل خاصية object_type ، والتي يمكن أن تكون إما وكيل أو مجموعة.

أريد العثور على أي بيان يشير إلى أحد الوكلاء المحتملين العديدين في أي من حقول المراجع. نحتاج إلى عامل تشغيل OR بين fieldConditions ، لكننا نحتاج أيضًا إلى التحقق من نوع object_type للحقل المرجعي لنوع متعدد الكيانات ، والتأكد من أنه أحد الاحتمالين.

يمثل الكود أدناه أبسط ما يمكن ، ففي حلنا كان للاستعلام العديد من الشروط والحقول الأخرى ، إلخ ... لذا فإن الكود المطلوب لعدم الاعتماد على ترتيب الشروط ، أو حتى إذا تم الاستعلام عن جميع هذه الحقول.

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

    $all_agents = array(4,10); //entity_ids to search for
    $query->addTag('tincan_statement_get_agents');
    $query->fieldCondition('tincan_actor', 'target_id', $all_agents, 'IN'); 
    //need OR between fields conditions
    $query->fieldCondition('tincan_authority', 'target_id', $all_agents, 'IN');
//need OR between fields conditions
    $query->fieldCondition('tincan_instructor', 'target_id', $all_agents, 'IN');
//need OR between fields conditions
    $query->fieldCondition('tincan_team', 'target_id', $all_agents, 'IN');
//need OR between fields conditions
//but then nested in the OR structure we need an AND for two columns of the multientity type reference field tincan_object
    $query->fieldCondition('tincan_object', 'target_id', $all_agents, 'IN');
    $query->fieldCondition('tincan_object', 'object_type', array('Agent', 'Group'), 'IN');
    $results = $query->$execute();

الحل: إشعار في EntityFieldQuery أعلاه

 $query->addTag('tincan_statement_get_agents');

يؤدي هذا إلى وضع علامة على الاستعلام ، مما يسمح بتنفيذ hook_query_TAG_alter ()

/**
 * Implements hook_query_TAG_alter()
 * alters the query for finding agents with or without the related_agents flag
 * used for Statement API Get processor EntityFieldQuery
 */
function tincan_lrs_query_tincan_statement_get_agents_alter(QueryAlterableInterface $query) {
  //need to or the search for all the fields (actor, object, authority, instructor, team)
  // the object_type of the object field needs to be Agent OR Group

  $conditions =& $query->conditions();
  // dsm($conditions);  //dsm() is your friend! comes with devel module
  $agent_grouping_condition = db_or(); 
  $object_parameters = array();
  $x = 0;
  foreach ($conditions as $key => $condition) {
    if (is_numeric($key) && isset($condition['field']) && is_scalar($condition['field'])) {
      if ( (strpos($condition['field'], 'tincan_object_object_type') !== FALSE  ||
          strpos($condition['field'], 'tincan_object_target_id') !== FALSE ) && $condition['operator'] == 'IN') {
  //u
            unset($conditions[$key]);
            $object_parameters[$x]['field'] = $condition['field'];
            $object_parameters[$x]['value'] = $condition['value'];
            $object_parameters[$x]['operator'] = $condition['operator'];
            $x += 1;
          }

       if(strpos($condition['field'], 'tincan_actor_target_id') !== FALSE ||
          strpos($condition['field'], 'tincan_instructor_target_id') !== FALSE ||
          strpos($condition['field'], 'tincan_team_target_id') !== FALSE ||
          strpos($condition['field'], 'tincan_authority_target_id') !== FALSE ) {
            unset($conditions[$key]);
            $agent_grouping_condition->condition($condition['field'], $condition['value'], $condition['operator']);

      } 
    }
  }

  // create new AND condition to nest in our OR condition set for the object parameters
  $object_condition = db_and();
  foreach($object_parameters as $key => $param) {
    $object_condition->condition($param['field'], $param['value'], $param['operator']);
  }

  $agent_grouping_condition->condition($object_condition);

  $query->condition($agent_grouping_condition);

  //By default EntityFieldQuery uses inner joins, change to left
  $tables =& $query->getTables();

  foreach($tables as $key => $table) {
    if (strpos($key, 'field_data_tincan_object') !== FALSE ||
        strpos($key, 'field_data_tincan_actor') !== FALSE ||
        strpos($key, 'field_data_tincan_authority') !== FALSE ||
        strpos($key, 'field_data_tincan_instructor') !== FALSE ||
        strpos($key, 'field_data_tincan_team') !== FALSE ) {
          if(!is_null($table['join type'])) {
            $tables[$key]['join type'] = 'LEFT';
          }
    }
  }

}
5
jackrabbithanna

يريد OP الاستعلام عن الكيانات التي يكون تاريخها فارغًا OR أكبر من x ، وأردت الاستعلام عن العقد بدون لغة محددة OR لغة المستخدم. addTag() هو أفضل حل لإضافة عبارة OR فعلية ، ولكنه سيكون مبالغًا فيه في حالتي. يمكن تحقيق OR البسيط من خلال البحث عن خاصية اللغة في مصفوفة باستخدام:

$query->propertyCondition('language', array($GLOBALS['language']->language, LANGUAGE_NONE), 'IN');
2
lmeurs