レガシー環境から脱却したい

プログラミングや環境構築の話をまとめています。

Surface Pro 7からケーブル1本でトリプルディスプレイに挑戦

サポート完全終了のCentOS6とPHP5.6の開発環境をDockerで作成する

f:id:odaryo:20200901175341p:plain

はじめに

2020年11月30日をもちまして、延長サポートを含めたCentOS 6系のすべてのサポートが終了しました。

しかしながら、社内システムなどまだまだ現役の環境はあると思いますし、
リプレース案件の確認作業のために同バージョンの開発環境が欲しいといった要望もあるかと思います。

今回、CentOS6.9で動いているシステムを保守する必要があり、過去に作った開発環境をDockerで動かそうとしたところ「yum install」でこけました。
yumリポジトリなどがすべてアーカイブに移動しているため、デフォルトのままだとリポジトリが見つからずにエラーとなるようです。

そこで、本日はDockerを使ってCentOS6.9環境を構築する方法をまとめます。

Dockerfileについて

実行環境

Dockerで構築する環境

  • CentOS6.9
  • PHP5.6
  • Apache2.2

動いたときのDockerfileはこちらになります。

FROM centos:6.9

ENV PHP_VERSION 5.6.40

RUN sed -i "s|#baseurl=|baseurl=|g" /etc/yum.repos.d/CentOS-Base.repo \
  && sed -i "s|mirrorlist=|#mirrorlist=|g" /etc/yum.repos.d/CentOS-Base.repo \
  && sed -i "s|http://mirror\.centos\.org/centos/\$releasever|http://vault\.centos\.org/centos/6.9|g" /etc/yum.repos.d/CentOS-Base.repo

RUN rpm -Uvh https://archives.fedoraproject.org/pub/archive/epel/6/x86_64/epel-release-6-8.noarch.rpm && \
    rpm -Uvh http://rpms.famillecollet.com/enterprise/remi-release-6.rpm

RUN yum install -y --enablerepo=remi --enablerepo=remi-php56 \
        php \
        php-devel \
        php-mbstring \
        php-pdo \
        php-gd \
        php-xml \
        php-mcrypt \
        php-mysql \
        php-pear \
        php-xdebug \
        php-pecl-xdebug \
    && yum install -y \
        zip \
        unzip \
        httpd \
        gcc

RUN yum clean all

CMD ["/usr/sbin/apachectl","-DFOREGROUND"]

CentOS6.9環境用に作ったものなので、ほかのバージョンにする場合は6.9の記述を変更してください。
PHPモジュールの記述は環境に合わせて修正してください。

変更点

CentOS-Base.repoを修正

yumリポジトリアーカイブされているので、参照先を書き換えます。

RUN sed -i "s|#baseurl=|baseurl=|g" /etc/yum.repos.d/CentOS-Base.repo \
  && sed -i "s|mirrorlist=|#mirrorlist=|g" /etc/yum.repos.d/CentOS-Base.repo \
  && sed -i "s|http://mirror\.centos\.org/centos/\$releasever|http://vault\.centos\.org/centos/6.9|g" /etc/yum.repos.d/CentOS-Base.repo

② PHP5.6をインストールするためのEPELリポジトリを修正

CentOSに標準搭載以外のバージョンのPHPをインストールする場合は、EPEL、REMIリポジトリの設定が必要になります。

EPELリポジトリアーカイブされているため、URLをアーカイブ先に設定します。
REMIレポジトリはそのままで良いみたいです。

RUN rpm -Uvh https://archives.fedoraproject.org/pub/archive/epel/6/x86_64/epel-release-6-8.noarch.rpm && \
    rpm -Uvh http://rpms.famillecollet.com/enterprise/remi-release-6.rpm

デフォルト設定の場合のエラーについて

Yumリポジトリが見つからない場合のエラー

CentOS-Base.repoを修正すると直ります。

Error: Cannot retrieve repository metadata (repomd.xml) for repository: base. Please verify its path and try again
YumRepo Error: All mirror URLs are not using ftp, http[s] or file.
 Eg. Invalid release/repo/arch combination/
removing mirrorlist with no valid mirrors: /var/cache/yum/x86_64/6/base/mirrorlist.txt

② EPELリポジトリの設定を変えていなかった場合のエラー(アーカイブ前のURLを指定した場合)

