1

The craft variable allows you to chain queries for your Elements. For example, you can query the first Entry in a section with either of the following syntaxes:

{% set entry = craft.entries({ section: 'news' }).one() %}
{% set entry = craft.entries.section('news').one() %}

How do we support both of these syntaxes in a Custom Element type?

The Craft Variable defines the entries tag like so:

public function entries(array $criteria = []): EntryQuery
{
  $query = Entry::find();
  Craft::configure($query, $criteria);

  return $query;
}

And, within the EntryQuery class, a public section method is defined:

public function section($value)
{
  if ($value instanceof Section) {
    $this->structureId = ($value->structureId ?: false);
    $this->sectionId = $value->id;
  } else if ($value !== null) {
    $this->sectionId = (new Query())
      ->select(['id'])
      ->from([Table::SECTIONS])
      ->where(Db::parseParam('handle', $value))
      ->column();
  } else {
    $this->sectionId = null;
  }

  return $this;
}

And there appears to be a __set method on the EntryQuery that also references the section method:

public function __set($name, $value)
{
  switch ($name) {
    case 'section':
      $this->section($value);
      break;
    case 'type':
      $this->type($value);
      break;
    case 'authorGroup':
      $this->authorGroup($value);
      break;
    default:
      parent::__set($name, $value);
  }
}

I've experimented with all of those and still only seem to be able to support the first syntax:

{% set entry = craft.entries({ section: 'news' }).one() %}

But can't seem to find a way to support the second syntax:

{% set entry = craft.entries.section('news').one() %}

What am I overlooking? What does a custom Element Type need to add to support the chained syntax for an Element Query via a Twig variable?

1 Answer 1

3

You need to return the instance in every single set call. As you noticed correctly the last line in every function that changes properties of your query is return $this which allows you to chain another function after the call. Simple as that.

Always return the query until you execute it with all() or another function like that is enough

1
  • Thanks for the clarification. Not sure why things were not working originally. It may have had something to do with where I was killing the script to test in the variable class and how the chained methods get processed. Seems as if it's all working now. Commented Apr 7, 2019 at 13:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.