Modelo do componente

Um conceito importante em Nette é o componente. Inserimos componentes visuais interativos em páginas, formulários ou todos os seus elementos são também componentes. Há duas classes básicas das quais todos esses componentes herdam, fazem parte do pacote nette/component-model e são responsáveis pela criação da hierarquia da árvore de componentes.

Component

Nette\ComponentModel\Component é o ancestral comum de todos os componentes. Ele contém o método getName() devolvendo o nome do componente e o método getParent() devolvendo seu pai. Ambos podem ser definidos com o método setParent() – o primeiro parâmetro é o pai e o segundo é o nome do componente.

lookup(string $type): ?Component

Procura na hierarquia por um objeto da classe ou interface desejada. Por exemplo, $component->lookup(Nette\Application\UI\Presenter::class) retorna apresentador se o componente estiver conectado a ele, apesar de vários níveis.

lookupPath(string $type): ?string

Retorna o chamado caminho, que é uma cadeia formada por concatenar os nomes de todos os componentes no caminho entre o componente atual e o componente que está sendo procurado. Assim, por exemplo, $component->lookupPath(Nette\Application\UI\Presenter::class) retorna o identificador único do componente em relação ao apresentador.

Container

Nette\ComponentModel\Container é o componente pai, ou seja, o componente que contém as crianças e assim formando a estrutura em árvore. Possui métodos para facilmente adicionar, recuperar e remover componentes. É o ancestral, por exemplo, da forma ou classes Control e Presenter.

getComponent(string $name): ?Component

Devolve um componente. Tentativa de chamar de criança indefinida causa invocação de fábrica criarComponente($nome). Método createComponent($name) invoca método createComponent<component name> no componente atual e ele passa o nome do componente como parâmetro. O componente criado é então passado para o componente atual como seu filho. Chamamos essas fábricas de componentes, elas podem ser implementadas em classes herdadas de Container.

Iterando sobre as crianças

O método getComponents($deep = falso, $type = nulo) é usado para iteração. O primeiro parâmetro especifica se os componentes devem ser percorridos em profundidade (ou recursivamente). Com true, ele não só itera todos os seus filhos, mas também todos os filhos de seus filhos, etc. Segundo parâmetro servidores como um filtro opcional por classe ou interface.

foreach ($form->getComponents(true, Nette\Forms\IControl::class) as $control) {
	if (!$control->getRules()->validate()) {
		// ...
	}
}

Monitoramento de Ancestrais

O modelo de componentes Nette permite um trabalho em árvore muito dinâmico (podemos remover, mover, adicionar componentes), portanto seria um erro confiar no fato de que, depois de criar um componente, o pai, o pai da mãe, etc. são conhecidos imediatamente (no construtor). Normalmente, o pai não é conhecido de forma alguma quando o componente é criado.

Como descobrir quando um componente foi adicionado à árvore apresentadora? Não basta acompanhar a mudança dos pais, porque os pais dos pais poderiam ter sido anexados ao apresentador, por exemplo. O método do monitor ($type, $attached, $detached) pode ajudar. Cada componente pode monitorar qualquer número de classes e interfaces. A conexão ou desconexão é anunciada ligando para $attached e $detached, respectivamente, e passando o objeto da classe monitorada.

Um exemplo: A classe UploadControl, que representa o elemento do formulário para carregar arquivos nos Formulários Nette, tem que definir o atributo do formulário enctype para valorizar multipart/form-data. Mas no momento da criação do objeto, ele não precisa ser anexado a nenhum formulário. Quando modificar o formulário? A solução é simples – nós criamos um pedido de monitoramento no construtor:

class UploadControl extends Nette\Forms\Controls\BaseControl
{
	public function __construct($label)
	{
		$this->monitor(Nette\Forms\Form::class, function ($form): void {
			$form->setHtmlAttribute('enctype', 'multipart/form-data');
		});
		// ...
	}

	// ...
}

e quando o formulário está disponível, a ligação de retorno é chamada. (Anteriormente, os métodos comuns attached e detached eram usados em seu lugar).

versão: 4.0