Pular para conteúdo

Conditions

O Condition Engine avalia regras de inclusao e exclusao baseadas em contextos Moodle. Ele responde a pergunta: "esta regra se aplica neste contexto?" — considerando categorias, cursos e tipos de atividade.

O sistema faz parte do Core Capability CC-09 (core.conditions) e esta sempre disponivel via core extension.


Exemplo rapido

Verificar se um contexto Moodle corresponde a uma regra de condicao:

use local_middag\facade\conditions;
use local_middag\framework\contract\condition_rule;

// Regra: incluir apenas cursos das categorias 5 e 12, excluindo atividades do tipo quiz
$rule = new condition_rule(
    include_category_ids: [5, 12],
    exclude_module_types: ['quiz'],
);

// Verificar se o contexto atual corresponde
$context = \core\context\course::instance($course_id);

if (conditions::matches($rule, $context)) {
    // A regra se aplica neste contexto
}

Conceitos

Conceito Descricao
Condition rule Value object que define criterios de inclusao/exclusao
Condition provider Implementacao que avalia um tipo customizado de condicao
Contexto Moodle Objeto core\context (sistema, categoria, curso, modulo, bloco)
Graceful degradation Quando nenhuma regra esta configurada, todos os contextos correspondem

A logica de avaliacao segue o padrao:

  1. Se nao ha regras (rule vazia), tudo corresponde.
  2. Se ha listas de inclusao, apenas os contextos listados correspondem.
  3. Se ha listas de exclusao, os contextos listados sao removidos do match.
  4. Inclusao e exclusao podem ser combinadas: inclusao filtra primeiro, exclusao remove depois.

Referencia da API

conditions_interface (contract @api)

Metodo Descricao
matches(condition_rule $rule, context $context): bool Verifica se o contexto corresponde a regra
get_applicable_context_ids(condition_rule $rule): array Retorna todos os context IDs que correspondem a regra

Acesso via facade:

use local_middag\facade\conditions;
use local_middag\framework\contract\condition_rule;

$rule = new condition_rule(include_course_ids: [10, 20, 30]);

// Verificar um contexto especifico
$matches = conditions::matches($rule, $context);

// Obter todos os contextos que correspondem
$context_ids = conditions::get_applicable_context_ids($rule);

condition_rule (value object @api)

final readonly class condition_rule
{
    public function __construct(
        public array $include_category_ids = [],  // Categorias a incluir (vazio = todas)
        public array $exclude_category_ids = [],  // Categorias a excluir
        public array $include_course_ids   = [],  // Cursos a incluir (vazio = todos)
        public array $exclude_course_ids   = [],  // Cursos a excluir
        public array $include_module_types = [],  // Tipos de atividade a incluir (ex: 'assign', 'quiz')
        public array $exclude_module_types = [],  // Tipos de atividade a excluir
    ) {}

    public function is_empty(): bool;  // True se nenhuma condicao esta configurada
}

O condition_rule e imutavel (readonly). Construa uma nova instancia para cada combinacao de regras.


Construindo regras

Sem restricoes (tudo corresponde)

$rule = new condition_rule();
// $rule->is_empty() === true
// matches() retorna true para qualquer contexto

Apenas categorias especificas

$rule = new condition_rule(
    include_category_ids: [3, 7, 15],
);

Excluir tipos de atividade

$rule = new condition_rule(
    exclude_module_types: ['quiz', 'forum'],
);

Combinacao: incluir cursos, excluir modulos

$rule = new condition_rule(
    include_course_ids: [101, 102, 103],
    exclude_module_types: ['quiz'],
);
// Apenas contextos nos cursos 101-103, excluindo atividades do tipo quiz

Implementar um condition provider

Extensions podem adicionar tipos customizados de condicao implementando condition_provider_interface e registrando o provider durante boot().

Exemplo: condicao por faixa horaria

namespace local_meuplugin\extensions\horarios;

use core\context;
use local_middag\framework\contract\condition_provider_interface;
use local_middag\framework\contract\condition_rule;

class time_range_condition_provider implements condition_provider_interface
{
    /**
     * Identificador unico deste tipo de condicao.
     */
    public function get_type(): string
    {
        return 'time_range';
    }

    /**
     * Avalia se o contexto corresponde dentro da faixa horaria.
     */
    public function matches(condition_rule $rule, context $context): bool
    {
        // Exemplo: verificar se a hora atual esta dentro de uma faixa
        $hour = (int) date('H');

        // Logica customizada: ativo entre 8h e 18h
        return $hour >= 8 && $hour < 18;
    }

    /**
     * Retorna todos os context IDs que correspondem.
     */
    public function get_applicable_context_ids(condition_rule $rule): array
    {
        // Para condicoes temporais, todos os contextos correspondem
        // quando a faixa horaria e valida
        if (!$this->matches($rule, \core\context\system::instance())) {
            return [];
        }

        // Delegar ao engine padrao para os context IDs
        return [];
    }
}

Registro no boot()

