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).