MPEGは「音声、映像関連の規格」
MP3は「音声データを扱うときの規格のひとつ」
MIMEタイプは「ファイルの種類を表す情報」
mp3ファイルはaudioタグで囲う
<h1>MP3の再生</h1> <audio src="test.mp3" controls></audio>

随机应变 ABCD: Always Be Coding and … : хороший
MPEGは「音声、映像関連の規格」
MP3は「音声データを扱うときの規格のひとつ」
MIMEタイプは「ファイルの種類を表す情報」
mp3ファイルはaudioタグで囲う
<h1>MP3の再生</h1> <audio src="test.mp3" controls></audio>

10個リクエストを送ります。
重複してレスポンスが返ってくるので、array_uniqueで重複を削除します。
<?php
require 'vendor/autoload.php';
$session = new SpotifyWebAPI\Session(
'id',
'secret',
'http://192.168.33.10:8000/callback/'
);
$api = new SpotifyWebAPI\SpotifyWebAPI();
$count = 10;
if (isset($_GET['code'])) {
$session->requestAccessToken($_GET['code']);
$api->setAccessToken($session->getAccessToken());
$tracks = $api->search('浜崎あゆみ', 'track', array(
'limit' => $count
));
// print_r('<pre>');
// var_dump($tracks);
// print_r('</pre>');
for($i=0; $i<$count; $i++){
$track_id[] = $tracks->tracks->items[$i]->album->id;
}
// print_r($track_id);
} else {
$options = [
'scope' => [
'user-read-email',
],
];
header('Location: ' . $session->getAuthorizeUrl($options));
die();
}
$track_id = array_unique($track_id);
foreach($track_id as $value){
echo "<iframe src=\"https://embed.spotify.com/?uri=spotify:album:".$value."\" width=\"300\" height=\"380\" frameborder=\"0\" allowtransparency=\"true\"></iframe>";
}
?>
あ、これは結構いい。昔の曲が聞ける。

LUNA SEA行ってみよう。 mothersはかっこよかった。

一曲全部じゃないのが惜しいが。
spotify api
$api->searchでtrackが返ってきます。
<?php
require 'vendor/autoload.php';
$session = new SpotifyWebAPI\Session(
'id',
'secret',
'http://192.168.33.10:8000/callback/'
);
$api = new SpotifyWebAPI\SpotifyWebAPI();
if (isset($_GET['code'])) {
$session->requestAccessToken($_GET['code']);
$api->setAccessToken($session->getAccessToken());
$tracks = $api->search('浜崎あゆみ', 'track', array(
'limit' => 1
));
$track_id = $tracks->tracks->items[0]->album->id;
print_r($track_id);
} else {
$options = [
'scope' => [
'user-read-email',
],
];
header('Location: ' . $session->getAuthorizeUrl($options));
die();
}
// print_r('<pre>');
// var_dump($tracks);
// print_r('</pre>');
?>
<h1>spotify</h1>
<iframe src="https://embed.spotify.com/?uri=spotify:album:<?php echo $track_id; ?>" width="300" height="380" frameborder="0" allowtransparency="true"></iframe>

まあまあいいんだけど、全部サビ前からサビの30秒位なんだよな。
1曲全部聞けないと、物足りない感が尋常ではない。
あ、iframeこんな感じです。うーん、違うな。やっぱりイントロから聞けないと絶対ダメでしょ。
index.php
$session = new SpotifyWebAPI\Session(
'client id',
'client secret',
'http://192.168.33.10:8000/callback'
);
spotify

invalid URIのレスポンスが返ってくるため、stackoverflowを見ていたら、
stackoverflow
https://stackoverflow.com/questions/32956443/invalid-redirect-uri-on-spotify-auth
app.js:
var redirect_uri = ‘http://localhost:8888/callback’;
Spotify > My application:
http://localhost:8888/callback/
それでもエラーで
なんでだろうと思っていたら、
myappとlocalで、callback urlは完全一致(バックスラッシュ)にしないといけないようです。
http://192.168.33.10:8000/callback/
http://192.168.33.10:8000/callback/
泣きたくなってきた。
まず、一つ目のテーブルを作くってデータを入れます。
create table cake.base(
id int unsigned auto_increment primary key,
code int,
name varchar(255)
);
insert into base(code, name) values
('3689', 'イグニス'),
('4579', 'ラクオリア創薬'),
('3825', 'リミックスポイント');

二つ目のテーブルを作って、こちらにもデータを挿入。
create table cake.data(
id int unsigned auto_increment primary key,
code int,
price int,
time datetime default null
);
insert into cake.data(code, price, time) values
('3689', '3240', now()),
('3689', '3245', now()),
('3689', '3250', now()),
('3689', '3245', now());

INNER JOINでカラムを指定して結合する
SELECT base.code, base.name, data.price, data.time FROM base INNER JOIN data ON base.code = data.code;

OUTER JOIN
SELECT base.code, base.name, data.price, data.time FROM base LEFT OUTER JOIN data ON base.code = data.code;
dataが入っていないラクオリア創薬、リミックスポイントもselectされます。

更にテーブルを連結する場合も、joinでok
create table cake.market(
id int unsigned auto_increment primary key,
code int,
market varchar(255)
);
insert into market(code, market) values
(‘3689’, ‘マザーズ’),
(‘4579’, ‘ジャスダック’),
(‘3825’, ‘東証二部’);
SELECT base.code, base.name, data.price, data.time, market.market FROM base JOIN market ON base.code = market.code JOIN data ON base.code = data.code;

