Modelo de Componente

Um conceito importante no Nette é o componente. Inserimos componentes interativos visuais nas páginas, formulários são componentes, assim como todos os seus elementos. As duas classes base das quais todos esses componentes herdam fazem parte do pacote nette/component-model e têm a tarefa de criar uma hierarquia de componentes em árvore.

Component

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

lookup (string $type): ?Component

Procura na hierarquia para cima um objeto da classe ou interface solicitada. Por exemplo, $component->lookup(Nette\Application\UI\Presenter::class) retorna o presenter, se o componente estiver anexado a ele, mesmo através de vários níveis.

lookupPath (string $type): ?string

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

Container

Nette\ComponentModel\Container é o componente pai, ou seja, um componente que contém descendentes e forma assim uma estrutura em árvore. Possui métodos para fácil adição, obtenção e remoção de objetos. É o ancestral, por exemplo, do formulário ou das classes Control e Presenter.

getComponent (string $name): ?Component

Retorna um componente. Ao tentar obter um descendente indefinido, a fábrica createComponent($name) é chamada. O método createComponent($name) chama o método createComponent<nome do componente> no componente atual e passa o nome do componente como parâmetro. O componente criado é então adicionado ao componente atual como seu descendente. Chamamos esses métodos de fábricas de componentes e eles podem ser implementados por descendentes da classe Container.

getComponents(): array

Retorna os descendentes diretos como um array. As chaves contêm os nomes desses componentes. Nota: na versão 3.0.x, o método retornava um iterador em vez de um array, e seu primeiro parâmetro determinava se os componentes deveriam ser percorridos em profundidade, e o segundo representava um filtro de tipo. Esses parâmetros estão obsoletos.

getComponentTree(): array

Obtém toda a hierarquia de componentes, incluindo todos os componentes filhos aninhados, como um array indexado. A busca é feita primeiro em profundidade.

Monitoramento de Ancestrais

O modelo de componente Nette permite um trabalho muito dinâmico com a árvore (podemos remover, mover, adicionar componentes), portanto seria um erro confiar que, após a criação de um componente, o pai, o pai do pai, etc., sejam imediatamente conhecidos (no construtor). Na maioria das vezes, o pai não é conhecido durante a criação.

Como saber quando um componente foi anexado à árvore do presenter? Observar a mudança do pai não é suficiente, porque o pai do pai pode ter sido anexado ao presenter, por exemplo. O método monitor($type, $attached, $detached) ajuda. Cada componente pode monitorar qualquer número de classes e interfaces. A anexação ou desanexação é sinalizada chamando o callback $attached ou $detached, respectivamente, e passando o objeto da classe monitorada.

Para melhor compreensão, um exemplo: a classe UploadControl, que representa o elemento de formulário para upload de arquivos no Nette Forms, precisa definir o atributo enctype do formulário para o valor multipart/form-data. No entanto, no momento da criação do objeto, ele pode não estar anexado a nenhum formulário. Em que momento, então, modificar o formulário? A solução é simple – no construtor, solicita-se o monitoramento:

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 assim que o formulário estiver disponível, o callback é chamado. (Anteriormente, os métodos comuns attached e detached eram usados em seu lugar).

versão: 3.x