curl: (22) The requested URL returned error: 403 Forbidden
error: skipping https://dl.fedoraproject.org/pub/epel/epel-release-latest-6.noarch.rpm - transfer failed
Retrieving https://dl.fedoraproject.org/pub/epel/epel-release-latest-6.noarch.rpm

EC-CUBE4のSQLで特定のIDの商品を先頭に表示したい場合の書き方

はじめに

EC-CUBEのカスタマイズ案件の中で、「商品一覧の先頭に指定した商品を指定した順に表示させる」という要望がありました。

MySQLだと慣れているので問題ないのですが、
EC-CUBE4ではSQLではなくDoctrineのDQLのため、作法が違う部分がいくつかあります。

そこで、EC-CUBEでうまくいった方法をまとめます。

対象環境

  • MySQL8
  • EC-CUBE4

やりたいこと

仕様

  • IDを指定した場合、その商品を先頭に持ってくる
    • IDは複数指定可能
  • IDを指定していない商品は、指定した商品の後にID順に並べる

次のようなデータがあった場合

id name
1 いちご
2 りんご
3 バナナ
4 メロン
5 すいか

ID [4, 2] を指定して、こう表示させたい

id name
4 メロン
2 りんご
1 いちご
3 バナナ
5 すいか

MySQLでのやり方

① order by句で直接指定

SELECT *
FROM table
ORDER BY id = '4' DESC, id = '2' DESC, id;

② FIELD関数を利用する

FIELD関数は知らなかったのですが、このやり方でもできるようです。
(本仕様を満たすにはIDを逆順に指定する必要があるので気持ち悪いですが)

SELECT *
FROM table
ORDER BY FIELD(id, '2', '4') DESC, id;

EC-CUBE(Doctrine)での問題

EC-CUBEのクエリビルダで上記のSQLを書こうとしたら、うまくいきませんでした。

① order by句で直接指定

orderBy関数にはカラム名しか指定できないためエラーとなる

例:

...
  ->orderBy('id = 4', 'DESC')    // <- error!
  ->addOrderBy('id = 2', 'DESC')  // <- error!
  ->addOrderBy('id')

(※変数のエスケープ処理はひとまず無視)

② FIELD関数を利用する方法

DoctrineにMySQL関数が実装されていないため使えません。

DoctrineExtensionsというものを入れると使えるようです。

参考

ですが、今回はデフォルトの機能で再現する方法を紹介します。

解決方法

CASE文を使って、条件に合致する要素を先頭に持ってくるように設定しました。

sort専用のパラメータを新しく作って、それを基準に並べ替えています。

$qb = $this->createQueryBuilder('p')
  ->addSelect('CASE WHEN p.id = 4 THEN 1 ELSE 0 END as HIDDEN sort_id1')
  ->addSelect('CASE WHEN p.id = 2 THEN 1 ELSE 0 END as HIDDEN sort_id2')
  ->orderBy('sort_id1', 'DESC')
  ->addOrderBy('sort_id2', 'DESC')
  ->addOrderBy('p.id');

$result = $qb->getQuery()->getResult();

結果

id name
4 メロン
2 りんご
1 いちご
3 バナナ
5 すいか

また、HIDDENキーワードを使った要素は取得結果に含まれないので、ソートの為に作った要素が取得オブジェクトには入らずすっきりします。

終わりに

素のSQLなら簡単にできることでもORMをかますと工夫が必要なことがあります。 複雑になってくるとSQLを直接書いたほうが早いこともありますが、可能ならORMの機能を生かすほうが良いですね。

EC-CUBE4(というかDoctrine)にまだ慣れていないので他に良い方法があるかもしれません。

Nuxt.jsで「Cannot read property '_normalized' of undefined」エラーが出た

f:id:odaryo:20200901175501p:plain

Nuxt.jsで静的サイトを作っていたときに、下記エラーが出るようになりました。

[error]  /blog

