プログラミングの話

Echoの挙動

事の発端

ふつうのLinuxプログラミング Linuxの仕組みから学べるgccプログラミングの王道

以上の本に”\007”って標準出力すると文字コード由来でベルが鳴ると書いてあった。

書いてあるなら試すしか無い。

普段から利用しているiTermを開いて

1
echo "\007"

ベルが鳴る。

1
echo "\008"

8と出力

1
echo "\009"

9と出力

変な気がする。

問題点

ここに沿って考えると、BSとか、HTとかが表現されるはず。

少なくとも、普通に8とか9とかは違う気がする。

検証

以上のようなスクリプトを作成し走らせた。

結果は両方共以下のとおり。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103








8
9











8
9








8
9








8
9

!
"
#
$
%
&
'
8
9
(
)
*
+
,
-
.
/
8
9
0
1
2
3
4
5
6
7
8
9
8
9
:
;
<
=
>
?
8
9
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99

途中でアルファベットとか出てきていいと思うのに、なんか違う気がする。

結論

echo コマンドの使い方の問題だった。

echoコマンド(引数で指定した内容を標準出力に出力する)

こんなことで日立にお世話になるとは思っていなかったけれど。

要するに、echoコマンドの使い方的には8進数か16進数を期待しているので、gistに上げたプログラムは自分の期待通りにはなりません。

自分が期待していた動きをするスクリプトは以下。実行結果は割愛

あと

1
echo "\007"

でベルがなるのは

1
2
3
4
5
6
7
8
9
注※1

    指定したASCIIコード文字が1桁または2桁の場合,前に0を付けて3桁で指定しても,同じ意味として解釈されます。例えば,次の3つの指定は同じ意味として解釈され,アラート文字(ベル)が3回出力されます。

    echo -e "\07"

    echo -e "\007"

    echo -e "\0007"

ということらしい。

Shpinxでapiのドキュメント生成をする時の注意点

sphinxとは?

ドキュメントを作るのがめんどくさい時に利用できるツールでして。

くわしくはこっちを見てください。

この記事の目的

このsphinxってやつは結構賢くて、有るパッケージ以下を認識させると、それ以下のpythonのパッケージを読み取ってくれて、 ファイルに記述されているコメントからドキュメント生成してくれます。

今回はそのコマンドを利用する際の注意点を幾つか挙げられれば。

コマンドの利用方法

インストール

1
pip install sphinx

利用方法

1
2
3
#sphinx-apidoc -f -o 出力先ディレクトリ調査対象ディレクトリ
#例) app内を調査し、docsに出力する
sphinx-apidoc -f -o docs/ app/

注意点

  1. config.pyを書き換える
  2. rst記法を学ぶ
  3. __init__.pyが大事
  4. ライブラリから関数をインポートしない
  5. コメント内に章立てを入れない

以上の理由を軽く解説します。

1. config.pyを書き換える

プロジェクトのルートはインポートするようにしましょう。

ドキュメント生成の際に普通にモジュールをインポートしたりするので、インポートするパスを追加しておかないとドキュメントがきちんと生成されません。

1
2
3
import sys
import os
sys.path.append('/path/to/project/root')

2. rst記法

意外と面倒で、マークダウンほどのシンプルではありません。

はやわかり reStructuredText

なんだかんだ上記のページで学ぶのが一番しっかりしていて早いと思われます。

3. __init__.py大事

ディレクトリでネストしている際は__init__.pyを設置しましょう。

当たり前ですが、置かないとpythonが関連しているディレクトリとして認識されません。

4. ライブラリから関数をインポートしない

自分がハマったのですが、

1
2
# aというモジュール内でhogeモジュールのHogeクラス functioと言う関数を想定
from hoge.Hoge import function

上記のようにインポートするとは、インポートした関数(function)を、ドキュメント生成したい(a)モジュール内の関数だと認識し、 aというモジュールのドキュメント内に、functionのドキュメントも生成されます。

(誰得の機能なのだろうか?)

たとえばSQLAlchemyを利用している際に、ralationship関数を読み込んでいるとsphinx-apidocはrelatiohship関数のドキュメントも生成しようとします。

ただし、対象関数のコメントでエラーを吐いて正しくドキュメント生成されません。

