EntityFramwork -> 実践

Posted by muchag | C#,Visual Studio | 2018-01-21 (日) 20:14:57

お試し で大分理解できたので
実際に挑戦!

【環境】
Visual C#: 15.5.4(2017)
経緯
C#,Visual Studio | 2018-01-21 (日) 20:14:57 |

EntityFramwork -> お試し

Posted by muchag | C#,Visual Studio | 2018-01-20 (土) 15:57:34

今ひとつピンとこないので
勉強のため、テストプロジェクトを作成。

【環境】
Visual C#: 15.5.4(2017)
経緯

EntityFramework なるものを見つけて
ぜひ挑戦したいと思った。

ただ、慣れない VS 環境であることもあり
なかなかピンとこない。

そこで、参考サイトをそのまま実践してみることにした。

SlideShare:「Entity Framework Coreを使ってみる」 公開用(2017-03-07)

プロジェクト作成
Model プロジェクト

[ファイル]-[新規作成]-[プロジェクト]
「新しいプロジェクト」
左ペイン [インストール済み]-[Visual C#]-[Windows クラシック デスクトップ]
右ペイン [クラス ライブラリ(.NET Framework)]
名前:KptBoardSystem
場所:任意
ソリューション名:「名前」から自動入力
[ソリューションのディレクトリを作成] にチェック
[新しい Git リポジトリの作成] にチェックなし
[OK]

参照設定

プロジェクトコンテキストメニューから [NuGet パッケージの管理]
Microsoft.EntityframeworkCore で検索
Microsoft.EntityframeworkCore.Sqlite 2.0.1
Microsoft.EntityframeworkCore.Tools 2.0.1

テストプロジェクト

ソリューションのコンテキストメニューから [追加]-[新しいプロジェクト]
後は前述同様に KptBoardSystemTest プロジェクトを作成。

参照設定

前述同様に、下記を設定。
Microsoft.EntityframeworkCore 2.0.1
xunit 2.3.1
xunit.runner.visualstudio 2.3.1
Moq 4.8.1

初回マイグレーション
クラス作成

P.12 User
P.13 KptBoardModel

コマンド

Enable-Migrations
Enable-Migrations is obsolete. Use Add-Migration to start using Migrations.
Add-Migration setp00
To undo this action, use Remove-Migration.
  1. マイグレーションを可能にする
  2. マイグレーションを追加する
ファイル生成

こんな感じで2ファイルが自動生成された。


KptBoardSystem
┗ Migrations
  ┣ 20180120074120_setp00.cs
  ┗ KptBoardModelModelSnapshot.cs
データベース生成
コマンド

Update-Database
Applying migration '20180120074120_setp00'.
Done.

参考サイト P.15 のように処理がズラズラ並ぶのではなく
とても簡素なリアクションでしたw

ファイルの場所

参考サイトには「ソリューション直下に「kpt.db」が作成される」とあったけど
実際には、ソリューションの2つ上に作成された。

後述の試行錯誤に見られた、テストとの階層の差分があるということは
コマンドを打つ際に、階層を設定するべきなのではないかと思うけど
現在は手法不明。

パス変更

そこで、

KptBoardModel.cs

のパスを下記のように変更したところ、ソリューション直下に作成された。


- var connectionString = new SqliteConnectionStringBuilder { DataSource = "../../../kpt.db" }.ToString();
+ var connectionString = new SqliteConnectionStringBuilder { DataSource = "../kpt.db" }.ToString();

この件には、大きな落とし穴が。。。
詳細は、後述の「試行錯誤」コーナーにて。

注意

コマンドを打つ際に、パッケージ マネージャー コンソールにおいて
「既定のプロジェクト」で何を選択しているかでファイル出力場所が変わる。

“kpt.db” というパスの場合は
プロジェクト直下へ生成されるので
KptBoardSystem を選択していれば、

KptBoardSystem/KptBoardSystem/kpt.db

KptBoardSystemTest を選択していれば、

KptBoardSystem/KptBoardSystemTest/kpt.db

となる。

KptBoardSystem/KptBoardSystem/kpt.db

この場合、テストではファイルが見つからないエラーになってしまうので
「既定のプロジェクト」は注意。

配置

後述の如く、コマンドと実行でファイルパスの意味合いが変わるので
コマンドで生成された DB ファイルを手動で配置換えをした。

テストと本番で DB を分けることも考え
ソリューション直下ではなく、プロジェクト直下としてみる。

つまり、最終的な配置とファイルパスの指定は下記の通り。

KptBoardSystem/KptBoardSystemTest/kpt.db

var connectionString = new SqliteConnectionStringBuilder { DataSource = "../../kpt.db" }.ToString();
注意

このようなやり方にすることで
コマンドを打つ度に
ファイルの移動が必要。

テスト
参照設定

P.18
KptBoardSystemTest プロジェクト内「参照」のコンテキストメニュー [参照の追加]
「参照マネージャー」
左ペイン [プロジェクト]-[ソリューション]
中央ペイン [KptBoardSystem] にチェック
[OK]

クラス作成

P.19 KptBoardModelTest


using Xunit;

namespace KptBoardSystem.Test
{
    public class KptBoardModelTest
    {
        [Fact]
        public void TestInsertUser()
        {
            using (var db = new KptBoardModel())
            {
                var user = new User
                {
                    Name = "User01"
                };
                db.Add(user);

                db.SaveChanges();
            }
        }
    }
}
テスト エクスプローラー

[テスト]-[ウィンドウ]-[テスト エクスプローラー]
で、開くことができる。

実施

[テスト]-[実行]-[全てのテスト]
または、テスト エクスプローラーにて、対象テストを選択した上で
[テスト]-[実行]-[選択したテスト]
で、テストを開始。

P.38
例外

私の記述ミスのせいで、


var kptBoard = db.KptBoards.Where(b => b.Problem.Contains("続ける")).First();

こちらが空になってしまった。

その際、下記のエラーが出た。

[2018/01/21 12:28:10 Error] [xUnit.net 00:00:01.7574752] KptBoardを修正する [FAIL]
[2018/01/21 12:28:10 Informational] [xUnit.net 00:00:01.7585683] System.InvalidOperationException : シーケンスに要素が含まれていません
テストのデバッグ

[テスト]-[デバッグ]
から、テストのデバッグをできる。

まだ使い方はよくわからない。

LINQ

P.34 では、u が括弧書きだったのに
今回は括弧がつかない理由がわからない。


var user02 = db.Users.Where((u) => u.Name == "User02").Include("KptBoards").First();

var kptBoard = db.KptBoards.Where(b => b.Problem.Contains("続ける")).First();

LINQ を勉強すべし。

試行錯誤
テスト実施1
エラー

テスト初回実行時、下記のエラーが出た。

[2018/01/20 17:48:52 Error] [xUnit.net 00:00:01.4263057] KptBoardSystem.Test.KptBoardModelTest.TestInsertUser [FAIL]
[2018/01/20 17:48:52 Informational] [xUnit.net 00:00:01.4272062] System.Exception : You need to call SQLitePCL.raw.SetProvider(). If you are using a bundle package, this is done by calling SQLitePCL.Batteries.Init().
原因

Google 先生に質問したところ、どうやら下記パッケージが不足していることらしい。

解決

テストプロジェクトへインストール。


Install-Package SQLitePCLRaw.bundle_e_sqlite3 -Version 1.1.9
Install-Package SQLitePCLRaw.bundle_sqlcipher -Version 1.1.9
Install-Package SQLitePCL.bundle_green -Version 0.9.3

NuGet パッケージ管理からインストールしても OK だと思う。

参考サイト

stackoverflow:Cannot run SQLite.net PCL in ASP.NET MVC(2017-02-09)

テスト実施2
エラー

上記エラーが取れてホッとしつつテストを行うと
次は下記エラーが出た。

[2018/01/20 21:48:11 Error] [xUnit.net 00:00:01.5294057] KptBoardSystem.Test.KptBoardModelTest.TestInsertUser [FAIL]
[2018/01/20 21:48:11 Informational] [xUnit.net 00:00:01.5303380] Microsoft.EntityFrameworkCore.DbUpdateException : An error occurred while updating the entries. See the inner exception for details.
[2018/01/20 21:48:11 Informational] [xUnit.net 00:00:01.5304014] —- Microsoft.Data.Sqlite.SqliteException : SQLite Error 1: ‘no such table: Users’.

Users テーブルが見つからないってさ。。。

調査
DB

kpt.db の中には、確かに Users テーブルがある。

ファイルパス

上で、DB ファイルへのパスを変えたからかもしれないと思い
パスを戻すと、エラーが出ないときもあるけど、確実ではないし
値は書き込まれない。

DB 接続

そもそも DB 接続に失敗しているのかと思って
ファイルパスを存在しないパスにしてみたら
エラー内容が下記の通り変わったので、接続には成功しているみたい。

[2018/01/20 21:52:21 Error] [xUnit.net 00:00:01.3878517] KptBoardSystem.Test.KptBoardModelTest.TestInsertUser [FAIL]
[2018/01/20 21:52:21 Informational] [xUnit.net 00:00:01.3888267] Microsoft.Data.Sqlite.SqliteException : SQLite Error 14: ‘unable to open database file’.
ファイル実体

途方に暮れて、ソリューションディレクトリをあちこち見ていたら
想定外の場所に kpt.db ファイルが!!!

原因

コマンドで作成した kpt.db のファイルパスと
テストコードが参照する kpt.db のファイルパスが
異なることが原因だった。

と言っても、何かがおかしいので
いずれわかる日が来ると信じたい。

ともかく、下記のような検証結果だった。


GrandMother
┣ Mother
┃ ┣ KptBoardSystem
┃ ┃ ┣ KptBoardSystem
┃ ┃ ┣ KptBoardSystemTest
┃ ┃ ┃ ┣ bin
┃ ┃ ┃ ┃ ┣ Debug
┃ ┃ ┃ ┃ ┃ ┗ kpt.db // テスト "kpt.db"
┃ ┃ ┃ ┃ ┣ Release
┃ ┃ ┃ ┃ ┗ kpt.db // テスト "../kpt.db"
┃ ┃ ┃ ┗ kpt.db // コマンド "kpt.db"、テスト "../../kpt.db"
┃ ┃ ┗ kpt.db // コマンド "../kpt.db"、テスト "../../../kpt.db"
┃ ┗ kpt.db // コマンド "../../kpt.db"
┗ kpt.db // コマンド "../../../kpt.db"

つまり
コマンドは、プロジェクトディレクトリがルート。
テスト(実行)は、アセンブリ(.dll)本体のある場所がルート?

C#,Visual Studio | 2018-01-20 (土) 15:57:34 |

さくら VPS -> CakePHP3

Posted by muchag | CakePHP 3.x,CentOS,さくらインターネット | 2018-01-18 (木) 19:37:55

【環境】
CakePHP: 3.5.8
php: 7.1.13
CentOS: 7.4.1708
さくらインターネット:VPS 2G プラン
ディレクトリ作成

後述するけど、Composer は root では使わない方がよいそうなので
一般ユーザで操作。

そのため、先にroot でディレクトリを作成して
パーミッションを設定しておく必要がある。


mkdir /var/www/my_app
cd /var/www
chown apache:[username] my_app
chmod 775 my_app
  1. ディレクトリ作成
  2. ディレクトリ移動
  3. 所有者変更
  4. パーミッションを設定
インストール

一般ユーザへ変更してから。


composer create-project --prefer-dist cakephp/app /var/www/my_app
試行錯誤
インストール警告

root でインストールをしようとすると、下記警告が出る。


composer create-project --prefer-dist cakephp/app /var/www/my_app
Do not run Composer as root/super user! See https://getcomposer.org/root for details
インストール例外

上記コマンドにてインストールをしようとしたところ
下記例外が投げられた。

[Composer\Downloader\TransportException]
The “https://packagist.org/p/provider-latest%240cbfb40ab72a881d21b70f78286d39cd72e3b0eb8704c13e79dc49624e549973.json” file could not be downloaded (HTTP/1.1 404 Not Found)
対応1

Google 先生に質問し、1つ目の対応。
下記参考サイトによると、composer の健康診断コマンドらしい。

参考サイトの内容とは異なるけど、まずは診断。


composer diag
Checking platform settings: OK
Checking git settings: OK
Checking http connectivity to packagist: OK
Checking https connectivity to packagist: OK
Checking github.com rate limit: OK
Checking disk free space: OK
Checking pubkeys:
Tags Public Key Fingerprint: 57815BA2 7E54DC31 7ECC7CC5 573090D0  87719BA6 8F3BB723 4E5D42D0 84A14642
Dev Public Key Fingerprint: 4AC45767 E5EC2265 2F0C1167 CBBB8A2B  0C708369 153E328C AD90147D AFE50952
OK
Checking composer version: OK
Composer version: 1.6.2
PHP version: 7.1.13
PHP binary path: /usr/bin/php

問題ないみたい。

参考サイト

ふたりはララベル:Composerのエラーの原因を調査する(2014-08-23)

対応2

下記参考サイトを見つけて、わけもわからないまま対応。


wget http://curl.haxx.se/ca/cacert.pem
cp -v -f cacert.pem /etc/pki/tls/certs/ca-bundle-curl.crt
  1. OpenSSL(正確にはcurl)で使用するCAをダウンロード
  2. 当該ファイルを、本家(?)ca-bundle.crt の存在するディレクトリへコピー

注意事項

このcrtファイルはcurlのエラーを回避するためのものですので、本来のca-bundle.crtを上書きしないように注意して下さい。

Qiita:ComposerからLaravelを導入しようとしてOpenSSL周りのエラーで困った件(2015-06-23)

php.ini へ上記ファイルを設定


vim /etc/php.ini

curl.cainfo=/etc/pki/tls/certs/ca-bundle-curl.crt
openssl.cafile=/etc/pki/tls/certs/ca-bundle-curl.crt
ファイルパス

最初コピペで作業をして、下記のように怒られた。


cp -v -f cacert.pem /full/path/to/certs/ca-bundle-curl.crt
`cacert.pem' -> `/full/path/to/certs/ca-bundle-curl.crt'
cp: 通常ファイル `/full/path/to/certs/ca-bundle-curl.crt' を作成できません: そのようなファイルやディレクトリはありません

そりゃ、/full/path/to は見つからなくて怒られるよねw

でも、コピー先のディレクトリがわからなかったので、
注意書きに書かれていた ca-bundle.crt ファイルを検索。


find / -name 'ca-bundle.crt'
/etc/pki/tls/certs/ca-bundle.crt
参考サイト

Qiita:ComposerからLaravelを導入しようとしてOpenSSL周りのエラーで困った件(2015-06-23)

解決

上記「対応2」で解決!
ありがたや~。

CakePHP 3.x,CentOS,さくらインターネット | 2018-01-18 (木) 19:37:55 |

さくら VPS -> Composer

Posted by muchag | Library & PlugIn & AddIn,PHP,さくらインターネット | 2018-01-16 (火) 22:41:44

【環境】
Composer: 1.6.2
php: 7.1.13
CentOS: 7.4.1708
さくらインターネット:VPS 2G プラン
インストール

curl -sS https://getcomposer.org/installer | php
All settings correct for using Composer
Downloading...

Composer (version 1.6.2) successfully installed to: /root/composer.phar
Use it: php composer.phar
起動

php composer.phar
Do not run Composer as root/super user! See https://getcomposer.org/root for details
   ______
  / ____/___  ____ ___  ____  ____  ________  _____
 / /   / __ \/ __ `__ \/ __ \/ __ \/ ___/ _ \/ ___/
/ /___/ /_/ / / / / / / /_/ / /_/ (__  )  __/ /
\____/\____/_/ /_/ /_/ .___/\____/____/\___/_/
                    /_/
Composer version 1.6.2 2018-01-05 15:28:41

Usage:
  command [options] [arguments]

Options:
  -h, --help                     Display this help message
  -q, --quiet                    Do not output any message
  -V, --version                  Display this application version
      --ansi                     Force ANSI output
      --no-ansi                  Disable ANSI output
  -n, --no-interaction           Do not ask any interactive question
      --profile                  Display timing and memory usage information
      --no-plugins               Whether to disable plugins.
  -d, --working-dir=WORKING-DIR  If specified, use the given directory as working directory.
  -v|vv|vvv, --verbose           Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug

Available commands:
  about                Shows the short information about Composer.
  archive              Creates an archive of this composer package.
  browse               Opens the package's repository URL or homepage in your browser.
  check-platform-reqs  Check that platform requirements are satisfied.
  clear-cache          Clears composer's internal package cache.
  clearcache           Clears composer's internal package cache.
  config               Sets config options.
  create-project       Creates new project from a package into given directory.
  depends              Shows which packages cause the given package to be installed.
  diagnose             Diagnoses the system to identify common errors.
  dump-autoload        Dumps the autoloader.
  dumpautoload         Dumps the autoloader.
  exec                 Executes a vendored binary/script.
  global               Allows running commands in the global composer dir ($COMPOSER_HOME).
  help                 Displays help for a command
  home                 Opens the package's repository URL or homepage in your browser.
  info                 Shows information about packages.
  init                 Creates a basic composer.json file in current directory.
  install              Installs the project dependencies from the composer.lock file if present, or falls back on the composer.json.
  licenses             Shows information about licenses of dependencies.
  list                 Lists commands
  outdated             Shows a list of installed packages that have updates available, including their latest version.
  prohibits            Shows which packages prevent the given package from being installed.
  remove               Removes a package from the require or require-dev.
  require              Adds required packages to your composer.json and installs them.
  run-script           Runs the scripts defined in composer.json.
  search               Searches for packages.
  self-update          Updates composer.phar to the latest version.
  selfupdate           Updates composer.phar to the latest version.
  show                 Shows information about packages.
  status               Shows a list of locally modified packages.
  suggests             Shows package suggestions.
  update               Upgrades your dependencies to the latest version according to composer.json, and updates the composer.lock file.
  upgrade              Upgrades your dependencies to the latest version according to composer.json, and updates the composer.lock file.
  validate             Validates a composer.json and composer.lock.
  why                  Shows which packages cause the given package to be installed.
  why-not              Shows which packages prevent the given package from being installed.
実行ファイルの移動

mv composer.phar /usr/local/bin/composer

これで、直接 composer で利用できる。

おまけ
インストール時警告

実は上記インストール時に、下記2行目の警告が出ていた。


curl -sS https://getcomposer.org/installer | php
PHP Warning:  Module 'intl' already loaded in Unknown on line 0
All settings correct for using Composer
Downloading...

Composer (version 1.6.2) successfully installed to: /root/composer.phar
Use it: php composer.phar

これは、php.ini で extension=intl.so をコメントアウトすることで消えたけど
CakePHP3 をインストールする際に intl は必要なはずなので、後ほど試す。

起動時警告

実は上記起動時に、下記2行目の警告が出ていた。


php composer.phar
Do not run Composer as root/super user! See https://getcomposer.org/root for details

あら、Composer って、root で利用してはいけないのね~。

実行ファイルを移動させて、一般ユーザに戻って利用したら
上記警告は出なくなった。

ちなみに、インストールを root でしたせいか
実行ファイルを移動しておかないと、php composer.phar では、実行できず


php composer.phar
Could not open input file: composer.phar

このように怒られた。。。

参考サイト

WinRoad徒然草:さくらのVPSサーバーにLaravelのインストール(2015-03-23)

挿入

Posted by muchag | CakePHP 3.x | 2018-01-08 (月) 16:22:17


公式:データの保存

【環境】
CakePHP: 3.5.8
php: 7.1.5
基本

use Cake\ORM\TableRegistry;

$articlesTable = TableRegistry::get('MyVendor/MyPlugin.Articles');
$article = $articlesTable->newEntity();

$article->title = '新しい記事';
$article->body = 'これは記事の本文です';

if ($articlesTable->save($article)) {
    // $article エンティティーは今や id を持っています
    $id = $article->id;
}
バルクインサート

これすごい!!!
メッチャ楽~♪


$users = array(
	0 => array(
	  'name' => 'Santa',
	  'age' => 25,
	  'created' => '2017-12-24 20:52:00',
	  'modified' => '2017-12-24 20:52:00',
	),
	1 => array(
	  'name' => 'Claus',
	  'age' => 52,
	  'created' => '2017-12-24 20:52:00',
	  'modified' => '2017-12-24 20:52:00',
	),
);

$fields = [
	'name',
	'age',
	'created',
	'modified',
];

$table = TableRegistry::get('Users');

$query = $table->query()
	->insert($fields);

$values_expression = $query->clause('values')->values($data);

$query = $query
	->values($values_expression)
	->execute();

ただし、28行目は、注意。

ただしclause()はqueryを返すものじゃないので、続けて書けないのでそこは注意
なので、最初の例のように一旦切ってくださいな

杏z 学習帳:[CakePHP]QueryBuilderを使ってバルクインサート(2016-03-16)

だそうなので、その通りにしたけど
->insert() より前にしたら、エラーになった。

つまり、->insert() で設定したカラムに対して
値をまとめてセットして、クエリを実行する
という流れなのね~。

ON DUPLICATE KEY UPDATE

epilog メソッドを用いて、更新対象カラムを指定。


$query->epilog('ON DUPLICATE KEY UPDATE `name`=VALUES(`name`), `modified`=VALUES(`modified`)');
参考サイト

杏z 学習帳:[CakePHP]QueryBuilderを使ってバルクインサート(2016-03-16)

Advanceffort WEB戦略会議室!:CakePHP3 クエリ作成パターンまとめ(find)(2016-02-14)

Qiita:CakePHP 3のQueryBuilderの使い方をまとめてみた!(2014-12-12)

CakePHP 3.x | 2018-01-08 (月) 16:22:17 |

debug

Posted by muchag | CakePHP 3.x | 2018-01-08 (月) 15:18:08

クエリのデバッグを行うメソッド。

公式:データの取り出しと結果セット クエリーのデバッグと結果セット

【環境】
CakePHP: 3.5.8
php: 7.1.5
種類
  • debug($query) SQL とバインドパラメーターが表示されます。結果は表示されません。
  • debug($query->all()) ResultSet のプロパティー (結果ではなく) が表示されます。
  • debug($query->toArray()) 結果を個々に見る簡単な方法です。
  • debug(json_encode($query, JSON_PRETTY_PRINT)) 人に読みやすい形で結果を表示します。
  • debug($query->first()) 単一のエンティティーのプロパティーを表示します。
  • debug((string)$query->first()) 単一のエンティティーのプロパティーを JSON として表示します。
CakePHP 3.x | 2018-01-08 (月) 15:18:08 |

finder

Posted by muchag | CakePHP 3.x | 2018-01-08 (月) 15:17:49

結果セット取得便利メソッド。

公式:データの取り出しと結果セット データのロードに Finder を使う

【環境】
CakePHP: 3.5.8
php: 7.1.5
書式
/vendor/cakephp/cakephp/src/ORM/Table.php

public function find($type = 'all', $options = [])

第1引数:ファイダタイプ。デフォルトは all
第2引数:オプション

タイプ

ファインダタイプを指定することで、専用ファインダメソッドを呼び出せる。

デフォルト
/vendor/cakephp/cakephp/src/ORM/Table.php

public function findAll(Query $query, array $options)

public function findList(Query $query, array $options)

public function findThreaded(Query $query, array $options)

とあるので
タイプには、上記3種は指定可能だと思う。

連鎖

find メソッドを繋げることも可能。


$children = $categories
    ->find('children', ['for' => 1])
    ->find('threaded')
    ->toArray();

公式:Tree クイックツアー
こちらに記載されている上記コードを実行してみて
ちゃんと目的通りの結果を得られたので
こういう記述が可能であることは理解できた。

が、どういう仕組みになっているのかは、現在不明。

オプション
  • conditions クエリーの WHERE 句に使う条件を提供します。
  • limit 欲しい行数をセットします。
  • offset 欲しいページオフセットをセットします。 page をあわせて使うことで計算を簡単にできます。
  • contain 関連をイーガーロード (eager load) するように定義します。
  • fields エンティティーへとロードされる列を制限します。いくつかの列だけがロードされることになるので エンティティーが正しく動かないこともありえます。
  • group クエリーに GROUP BY 句を加えます。集約関数を使う際に便利です。
  • having クエリーに HAVING 句を加えます。
  • join カスタム JOIN を追加で定義します。
  • order 結果セットに並び順を設定します。
カスタム(自作)

公式:データの取り出しと結果セット カスタム Finder メソッド

書式

use Cake\ORM\Query;
use Cake\ORM\Table;

class ArticlesTable extends Table
{

    public function findOwnedBy(Query $query, array $options)
    {
        $user = $options['user'];
        return $query->where(['author_id' => $user->id]);
    }

}

// コントローラーやテーブルのメソッド内で
$articles = TableRegistry::get('Articles');
$query = $articles->find('ownedBy', ['user' => $userEntity]);
動的

Symfony 2 のときと考え方は同じ~♪


// findBy, findAllBy の後ろにカラム名を付ける
// 引数に、当該カラムに設定したい検索条件を設定する
$query = $this->Users->findByUsername('joebob');

// 複数カラムの場合は、And, Or で繋げる
// 但し、And, Or の混在は NG
$query = $users->findAllByUsernameAndApproved('joebob', 1);
$query = $users->findAllByUsernameOrEmail('joebob', 'joe@example.com');

// カスタムファインダにも利用可能
$query = $users->findTrollsByUsername('bro');
CakePHP 3.x | 2018-01-08 (月) 15:17:49 |

get

Posted by muchag | CakePHP 3.x | 2018-01-08 (月) 15:16:19

主キーで単一のエンティティーを取得するメソッド。

公式:データの取り出しと結果セット 主キーで単一のエンティティーを取得する

【環境】
CakePHP: 3.5.8
php: 7.1.5
書式
/vendor/cakephp/cakephp/src/ORM/Table.php

public function get($primaryKey, $options = [])

第1引数:プライマリキー値。一般的には id
第2引数:テーブル結合などのオプション

オプション

判明したら追記。


$article = $articles->get($id, [
    'cache' => 'custom',        // cache
    'contain' => ['Comments'],  // JOIN
    'finder' => 'translations', // finder
]);
CakePHP 3.x | 2018-01-08 (月) 15:16:19 |

データ取得

Posted by muchag | CakePHP 3.x | 2017-12-23 (土) 0:40:15


公式:データベースアクセス & ORM
公式:クエリービルダー
公式:データの取り出しと結果セット
公式:データの保存

【環境】
CakePHP: 3.5.8
php: 7.1.5
取得タイプ

// 全行取得
$results = $articles->find()->all();

// 全行を配列に変換して取得
$results = $articles->find()->toArray();

// 先頭の1行だけ取得
$results = $articles->find()->first();
SELECT
フィールド指定

テーブル名を省略すると、
自動的に当該テーブル(FROM に設定されるテーブル)のカラムとして認識される。


$query = $articles->find();
$query->select(['country']);

$query = $articles->find();
$query->select(['Users.country']);

SELECT DISTINCT Users.country AS `Users__country`

よって、普段からテーブル名を付記する癖を付ける方がよさそう。

DISTINCT

$query = $articles->find();
$query->select(['Users.country'])
      ->distinct(['Users.country']);

SELECT DISTINCT Users.country AS `Users__country`
COUNT

$query = $articles->find();
$query->select(['count' => $query->func()->count('*')]);

SELECT COUNT(*) AS count
GROUP BY

$query = $articles->find();
$query = ->group(['Users.country', 'Users.gender']);

GROUP BY
    Users.country,
    Users.gender
WITH ROLLUP

GROUP BY -> WITH ROLLUP


$query = $articles->find();
$query = ->group(['Users.country', 'Users.gender'])
         ->epilog('WITH ROLLUP');

Raph’s world:CakePHP 3 ORM – with rollup(2015-09-20)
こちらには、上記のようにするように書いてあったけど
これではエラーになる。

500エラーだけど、原因は探っていない。

その上に書いてあった、下記の書式で誤魔化せた。
GROUP BY -> WITH ROLLUP


$query = $articles->find();
$query = ->group(['Users.country', 'Users.gender WITH ROLLUP']);

GROUP BY
    Users.country,
    Users.gender WITH ROLLUP

但し!
抽出カラムと GROUP BY 指定カラムが同一でなければエラーになる。

Error: SQLSTATE[42000]: Syntax error or access violation: 1055 Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column ‘database_name.Users.id’ which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by

CakePHP3 では、JOIN したテーブルの id カラムを自動的に抽出カラムに加えるので
最初から抽出カラムに指定した上で、GROUP BY 対象にも指定する必要がある。

ORDER BY

$query = $articles->find();
$query = ->order(['Users.country' => 'ASC', 'Users.gender' => 'DESC']);

ORDER BY
    Users.country ASC
    Users.gender DESC
CakePHP 3.x | 2017-12-23 (土) 0:40:15 |

初期設定

Posted by muchag | CakePHP 3.x | 2017-12-10 (日) 23:20:05

【環境】
CakePHP: 3.5.6
php: 7.1.5
app.php
/config/app.php
ローカライズ

App 項目の defaultLocale を ja_JP とする。


'App' => [
    'namespace' => 'App',
    'encoding' => env('APP_ENCODING', 'UTF-8'),
    'defaultLocale' => env('APP_DEFAULT_LOCALE', 'en_US'),
    'base' => false,
    'dir' => 'src',
    'webroot' => 'webroot',
    'wwwRoot' => WWW_ROOT,
    // 'baseUrl' => env('SCRIPT_NAME'),
    'fullBaseUrl' => false,
    'imageBaseUrl' => 'img/',
    'cssBaseUrl' => 'css/',
    'jsBaseUrl' => 'js/',
    'paths' => [
        'plugins' => [ROOT . DS . 'plugins' . DS],
        'templates' => [APP . 'Template' . DS],
        'locales' => [APP . 'Locale' . DS],
    ],
],
DB

DB 周りの設定。

  • host
  • usernama:MySQL のユーザ名
  • password:MySQL パスワード
  • database:当該アプリデータベース名(テスト用は、test_ プレフィクスを付ける)
  • timezone:Asia/Tokyo

'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' => 'non_standard_port_number',
        'username' => 'my_app',
        'password' => 'secret',
        'database' => 'test_myapp',
        'encoding' => 'utf8',
        'timezone' => 'UTC',

    'test' => [
        'className' => 'Cake\Database\Connection',
        'driver' => 'Cake\Database\Driver\Mysql',
        'persistent' => false,
        'host' => 'localhost',
        //'port' => 'non_standard_port_number',
        'username' => 'my_app',
        'password' => 'secret',
        'database' => 'test_myapp',
        'encoding' => 'utf8',
        'timezone' => 'UTC',
タイムゾーンエラー

タイムゾーンに Asia/Tokyo を設定したら
苦労して辿り着いた CakePHP3 のTOPページが姿を消し
エラーの画面になった。 X-P

SQLSTATE[HY000]: General error: 1298 Unknown or incorrect time zone: ‘Asia/Tokyo’

そして、MySQL への対応。
タイムゾーン

bootstrap.php
タイムゾーン

- date_default_timezone_set('UTC');
+ date_default_timezone_set('Asia/Tokyo');
.htaccess

アプリケーションディレクトリに phpMyAdmin を配置するとき
こちらも CakePHP のルーティング対象となってしまうため
ルーティングルールから除外する必要が生じる。


<IfModule mod_rewrite.c>
    RewriteEngine on    
+   RewriteCond   %{REQUEST_URI} !(^/pma/)
    RewriteRule   ^$    webroot/    [L]
+   RewriteCond   %{REQUEST_URI} !(^/pma/)
    RewriteRule   (.*) webroot/$1    [L]
</IfModule>

除外ルールは、各リライトルールに対して設定する必要があるため
同じ内容を2回記述する必要がある。

参考サイト

Step On Board:RewriteCondが効かない?特定のディレクトリを除外する方法でつまずいたお話(2015-05-13)

CakePHP 3.x | 2017-12-10 (日) 23:20:05 |
次ページへ »