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


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にメジャーアップデートする際の対応録。


イメージビルド編


ベースイメージの変更




# 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を削除して解決。


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のインストール追加でイメージビルドは成功した。


# 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に変更


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モジュールがローディングできていないようだ。


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に詰め込みたいとき


# 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する


[ 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-{バージョン}でアーカイブがディストリビュートされている


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


# => Class 'Phalcon\Session\Adapter\Files' not found
$di->setShared('session',function(){
    $session = new \Phalcon\Session\Adapter\Files();
    $session->start();
    return $session;
});

// 保存先`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


$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


// Handle the request
$application = new Phalcon\Mvc\Application();
# $application->handle(); triggers a "Wrong number of parameters"
$response = $application->handle();
$response->send();

// Handle the request
$application = new Phalcon\Mvc\Application();
$request = new Phalcon\Http\Request();
$response = $application->handle($request->getURI());
$response->send();

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


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

$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


$volt = new Phalcon\Mvc\View\Engine\Volt()
$volt->setOptions(
    [
        'compiledPath'      => BASE_PATH . $config->application->cacheDir,
        'compiledExtension' => '.compiled',
        'compiledSeparator' => '_',
        'stat' => true,
        'compiledAlways' => true
    ]
);

$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


// $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


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型宣言の厳格化でオーバーライドに戻り値の宣言が必要

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


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

// assignに変更
$model->assign($assign_key_val);
$model->save();
Share:

0 Comments:

コメントを投稿