TypeError: Cannot read property '_normalized' of undefined
    at normalizeLocation (/opt/build/repo/front/node_modules/vue-router/dist/vue-router.common.js:971:12)
    at VueRouter.resolve (/opt/build/repo/front/node_modules/vue-router/dist/vue-router.common.js:3015:18)
    at a.render (/opt/build/repo/front/node_modules/vue-router/dist/vue-router.common.js:1062:22)
    at a.t._render (/opt/build/repo/front/node_modules/vue/dist/vue.runtime.common.prod.js:6:35273)
    at /opt/build/repo/front/node_modules/vue-server-renderer/build.prod.js:1:70637
    at Yi (/opt/build/repo/front/node_modules/vue-server-renderer/build.prod.js:1:67201)
    at io (/opt/build/repo/front/node_modules/vue-server-renderer/build.prod.js:1:70613)
    at ro (/opt/build/repo/front/node_modules/vue-server-renderer/build.prod.js:1:70244)
    at _t.eo [as renderNode] (/opt/build/repo/front/node_modules/vue-server-renderer/build.prod.js:1:67491)
    at _t.next (/opt/build/repo/front/node_modules/vue-server-renderer/build.prod.js:1:20507)
    at n (/opt/build/repo/front/node_modules/vue-server-renderer/build.prod.js:1:18719)
    at /opt/build/repo/front/node_modules/vue-server-renderer/build.prod.js:1:68602
    at _t.eo [as renderNode] (/opt/build/repo/front/node_modules/vue-server-renderer/build.prod.js:1:68610)
    at _t.next (/opt/build/repo/front/node_modules/vue-server-renderer/build.prod.js:1:20507)
    at n (/opt/build/repo/front/node_modules/vue-server-renderer/build.prod.js:1:18719)
    at /opt/build/repo/front/node_modules/vue-server-renderer/build.prod.js:1:68602

開発環境のyarn devでは出ず、本番用ビルドのyarn generateで発生。

原因

nuxt-linkの内容がundefinedだったため。

例:

<nuxt-link :to='link'>リンク</nuxt-link>

↑のようなコードでlink変数がundefinedとなっていました。

開発環境でSSRで動いているときはデータを都度取得していたのに対し、 静的ビルドのときはpayloadで予めデータを取得していました。 そのpayloadの書き方がまずく、データが取れていなかったのが原因でした。

分かってみれば簡単なことですが、
1行目のTypeError: Cannot read property '_normalized' of undefinedだけ読んでも意味不明。 内容にvue-routerの記載があるのでルーティング周りかなと思ったものの、場所がわからずなかなか特定できませんでした。

UbuntuへIntellij IDEAをインストールする

はじめに

Ubuntuへインストールする方法のメモ

ほかにスマートなやり方はあると思いますが、とりあえずできた方法をメモします。
Intellij IDEA以外のJetbrain製品も手順は同じだと思いますので、参考になるかと思います。

①ダウンロード

ダウンロードページからtar.gzファイルをダウンロードします。

www.jetbrains.com

②インストール

/opt/ideaにインストールして、コマンドで実行できるように/usr/local/binシンボリックリンクを張ります。

$ sudo mkdir /opt/idea && sudo tar xfz ideaIU-*.tar.gz -C /opt/idea --strip-components 1
$ sudo ln -s /opt/idea/bin/idea.sh /usr/local/bin/idea

下記のように起動できます。

$ idea

ちなみに、tarの-C--strip-componentsオプションの意味はこちらが参考になります。

kakakakakku.hatenablog.com

Dockerでファイルのパーミッションをホストユーザと合わせる方法

f:id:odaryo:20200901175341p:plain

UbuntuへHugoをインストール

f:id:odaryo:20200901174711p:plain

はじめに

公式のページに情報はありますが、Linux版はHomuBrewでの方法しか書かれていなかったため、バイナリからインストールしました。

gohugo.io

インストール手順

下記リンク先より、Hugoの最新バイナリを取得します。

github.com

scssのコンパイルもしたかったので、extendedバージョンをダウンロードします。(2020/07/24更新)

$ wget https://github.com/gohugoio/hugo/releases/download/v0.74.3/hugo_extended_0.74.3_Linux-64bit.deb

Ubuntuではdebパッケージもaptでインストールできるので、管理しやすいようにaptで行います。

$ sudo apt install hugo_extended_0.73.0_Linux-64bit.deb

インストールされたことを確認する

$ hugo version
Hugo Static Site Generator v0.73.0-428907CC/extended linux/amd64 BuildDate: 2020-06-23T16:40:09Z

以上