初心者用CakePHP4でブログサイト①環境構築をしてページを表示する

初心者用CakePHP4でブログサイト①環境構築をしてページを表示する

511 回閲覧されました

みなさんこんにちは、joinioです。

MAMPでCakePHPを使ってブログサイトを作ったのですが忘れない為にメモを残します。

この記事を書いているのが2024年9月ですが記事を見た時期によってはGitのコマンドやコードがバージョンに対応できなくなっているかもしれないのでご了承下さい。

全3回で解説をしています。

おすすめ参考書

CakePHP3はまだまだ仕事で使われます。

下記の参考書がおすすめです。

動作環境

MAMPです。

CakePHPのバージョン

4系です。

今回の解説内容

MAMPにCakePHPをインストールしてデータベースにアクセスしてページを表示する所までを解説しています。

前提条件

MAMPのインストールの手順は説明しないので自分で調べて下さい。

htdocsの下の階層にフォルダの作成

MAMPを起動してhtdocsの下の階層にフォルダ(cakephpとします)を作成します。

phpのバージョン・composerをインストールしているかの確認

CakePHPの公式サイトに4系のPHPのバージョンの指定があるので「php -v」で自分のパソコンのPHPのバージョンを表示して満たしているかを確認します。

また「composer -v」でcomposerをインストールしているかを確認します。

大丈夫ならCakePHPをインストールします。

CakePHPのインストール

ターミナルでcakephpまで移動して下記のコマンドを入力します、「CakeBlog1」はプロジェクト名です。

composer create-project --prefer-dist cakephp/app:4.1 CakeBlog1

インストールしている途中で下記の3つで選択をしないといけないので全て「y」にします。

Do you trust "cakephp/plugin-installer" to execute code and wish to enable it now? (writes "allow-plugins" to composer.json) [y,n,d,?]
Do you trust "dealerdirect/phpcodesniffer-composer-installer" to execute code and wish to enable it now? (writes "allow-plugins" to composer.json) [y,n,d,?]
Set Folder Permissions ? (Default to Y) [Y,n]?

最初の修正

