情弱エンジニアのなかのblog

一人前のエンジニアになる為のブログです

CakePHPのBehaviorを自作する方法

Modelを拡張させる方法

現在cakePHPでアプリを作っていてBehaviorの自作について理解したので手順等記載していきます。 Behaviorを自作するときの基本の基本になります。

1.なぜBehaviorを作るのか

まずCakePHPアプリ制作において、なぜBehaviorを使うのかというところですが 例えばModelに新しい機能を作ったとして、複数のModelでも使うことになり 利用するModelでいちいち同じ処理を書くのは手間になります。

そこでBehaviorというものを使って共通する処理を一つの場所に書いて それをModelで使いまわそうというものになります。

2.実装の仕方

Behaviorを作ることになったら app/Model/Behaviorに追加していきます。 今回はごくごく簡単な処理を確認していきます。

class TestBehavior extends ModelBehavior {

    public function test() {
        //返り値を「5」にしておきます
        return 5;
    }
}

続いて利用したいModelを編集していきます。

//利用したいBehaviorを指定します
public $actsAs = array('Test');

Modelに記載するのはこれだけになります!

2.処理をを出力する

続いてその処理をControllerからViewに渡してみます。

ControllerでBehaviorのメソッドを呼び出します。

$data = $this->Model->test();
$this->set("data",$data);

最後にViewで表示してみます。

echo $data;

とすると返り値に指定した5が出力されます。

といったここまでがBehaviorの実装の流れになります。 Behaviorでいい感じの処理を作ったら再度記事をあげます。

それでは

CakePHP ログイン認証チェック

CakePHPのAuthComponentでログイン認証がうまくいかない時は?

CakePHPで記事を投稿するアプリを作っていてログイン状態の保持の為にAuthComponentを利用していたのですが ログインページでユーザ名とパスワードは合っているのにログインができないということが起こったので解決法、手順等を記載していきます。

1. なぜか認証されない

まずログイン機能を実装するために「CakePHP ログイン Auth」などで検索すると 以下のような文が出てくると思います。

if($this->Auth->login()){
    //ログイン成功したときの処理
}else{
    //ログイン失敗したときの処理
}

私もこれを実装したわけですがユーザー名とパスワードは合っているのに「ログイン成功」しませんでした。

2.テーブル名、フィールド名は正しいのか?

では原因は何か探していきます。

まずユーザーテーブルとフィールド名が正しく用意できているかを確認してください。 参考書などを読んでいるとどうやら テーブル名は「Users」 フィールド名は「username」と「password」でないといけないようです。

テーブル作った後に知りました。 ModelのvalidateやViewのaddなどなど色々変えていかなくてはいけません。

ちなみにフィールドの「password」ですが、varcharで最低でも40文字以上は保管できるようにしてください。 「password」にはハッシュにより暗号化された文字列が入るので保管できる量が少ないと正しく値を保持できなくなります。

3.ハッシュ化はされているか?

こちらも重要なのですがAuthComponentで認証するにはパスワードがハッシュ化されている必要があります。 なのでハッシュ化の確認をしてください。

phpMyAdminのUserテーブルを確認してpasswordに入力した値がそのまま入っていたら パスワードをハッシュ化する必要があります。

手順ですが、新しくユーザーを追加するときにpasswordをハッシュ化させるのでUsersControllerのaddに

$this->request->data['User']['password'] = $this->Auth->password($this->request->data['User']['password']);

を追記します。ただし

$this->User->create();

createの上に書きましょう。

さてこれで新たにユーザーを作ってからphpMyAdminを見るとパスワードがハッシュ化されているはずです。

ハッシュ化されていれば、ログインをすると成功します!

それでは

Cakephp でjQuery を使ってみる

マウスオーバーした時に枠線を表示する

CakePHPで記事を投稿するサイトを作っているのですが、マウスオーバーで反応があるものを作りたいと思い 簡単ではありますがjQueryを使ってマウスオーバーで記事に枠線をつけたので手順等記載していきます。

1. jsファイルを作る

まずはjsファイルを作るのですが、CakePHPではjsファイルは基本的にwebrootの中のjsフォルダの中に入れていきます。 (jQueryのライブラリーも入れておいてください)

cssファイルや画像ファイルも入れる場所があります。

さて重要な中身ですが、記事をマウスオーバーするとその記事の周りにグレーの枠線が出るようにしました。

$(function(){

  $(".article_chunk").mouseover(function(){
      //記事にマウスが重なっている間は枠線を出す
      $(this).css("outline","5px solid #e6e6e6");
  });

});

これで枠線はつくのですがこれだと枠線が出っぱなしで消えなくなってしまうので

$(function(){

  $(".article_chunk").mouseover(function(){
      //記事にマウスが重なっている間は枠線を出す
      $(this).css("outline","5px solid #e6e6e6");
  }).mouseout(function(){
      //記事からマウスが離れたら枠線を消す
      $(this).css("outline","");
  });

});

こうすることで、マウスが離れると枠線が消えます。

$(this).css("outline","");