1
2
3
4
#relationshipの関数までドキュメント生成される例
from sqlalchemy import relationship

relationship()

回避方法は以下のとおり

1
2
3
4
#ドキュメント生成されない例
import sqlalchemy as sa

sa.relationship()

5. コメント内に章立てを入れない

ソースコードのコメントで章立てをしないというのは、おそらく既に、モジュール名、クラス名、関数名で章立てができているので不要だからだと思います。

(はっきりと検証していないので不確かですが、)コメント内で章立てをするとエラーが出てまたしてもドキュメント生成されません。

Chefとapacheとphp

問題点

chefでapacheとphpをインストールした際に、PHPがうまく動かない

PHPの拡張子なのにテキストファイルとして認識される

ダメだったこと

  1. PHPをインストール後にapacheを再起動しなかったこと
  2. PHPをインストール後に etc/httpd/conf.d/php.conf を自分で作成してしまったこと

1.については有る有るかもしれないが、2については個人的には意外な話だった。

PHPをインストールする際に、apacheの設定用ディレクトリにPHPの設定ファイルをphp.confという名前で設置してくれるようです。

ただ今回私はPHP用のバーチャルホストの設定として個人的にphp.confを設置していて、それが悪影響を及ぼしてました。

Rubyの配列

コード

問題点

AというオブジェクトからBというオブジェクトに値を受け渡しするプログラムを書いているつもりだった。

値を渡しているつもりなので、Aの方で値を変えても、Bの方の値は動くはずないと思っていた。コードでいうところのcloneの方の挙動

しかし、実際にはAの値を変えるとBの方の値も変化する。コードでいうところのplainの方の挙動

理由

単純な話で、値を渡しているつもりが参照を渡していた。

「Ruby 配列 コピー」でググると一番上に出てくるリンクにも

Array#cloneないしはArray#dupを使います。

と書いてある。

この話って多分Ruby特有の話ではないと思うんですけど、実際にハマってみないと分からないもんですね。

Scpより簡単にファイルをローカルに落とす方法

scpとは

リモートのPCにファイルをアップロードしたり、ダウンロードできるコマンド 基本的にはcpと同じ体系になってると思う。 で、最初のsは多分sshのs

問題点

sshの問題点でも有るんだけど、scpのコマンドの問題でも合って、 多段sshをしている時って、ファイルをアップロードしたりダウンロードしたりって結構面倒。 ただでさえコマンドが長くなりがちなのに、「踏み台を一度経由してー」とかやってると日が暮れる。

解決の仕組み

webのリンクを踏むとファイルをダウンロードさせる仕組みを使うとリモートからローカルの転送はかなり楽になる。 この方法を応用すると、同じネットワーク内にいる際にこの方法でファイル共有が出来るのかな。

必要なもの

  • PHP5.4以上

PHP5.4以上にはビルトインサーバーが組み込まれているのでこれを使いたい

参考

PHPでユーザーにファイルをダウンロード「させる」方法

方法

上記のリンクのファイルを作成し、以下のコマンドで起動する

1
2
#sample.phpで作成した例, optionはip:ポート番号
php -S 0.0.0.0:5000 sample.php

こうすることで、webサーバーがsample.phpを動かすので気軽にファイルをダウンロードは出来るようになる。

(当然リモート側はアクセスできるようにiptables等の設定が必要です)

本当は取り組みたかったこと

1
php -S 0.0.0.0:5000 sample.php ファイル名

で任意のファイルをダウンロードさせるスクリプトを作りたかった。

が、コマンドライン引数を受け付けてくれなくて断念した。

コマンドライン引数とかを指定してもipとポート番号と以外無駄。

他の事例として

最近python製のマイクロフレームワークのflaskを取り組んでいまして、そっちでも似たようなことをやっていた。

1
python app.py 引数

って感じでやるといい感じにwebアプリケーションだけどコマンドライン引数を受け取ってくれてた。

これができちゃうのにはスクリプトからwebサーバーを動かす仕組みになっているからですが。 (つまり、本日、本当にやりたかったことはflaskとpythonがあればできるので、それは後日書きます。)

結論として