// making migration
[vagrant@localhost myblog]$ bin/cake bake migration_snapshot Initial
[vagrant@localhost myblog]$ bin/cake migrations status
using migration paths
- /home/vagrant/fw/myblog/config/Migrations
using seed paths
- /home/vagrant/fw/myblog/config/Seeds
using environment default
Status Migration ID Migration Name
-----------------------------------------
up 20180306042845 Initial
[vagrant@localhost myblog]$ bin/cake bake migration CreateComments post_id:integer body:string created modified
Creating file /home/vagrant/fw/myblog/config/Migrations/20180306043056_CreateComments.php
Wrote `/home/vagrant/fw/myblog/config/Migrations/20180306043056_CreateComments.php
[vagrant@localhost myblog]$ bin/cake migrations migrate
`
mysqlで確認
mysql> use cake Reading table information for completion of table and column names You can turn off this feature to get a quicker startup with -A Database changed mysql> show tables; +----------------+ | Tables_in_cake | +----------------+ | comments | | phinxlog | | posts | +----------------+ 3 rows in set (0.00 sec)
すげー
commentController
<?php
namespace App\Controller;
class CommentsController extends AppController
{
public function add()
{
$this->viewBuilder()->layout('my_layout');
$comment = $this->Comments->newEntity();
if($this->request->is('post')){
$comment = $this->Comments->patchEntity($comment, $this->request->data);
if($this->Comments->save($comment)){
$this->Flash->success('Comment Add Success!');
return $this->redirect(['controller'=>'Posts','action'=>'view', $comment->post_id]);
}else {
$this->Flash->success('Error');
}
}
$this->set('post', $comment);
}
public function delete($id = null)
{
$this->viewBuilder()->layout('my_layout');
$this->request->allowMethod(['post', 'delete']);
$comment = $this->Comments->get($id);
if($this->Comments->delete($comment)){
$this->Flash->success('Comment Delete Success!');
}else {
$this->Flash->success('Error');
}
return $this->redirect(['controller'=>'Posts','action'=>'view', $comment->post_id]);
}
}
?>

controllerでgetして、$this->Posts->save
public function edit($id = null)
{
$this->viewBuilder()->layout('my_layout');
$post = $this->Posts->get($id);
if($this->request->is(['post','patch','put'])){
$post = $this->Posts->patchEntity($post, $this->request->data);
if($this->Posts->save($post)){
$this->Flash->success('Edit Success!');
return $this->redirect(['action'=>'index']);
}else {
$this->Flash->success('Error');
}
}
$this->set('post', $post);
}
deleteは $this->Posts->deleteになる
public function edit($id = null)
{
$this->viewBuilder()->layout('my_layout');
$this->request->allowMethod(['post', 'delete']);
$post = $this->Posts->get($id);
if($this->Posts->delete($post)){
$this->Flash->success('Delete Success!');
}else {
$this->Flash->success('Error');
}
return $this->redirect(['action'=>'index']);
}
<?= $this->Form->create($post); ?>
<?= $this->Form->input('title'); ?>
<?= $this->Form->input('body', ['rows'=> '3']); ?>
<?= $this->Form->button('Add'); ?>
<?= $this->Form->end(); ?>
なるほど、だんだんテンションが下がってきた。

DBへのinsertをcontrollerで書きます。
public function add()
{
$this->viewBuilder()->layout('my_layout');
$post = $this->Posts->newEntity();
if($this->request->is('post')){
$post = $this->Posts->patchEntity($post, $this->request->data);
$this->Posts->save($post);
return $this->redirect(['action'=>'index']);
}
$this->set('post', $post);
}
validatorはmodelに書きます。
<?php
namespace App\Model\Table;
use Cake\ORM\Table;
use Cake\Validation\Validator;
class PostsTable extends Table
{
public function initialize(array $config)
{
$this->addBehavior('Timestamp');
}
public function validationDefault(Validator $validator)
{
$validator
->notEmpty('title')
->requirePresence('title')
->notEmpty('body')
->requirePresence('body')
->add('body', [
'length' => [
'rule' => ['minLength', 10],
'message' => 'body length must be 10+'
]
]);
return $validator;
}
}
controllerでvalidationの設定
public function add()
{
$this->viewBuilder()->layout('my_layout');
$post = $this->Posts->newEntity();
if($this->request->is('post')){
$post = $this->Posts->patchEntity($post, $this->request->data);
if($this->Posts->save($post)){
return $this->redirect(['action'=>'index']);
}else {
// error
}
}
$this->set('post', $post);
}
index.ctp
Htmlヘルパーを使う場合
Html->linkとする テーブルのカラムを指定し、コントローラーとアクションを作成。
うーん、慣れるまで時間がかかりそう。
<?php foreach($posts as $post):?> <li><?= $this->Html->link($post->title, ['controller'=>'Posts', 'action'=>'view']); ?></li> <?php endforeach; ?>
ブラウザで確認。反映されてますね。

urlヘルパーを使う場合
<a href="<?= $this->Url->build(['action'=>'view', $post->id]); ?>"> <?= h($post->title); ?></a>
Htmlヘルパーの方がコード量が少なく楽そうに見えます。
共通ヘッダーをつくります。
app/src/Template/Element/my_header.ctp
<header>My Blog</header>
作ったelementをレイアウトファイルに書き込みます。
app/src/Template/Layout/my_layout.ctp
<!DOCTYPE html>
<html>
<head>
<?= $this->Html->charset() ?>
<title>
<?= $this->fetch('title') ?>
</title>
<?= $this->Html->css('styles.css') ?>
</head>
<body>
<?= $this->element('my_header') ?>
<section class="container">
<?= $this->fetch('content') ?>
</section>
</body>
</html>
サーバーを再起動します。
bin/cake server -H 192.168.33.10 -p 8000
ブラウザ読み込みます。なるほど、エレメントはパーツですね。

PostController.phpはAppControllerのclassをextendしているので、AppControllerのクラスに記載してもOK
$this->viewBuilder()->layout(‘my_layout’);