Injecting controller actions in Laravel views

Disclaimer: Depending on the kind of logic you need, it’s also possible to use View Composers to achieve a similar result.

I’m using Laravel in this new project I’m working on. Some other PHP frameworks have a feature to use controllers as services. Symfony, for instance, has something like that. The project team thought Laravel, as Symfony-based, would have something like that. Well, if it has, it’s not clear in the docs.

Another team member ended up with a solution I never thought before:

 @inject('someController', 'App\Http\Controllers\SomeController')
 {!! $someController->index() !!}

Now, we’re using Blade’s @inject directive to call controller actions from inside views. That’s useful for reusing actions as widgets, for example.

If you find that interesting and want to use in your application, remember two things:

  1. Since you’re calling the action method directly, you have to pass all the required params. If it expects a request instance, you can do this: $someController->index(request()).
  2. Probably the method returns a view that contains HTML code. So wrap the call within {!! and !!}. Using the {{ }} regular tag will cause the code to be escaped.
Advertisements

Passing Node args to Mocha tests

This is a really quick tip. I was looking around on the internet for a way to pass Node arguments when calling Mocha binary. And I couldn’t find anything useful. Then I tried the following and it worked:

$ test node --expose-gc ./node_modules/.bin/mocha [...]

The --expose-gc argument is just an example. You can pass any argument accepted by Node program.

In my specific case, I was trying to load dotenv config. In the end, the project’s MakeFile looked like:

test:
    @NODE_ENV=test node -r dotenv/config ./node_modules/.bin/mocha \
        --require should \
        --reporter spec \
        --harmony \
        --bail \
        tests

.PHONY: test

Photo credit: Matt Benson

Testando comandos do Symfony que usam serviços da aplicação

Se você tem um comando no Symfony2 que usa serviços da aplicação, como um ORM por exemplo, e seguir o modelo que a documentação do framework fornece para escrever testes unitários, poderá ver erros com os a seguir:

Fatal error: Call to undefined method Symfony\Component\Console\Application::getKernel() in [...]/vendor/symfony/symfony/src/Symfony/Bundle/FrameworkBundle/Command/ContainerAwareCommand.php on line [...]

ao acessar o kernel da aplicação, a partir do comando, ou:

Fatal error: Call to a member function getParameter() on a non-object in [...]

ao tentar acessar algum método do container.

O primeiro caso, acontece quando você usa a classe Symfony\Component\Console\Application ao invés de Symfony\Bundle\FrameworkBundle\Console\Application. Verifique os uses da sua classe de testes e ajuste se for necessário.

A segunda exceção é lançada quando você está usando a classe Application correta, mas usando um kernel inválido na sua instanciação. Talvez exista outro modo de fazer isso, mas para mim funcionou extender a classe Symfony\Bundle\FrameworkBundle\Test\WebTestCase no lugar de \PHPUnit_Framework_TestCase e construir a aplicação da seguinte forma:

$application = new Application(self::createClient()->getKernel());

Script de deploy para projetos que usam git

Há alguns meses atrás desenvolvi um script de deploy para um projeto em que estou trabalhando. Com o tempo vi a possibilidade de melhorar alguns pontos, especialmente com o uso do componente Console do Symfony2,  e agora disponibilizo uma versão pública que pode ser usada com projetos armazenados em um repositório git.

https://github.com/straube/deploy

Uma das limitações dessa versão é que ela trabalha apenas com SSH, mas em breve devo adicionar suporte a FTP.

Falha inexplicável (ou não) no composer install

Quando você vir falhas inexplicáveis (gerando exceções) ao executar o composer install, verifique se a opção apc.enable_cli, do PHP, não está ativada.

Usando o APC para cachear variáveis no PHP

Sempre associei o APC (Alternative PHP Cache) ao cache de opcode no PHP, e somente a isso. Acredito que essa ligação seja natural para muitas pessoas, mas o APC pode ir além disso, cacheando qualquer variável dentro do PHP. Para isso existem algumas funções na extensão: apc_add, apc_fetch, apc_delete etc.

Para um experimento básico é possível usar apenas as funções apc_add e apc_fetch, seguindo o padrão de design lazy loading:

class City
{
    private $state;
    public function getState()
    {
        $cacheKey = 'state';
        if (false === ($state = apc_fetch($cacheKey))) {
            $state = ... // Buscar o estado de algum lugar, talvez do BD.
            apc_add($cacheKey, $state, 3600);
        }
        return $state;
    }
}

A primeira vez que a função getState é chamada, ela carrega o estado e armazena no cache, nas próximas chamdas a variável armazenada no cache será usada, evitando o acesso ao banco de dados. Passada uma hora (3.600 segundos) a variável é removida automaticamente do cache e na chamada seguinte ao método, o banco será consultado novamente. O tempo de vida (TTL) do cache pode ser alterado conforme as características da aplicação e do contéudo a ser cacheado.

Sobre as chaves

A chave usada para armazenar a variável no APC é global e compartilhada entre todas as aplicações em um mesmo ambiente. Isso pode ser interessante, porque o cache é compartilhado e, além da questão de otimização, pode ser um caminho para soluções que envolvem a troca de informações entre requisições ou programas distintos, mas também pode gerar bugs inesperados e difíceis de identificar se diferentes scripts PHP usarem a mesma chave para diferentes propósitos. Assim é sempre muito importante criar chaves com nomes distintos e exclusivos.

Correção de bug no AvalancheImagineBundle

O AvalancheImagineBundle é um bundle super útil para o Symfony2. Ele adiciona funções de geração de thumbnails com caching ao framework. Porém, dependendo da estrutura de diretório e do número de requisições da aplicação, dois problemas podem acontecer:

  1. loop infinito de redirects; e
  2. bug na criação recursiva de diretórios devido a concorrência.

Para resolver essas situações em um projeto de Classificados da Gazeta do Povo, precisamos alterar o core do bundle e, ontem, nosso pull request foi aceito: https://github.com/avalanche123/AvalancheImagineBundle/pull/160.

Se você usa o AvalancheImagineBundle, atualize para última versão e evite esses erros.