phpの場合はサーバーの上にスクリプトが存在してて、URLから別ファイルを参照することも(ファイルが存在すると)可能。

python(flask)の場合はスクリプトからwebサーバーを動いているので、そのスクリプト上にルーティングが存在しないとだめ。

両者ともにwebサーバーの機能を実現しているが、仕組みが結構異なるということだと思われる。 この話を突き詰めていくと結構ちゃんとした話になると思うが、何を突っついたらいいのか分からないのが本音。

話がずれたけど以上。

python3.4のenumでちょっとハマった話

enumとは

列挙型ってやつらしいです。 python3.4から使えるらしいです。

使い方

インポートして直接利用する方法

第一引数を定義名、第二引数をリストか空白区切りの文字列としEnumの要素とする

以下の方法だと、Aって言うEnum型の定義名にBとCと言う要素を宣言した形となる

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from enum import Enum

hoge = Enum('A',['B','C'])

if __name__ == 'main':
    for tmp in hoge:
        print(tmp.name)
        print(tmp.value)

#出力
#B
#1
#C
#2
    print(hoge.B)
# A.B

インポートして、Enumを継承して利用する方法

先ほどとはちょっと異なる定義をします。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from enum import Enum

class Hoge(Enum):
    A='a'
    B='b'

if __name__ == 'main':
    for tmp in Hoge:
        print(tmp.name)
        print(tmp.value)

#出力
#A
#a
#B
#b
    print(Hoge.A)
#出力
#Hoge.A

何にハマったか

keyとvalueのシンプルな関係を持たせることが出来るなら、正誤表みたいな使い方が連想配列の代わりにEnumで出来るな!と考えて以下の様な定義と使い方をしてみました。

1
2
3
4
5
6
7
8
9
10
11
from Enum import enum

class Hoge(Enum):
    A=True
    B=False
    C=True

if __name__ == 'main':
    for tmp in Hoge:
        print(tmp.name)
        print(tmp.value)

すると結果は

1
2
3
4
5
#出力
#A
#True
#B
#False

何故かCが定義されてない。

なぜ定義されていないか

ドキュメントにきちんと書いてありました。

ただし、複数の列挙型メンバーが同じ値を持つことはできます。同じ値を持つ 2 つのメンバー A および B (先に定義したのは A) が与えられたとき、B は A の別名になります。A および B を値で調べたとき、A が返されます。B を名前で調べたとき、A が返されます:

つまり、同じ値を持っているものは同じ名前だよね?って処理がされます。

上の例ではAとCが両方TrueなのでCの定義はAと同義とみなされたということです。

wikipediaの列挙型のページを見る限りいくつかの定数の集まりとして使うのが正解なのでしょうかね?

列挙型を使うのが初めてで存じ上げませんでした。

ドキュメントをきちんと読まなかったので、ちょっとだけハマった話でした。

cakePHP3にチャレンジ!

この投稿はCakePHP Advent Calendar 2014の6日目の記事です。

5日目:CakePHPでType Hinting!!!::CakePHP Advent(5日目)

前提

現在のcakePHPは 2.5.6が安定版、2.6.0がRC、3.0がbeatとしてリリースされています。

cakeの3って、2と何が違うの?という話は、Engine Yardさんの以下の記事がわかりやすいと思うので、そちらを参照してください。

第3回 週末ランサーズにてCakePHP3についての講演をしました

マドリードで見たCakePHP3の明るい未来

本日はまだ英語版しか無い、cakePHP3のBookmarkerチュートリアルほど取り組みます!

扱うこと

  • cakePHP3を始めるにあたって必要なもの
  • cakePHP3のインストール
  • プロジェクトの始め方
  • ちょっとだけカスタマイズ

cake以前の準備

InstallationQuick Start Guideを参考に進めていきます。

実行環境

必要なものに以下が指定されています。

  • webサーバー
  • PHP 5.4.16 以上
  • mbstring extension
  • mcrypt extension
  • intl extension
  • pdo
  • DB(後述)

DBは以下の内のどれか

  • MySQL 5.1.10以上
  • PostgreSQL
  • Microsoft SQL Server 2008以上
  • SQLite 3

まぁつまり、通常のLAMP構成みたいなものがあれば良いのでは無いかと思います。

