Back-End

15 mai, 2018

Atlas 3.x (“Cassini”) e PHPStorm Completion

Publicidade

Tenho o orgulho de anunciar o lançamento do Atlas.Orm 3.0.0-beta1, juntamente com os lançamentos dos pacotes de suporte do Mapper, Table, Query, Cli e Pdo (Atlas é um mapeador de dados para seu modelo de persistência, não seu modelo de domínio, em PHP).

O objetivo dessa rodada de lançamentos era “melhor suporte para IDE para retorno de tipos”, e estou feliz em dizer que foi um grande sucesso, embora tenha sido necessário renomear substancialmente as classes. Infelizmente isso resulta em uma grande ruptura com a versão alfa anterior; se você já tiver classes de esqueleto de fonte de dados com base em alfa, precisará regenerá-las com os novos nomes de classe. Exceto o imprevisto, isso marca a primeira, a última, e a única vez que a regeneração será necessária.

I.

Eu não sou um heavy user de IDEs; eu prefiro editores de texto, como o Sublime. No entanto, trabalho com pessoas que usam o PHPStorm IDE extensivamente e passei a apreciar alguns de seus recursos. Um desses recursos é o autocompletar de código. Por exemplo, se você digitar $foo = new Foo() e, em seguida, referir-se a $foo mais tarde, o IDE exibirá uma lista de métodos e propriedades nesse objeto.

Isso é muito conveniente, exceto que o IDE precisa saber que classe está sendo referenciada para descobrir qual deve ser a sugestão. Se você estiver usando fábrica/localizador/container de formatação não retornável, o IDE não saberá por padrão como mapear o nome solicitado para uma classe real. Neste exemplo:

class Factory
{
    public static function new($class)
    {
        return new $class();
    }
}

$foo = Factory::new(Foo::CLASS);

O IDE não tem ideia do que o retorno do método new() é ou deveria ser, portanto, ele não pode fornecer dicas de preenchimento automático em $foo.

Esse idioma é exatamente o que Atlas MapperLocator:: get() e TableLocator::get() usam: o parâmetro get() é um nome de classe, e o localizador retém e retorna uma instância dessa classe. Da mesma forma, todos os métodos de classe Atlas tomam um nome de classe mapeador como seu primeiro parâmetro, que o Atlas usa para descobrir qual mapeador usar para essa chamada de método.

Você pode digitar esses métodos para abstrair classes ou interfaces, mas o IDE não reconhecerá nenhuma extensão personalizada ou substituição nas classes concretas retornadas. O que é necessário é uma maneira de determinar o tipo de retorno do parâmetro get(), em vez de usar o tipo de retorno do método.

II.

Para nossa sorte, o PHPStorm IDE permite um arquivo .phpstorm.meta.php (ou uma coleção de arquivos em um diretório .phpstorm.meta.php /), onde você pode mapear as entradas do método de fábrica para seus tipos de retorno (veja aqui a documentação).

Ao trabalhar com ele, porém, achei-o um pouco inflexível. Eu esperava poder mapear uma string diretamente para um nome de classe literal, mas isso realmente não funcionava. O IDE nunca pareceu pegar o tipo de retorno. Além disso, com nomes de classes do jeito que estão nas versões 1.x, 2.xe 3.x-alpha, eu precisaria adicionar uma série de mapeamentos de parâmetro para tipo para cada classe de origem de dados (isto é, cerca de 10 entradas para cada tipo de fonte de dados). Imaginei que isso seria complicado.

Para me adaptar a isso, decidi modificar a nomenclatura da classe Atlas com o token de metadados “@” do PHPStorm em mente. O token “@”, de acordo com a documentação acima, é substituído pelo valor do parâmetro do método de fábrica, tornando-o perfeito como um prefixo de nome de classe. No entanto, você não pode fazer manipulações de strings; você não pode, digamos, chamar um substr(‘@’, 0, -6). “Record” e dar a ele um “FooMapper” para recuperar “FooRecord”. Teria que ser “@Record” ou nada.