トップページ(私の場合はhttp://localhost:8888/cakephp/CakeBlog1/)にアクセスすると下記の赤枠のエラーが表示されます。

エラーを取りますが記事にしているのでそれを読んで下さい。

データベースにアクセスできるようにする

トップページで下にスクロールするとデータベースへの接続がない状態になっています。

今回はSqliteを使います。

.envの修正

「CakePHPのプロジェクト > config > .env.example」の「.env.example」を「.env」に変更して中身の修正をします。

#!/usr/bin/env bash
# Used as a default to seed config/.env which
# enables you to use environment variables to configure
# the aspects of your application that vary by
# environment.
#
# Having this file in production is considered a **SECURITY RISK** and also decreases
# the boostrap performance of your application.
#
# To use this file, first copy it into `config/.env`. Also ensure the related
# code block for loading this file is uncommented in `config/boostrap.php`
#
# In development .env files are parsed by PHP
# and set into the environment. This provides a simpler
# development workflow over standard environment variables.
export APP_NAME="CakeBlog1"                //この行を修正
export DEBUG="true"
export APP_ENCODING="UTF-8"
export APP_DEFAULT_LOCALE="ja_JP"          //この行を修正
export APP_DEFAULT_TIMEZONE="Asia/Tokyo"   //この行を修正
export SECURITY_SALT="adfdffef"            //「」の中に適当に文字列を入れる

# Uncomment these to define cache configuration via environment variables.
#export CACHE_DURATION="+2 minutes"
#export CACHE_DEFAULT_URL="file://tmp/cache/?prefix=${APP_NAME}_default&duration=${CACHE_DURATION}"
#export CACHE_CAKECORE_URL="file://tmp/cache/persistent?prefix=${APP_NAME}_cake_core&serialize=true&duration=${CACHE_DURATION}"
#export CACHE_CAKEMODEL_URL="file://tmp/cache/models?prefix=${APP_NAME}_cake_model&serialize=true&duration=${CACHE_DURATION}"

# Uncomment these to define email transport configuration via environment variables.
#export EMAIL_TRANSPORT_DEFAULT_URL=""

# Uncomment these to define database configuration via environment variables.
#export DATABASE_URL="mysql://my_app:secret@localhost/${APP_NAME}?encoding=utf8&timezone=UTC&cacheMetadata=true&quoteIdentifiers=false&persistent=false"
#export DATABASE_TEST_URL="mysql://my_app:secret@localhost/test_${APP_NAME}?encoding=utf8&timezone=UTC&cacheMetadata=true&quoteIdentifiers=false&persistent=false"

# Uncomment these to define logging configuration via environment variables.
#export LOG_DEBUG_URL="file://logs/?levels[]=notice&levels[]=info&levels[]=debug&file=debug"
#export LOG_ERROR_URL="file://logs/?levels[]=warning&levels[]=error&levels[]=critical&levels[]=alert&levels[]=emergency&file=error"

bootstrap.phpの修正

「CakePHPのプロジェクト > config > bootstrap.php」を修正します。

<?php
declare(strict_types=1);

/**
 * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
 * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
 *
 * Licensed under The MIT License
 * For full copyright and license information, please see the LICENSE.txt
 * Redistributions of files must retain the above copyright notice.
 *
 * @copyright     Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
 * @link          https://cakephp.org CakePHP(tm) Project
 * @since         0.10.8
 * @license       https://opensource.org/licenses/mit-license.php MIT License
 */

/*
 * Configure paths required to find CakePHP + general filepath constants
 */
require __DIR__ . '/paths.php';

/*
 * Bootstrap CakePHP.
 *
 * Does the various bits of setup that CakePHP needs to do.
 * This includes:
 *
 * - Registering the CakePHP autoloader.
 * - Setting the default application paths.
 */
require CORE_PATH . 'config' . DS . 'bootstrap.php';

use Cake\Cache\Cache;
use Cake\Core\Configure;
use Cake\Core\Configure\Engine\PhpConfig;
use Cake\Datasource\ConnectionManager;
use Cake\Error\ConsoleErrorHandler;
use Cake\Error\ErrorHandler;
use Cake\Http\ServerRequest;
use Cake\Log\Log;
use Cake\Mailer\Mailer;
use Cake\Mailer\TransportFactory;
use Cake\Routing\Router;
use Cake\Utility\Security;
use Cake\Error\ErrorTrap;
use Cake\Error\ExceptionTrap;

/*
 * See https://github.com/josegonzalez/php-dotenv for API details.
 *
 * Uncomment block of code below if you want to use `.env` file during development.
 * You should copy `config/.env.example` to `config/.env` and set/modify the
 * variables as required.
 *
 * The purpose of the .env file is to emulate the presence of the environment
 * variables like they would be present in production.
 *
 * If you use .env files, be careful to not commit them to source control to avoid
 * security risks. See https://github.com/josegonzalez/php-dotenv#general-security-information
 * for more information for recommended practices.
*/


//ここからコメントアウトを外して同じ内容に変更する
if (!env('APP_NAME') && file_exists(CONFIG . '.env')) {
    $dotenv = new \josegonzalez\Dotenv\Loader([CONFIG . '.env']);
    $dotenv->parse()
        ->putenv()
        ->toEnv()
        ->toServer();
}
//ここまでコメントアウトを外して同じ内容に変更する


/*
 * Read configuration file and inject configuration into various
 * CakePHP classes.
 *
 * By default there is only one configuration file. It is often a good
 * idea to create multiple configuration files, and separate the configuration
 * that changes from configuration that does not. This makes deployment simpler.
 */
 
 
 //以下コードの変更はないので省略

app_localの修正

「CakePHPのプロジェクト > config > app_local.php」を修正します。

<?php
use Cake\Database\Driver\Sqlite;        //この行を追加

/*
 * Local configuration file to provide any overrides to your app.php configuration.
 * Copy and save this file as app_local.php and make changes as required.
 * Note: It is not recommended to commit files with credentials such as app_local.php
 * into source code version control.
 */
return [
    /*
     * Debug Level:
     *
     * Production Mode:
     * false: No error messages, errors, or warnings shown.
     *
     * Development Mode:
     * true: Errors and warnings shown.
     */
    'debug' => filter_var(env('DEBUG', true), FILTER_VALIDATE_BOOLEAN),

    /*
     * Security and encryption configuration
     *
     * - salt - A random string used in security hashing methods.
     *   The salt value is also used as the encryption key.
     *   You should treat it as extremely sensitive data.
     */
    'Security' => [
        'salt' => env('SECURITY_SALT', 'f6bd7a113d60c323102826b1fc792f633bd8d13337726df2a6075336d21cb605'),
    ],

    /*
     * Connection information used by the ORM to connect
     * to your application's datastores.
     *
     * See app.php for more configuration options.
     */
    'Datasources' => [
        'default' => [
            'driver' => Sqlite::class,      //この行を追加
            // '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' => 'non_standard_port_number',

            // 'username' => 'my_app',            //この行をコメントアウト
            // 'password' => 'secret',            //この行をコメントアウト

            'database' => ROOT . DS . 'database' . DS . 'product.sqlite',      //この行を修正
            /**
             * If not using the default 'public' schema with the PostgreSQL driver
             * set it here.
             */
            //'schema' => 'myapp',



 //以下コードの変更はないので省略

フォルダの作成

一旦MAMPの接続を切ります。(下記の赤枠の状態にします)

そしてCakeBlog1の直下に「database」フォルダを作成します。(MAMPの接続を切らない状態でフォルダを作成すると上手く行かなかったので必ず接続を切ってからフォルダの作成をして下さい)

そしてMAMPの接続を入れます。(下記の赤枠の状態にします)

これでトップページを開くとデータベースにアクセスできているのが確認できます。

それではページに表示をしていきます。

コントローラーの作成

まずはコントローラーを作成します。

コントローラーを作成するコマンドは下記になります。

bin/cake bake controller コントローラー名s

今回はコントローラー名を「Posts」とします、コマンドは下記になります。

bin/cake bake controller Posts

コマンド入力が終わると「CakePHPのプロジェクト > src > Controller」の中に「PostsController.php」が作成されたのが確認できます。

コントローラーに記述を行いページの表示をします。

コントローラーに記述

PostsControllerの中にindexメソッドがあるので下記に変更します。

public function index()
{
  echo "デモで表示";
}

ページにアクセス

コントローラーにビューの内容を書いてページにアクセスする時のURLはCakePHPの規約で下記になります。

localhost:8888/プロジェクト名/コントローラー名/メソッド名

今回はプロジェクト名が「CakeBlog1」でPostsコントローラーのindexメソッドなのでURLは下記になります。

localhost:8888/CakeBlog1/Posts/index

「localhost:8888」はMAMPの設定によって変わってくるので必ず私と同じにしないといけない訳ではないです。

ページにアクセスすると「デモで表示」と表示されます。

なお、indexメソッドの時のみコントローラー名を省略していいです。(メソッドをアクションとも言います)

その場合のURLは下記になります。

localhost:8888/CakeBlog1/Posts

メソッドからページにパラメーターを渡したい時はメソッドを下記にします。

public function view($id = null)
{
  echo $id."view.php";
}

メソッドの引数にパラメーターを記述するとURLにパラメーターが自動的に設定されます。

localhost:8888/CakeBlog1/Posts/view/パラメーター名

パラメーターは今の段階では何でもいいです。

例えば「demo」とすると「localhost:8888/CakeBlog1/Posts/view/demo」にアクセスすると「demoview.php」を表示されます。

ビューファイルを作成して表示

ここまではコントローラーに記述した内容をビューで表示していましたがビューファイルを作成して表示します。

ビューファイルは「CakePHPのプロジェクト > templatesフォルダ」の下の階層に作成します。

例えばPostコントローラーのindexメソッドに対応したビューファイルを作成する場合はtemplateフルダの下にコントローラー名のPostsフォルダを作りその下にメソッド名のindex.phpを作成します。

index.phpの中には下記の記述をします。

<h1>index.php</h1>

そしてPostsController.phpを一部修正します。

<?php
declare(strict_types=1);

namespace App\Controller;

/**
 * Posts Controller
 *
 * @method \App\Model\Entity\Post[]|\Cake\Datasource\ResultSetInterface paginate($object = null, array $settings = [])
 */
class PostsController extends AppController
{
    public $autoRender = false;         //この行をコメントアウト

    /**
     * Index method
     *
     * @return \Cake\Http\Response|null|void Renders view
     */
    public function index()
    {
        //indexメソッドの中を削除する
    }

13行目をコメントアウトすることでコントローラー名のフォルダに対応したメソッド名のファイルを自動的に表示できるようになります。

「localhost:8888/CakeBlog1/Posts/」(または「localhost:8888/CakeBlog1/Posts/index」)にアクセスすると下記の表示になります。

コントローラーからビューにパラメーターを渡す

postsフォルダの下にview.phpを作成します。

コントローラーのviewメソッドを下記にします。

public function view($id = null)
{
  $this->set(['id' => $id]);
}

3行目ですがパラメーターを渡す時は「setメソッド」を使い引数に連想配列を使います、「id」がkeyで「$id」がvalueです。

valueの$idはviewメソッドの引数と同じにします。

そしてindex.phpを下記にします。

<?= $id>

これで「localhost:8888/CakeBlog1/Posts/view/適当なパラメーター名」にアクセスするとパラメーター名が表示されます。

compact関数

viewメソッドは下記でした。

public function view($id = null)
{
  $this->set(['id' => $id]);
}

3行目のkeyとvalueのidは同じですがこの場合はcompact関数を使ってもよく下記の書き方をします。

public function view($id = null)
{
  $this->set(compact('id'));
}

変数を2つ以上渡す

さっきはコントローラーからビューに渡す変数が1つでしたが2つ以上にする場合は下記4行目のように変数を配列の中(今はidとtitleが入っています)に書きます。

public function view($id = null)
{
  $title = '変数';
  $this->set(compact(['id', 'title']));
}

この時のview.phpは下記になります。

<?= $id ?>
<?= $title ?>

別のビューファイルを表示する

今の状態は例えば「localhost:8888/CakeBlog1/Posts/view」にアクセスするとview.phpが表示されますが他のビューファイルを表示したい場合もあります。

今回はindex.phpを表示してみますがviewメソッドに下記の記述をします。

public function view()
{
  $this->render('/Posts/index');
}

3行目の「render」メソッドで他のファイルを表示できます、「/Posts/index」はtemplatesフォルダの下の階層のパスです。

これで「localhost:8888/CakeBlog1/Posts/view」にアクセスした時にindex.phpの内容が表示されます。

次はデフォルトのレイアウトの表示です。

デフォルトのレイアウト

「localhost:8888/CakeBlog1/Posts/index」にアクセスした時にindex.phpに記述してないはずの下記の赤枠の部分が表示されます。

これはデフォルトのレイアウトが使われています。

「CakePHPのプロジェクト > templates > layout > default.php」がデフォルトのレイアウトになります。

文言を変更して本当にデフォルトのレイアウトなのかの確認をします。

default.phpを下記に変更します。

<?php
/**
 * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
 * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
 *
 * Licensed under The MIT License
 * For full copyright and license information, please see the LICENSE.txt
 * Redistributions of files must retain the above copyright notice.
 *
 * @copyright     Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
 * @link          https://cakephp.org CakePHP(tm) Project
 * @since         0.10.0
 * @license       https://opensource.org/licenses/mit-license.php MIT License
 * @var \App\View\AppView $this
 */

$cakeDescription = 'CakePHP: the rapid development php framework';
?>
<!DOCTYPE html>
<html>
<head>
    <?= $this->Html->charset() ?>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>
        <?= $cakeDescription ?>:
        <?= $this->fetch('title') ?>
    </title>
    <?= $this->Html->meta('icon') ?>

    <link href="https://fonts.googleapis.com/css?family=Raleway:400,700" rel="stylesheet">

    <?= $this->Html->css(['normalize.min', 'milligram.min', 'cake']) ?>

    <?= $this->fetch('meta') ?>
    <?= $this->fetch('css') ?>
    <?= $this->fetch('script') ?>
</head>
<body>
    <nav class="top-nav">
        <div class="top-nav-title">
            <a href="<?= $this->Url->build('/') ?>"><span>Cake</span>PHPのデフォルトを確認する</a>   //「PHP」の文言を修正する
        </div>
        <div class="top-nav-links">
            <a target="_blank" rel="noopener" href="https://book.cakephp.org/4/">Documentation</a>
            <a target="_blank" rel="noopener" href="https://api.cakephp.org/4/">API</a>
        </div>
    </nav>
    <main class="main">
        <div class="container">
            <?= $this->Flash->render() ?>
            <?= $this->fetch('content') ?>
        </div>
    </main>
    <footer>
    </footer>
</body>
</html>

変更したのは41行目です。

「localhost:8888/CakeBlog1/Posts/index」にアクセスすると下記に変わります。

ここまでで使ったビューファイルのindex.phptとview.phpはdefault.phpの51行目の部分で表示されています。

デフォルトのレイアウトを無効にする

場合によってはデフォルトのレイアウトを使わない場合もあります。

そんな時はコントローラーに記述を追加します。

Postsコントローラーで先ほど書いたviewメソッドに記述してみます。(ビューはそのままです)

public function view($id = null)
{
  $this->viewBuilder()->disableAutoLayout();         //この行を追加
  $title = '変数';
  $this->set(compact(['id', 'title']));
}

これで「http://localhost:8888/cakephp/CakeBlog1/posts/view/a」にアクセスすると下記の表示になりデフォルトのレイアウトが適用されていないのが確認できます。

自作したレイアウトを使う

デフォルトのレイアウトですが自作したレイアウトを使いたい場合があります。

その場合はこうします。

まずlayoutフォルダの下に任意のphpファイル(test.phpとします)を作成してdefault.phpの中身をコピペします。

そしてPostsコントローラーのviewメソッドを下記に変更します。

public function view($id = null)
{
  $this->viewBuilder()->setLayout('test');      //この行を修正
  $title = '変数';
  $this->set(compact(['id', 'title']));
}

3行目でデフォルトのレイアウトを変更する時は「setLayout」メソッドを使います。

「test」はデフォルトレイアウトのファイル名から「.php」を取った名称です。

これで「http://localhost:8888/cakephp/CakeBlog1/posts/view/a」にアクセスするとtest.phpが反映されているのが確認できます。

全てのビューのレイアウトを変更する

さっきはview.phpだけレイアウトを変更しましたが全てのビューファイルのレイアウトを変更します。

この場合はinitializeメソッドを追加します。

PostsController.phpを下記にします。

//ここから追加
public function initialize(): void{
  parent::initialize();
  $this->viewBuilder()->setLayout('test');
}
//ここまで追加


public function index()
{
    //
}

public function view($id = null)
{
  //$this->viewBuilder()->setLayout('test');を4行目に移動   
  $title = '変数';
  $this->set(compact(['id', 'title']));
}

initializeメソッドですが4行目以外はそのまま書くと思っていいです。

16行目にあったレイアウトを適用する為の記述を4行目に移動します。

これで「http://localhost:8888/cakephp/CakeBlog1/posts/view/a」・「http://localhost:8888/cakephp/CakeBlog1/posts/index」のどちらにアクセスしてもレイアウトにtest.phpが適用されているのが確認できます。

次回の解説

次回の解説はテーブルの作成とテーブルにデータを挿入します。