いきなりですが、業務でこんなことありませんか?
DBからデータを取ってきて、それを用途に合わせて加工したい!
例えばこんなのなど。
- 違う項目で並び替えたい → 男性好感度ランキングと女性好感度ランキングを表示
- 指定した条件でデータが欲しい → 男性好感度80%以上のデータの表示
- グループ化したデータが欲しい → 地域別好感度を出したい
その時に「都度findするかー」とか「foreachしてデータ生成するかー。面倒だけど…」と思われた方。
ありがとうございます。この記事適性MAXでございます。
当記事が参考になれば幸いです。
まず、Hashにはいくつか種類が用意されています。(以下)
Hash::get | Hash::extract | Hash::insert | Hash::remove |
Hash::combine | Hash::format | Hash::contains | Hash::check |
Hash::filter | Hash::flatten | Hash::format | Hash::expand |
Hash::merge | Hash::numeric | Hash::dimensions | Hash::maxDimensions |
Hash::map | Hash::reduce | Hash::apply | Hash::sort |
Hash::diff | Hash::mergeDiff | Hash::normalize | Hash::nest |
・・・
書き出してみて「こんなにあったのか。。」と焦っているのは内緒にしつつ、、、
今ここで全部説明するのは時間的にも労力的にも厳しいので、
実際に業務で使用したもの、便利そうだと思ったもの を抜粋して紹介していきたいと思います。
mysql> select * from books;
+----+-----------+-------+-------+-----------+---------------------+---------------------+
| id | name | price | sales | category | created | modified |
+----+-----------+-------+-------+-----------+---------------------+---------------------+
| 1 | HTML5 Lv1 | 100 | 81 | front_end | 2019-12-01 10:00:00 | 2019-12-01 10:00:00 |
| 2 | HTML5 Lv2 | 500 | 24 | front_end | 2019-12-01 10:00:00 | 2019-12-01 10:00:00 |
| 3 | php Lv1 | 300 | 50 | back_end | 2019-12-01 10:00:00 | 2019-12-01 10:00:00 |
| 4 | php Lv2 | 200 | 102 | back_end | 2019-12-01 10:00:00 | 2019-12-01 10:00:00 |
| 5 | MySQL Lv1 | 400 | 5 | server | 2019-12-01 10:00:00 | 2019-12-01 10:00:00 |
| 6 | MySQL Lv2 | 400 | 30 | server | 2019-12-01 10:00:00 | 2019-12-01 10:00:00 |
+----+-----------+-------+-------+-----------+---------------------+---------------------+
その1 Hash::sort
これは名前からも想像できるように配列をソートするものです。
前段の例にも上げた「一度取り出したデータ配列を別のキーでソートし直したい」といった事を実現できます。
まず初めにbooksテーブルをidの昇順で取得します。
$books = TableRegistry::get('Books');
$query = $books->find();
$query->order(['price' => 'asc']);
$query->all();
$data = $query->toArray();
すると上記した「今回使用するテーブル」の通りのデータが採取されます。
そして、売上ランキングを表示するために売上(sales)の降順データも欲しい。という場合はこうするとOK!
$result = Hash::sort($data, '{n}.sales', 'desc');
以下のようにデータが取れます。
(int) 0 => [
'id' => (int) 4,
'name' => 'php Lv2',
'price' => (int) 200,
'sales' => (int) 102,
'category' => 'back_end',
'created' => object(Cake\I18n\FrozenTime) {
'time' => '2019-12-01T10:00:00+09:00',
'timezone' => 'Asia/Tokyo',
'fixedNowTime' => false
},
'modified' => object(Cake\I18n\FrozenTime) {
'time' => '2019-12-01T10:00:00+09:00',
'timezone' => 'Asia/Tokyo',
'fixedNowTime' => false
}
],
(int) 1 => [
'id' => (int) 1,
'name' => 'HTML5 Lv1',
'price' => (int) 100,
'sales' => (int) 81,
'category' => 'front_end',
'created' => object(Cake\I18n\FrozenTime) {
'time' => '2019-12-01T10:00:00+09:00',
'timezone' => 'Asia/Tokyo',
'fixedNowTime' => false
},
'modified' => object(Cake\I18n\FrozenTime) {
'time' => '2019-12-01T10:00:00+09:00',
'timezone' => 'Asia/Tokyo',
'fixedNowTime' => false
}
],
(int) 2 => [
'id' => (int) 3,
'name' => 'php Lv1',
'price' => (int) 300,
'sales' => (int) 50,
'category' => 'back_end',
'created' => object(Cake\I18n\FrozenTime) {
'time' => '2019-12-01T10:00:00+09:00',
'timezone' => 'Asia/Tokyo',
'fixedNowTime' => false
},
'modified' => object(Cake\I18n\FrozenTime) {
'time' => '2019-12-01T10:00:00+09:00',
'timezone' => 'Asia/Tokyo',
'fixedNowTime' => false
}
],
(int) 3 => [
'id' => (int) 6,
'name' => 'MySQL Lv2',
'price' => (int) 400,
'sales' => (int) 30,
'category' => 'server',
'created' => object(Cake\I18n\FrozenTime) {
'time' => '2019-12-01T10:00:00+09:00',
'timezone' => 'Asia/Tokyo',
'fixedNowTime' => false
},
'modified' => object(Cake\I18n\FrozenTime) {
'time' => '2019-12-01T10:00:00+09:00',
'timezone' => 'Asia/Tokyo',
'fixedNowTime' => false
}
],
(int) 4 => [
'id' => (int) 2,
'name' => 'HTML5 Lv2',
'price' => (int) 500,
'sales' => (int) 24,
'category' => 'front_end',
'created' => object(Cake\I18n\FrozenTime) {
'time' => '2019-12-01T10:00:00+09:00',
'timezone' => 'Asia/Tokyo',
'fixedNowTime' => false
},
'modified' => object(Cake\I18n\FrozenTime) {
'time' => '2019-12-01T10:00:00+09:00',
'timezone' => 'Asia/Tokyo',
'fixedNowTime' => false
}
],
(int) 5 => [
'id' => (int) 5,
'name' => 'MySQL Lv1',
'price' => (int) 400,
'sales' => (int) 5,
'category' => 'server',
'created' => object(Cake\I18n\FrozenTime) {
'time' => '2019-12-01T10:00:00+09:00',
'timezone' => 'Asia/Tokyo',
'fixedNowTime' => false
},
'modified' => object(Cake\I18n\FrozenTime) {
'time' => '2019-12-01T10:00:00+09:00',
'timezone' => 'Asia/Tokyo',
'fixedNowTime' => false
}
]
きちんと売上(sales)の降順データに並んでますね。
もう一度findして取ってこなくていいから楽ちん楽ちん
その2 Hash::extract
公式ページの説明文をそのまま記載すると
extractは好きなパスに沿ったデータを手早く取り出すことができます。
・・・直感で理解しがたいですね。
要するに「引数に条件を指定してそれを満たすデータを配列から取り出すことができる」という事です。
例えば、「今回使用するテーブル」から売上が50以上のものが欲しい。という時は、
$result = Hash::extract($data, '{n}[sales>=50]');
としてあげる事で以下のようにデータが取れます。
(int) 0 => [
'id' => (int) 1,
'name' => 'HTML5 Lv1',
'price' => (int) 100,
'sales' => (int) 81,
'category' => 'front_end',
'created' => object(Cake\I18n\FrozenTime) {
'time' => '2019-12-01T10:00:00+09:00',
'timezone' => 'Asia/Tokyo',
'fixedNowTime' => false
},
'modified' => object(Cake\I18n\FrozenTime) {
'time' => '2019-12-01T10:00:00+09:00',
'timezone' => 'Asia/Tokyo',
'fixedNowTime' => false
}
],
(int) 1 => [
'id' => (int) 3,
'name' => 'php Lv1',
'price' => (int) 300,
'sales' => (int) 50,
'category' => 'back_end',
'created' => object(Cake\I18n\FrozenTime) {
'time' => '2019-12-01T10:00:00+09:00',
'timezone' => 'Asia/Tokyo',
'fixedNowTime' => false
},
'modified' => object(Cake\I18n\FrozenTime) {
'time' => '2019-12-01T10:00:00+09:00',
'timezone' => 'Asia/Tokyo',
'fixedNowTime' => false
}
],
(int) 2 => [
'id' => (int) 4,
'name' => 'php Lv2',
'price' => (int) 200,
'sales' => (int) 102,
'category' => 'back_end',
'created' => object(Cake\I18n\FrozenTime) {
'time' => '2019-12-01T10:00:00+09:00',
'timezone' => 'Asia/Tokyo',
'fixedNowTime' => false
},
'modified' => object(Cake\I18n\FrozenTime) {
'time' => '2019-12-01T10:00:00+09:00',
'timezone' => 'Asia/Tokyo',
'fixedNowTime' => false
}
]
その3 Hash::combine
この機能では、キーと値を自由に指定して配列を組み替えることができます。
また、グループを指定する事でそれに従ってグルーピングされたデータを取得することができます。
例えば、カテゴリーごとにグルーピングしてデータを取得したい場合は、
$result = Hash::combine($data, '{n}.id', '{n}', '{n}.category');
とする事で以下のようにグルーピングされたデータが取得できます。
'front_end' => [
(int) 1 => [
'id' => (int) 1,
'name' => 'HTML5 Lv1',
'price' => (int) 100,
'sales' => (int) 81,
'category' => 'front_end',
'created' => object(Cake\I18n\FrozenTime) {
'time' => '2019-12-01T10:00:00+09:00',
'timezone' => 'Asia/Tokyo',
'fixedNowTime' => false
},
'modified' => object(Cake\I18n\FrozenTime) {
'time' => '2019-12-01T10:00:00+09:00',
'timezone' => 'Asia/Tokyo',
'fixedNowTime' => false
}
],
(int) 2 => [
'id' => (int) 2,
'name' => 'HTML5 Lv2',
'price' => (int) 500,
'sales' => (int) 24,
'category' => 'front_end',
'created' => object(Cake\I18n\FrozenTime) {
'time' => '2019-12-01T10:00:00+09:00',
'timezone' => 'Asia/Tokyo',
'fixedNowTime' => false
},
'modified' => object(Cake\I18n\FrozenTime) {
'time' => '2019-12-01T10:00:00+09:00',
'timezone' => 'Asia/Tokyo',
'fixedNowTime' => false
}
]
],
'back_end' => [
(int) 3 => [
'id' => (int) 3,
'name' => 'php Lv1',
'price' => (int) 300,
'sales' => (int) 50,
'category' => 'back_end',
'created' => object(Cake\I18n\FrozenTime) {
'time' => '2019-12-01T10:00:00+09:00',
'timezone' => 'Asia/Tokyo',
'fixedNowTime' => false
},
'modified' => object(Cake\I18n\FrozenTime) {
'time' => '2019-12-01T10:00:00+09:00',
'timezone' => 'Asia/Tokyo',
'fixedNowTime' => false
}
],
(int) 4 => [
'id' => (int) 4,
'name' => 'php Lv2',
'price' => (int) 200,
'sales' => (int) 102,
'category' => 'back_end',
'created' => object(Cake\I18n\FrozenTime) {
'time' => '2019-12-01T10:00:00+09:00',
'timezone' => 'Asia/Tokyo',
'fixedNowTime' => false
},
'modified' => object(Cake\I18n\FrozenTime) {
'time' => '2019-12-01T10:00:00+09:00',
'timezone' => 'Asia/Tokyo',
'fixedNowTime' => false
}
]
],
'server' => [
(int) 5 => [
'id' => (int) 5,
'name' => 'MySQL Lv1',
'price' => (int) 400,
'sales' => (int) 5,
'category' => 'server',
'created' => object(Cake\I18n\FrozenTime) {
'time' => '2019-12-01T10:00:00+09:00',
'timezone' => 'Asia/Tokyo',
'fixedNowTime' => false
},
'modified' => object(Cake\I18n\FrozenTime) {
'time' => '2019-12-01T10:00:00+09:00',
'timezone' => 'Asia/Tokyo',
'fixedNowTime' => false
}
],
(int) 6 => [
'id' => (int) 6,
'name' => 'MySQL Lv2',
'price' => (int) 400,
'sales' => (int) 30,
'category' => 'server',
'created' => object(Cake\I18n\FrozenTime) {
'time' => '2019-12-01T10:00:00+09:00',
'timezone' => 'Asia/Tokyo',
'fixedNowTime' => false
},
'modified' => object(Cake\I18n\FrozenTime) {
'time' => '2019-12-01T10:00:00+09:00',
'timezone' => 'Asia/Tokyo',
'fixedNowTime' => false
}
]
]
以上、簡単ではありますが、
便利だと思った機能について紹介させてもらいました。
最後に
Hashにはまだまだ便利な機能があるので公式ページを参考にしてみてください。
https://book.cakephp.org/3/ja/core-libraries/hash.html
実際に中でどのように動いているかを知りたい人は、、、コアを覗いてみてください。フフ
/scripts/vendor/cakephp/cakephp/src/Utility/Hash.php