Isso leva à maior mudança no Atlas desde sua criação: as classes do mapeador da origem de dados não são mais sufixadas com o “Mapper”. Anteriormente, se você tivesse uma tabela foo, esperaria um nome de classe de mapeador como App\DataSource\Foo\FooMapper. Com essa alteração de nomenclatura, o nome da classe de mapeador é agora App\DataSource\Foo\Foo.

Isso torna o nome da classe do mapeador de origem de dados uma boa base como prefixo para todas as outras classes de tipo de fonte de dados, o que significa que o token ‘@’ pode ser usado sem necessidade de manipulação de strings e funciona apenas com poucas linhas de código de metadados do PHPStorm.

Você pode ver o recurso resultante .phpstorm.meta.php incluído no Atlas 3.x aqui. Coloque isso na raiz do seu projeto, e o PHPStorm agora irá digitar com sucesso todos os retornos do método Atlas (você pode ter que reiniciar o PHPStorm para que ele tenha efeito total).

III.

Entretanto, havia ainda outra categoria de problemas. Embora a classe Atlas abrangente tenha agora a conclusão do IDE, os pacotes Mapper e Table subjacentes não tinham algumas dicas sobre suas classes e métodos.

Por exemplo, o método base Mapper::fetchRecord() é typehinted para retornar um Record, mas o filho FooMapper::fetchRecord() na verdade retorna um FooRecord. As propriedades no FooRecord são específicas do FooRow subjacente da tabela e de qualquer FooRelationships no mapeador, e isso precisa ser indicado pelo IDE.

Da mesma forma, a classe Mapper::select() é typehinted para retornar a classe base MapperSelect; por sua vez, o método MapperSelect::fetchRecord() é typehinted para retornar um Record. Mas uma chamada $fooMapper->select()->fetchRecord(), na verdade, retorna um FooRecord. Esses também precisam ser indicados pelo IDE.

Acabei resolvendo isso em duas etapas:

  1. Cada tipo de fonte de dados agora recebe sua própria classe de seleção específica do tipo; enquanto FooMapper::select() costumava retornar um Select de propósito geral, ele agora retorna uma instância de FooSelect estendida da seleção de propósito geral. Essa classe de seleção específica do tipo é gerada pelo conjunto de ferramentas Atlas.Cli.
  2. No mapeador específico de tipo e classes select, o conjunto de ferramentas Atlas.Cli agora gera um dockblock de declarações @method com a substituição de retornos específicos de tipo (você pode ver um exemplo disso nas classes Author e AuthorSelect do pacote Atlas.Testing.). O PHPStorm seleciona esses docblocks e os utiliza para fornecer dicas de tipo de retorno quando essas classes são usadas.

Com essas duas adições ao gerador de esqueleto Atlas.Cli, o autocompletar no PHPStorm IDE parece estar completo.

IV.

É claro que “não há soluções, só há trocas”. Essa situação não é diferente. Sim, o Atlas agora tem uma abordagem de conclusão de IDE relativamente direta, mas com estes custos:

  • Se a conclusão de IDE não for importante para você, essas mudanças muito significativas da versão alfa para a versão beta parecerão inúteis, ou até mesmo contraproducentes.
  • Existem mais duas classes por tipo de fonte de dados: um MapperSelect específico de tipo e um TableSelect específico de tipo (para digitar os retornos de Row).
  • Não ter um sufixo “Mapper” na classe mapeador da origem de dados pode parecer errado ou contraintuitivo.
  • Para alguns, essas trocas não valerão o esforço para fazer a transição da versão alfa para a versão beta. No entanto, depois de trabalhar com o beta por um tempo, eu acho que eles acabam sendo um benefício global em geral.

***

Paul M. Jones faz parte do time de colunistas internacionais do iMasters. A tradução do artigo é feita pela Redação iMasters, com autorização do autor, e você pode acompanhar o artigo em inglês no link: http://paul-m-jones.com/archives/6885