0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

php phalconをv3からv4にアップグレードする

Posted at
phalcon php

php:7.2-fpm-alpine3.12コンテナイメージが、vscode-v1.77以降のDevContainersでvscode-serverの起動エラーでコンテナに接続出来なくなったので、alpine-v3.16以降の
コンテナイメージへのアップグレードの必要に迫られた。

[[VsCode v1.77以降のDevContainers拡張でalpine v3.12コンテナに接続できない]]

php公式イメージで要件を満たすもっとも世代の近いイメージphp:7.4-fpm-alpine3.16php-v7.4に対応するphalconのバージョン要件がv4以降のため、phalconをv3からv4にメジャーアップデートする際の対応録。

イメージビルド編

ベースイメージの変更

Dockerfile
# FROM php:7.2-fpm-alpine
FROM php:7.4-fpm-alpine3.16

oniguruma

docker-php-ext-installツールでmbstringをインストールしようとすると依存ライブラリのonigurumaがないといってビルドに失敗する。

が、php:7.4-fpm-alpine3.16にはそもそもoniguruma非依存のmbstringがセットアップ済みのため、追加インストールなど不要だったのでシンプルにdocker-php-ext-installからmbstringを削除して解決。

Dockerfile
FROM php:7.4-fpm-alpine3.16
RUN docker-php-ext-install pdo_mysql mysqli mbstring < これ
#5 15.29 configure: error: Package requirements (oniguruma) were not met:
#5 15.29 
#5 15.29 Package 'oniguruma', required by 'virtual:world', not found
#5 15.29 
#5 15.29 Consider adjusting the PKG_CONFIG_PATH environment variable if you
#5 15.29 installed software in a non-standard prefix.
#5 15.29 
#5 15.29 Alternatively, you may set the environment variables ONIG_CFLAGS
#5 15.29 and ONIG_LIBS to avoid the need to call pkg-config.
#5 15.29 See the pkg-config man page for more details.

備忘録として

こちらさまによるとphp-v7.4らへんのmbstringビルドではonigurumaという荒々しい名の正規表現ライブラリに依存するようになったらしく、libonig-devというパッケージに収納されているとのこと。apkではこちらさまのとおりoniguruma-devというパッケージ名で配布されていた。oniguruma-devのインストール追加でイメージビルドは成功した。

Dockerfile
# RUN docker-php-ext-install pdo_mysql mysqli mbstring
# docker-php-ext-installからmbstringを削除してapkでoniguruma-devをインストールする
RUN docker-php-ext-install pdo_mysql mysqli mbstring
apk add --no-cache oniguruma-dev < これ

phalcon

phalconのソースをバージョンを4.0系のlatestバージョンv4.0.6に変更

Dockerfile
RUN cd /usr/local \
# phalconのビルドソースを3系から4系に変更
# && git clone https://github.com/phalcon/cphalcon.git -b v3.4.3 \
&& git clone https://github.com/phalcon/cphalcon.git -b v4.0.6 \
&& cd cphalcon/build \
&& sh install \
&& echo "extension=phalcon.so" > /usr/local/etc/php/conf.d/phalcon.ini \

psr

コンテナを起動してhttpアクセスするとphpワーニングでUncaught Error: Class 'Phalcon\Config' not found
え?メジャーアップデートでnamespaceがっつり変わった?と焦るも、公式見てもPhalcon\Configは健在だ。

ビルド失敗している?と思ってphpのロードモジュールを確認すると、psrモジュールがローディングできてない?からphalconモジュールがローディングできていないようだ。

sh
php -m | grep phalcon
PHP Warning:  Cannot load module 'phalcon' because required module 'psr' is not loaded in Unknown on line 0

phalcon-v4からpsrに対応するためライブラリ依存するようだ。
Fatal error: Uncaught Error: Class 'Phalcon\Config' not found
Php can not load module phalcon
Installation - Phalcon Documentation