namespace local_meuplugin\extensions\horarios;

class horarios_extension extends \local_middag\base\extension
{
    public function boot(): void
    {
        // Registrar o provider no conditions registry
        // O registro concreto depende da implementacao do registry;
        // consulte a documentacao da versao para o metodo exato.
    }
}

Referencia do condition_provider_interface

Metodo Descricao
get_type(): string Identificador unico do tipo de condicao
matches(condition_rule $rule, context $context): bool Avalia se o contexto corresponde
get_applicable_context_ids(condition_rule $rule): list<int> Retorna todos os context IDs que correspondem

Patterns

Visibilidade condicional de componentes

Use conditions para controlar onde um componente e exibido:

use local_middag\facade\conditions;
use local_middag\framework\contract\condition_rule;

class banner_widget
{
    public function render(int $course_id): string
    {
        $rule = $this->load_visibility_rule();

        $context = \core\context\course::instance($course_id);

        if (!conditions::matches($rule, $context)) {
            return ''; // Nao exibir neste contexto
        }

        return $this->build_html();
    }

    private function load_visibility_rule(): condition_rule
    {
        // Carregar regra do banco de dados ou configuracao
        return new condition_rule(
            include_category_ids: [5, 12],
        );
    }
}

Filtrar contextos para operacoes em massa

Use get_applicable_context_ids() quando precisar aplicar uma operacao a todos os contextos validos:

use local_middag\facade\conditions;
use local_middag\framework\contract\condition_rule;

$rule = new condition_rule(
    include_category_ids: [5],
    exclude_module_types: ['quiz'],
);

$context_ids = conditions::get_applicable_context_ids($rule);

// Aplicar operacao aos contextos filtrados
foreach ($context_ids as $context_id) {
    $this->process_context($context_id);
}

Combinar conditions com segments

Conditions e segments resolvem dimensoes diferentes e podem ser compostos:

use local_middag\facade\conditions;
use local_middag\facade\segments;
use local_middag\framework\contract\condition_rule;

// 1. Verificar se o contexto e aplicavel (conditions)
$rule = new condition_rule(include_category_ids: [5]);
$context = \core\context\course::instance($course_id);

if (!conditions::matches($rule, $context)) {
    return; // Contexto nao se aplica
}

// 2. Verificar se o usuario pertence ao segmento (segments)
$subquery = segments::get_subquery($segment_id);
global $DB, $USER;

$is_targeted = $DB->record_exists_sql(
    "SELECT 1 FROM ({$subquery->sql}) sub WHERE sub.userid = ?",
    array_merge($subquery->params, [$USER->id])
);

if ($is_targeted) {
    // Contexto valido E usuario no segmento — entregar conteudo
}

Anti-patterns

Usar conditions para filtrar usuarios

Conditions filtram contextos, nao usuarios. Para filtrar usuarios, use Segments:

// ERRADO: conditions nao filtra usuarios
$rule = new condition_rule(include_course_ids: [10]);
// Nao ha como verificar "usuario X pertence a esta condicao"

// CORRETO: usar segments para usuarios
$subquery = segments::get_subquery($segment_id);

Criar regras com inclusao e exclusao redundantes

Nao inclua e exclua o mesmo valor:

// ERRADO: contraditorrio
$rule = new condition_rule(
    include_course_ids: [10, 20],
    exclude_course_ids: [20],    // 20 esta nas duas listas
);

// CORRETO: incluir apenas o necessario
$rule = new condition_rule(
    include_course_ids: [10],
);

Avaliar conditions em loop sem cache

Se voce precisa verificar o mesmo rule contra multiplos contextos, obtenha os context IDs de uma vez:

// ERRADO: N chamadas para o mesmo rule
foreach ($contexts as $ctx) {
    if (conditions::matches($rule, $ctx)) { /* ... */ }
}

// CORRETO: obter todos os IDs de uma vez
$valid_ids = conditions::get_applicable_context_ids($rule);
$valid_set = array_flip($valid_ids);

foreach ($contexts as $ctx) {
    if (isset($valid_set[$ctx->id])) { /* ... */ }
}

Diferenca entre Conditions e Segments

Aspecto Conditions (CC-09) Segments (CC-07)
Pergunta "Em quais contextos esta regra se aplica?" "Quais usuarios pertencem a este grupo?"
Alvo Contextos Moodle (categorias, cursos, atividades) Usuarios (user IDs)
Retorno bool (match) ou list<int> (context IDs) segment_subquery (SQL de user IDs)
Uso Visibilidade, filtro por area do site Audiencia, targeting, conteudo segmentado
Analogia "Onde mostrar" (page builder display conditions) "Para quem mostrar" (audience targeting)

Conditions responde onde. Segments responde para quem. Combine os dois para targeting completo.


Referencias

  • ADR-607 -- Modelo de Subdominios Core (CC-09)
  • Segments -- segmentacao de usuarios por criterios composiveis
  • Hooks -- integrar conditions com o sistema reativo