自分はvagrantを利用して以下を用意しました。

  • centOS6.5
  • nginx
  • php5.6
  • mysql

caekPHPのインストールの準備

コマンドラインから適当なディレクトリで以下を実行します。

練習ということで、cakePHPを配置したいディレクトリで実行するのがいいと思います。

まず、cakeをインストールするためのcomposerをインストール

1
curl -s https://getcomposer.org/installer | php

チュートリアル Bookmarker

Bookmarkerを作るチュートリアルです。

チュートリアルの概要は、簡易版のソーシャルブックマークを作成しよう!というものです。

サイトに登録したユーザーは、URLを登録する事ができ、そのURLに対してタグを付与することが出来るようになります。

cakePHP3をcomposerでインストール

以下を実行するとcakeがインストールされます。

最後のbookmarkerってやつがインストールされるディレクトリ名になります。

1
php composer.phar create-project --prefer-dist -s dev cakephp/app bookmarker

時間が少々かかります。成功すると標準出力に以下の様なものが表示されます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
Installing cakephp/app (dev-master 28008873514274db441338eff5e2d07e75274f48)
  - Installing cakephp/app (dev-master master)
      Loading from cache

Created project in bookmarker
Loading composer repositories with package information
Installing dependencies (including require-dev)
  - Installing cakephp/plugin-installer (0.0.1)
      Downloading: 100%

  - Installing aura/installer-default (1.0.0)
      Downloading: 100%

  - Installing nesbot/carbon (1.13.0)
      Downloading: 100%

  - Installing psr/log (1.0.0)
      Downloading: 100%

  - Installing aura/intl (1.1.1)
      Downloading: 100%

  - Installing ircmaxell/password-compat (v1.0.4)
      Downloading: 100%

  - Installing cakephp/cakephp (3.0.x-dev 0e787e9)
      Downloading: 100%

  - Installing cakephp/debug_kit (3.0.x-dev 8a6f3da)
      Downloading: 100%

  - Installing mobiledetect/mobiledetectlib (2.8.11)
      Downloading: 100%

  - Installing d11wtq/boris (v1.0.8)
      Downloading: 100%

d11wtq/boris suggests installing ext-posix (*)
Writing lock file
Generating autoload files
Created `config/app.php` file
Permissions set on /vagrant/bookmarker/tmp/cache
Permissions set on /vagrant/bookmarker/tmp/cache/models
Permissions set on /vagrant/bookmarker/tmp/cache/persistent
Permissions set on /vagrant/bookmarker/tmp/cache/views
Permissions set on /vagrant/bookmarker/tmp/sessions
Permissions set on /vagrant/bookmarker/tmp/tests
Permissions set on /vagrant/bookmarker/tmp
Permissions set on /vagrant/bookmarker/logs
Updated Security.salt value in config/app.php

失敗してるとちゃんとproblemって出るので見落とさないように。

自分の環境(ここのCentOS 6.5 x86_64)では php-intl がインストール出来なくてエラーが出てました。最後にちょろっと補足を書いておきます。

アクセスするとこんな感じ

2系列の時より綺麗!!!

(だけどまっさらで、必要な情報はもうちょい上に挙げられなかったのかなーなんてね)

cakephp3 top

ディレクトリ構成

appがsrcに変わった感じ?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
bookmarker
├── README.md
├── bin
├── composer.json
├── composer.lock
├── config
├── index.php
├── logs
├── phpunit.xml.dist
├── plugins
├── src
├── tests
├── tmp
├── vendor
└── webroot

src以下はずいぶんスッキリ

1
2
3
4
5
6
7
src
├── Console
├── Controller
├── Model(以下にTable,Entity,Behaviorがあります)
├── Shell
├── Template (2系列までのView相当)
└── View (3系列でViewがオブジェクトになった影響のディレクトリ)

設定

まずtmpとかlogsとかの権限をphpが関与できる権限に変更しましょう。

つぎにDBの作成とテーブルの設定。チュートリアルにある、以下をまんま流し込む

今回は面倒かつ練習用なので