mouseoverで指定したcssの値を"“にすれば解決できます。

また「border」を使うとレイアウトが崩れてしまったので「outline」を使いました。

2. 記事一覧のビュー

記事一覧側はまずjQueryを読み込みます

    <?php echo $this->Html->script('jquery-3.2.0.min.js'); ?>
    <?php echo $this->Html->script('jsファイル名.js'); ?>

これでwebroot/js内のjsファイルを読み込みます。

続いて記事のひとまとめでclassを指定すればオーケーです。

<div class="article_chunk">

//記事を表示する処理

</div>

以上になります。 それでは

CakePHP Paginatorでページ分けと表示順を指定

記事の表示件数と表示する順番を指定する

CakePHPで記事を投稿するアプリを作っていて、表示するページを分けたいと思いPaginatorでページ分けをしたので手順等を記載します。

1.ページを分ける

まずはページごとに分けていきます。 Cntrollerを編集していきます。

表示件数を5件、表示順は記事の降順で表示する

class ArticlesController extends AppController {

public $paginate = array(
    //表示件数を5件に指定する
    'limit' => 5,
    //表示順番をArticleのidの降順
    'order' => array('Article.id' => 'desc')
);

これでページを分けて表示できます。

2.ページ遷移をさせる

続いてビュー側でページ遷移の選択肢を作ります。

・前のページ ・次のページ ・ページ数を選ぶ ・最初のページ ・最後のページ

これらを実装します

<?php
    //最初のページへ
    echo $this->Paginator->first('最初のページへ' , array());
    //一つ前のページへ
    echo $this->Paginator->prev('戻る', array(), null, array('class' => 'prev disabled'));
    //ページ数を選択する
    echo $this->Paginator->numbers(array('separator' => ''));
    //一つ次のページへ
    echo $this->Paginator->next('進む', array(), null, array('class' => 'next disabled'));
    //最後のページへ
    echo $this->Paginator->last('最後のページへ', array());
?>

f:id:nonaka-katuma-hal:20170615185025j:plain

これでページ遷移が出来るのですが、一つ注意点があります。

3.デフォルトを参照していないか

私が引っかかったところなのですが、Controllerで使うPaginatorがlib/Cake/Controller/Component にある「PaginatorComponent.php」を参照していていくらlimitを指定しても結果が反映されないという状況に陥りました。

まず原因としてはControllerで$componentsでPaginatorを指定していることになります。

public $components = array(
    'Paginator',
    'Session', 
    'Flash'
    );

解決策としては簡単で'Paginator'を削除すればオーケーです。

それでは

サブクエリの使い方

サブクエリでのWHEREについて

今回はサブクエリの使い方に関して記載していきます。

1.WHERE

まずはサブクエリであるデータを検索して全体の平均以上もしくは以下の場合出力したいとき

例題 ・とあるショッピングサイトには会員がいて買い物をするごとにポイントがつきます。各会員が保有しているポイントの平均値以上のポイントを持っている顧客を抽出したい。

customersテーブル

+------+-----+
| name |point|
+------+-----+
| 上田 | 15  |
| 田口 | 25  |
| 赤西 | 20  |
| 中丸 | 45  |
| 田中 | 10  |
| 亀梨 | 35  |
+------+-----+
SELECT
    name , point
FROM
    customers
WHERE
    point >= (
    SELECT
        avg(point)
    FROM
        customers
);


田口 | 25 
中丸 | 45
亀梨 | 35

保有ポイントの平均値以上のポイントを持っているメンバーのみ表示されます。

ちなみにサブクエリを使わずに無理矢理WHERE句だけで書こうとした場合

SELECT
    name , point
FROM
    customers
WHERE
    point >= avg(point)

これはうまくいきません

今回は以上になります。

CakePHP 画像のサイズを決めて出力する

アップロードした画像を任意のサイズにして表示する

画像のアップロードが出来たらその画像を丁度いいサイズにして出したいでよね ということでやり方をアップします。

前提として「webroot」に「upimg」というフォルダを作っているものとします。

今回は私は記事一覧を表示するところで画像の表示を行いました。 なのでforeachの中だと考えてください。

まず画像のファイルパスを取得していきます。

$article_id = $article['Article']['id'];
$id = "/img/" . $article_id . ".jpg" ;

// コピー元画像の指定
$path = WWW_ROOT . "upimg/" . $article_id  . ".jpg";
//出力先のファイル
$file = WWW_ROOT . "img/" . $article_id  . ".jpg";

続いて画像サイズの取得や表示するサイズ設定をしていきます。

// ファイル名から、画像インスタンスを生成
$in = imagecreatefromjpeg($path);
//元画像サイズ取得
$size = GetImageSize($path);
$width = 200;
$height = 200;
//サイズを指定した背景画像を生成
$out = ImageCreateTrueColor($width, $height);
//サイズ変更・コピー
ImageCopyResampled($out, $in, 0, 0, 0, 0, $width, $height, $size[0], $size[1]);

最後に出力と不要なデータの削除を行います。

//画像保存
imagejpeg($out, $file ,100);
echo $this->Html->image($id, array('alt' => 'baz'));

ImageDestroy($in);
ImageDestroy($out);

これで画像のサイズを指定して出力することができます。

それでは

CakePHP画像のアップロード

ファイル形式の指定とフォルダを移動して保存するまで

CakePHPでのアプリ制作で画像のアップロードを実装したので手順等を記載致します。

1.addでファイルをアップロード

まず最初にやることは当然addでファイルのアップロードを出来るようにすることです。 こちらはaddに少し記述するだけで済みます。

<?php
echo $this->Form->input('image', array(
    'label' => false,
    'type' => 'file','multiple'));
?>

これでaddを確認するとファイルのアップロードが出来るようになっていると思います。

f:id:nonaka-katuma-hal:20170531202624j:plain

2.アップロードファイルの情報確認方法

では早速アップロードしたファイルを扱っていく、、、前にですね アップロードしたファイルの情報を見る方法をご紹介します。

今後ファイルパスやファイル名を確認するのに必須になってくるものなので使い方を覚えましょう! と言っても確認方法は簡単です。

addからファイルをアップロードした後にControllerで

//中身をみたい変数などあれば確認できます。
debug();
//処理をここで止めます
return;

こう記述することで記述した場所で処理を止めることが出来ます。 これを書いて実行しまして右上のケーキのマークを押します。

するとビロビロと出てくるので「Request」をおすとアップロードしたファイルの情報を見ることができます。

f:id:nonaka-katuma-hal:20170531203943j:plain

「image」の中身を見てもらうと

「name」がアップロードしたファイルのファイル名になります。

「type」がファイルの拡張子になります。

「tmp_name」がアップロードしたファイルの一時的なパスになります。 この一時的なパスはファイルを識別するために与えられるものでして、 コードでファイル自体を扱いたいときはこのパスを指定することになるので覚えておいてください。

3.受け取ったファイルを保存する、パスを指定する

続いてControllerでDBにファイルの保存して、特定のフォルダに画像ファイルを保存していきます。

1.ファイルの保存先を指定

2.ファイルのパスを保存

3.ファイルの名前を取得

4.ファイルの保存

//保存先のパスを保存、WWW_ROOT はwebrootを示します。
$path = WWW_ROOT . "upimg/";

//アップロードしたファイルの一時的なパスを取得します
$img = $this->request->data('Article.image.tmp_name');

//アップロードしたファイル名を取得します
$name = $this->request->data('Article.image.name');

//現在ある記事のidの最大値を取得します
$box = $this->Article->find('first', array("fields" => "MAX(Article.id) as max_id"));
$id = $box[0]['max_id'];

//今回追加する記事番号にします
$id++;

$uploadfile = $path .  "$id.jpg";

//画像のフォルダとファイル名を指定して保存します
if(!move_uploaded_file($img,$uploadfile)) {
    $this->Flash->error(__('画像ファイル保存できませんでした'));
    return $this->redirect(array('action' => 'index'));
}

//DB保存用にファイル名を保存します
$this->request->data['Article']['image'] = $name;

こちらまでがファイル自体の保存になります この場合画像は「webroot/upimg」というフォルダに保存されます。

続いてDBへの保存がこちらになります。

if ($this->Article->save($this->request->data)) {
    $this->Flash->success(__('記事の追加が出来ました!'));

    return $this->redirect(array('action' => 'index'));

} else {
        $this->Flash->error(__('記事の追加でエラー'));
}

これで保存は完了です。

4.拡張子をチェックして画像以外をはじく

続いてはアップロードされたファイルが本当に画像ファイルかチェックしていきます。 悪意のあるファイルでもアップされたら大変ですからね!

書き方は「jpeg」「jpg」「gif」「png」以外のファイルがアップロードされたら別のビューに移動して はじくというものになります。

//アップロードしたファイルの拡張子を取得します
$extension = $this->request->data('Article.image.type');

//アップロードを許可するファイルの拡張子を代入します
$check_array = array(1 => 'image/jpeg', 2 => 'image/jpg', 3 => 'image/gif', 4 => 'image/png');

//アップロードされたファイルが画像ファイルかどうかチェックします
if(!array_search($extension , $check_array)) {
    $this->Flash->error(__('画像ファイルを入れて下さい'));
    return $this->redirect(array('action' => 'index'));
}

これで画像ファイルだけがアップロードされます。 なぜ配列が 1 => からなのか気になる方はこちらのサイトを見てみてください。

【array_search関数】は戻り値に注意!! | HANGOUT - ハングアウトエンジニアブログ

5.GitHubにアップするときの注意

さて機能としてはこれで完成なのですがGitHubなどバージョン管理ツールにアプリをアップするときは画像を保存しているファイルをアップしないように注意しましょう。 と言っても方法は簡単でgitignoreに「app/webroot/upimg」と記載すればオーケーです。

さてこれで一通りの画像アップロードが出来ます。 もっと効率的な方法など見つけたらまたアップします。それでは