Dockerfileにpecl-psrのインストールコマンドを追加して、phalconモジュールのローディングの前にローディングする
Phalconをdocker imageに詰め込みたいとき

Dockerfile
# xdebugのインストール
RUN pecl install psr \
&& docker-php-ext-enable psr \
&& echo "extension=psr.so" >> /usr/local/etc/php/conf.d/phalcon.ini \
&& echo "extension=phalcon.so" >> /usr/local/etc/php/conf.d/phalcon.ini \

xdebugバージョン

xdebug3.2.0でphp7がサポート対象外になったのでDockerfileを直した

xdebug-v3.2.0以降、php-v7がサポート対象外になったため、xdebugはバージョン指定でアーカイブDLする

sh
[ 5/17] RUN pecl install xdebug && docker-php-ext-enable xdebug:
> #9 5.238 pecl/xdebug requires PHP (version >= 8.0.0, version <= 8.2.99), installed version is 7.3.29
> #9 5.238 No valid packages found
> #9 5.238 install failed

peclではxdebug-{バージョン}でアーカイブがディストリビュートされている

Dockerfile
RUN pecl install xdebug-3.1.6 && docker-php-ext-enable xdebug

アプリケーション編

How to upgrade - Phalcon Documentation

Class 'Phalcon\Session\Adapter\Files' not found

サーバーセッションのファイルアダプタクラスはv4でPhalcon\Session\Adapter\Streamに置き換えられた
Phalcon 4.0 setting up Session

config/service.php:before
# => Class 'Phalcon\Session\Adapter\Files' not found
$di->setShared('session',function(){
    $session = new \Phalcon\Session\Adapter\Files();
    $session->start();
    return $session;
});
config/service.php:after
// 保存先`savePath`を指定する
$di->setShared('session',function(){
    $session = new Phalcon\Session\Manager();
    $files = new Phalcon\Session\Adapter\Stream( [
        'savePath' => '/tmp',
    ]);
    $session->setAdapter($files)->start();
    return $session;
});

Fatal error: Uncaught Error: Call to undefined method

Phalcon\Logger\Adapter\Stream::log()

v3ではPhalcon\Logger\Adapter\Streamが出力log()と出力先のストリームアダプタを担っていたが、v4から出力はPhalcon\Loggerに分離されてPhalcon\Logger\Adapter\Streamを利用する形に変更となった。ログのインターフェースはpsr-3準拠。
ということでアダプタがlog()など知らんと言っている。

Fatal error: Uncaught Error: Call to undefined method Phalcon\Logger\Adapter\Stream::log() - Discussion - Phalcon Framework
Phalcon logger - Phalcon Documentation
PSR-3: Logger Interface 読了 #PHP - Qiita

config/service.php
$formatter = new Phalcon\Logger\Formatter\Line("[%date%] %message%");
$formatter->setDateFormat('Y/m/d H:i:s');

$adapter = new Phalcon\Logger\Adapter\Stream("php://stdout");
$adapter->setFormatter($formatter);

$logger = new Phalcon\Logger(
	// ロガーに名前をつけられるがマニュアルに書いてないのでとりあえず任意名
	// public function __construct( string $name, array $adapters = [] );
    'hoge', 
    [
		// 任意名のラベル名。Loggerからラベルに対してアダプタを選択したりできる。
        'stdout' => $adapter,
    ]
);

$logger->info('this is log message');

$application->handle(); triggers a "Wrong number of parameters"

フレームワークのエントリポイントapplication#handle()ではリクエストURIをとるようになった
$application->handle(); triggers a "Wrong number of parameters" error after last upgrade - Discussion - Phalcon Framework

public/index.php:before
// Handle the request
$application = new Phalcon\Mvc\Application();
# $application->handle(); triggers a "Wrong number of parameters"
$response = $application->handle();
$response->send();
public/index.php:after
// Handle the request
$application = new Phalcon\Mvc\Application();
$request = new Phalcon\Http\Request();
$response = $application->handle($request->getURI());
$response->send();

