これは何
以下のアップグレードガイドにしたがって laravel 5.5 => 5.6 のアップデートをやっていたら、ガイドに書いていない部分のテストが落ちたので困った話。
https://readouble.com/laravel/5.6/ja/upgrade.html
問題
手元のLaradockでphpunitを流すとテストが落ちないのだが、circleCI環境でテストを回すと落ちる。
エラーメッセージ
Call to undefined function Illuminate\Http\Testing\imagejpeg()
該当テストコードの例
public function testAdd()
{
$this->post('/hoge/create', [
'image' => UploadedFile::fake()->image('image.jpeg', 1400, 1400)->size(1000),
'content' => '内容',
])->assertRedirect('/hoge');
}
解決策
次の2ステップを行う
- libjpeg-dev をパッケージマネージャでインストールする
- gd のconfigure時に上記パッケージのパスを指定してあげるオプションを追加する
--with-jpeg-dir=DIR
今回私はcircleCIにおけるファイルを編集したので参考として載せておきます。
# Install Library
- run: sudo apt-get install -y libpng-dev libjpeg-dev
# Install PHP Extension
- run: sudo docker-php-ext-configure gd --with-png-dir=/usr/include --with-jpeg-dir=/usr/include
- run: sudo docker-php-ext-install gd
補足:なぜこの問題はlaravel updateのタイミングで起こったのか
Laravel 5.6においては
上記テストコードで呼んでいる image() メソッドは以下で、
public function image($name, $width = 10, $height = 10)
{
return new File($name, $this->generateImage(
$width, $height, Str::endsWith(Str::lower($name), ['.jpg', '.jpeg']) ? 'jpeg' : 'png'
));
}
さらに呼ばれている generateImage() がもともと以下のようになっている。
protected function generateImage($width, $height, $type)
{
return tap(tmpfile(), function ($temp) use ($width, $height, $type) {
ob_start();
$image = imagecreatetruecolor($width, $height);
switch ($type) {
case 'jpeg':
imagejpeg($image);
break;
case 'png':
imagepng($image);
break;
}
fwrite($temp, ob_get_clean());
});
}
このファイルがlaravel 5.5では以下のようになっていた
protected function generateImage($width, $height)
{
return tap(tmpfile(), function ($temp) use ($width, $height) {
ob_start();
imagepng(imagecreatetruecolor($width, $height));
fwrite($temp, ob_get_clean());
});
}
つまり、imagejpeg() は呼ばれておらずimagepngだけが呼ばれていた。(我々のコードではおそらくこの仕様を知らず jpeg拡張子を指定していたが結局裏ではpngファイルが生成されていたと思われる。)
laravel 5.6においては分岐が追加されたことにより imagejpeg() が呼び出されることになり、今回のエラーが発生した。