Pular para conteúdo

Query Engine

O MIDDAG possui um query engine com query builder imutavel. Toda chamada retorna uma nova instancia, preservando a query original.

Query básica

use local_middag\facade\query_executor;
use local_middag\facade\query_builder;
use local_middag\framework\shared\enum\operator;

$query = query_builder::make()
    ->domain(\local_meuplugin\extensions\catalogo\item_catalogo::class)
    ->where('status', operator::EQ, 'active');

$result = search_executor::execute($query);

foreach ($result as $item) {
    echo $item->get_id();
}

Operadores

Operador SQL Uso
operator::EQ = Igualdade
operator::NEQ <> Diferente
operator::GT > Maior que
operator::GTE >= Maior ou igual
operator::LT < Menor que
operator::LTE <= Menor ou igual
operator::LIKE LIKE Pattern matching (%valor%)
operator::IN IN Pertence a lista
operator::NOT_IN NOT IN Não pertence a lista
operator::BETWEEN BETWEEN Dentro de faixa (inclusive)
operator::IS IS Comparacao com NULL
operator::IS_NOT IS NOT Comparacao negada com NULL

Paginacao

$query = query_builder::make()
    ->domain(\local_meuplugin\extensions\catalogo\item_catalogo::class)
    ->where('status', operator::EQ, 'active')
    ->paginate(page: 1, per_page: 20);

$result = search_executor::execute($query);

$result->items();       // Itens da página atual.
$result->total();       // Total de registros (ignora páginação).
$result->page();        // Página atual.
$result->perpage();     // Itens por página.
$result->pages();       // Total de páginas.
$result->count();       // Quantidade de itens nesta página.
$result->is_empty();    // Nenhum resultado?
$result->first();       // Primeiro item ou null.
$result->last();        // Ultimo item ou null.

O result implementa Countable e IteratorAggregate. Use diretamente em foreach.


Ordenacao

$query = query_builder::make()
    ->domain(\local_meuplugin\extensions\catalogo\item_catalogo::class)
    ->order_by('timecreated DESC');

O parametro é uma string SQL raw: 'campo ASC' ou 'campo DESC'.


Metadata

Filtre por campos de metadata (tabela auxiliar):

$query = query_builder::make()
    ->domain(\local_meuplugin\extensions\catalogo\item_catalogo::class)
    ->where_meta('cor', operator::EQ, 'azul')
    ->where_meta_in('tamanho', ['P', 'M', 'G']);

Para carregar metadata nos resultados (eager loading):

$query = query_builder::make()
    ->domain(\local_meuplugin\extensions\catalogo\item_catalogo::class)
    ->with_metadata(['cor', 'tamanho', 'peso']);

Global scopes

Global scopes são filtros automaticos aplicados a toda query (multi-tenancy, soft deletes, etc.).

Criar um global scope

namespace local_meuplugin\extensions\catalogo;

use local_middag\base\global_scope;
use local_middag\framework\infrastructure\query_engine\query_builder_interface;

class active_items_scope extends global_scope
{
    public function apply(query_builder_interface $builder): query_builder_interface
    {
        return $builder->where('status', \local_middag\framework\shared\enum\operator::EQ, 'active');
    }

    public function should_apply(): bool
    {
        return true;
    }
}

Ignorar scopes em uma query específica

// Ignorar um scope específico.
$query = query_builder::make()
    ->without_global_scope('active_items');

// Ignorar todos os global scopes.
$query = query_builder::make()
    ->without_global_scopes();

Atalhos de filtragem

// IN / NOT IN
$query = query_builder::make()
    ->where_in('type', ['article', 'page'])
    ->where_not_in('status', ['deleted', 'archived']);

// BETWEEN
$query = query_builder::make()
    ->where_between('timecreated', $start_timestamp, $end_timestamp);

// LIMIT sem páginação
$query = query_builder::make()
    ->limit(10);

Joins

$query = query_builder::make()
    ->domain(\local_meuplugin\extensions\catalogo\item_catalogo::class)
    ->join_course('c')
    ->join_user('u')
    ->where('c.visible', operator::EQ, 1);

Joins disponiveis:

Metodo Tabela
join_item($alias) middag_items
join_course($alias) course
join_user($alias) user
join($table, $alias, $on, $type) Qualquer tabela

Relations (eager loading)

$query = query_builder::make()
    ->domain(\local_meuplugin\extensions\catalogo\item_catalogo::class)
    ->with_relation('author')
    ->with_relation('category');

Relations são registradas pela extension e resolvidas automaticamente pelo query engine.


Select específico

$query = query_builder::make()
    ->domain(\local_meuplugin\extensions\catalogo\item_catalogo::class)
    ->select(['id', 'fullname', 'status']);

Resultados como stdClass

Por padrão, resultados são hidratados como entities do dominio. Para receber stdClass raw:

$query = query_builder::make()
    ->domain(\local_meuplugin\extensions\catalogo\item_catalogo::class)
    ->as_std_class();

Query completa

Exemplo combinando multiplas condicoes:

use local_middag\facade\query_executor;
use local_middag\facade\query_builder;
use local_middag\framework\shared\enum\operator;

$query = query_builder::make()
    ->domain(\local_meuplugin\extensions\catalogo\item_catalogo::class)
    ->where('status', operator::EQ, 'active')
    ->where('timecreated', operator::GTE, $desde_timestamp)
    ->where_in('type', ['article', 'page'])
    ->where_meta('featured', operator::EQ, '1')
    ->with_metadata(['cor', 'tamanho'])
    ->with_relation('author')
    ->join_course('c')
    ->where('c.visible', operator::EQ, 1)
    ->order_by('timecreated DESC')
    ->paginate(page: 1, per_page: 20);

$result = search_executor::execute($query);

echo "Total: {$result->total()}, Paginas: {$result->pages()}";

foreach ($result as $item) {
    echo $item->get_id() . ' - ' . $item->get_fullname();
}