Phalcon\Mvc\Router#handle()も同じく

config/route.php
// triggers a "Wrong number of parameters"
$router->handle();
config/route.php
$request = new Phalcon\Http\Request();
$router->handle($request->getURI());

Class 'Phalcon\Mvc\Url' not found

Phalcon\Mvc\Urlはv4でPhalcon\Urlになった。そしてv5ではまさかのPhalcon\Mvc\Urlになった

VoltEngine#setOptionsのキーが変わった

compiledプレフィックスがなくなった
How to disable volt cache - Discussion - Phalcon Framework

config/service.php:before
$volt = new Phalcon\Mvc\View\Engine\Volt()
$volt->setOptions(
    [
        'compiledPath'      => BASE_PATH . $config->application->cacheDir,
        'compiledExtension' => '.compiled',
        'compiledSeparator' => '_',
        'stat' => true,
        'compiledAlways' => true
    ]
);
config/service.php:after
$volt = new Phalcon\Mvc\View\Engine\Volt()
$volt->setOptions(
    [
        'path'      => BASE_PATH . $config->application->cacheDir,
        'extension' => '.compiled',
        'separator' => '_',
        'stat' => true,
        'always' => true
    ]
);

Too few arguments to function {closure}(), 2 passed …

DIに渡すクロージャに設定していた引数がエラーになったので、キャプチャで渡す。変更になったのか元々バグっていてpsrで顕在化したのかな。
Task Too few arguments to function {closure}(), 2 passed and exactly 4 expected · Issue #4576 · swoole/swoole-src

config/service.php
// $di->setShared('voltService', function ($view, $di) use ( $config ){
$di->setShared('voltService', function () use ($config){

		$di = Phalcon\DI::getDefault();
        $volt = new Volt($di->get('view'), $di);
        $volt->setOptions(
            [
                'path'      => BASE_PATH . $config->application->cacheDir,
                'extension' => '.compiled',
                'separator' => '_',
                'stat' => true,
                'always' => true
            ]
        );
        return $volt;
    }
);

Fatal error: Cannot override final method Phalcon\Mvc\Model::getSource()

Model::getSource()はオーバーライド不可となったのでイニシャライザにModel::setSource('テーブル名')で指定する
Fatal error: Cannot override final method Phalcon\Mvc\Model::getSource() - Discussion - Phalcon Framework

models/*.php
public function initialize()
{       
    $this->setSchema("phalcon_demo-app");       
    $this->setSource("users");        
}

Fatal error: Uncaught Error: Class 'Phalcon\Validation\Validator' not found

カスタムバリデーションの実装で問題が発生

  • Phalcon\Validation\ValidatorはアブストラクトクラスPhalcon\Validation\Validatorに置き換えられた
  • PHP7型宣言の厳格化でオーバーライドに戻り値の宣言が必要
forms/*php
// phalcon v4でのカスタムバリデーションクラス実装
class CustomEmailValidator extends \Phalcon\Validation\AbstractValidator implements \Phalcon\Validation\ValidatorInterface
{
    public function validate(Validation $validation, $attribute): bool { ... }
}

Fatal error: Declaration of { 関数宣言 } must be compatible with { 関数宣言 }: string

PHP7型宣言の厳格化でオーバーライドに戻り値の宣言が必要

Phalcon\Model::findFirst to return null instead of false if no record was found

Phalcon\Model::findFirstで結果が無い場合に戻り値falsenullになった
変更箇所が多岐にわたるので、モデルクラスでfindFirstをオーバーライドしてnullの場合はfalseを返却して後方互換性を維持する

Model::saveのホワイトリストが効かない

The save() method no longer accepts parameters to set data. You can use assign instead.

php
// フィールドnullになる
$model->save($assign_key_val, $whitelist_key);

// assignに変更
$model->assign($assign_key_val);
$model->save();
0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?