ユーザー名 root パスワード root 作成したDBの名前 bookmarker

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
CREATE TABLE users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    email VARCHAR(255) NOT NULL,
    password VARCHAR(255) NOT NULL,
    created DATETIME,
    updated DATETIME
);

CREATE TABLE bookmarks (
    id INT AUTO_INCREMENT PRIMARY KEY,
    user_id INT NOT NULL,
    title VARCHAR(50),
    description TEXT,
    url TEXT,
    created DATETIME,
    updated DATETIME,
    FOREIGN KEY user_key (user_id) REFERENCES users(id)
);

CREATE TABLE tags (
    id INT AUTO_INCREMENT PRIMARY KEY,
    title VARCHAR(255),
    created DATETIME,
    updated DATETIME,
    UNIQUE KEY (title)
);

CREATE TABLE bookmarks_tags (
    bookmark_id INT NOT NULL,
    tag_id INT NOT NULL,
    PRIMARY KEY (bookmark_id, tag_id),
    INDEX tag_idx (tag_id, bookmark_id),
    FOREIGN KEY tag_key(tag_id) REFERENCES tags(id),
    FOREIGN KEY bookmark_key(bookmark_id) REFERENCES bookmarks(id)
);

でもって、作成したDBの設定をconfig/app.phpに反映

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#config/app.phpの200行目付近

        'Datasources' => [
            'default' => [
                'className' => 'Cake\Database\Connection',
                'driver' => 'Cake\Database\Driver\Mysql',
                'persistent' => false,
                'host' => 'localhost',
                 /*
                  * CakePHP will use the default DB port based on the driver selected
                  * MySQL on MAMP uses port 8889, MAMP users will want to uncomment
                  * the following line and set the port accordingly
                  */
                 //'port' => 'nonstandard_port_number',
                'username' => 'root',
                'password' => 'root',
              'database' => 'bookmarker',
                'encoding' => 'utf8',
                'timezone' => 'UTC',
                'cacheMetadata' => true,

                /*
                 * Set identifier quoting to true if you are using reserved words or
                 * special characters in your table or column names. Enabling this
                 * setting will result in queries built using the Query Builder having
                 * identifiers quoted when creating SQL. It should be noted that this
                 * decreases performance because each query needs to be traversed and
                 * manipulated before being executed.
                 */
                'quoteIdentifiers' => false,

                /*
                 * During development, if using MySQL < 5.6, uncommenting the
                 * following line could boost the speed at which schema metadata is
                 * fetched from the database. It can also be set directly with the
                 * mysql configuration directive 'innodb_stats_on_metadata = 0'
                 * which is the recommended value in production environments
                 */
                 //'init' => ['SET GLOBAL innodb_stats_on_metadata = 0'],
            ],

スキャッフォルドで色々と生成

おなじみのスキャッフォルド

bookmarkerとしてcakeをインストールしたディレクトリで以下を叩きます

1
2
3
php bin/cake.php bake all users
php bin/cake.php bake all bookmarks
php bin/cake.php bake all tags

成功してると最後に以下が表示される

1
Bake All complete.

成功したなら以下にアクセス

1
http://example.com/bookmarks

3系ではcakeのデフォはフラットですね。

cake3 bookmarker

これだけで、結構な色々な機能が使えるのですが、見れない所がちょいちょい有る。

が、それは後で治すと思うのでとりあえず放置

とりあえず、この後色々試すのにユーザーとタグとブクマのデータを入れて欲しい。 順番もきちんとユーザー、タグ、ブクマで入れると勘違いが起きない。

パスワードを暗号化させよう

現状のままだと、ユーザーのパスワードが暗号化されていないので実用性が低いと思われるので。

src/Model/Entity/User.phpに追記していきます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?php
namespace App\Model\Entity;

use Cake\ORM\Entity;
use Cake\Auth\DefaultPasswordHasher; #追記
/**
 * User Entity.
 */
class User extends Entity {

/**
 * Fields that can be mass assigned using newEntity() or patchEntity().
 *
 * @var array
 */
    protected $_accessible = [
        'email' => true,
        'password' => true,
        'bookmarks' => true,
        ];

    protected function _setPassword($value) {  #追記
            $hasher = new DefaultPasswordHasher(); #追記
            return $hasher->hash($valu             #追記

    }
}

(どうでもいいけど、cakeのスキャッフォルド、tab文字で生成されるの凄く気になりませんか?)

これで、Userを編集したり、新しく保存するとユーザーのパスワードが暗号化されるはず。

2系列で使っていたModelは、Model/Entityに移動した形ですかね? 3系列ではModelがオブジェクトを返すようになったらしいので、それに伴い、大きく変更されてるっぽいですね。

面倒だけど、ドキュメンを読む

Modelから抜粋

In CakePHP your application’s domain model gets split into 2 primary object types. The first are repositories or table objects. These objects provide access to collections of data. They allow you to save new records, modify/delete existing ones, define relations, and perform bulk operations. The second type of objects are entities. Entities represent individual records and allow you to define row/record level behavior & functionality.

ざっくり訳すと、modelは2つに別れて、

オブジェクト 役割
table 新しいデータの保存とか、変更、削除と、リレーションの定義
entities 独立したレコードの表示や、行の振る舞いや関数の定義

つまり、tableはデータを弄る系とリレーション、entitiesはデータの利用ってことでいいのかな?

ついでにViewがどう変わったのかも確認する

3.0 Migration Guideがわかりやすそう

The folders containing view files now go under src/Template instead of src/View. This was done to separate the view files from files containing php classes (eg. Helpers, View classes).

いままでのViewがTemplateに変わったとの事。

cake3ではViewもオブジェクトになったからだと思われる。

でもって、Viewのオブジェクトで色々と設定が出来るようになった?って感じかな。

タグ付けされてるブックマークを探したいよね。

たとえば

1
http://example.com/bookmarks/tagged/funny/cat/gifs

以上だと、funnyとかタグ付けされてるやつブクマが分かることを期待する。

この機能を実現するために、以下の手順を通して行う。

  1. config/routes.phpを編集
  2. src/Controller/BookmarksController.phpの編集
  3. src/Model/Table/BookmarksTable.phpの編集
  4. Template/Bookmarks/tags.ctpの追加

まず、config/routes.phpを編集

1
2
3
4
5
6
7
8
#URLのbookmarks以下でtaggedにマッチしたら、BookmarksControllersのtagsメソッドにアクセス
Router::scope(
    '/bookmarks',
        ['controller' => 'Bookmarks'],
        function ($routes) {
            $routes->connect('/tagged/*', ['action' => 'tags']);
        }
);

以上を、

1
Router::scope("/",#以下略

が出てくる前に記述する。

記述しないと、/ が追記したものより先にマッチして思うようにアクセス出来ない。

コントローラーの編集

routesに追記したのはBookmarksControllersのtagsにアクセスと書いたが、まだ無いので追記。 位置は基本的に気にしなくていい。

1
2
3
4
5
6
7
8
public function tags() {
    $tags = $this->request->params['pass'];
        #findの第一引数のtaggedが、ModelのfindTaggedに関連づいている
    $bookmarks = $this->Bookmarks->find('tagged', [
                'tags' => $tags
                ]);
    $this->set(compact('bookmarks', 'tags'));
}

モデルの編集

チュートリアルには、コントローラーを薄く保つために、モデルにロジックを記述するんだ!とか書いてある。

結果として、より規約を意識する形になったと思う。

コードのコメントにも書いたが、Controller内のModel呼び出しで、find('tagged'〜のところが、findTaggedと結びついている。

Model/Table/BookmarksTable.phpに以下を追記

1
2
3
4
5
6
7
8
9
10
11
12
public function findTagged(Query $query, array $options) {
    $fields = [
            'Bookmarks.id',
            'Bookmarks.title',
            'Bookmarks.url',
        ];
    return $this->find()
                ->distinct($fields)
                ->matching('Tags', function ($q) use ($options) {
                    return $q->where(['Tags.title IN' => $options['tags']]);
                });
}

Templateの追加

Controllerにメソッドを追加したら、Templateも追加しましょう。

/Template/Bookmarks/tags.ctpに以下を記述して保存

1
2
3
4
5
6
7
8
9
10
11
<h1>Bookmarks tagged with <?= $this->Text->toList($tags) ?> </h1>

<section>
    <?php foreach ($bookmarks as $bookmark): ?>
        <article>
            <h4><?= $this->Html->link($bookmark->title, $bookmark->url) ?></h4>
            <small><?= h($bookmark->url) ?></small>
            <?= $this->Text->autoParagraph($bookmark->description) ?>
        </article>
    <?php endforeach; ?>
</section>

全て終えると

1
http://example.com/bookmarks/tagged/hogehoge

にアクセスするとhogehogeとタグ付けされた本がリストアップされる。

スクショは、予めブクマしたものにプログラミングとタグ付けをしてURLにアクセスしたもの。

1
http://example.com/bookmarks/tagged/プログラミング

cake3 tagged

寂しいけどこんな感じ。 これでbookmarkerチュートリアルは終了。

cake3の感想

結構色々変わった!というのがチュートリアルを終えての印象。

cake2の頃も結構規約を意識しなければならなかったが、更に規約を意識してプログラムを書かなければと思う。

cake慣れていれば問題ないけど、初心者とかは結構詰まるのではないかな?

ModelとViewが更に大きく変わっていると思うけれど、今回のチュートリアルでは構成と役割が分割されたくらいしかわからないので、次回に持越し。

とりあえず、正式にリリースされたら、新規で作るものに関しては使っていきたいと思う。 これだけの変更があると、マイグレーションツールとかがどの位通用するのかとかも気になる所。


想像以上に長くなったので、とりあえず本日の記事は以上にします。 近いうちにBookmarkarチュートリアル2に取り組む記事もあげる予定です。

cakePHP3のチュートリアルの足掛かりになればと思います。

補足

php-intlがインストールできて無かった話

libicudata.so.50()(64bit)が無いと言われたので

1
2
3
wget ftp://195.220.108.108/linux/remi/enterprise/6/remi/x86_64/libicu-last-50.1.2-11.el6.remi.x86_64.rpm
rpm -iV libicu-last-50.1.2-11.el6.remi.x86_64.rpm
yum -y install --enablerepo=remi-php56 php-intl

って感じでインストールした。

Octopressのシンタックスハイライト

このブログはoctopressってやつで運営しているんです。

octopressとは

octopressは静的ファイルで運営するブログでして、本文をマークダウンで記述出来て、さくっとコードの埋め込みとかも出来ます。

1
2
3
4
5
rake new_post['hogehoge']

rake preview

rake gen_deploy

の一連で記事を更新できます。

シンタックスハイライトが無効問題

コードを埋め込んでシンタックスハイライトを期待する文章で

1
rake preview

を叩くと

1
jekyll 2.5.1 | Error:  Pygments can't parse unknown language: php.

とかでる。

でもってシンタックスハイライト有効にならない。

問題点

stackoverflowに出てました。 ここ

つまり、python2.7でないとダメらしく、自分の環境のpythonは3.4.0だからっぽい。

解決方法

自分の環境はmacにpyenvがインストールされているので、octopressのディレクトリ内では2.7が動くように指定しました。

macのシステムで利用しているpythonは2.7だと思うので

1
pyenv local system

以上をoctopressの設置しているディレクトリ内で叩くことにより、シンタックスハイライトが有効になりました。

めでたしめでたし。

Python3のisとかinとnotの話

要は論理否定演算子の話

PHP

PHPでは

1
2
3
4
5
<?php
$hoge = array('A','B','C');

if( !is_array($hoge) ){
}

とか

1
2
3
4
5
<?php
$hoge = "A";

if ($hoge != "A"){
}

とかで、! を論理否定演算子に使う。

Python

だが、Pythonではnotを利用して論理否定を表現する。

1
2
3
hoge = None

hoge is not None

とか

1
2
3
hoge = ['1','2','3']

'1' in not hoge

で表現する。

補足1

pythonだと

1
2
3
hoge = ['1','2','3']

not '1' in hoge

とか表現できるけど、こっちの方だと、pytestとかで警告が出る。

補足2

確認する際はphp -aか、ipythobを利用して確認すると良い。

ただしphp -a は環境によっては使えないことと、Trueを1、Falseを出力なしで表現することに注意

はじめてみる

どこまで続くかわからないですけど。 始めてみます。 プログラミングetcのはなしです。