Rodhos Soft

備忘録を兼ねた技術的なメモです。Rofhos SoftではiOSアプリ開発を中心としてAndroid, Webサービス等の開発を承っております。まずはご相談下さい。

デバッグ lldb

ブレークポイントセット

breakpoint set -n semaphore_wait_trap

LLDB 使い方まとめ - Qiita
dispatch_barrier_sync blocks main thread when re-requesting an image. · Issue #803 · rs/SDWebImage · GitHub

script

Pythonでscript入力
exit()で終了

[LLDB] Pythonで独自コマンドを作ってみる - Qiita
https://lldb.llvm.org/python-reference.html
https://lldb.llvm.org/scripting.html

ヘルプ

help

スレッド全リスト

th list

スレッドの選択

(lldb) th sel 2

frame情報

fr info

frame選択

fr sel 1

frame内ローカル変数

fr variable

バックトレース

bt

bt allで全スレッドバックトレース



iOSエンジニアのための LLDB Plugin 入門 - NANAIRO

連打防止

秒数をカウントしてやる。

    class DoubleTap {
        var actionTime:Date? = nil
        let actionInterval:TimeInterval = 0.3
        
        func check() -> Bool {
            if let actionTime = actionTime {
                if -actionTime.timeIntervalSinceNow < actionInterval {
                    return false
                }
            }
            
            self.actionTime = Date()
            return true
        }
    }
    let doubleTap:DoubleTap = DoubleTap()

事前にチェックしてfalseなら無視する。

テーブルを連携させる

2つのテーブルの連携を考える。

peapleテーブル(personの複数形)

id INT,プライマリキー,AutoIncrement
name Text, Not Null, Unique
password Text, Not Null
comment Text, Null

boardsテーブル

id Int,プライマリキー,AutoIncrement
person_id Not Null
title Text
content Text

person_idは外部キーということになる。

テーブルの結合

3つのJOIN

  1. LEFT JOIN
  2. RIGHT JOIN
  3. INNER JOIN

わかりやすい解説があった。
A Visual Explanation of SQL Joins

このリンクを読んだ後以下を読むと意味がわかる。
qiita.com








PHPフレームワーク CakePHP 3入門

bake

bookモデルを作りそのCRUDをbakeで作る。

データベースでbooksテーブル作成

id 整数、プライマリー、自動インクリメント
title テキスト
author テキスト
price 整数

bake

$ ./bin/cake bake all books

しかし失敗する

Exception: SQLSTATE[HY000] [2002] Connection refused in [*****/hogemysql/vendor/cakephp/cakephp/src/Database/Driver/PDODriverTrait.php, line 47]

Config/app.php で 以下のようにhostとportを設定したところ通った。

'Datasources' => [
        'default' => [
// 略
            'host' => '127.0.0.1',
            'port' => '8889',
        // 略
        ],


これだけで追加、編集等の画面毎作れる。

TableのvalidationDefault

bakeしたtableにはバリデーションが設定されている。

    public function validationDefault(Validator $validator)
    {
        $validator
            ->integer('id')
            ->allowEmpty('id', 'create');

        $validator
            ->requirePresence('title', 'create')
            ->notEmpty('title');

        $validator
            ->requirePresence('author', 'create')
            ->notEmpty('author');

        $validator
            ->integer('price')
            ->requirePresence('price', 'create')
            ->notEmpty('price');

        return $validator;
    }

データベース操作

レコード追加

テンプレー側にフォームを用意

<?= $this->Form->Create($entity, ['url'=>['action'=>'addRecord']]) ?>
<fieldset>
<?= $this->Form->text("name") ?>
<?= $this->Form->text("title") ?>
<?= $this->Form->textarea("content") ?>
</fieldset>
<?= $this->Form->button("送信") ?>
<?= $this->Form->end() ?>

コントローラにaddRecord追加

<?php

namespace App\Controller;

class BoardsController extends AppController {
  public function index() {
    $data = $this->Boards->find('all');
    $this->set('data', $data);
    $this->set('entity', $this->Boards->newEntity());/* 空のものをセット*/
  }

  public function addRecord() {
    if ($this->request->is('post')) {
      $board = $this->Boards->newEntity($this->request->data);
      $this->Boards->save($board);
    }

    return $this->redirect(['action' => 'index']);
  }
}

?>

request_dataの中身確認

中身をprintしてみる

  public function addRecord() {
    if ($this->request->is('post')) {
      $board = $this->Boards->newEntity($this->request->data);
      $this->Boards->save($board);
    }

    $this->autoRender = false;
    echo "<pre>";
    print_r($this->request->data);
    echo "</pre>";

//    return $this->redirect(['action' => 'index']);
  }

結果、
このような連想配列が入っていることがわかった。

Array
(
    [name] => hoge
    [title] => hello
    [content] => I have a pen.
)

レコードの検索

特定レコード表示をfindを使って実装する。index.ctpに以下を追加

<h2>検索</h2>
<?= $this->Form->Create($entity, ['url'=>['action'=>'index']]) ?>
<fieldset>
<?= $this->Form->text("id") ?>
</fieldset>
<?= $this->Form->button("送信") ?>
<?= $this->Form->end() ?>

コントローラのindexを修正

  public function index() {

    $this->set('entity', $this->Boards->newEntity());

    if ($this->request->is('post')) {
      $data = $this->Boards->find('all',
        ['conditions' => ['id' => $this->request->data['id']]]
      );
    } else {
      $data = $this->Boards->find('all');
    }
    $this->set('data', $data);
  }

find

第1引数

all 全レコード
list レコードのリスト(表示用のフィールドだけ入っている)
threaded スレッド状レコード(ネストされたエンティティを扱う際に必要)

第2引数

conditions 条件設定
fields 取得するフィールド名を配列として用意
recursive 再帰的に取得する深度
order 取得順
limit 上限
offset 取得開始位置
page 取得ページ数

like 検索

テンプレートをidからtitleに書き換え

<h2>検索</h2>
<?= $this->Form->Create($entity, ['url'=>['action'=>'index']]) ?>
<fieldset>
<?= $this->Form->text("name") ?>
</fieldset>
<?= $this->Form->button("送信") ?>
<?= $this->Form->end() ?>

コントローラもlikeを使ったものにかきかえ

  public function index() {

    $this->set('entity', $this->Boards->newEntity());

    if ($this->request->is('post')) {
      $data = $this->Boards->find('all',
        ['conditions' =>
          ['name like' => "%{$this->request->data['name']}%"]
        ]
      );
    } else {
      $data = $this->Boards->find('all');
    }
    $this->set('data', $data);
  }

これでその文字を含むnameの検索になった。

findで取得したQueryを調べる。

コントローラにindexを生やして出力させてみた。

public function findtest() {
    $query = $this->Boards->find('all');

    $this->autoRender = false;
    echo "<div>";
    echo "数";
    echo "<pre>";
    print_r($query->count());
    echo "</pre>";
    echo "</div>";

    echo "<div>";
    echo "first";
    echo "<pre>";
    print_r($query->first()->toArray());
    echo "</pre>";
    echo "</div>";

    echo "<div>";
    echo "last";
    echo "<pre>";
    print_r($query->last()->toArray());
    echo "</pre>";
    echo "</div>";

    echo "<div>";
    echo "max_id";
    echo "<pre>";
    print_r($query->max('id'));
    echo "</pre>";
    echo "</div>";

    echo "<div>";
    echo "min_id";
    echo "<pre>";
    print_r($query->min('id'));
    echo "</pre>";
    echo "</div>";


  }

結果は

数
4
first
Array
(
    [id] => 1
    [name] => poi
    [title] => asdasd
    [content] => fawefsfawefaewf
)
last
Array
(
    [id] => 1
    [name] => poi
    [title] => asdasd
    [content] => fawefsfawefaewf
)
max_id
Cake\ORM\Entity Object
(
    [id] => 1
    [name] => poi
    [title] => asdasd
    [content] => fawefsfawefaewf
    [[new]] => 
    [[accessible]] => Array
        (
            [*] => 1
        )

    [[dirty]] => Array
        (
        )

    [[original]] => Array
        (
        )

    [[virtual]] => Array
        (
        )

    [[errors]] => Array
        (
        )

    [[invalid]] => Array
        (
        )

    [[repository]] => Boards
)
min_id
Cake\ORM\Entity Object
(
    [id] => 1
    [name] => poi
    [title] => asdasd
    [content] => fawefsfawefaewf
    [[new]] => 
    [[accessible]] => Array
        (
            [*] => 1
        )

    [[dirty]] => Array
        (
        )

    [[original]] => Array
        (
        )

    [[virtual]] => Array
        (
        )

    [[errors]] => Array
        (
        )

    [[invalid]] => Array
        (
        )

    [[repository]] => Boards
)

firstとlastがおなじになっている。
これは$data->$first とやったことでqueryの内容が変わってしまったことを意味する。

そうならないようにすると(取り直した)

  public function findtest() {
    $query = $this->Boards->find('all');
    $count = $query->count();
    $max_id = $query->max('id');
    $min_id = $query->min('id');

    $first = $this->Boards->find('all')->first();
    $last = $this->Boards->find('all')->last();

    $this->autoRender = false;
    echo "<div>";
    echo "数";
    echo "<pre>";
    print_r($count);
    echo "</pre>";
    echo "</div>";

    echo "<div>";
    echo "first";
    echo "<pre>";
    print_r($first->toArray());
    echo "</pre>";
    echo "</div>";

    echo "<div>";
    echo "last";
    echo "<pre>";
    print_r($last->toArray());
    echo "</pre>";
    echo "</div>";

    echo "<div>";
    echo "max_id";
    echo "<pre>";
    print_r($max_id);
    echo "</pre>";
    echo "</div>";

    echo "<div>";
    echo "min_id";
    echo "<pre>";
    print_r($min_id);
    echo "</pre>";
    echo "</div>";


  }

確かに正常に検索結果がでている。

数
4
first
Array
(
    [id] => 1
    [name] => poi
    [title] => asdasd
    [content] => fawefsfawefaewf
)
last
Array
(
    [id] => 4
    [name] => hoge
    [title] => hello
    [content] => I have a pen.
)
max_id
Cake\ORM\Entity Object
(
    [id] => 4
    [name] => hoge
    [title] => hello
    [content] => I have a pen.
    [[new]] => 
    [[accessible]] => Array
        (
            [*] => 1
        )

    [[dirty]] => Array
        (
        )

    [[original]] => Array
        (
        )

    [[virtual]] => Array
        (
        )

    [[errors]] => Array
        (
        )

    [[invalid]] => Array
        (
        )

    [[repository]] => Boards
)
min_id
Cake\ORM\Entity Object
(
    [id] => 1
    [name] => poi
    [title] => asdasd
    [content] => fawefsfawefaewf
    [[new]] => 
    [[accessible]] => Array
        (
            [*] => 1
        )

    [[dirty]] => Array
        (
        )

    [[original]] => Array
        (
        )

    [[virtual]] => Array
        (
        )

    [[errors]] => Array
        (
        )

    [[invalid]] => Array
        (
        )

    [[repository]] => Boards
)

昇順、降順

orderを使う。

  public function findtest() {
    $query = $this->Boards->find('all');
    $query->order(['name' => 'ASC', 'id' => 'DESC']);


    $this->autoRender = false;
    echo "<div>";
    echo "<pre>";
    print_r($query->toArray());
    echo "</pre>";
    echo "</div>";

  }

動的FInderで検索 findBy___()

以下のようにキャメル記法でフィールド名をByの後に書く。

  public function findtest() {
    $query = $this->Boards->findById('1');

    $this->autoRender = false;
    echo "<div>";
    echo "<pre>";
    print_r($query->toArray());
    echo "</pre>";
    echo "</div>";

  }

2つの条件をorで結びたい場合

    $query = $this->Boards->findByIdOrName('1',"poi");

andも同様。

削除

<h2>削除</h2>
<?= $this->Form->Create($entity, ['url'=>['action'=>'deleteRecord']]) ?>
<fieldset>
<?= $this->Form->text("id") ?>
</fieldset>
<?= $this->Form->button("送信") ?>
<?= $this->Form->end() ?>


コントローラに

use \Exception;
use Cake\Log\Log;

を追加しつつ、以下を追加

  public function deleteRecord() {
    if ($this->request->is('post')) {
      try {
        $entity = $this->Boards->get($this->request->data['id']);
        $this->Boards->delete($entity);
      } catch (Exception $e) {
        Log::write('debug', $e->getMessage());
      }
    }
    $this->redirect(['action' => 'index']);
  }

IDがプライマリーキーなのでエンティティがgetで得られる。
Logはレベルを指定して出力できる。

debug デバッグ
info 情報
notice 注意
warning 警告
error 例外
critical 危険
alert 直ちに対処すべき
emergency システム停止級

条件の範囲を消したい時、例えばnameがhogeのものすべてを消す場合、

$this->Boards->deleteAll(['name' => 'hoge']);

レコードの更新

saveで良い。

index側

<h2>編集</h2>
<?=$this->Form->create($entity,
['url'=>['action'=>'editRecord']]) ?>
<fieldset>
  <p><?= 'ID =' . $entity->id ?></p>
  <?=$this->Form->hidden("id") ?>
  <?=$this->Form->text("name") ?>
  <?=$this->Form->text("title") ?>
  <?=$this->Form->text("content") ?>
</fieldset>
<?=$this->Form->button("送信") ?>
<?=$this->Form->end() ?>

コントローラ側

  public function index($id = null) {

    $this->set('entity', $this->Boards->newEntity());

    if ($id != null) {
      try {
        $entity = $this->Boards->get($id);
        $this->set('entity', $entity);
      } catch (Exception $e){
        Log::write('debug', $e->getMessage());
      }
    }

    $data = $this->Boards->find('all')->order(['id'=>'DESC']);
    $this->set('data', $data->toArray());
  }

  public function editRecord() {

// putに注意
    if ($this->request->is('put')) {
      try {
        $entity = $this->Boards->get($this->request->data['id']);
        $this->Boards->patchEntity($entity, $this->request->data);
        $this->Boards->save($entity);
      } catch (Exception $e) {
        Log::write('debug', $e->getMessage());
      }
    }
    $this->redirect(['action' => 'index']);
  }

これでboards/index/1のようにアクセスして編集できる。



PHPフレームワーク CakePHP 3入門

使いかた

http://pubman.mpdl.mpg.de/pubman/item/escidoc:150722:1/component/escidoc:150721/cadabra.pdf


A brief introduction to Cadabra: a tool for tensor computations in General Relativity
https://arxiv.org/pdf/0903.2085.pdf

https://suppiya.files.wordpress.com/2008/05/comprund_41_016.pdf

http://cds.cern.ch/record/1013176/files/0701238.pdf

macにinstall

github.com

に従ってmakeしようとしたが"cmake .."で失敗中

500エラー

PHPでエラーがみたい

php.iniファイルで

error_reporting  =  E_ALL
display_errors On
display_startup_errors = On

公開用サーバではlog_errorsでログでみるべき。

internal error 500

新しくプロジェクトを作ったところそのようなエラーがでた。
ログを確認したところ

 PHP Fatal error:  require(): Failed opening required '/Applications/MAMP/htdocs/hogemysql/vendor/autoload.php' (include_path='.:/Applications/MAMP/bin/php/php7.1.1/lib/php') in /Applications/MAMP/htdocs/hogemysql/webroot/index.php on line 27

PHP Warning:  require(/Applications/MAMP/htdocs/hogemysql/vendor/autoload.php): failed to open stream: No such file or directory in /Applications/MAMP/htdocs/hogemysql/webroot/index.php on line 27

つまりautoload.phpがないといわれている。

同様の問題と思わしきページ
chaika.hatenablog.com

たしかにログをみてみると

$ php composer.phar create-project --prefer-dist cakephp/app hogemysql
Installing cakephp/app (3.4.2)
  - Installing cakephp/app (3.4.2): Downloading (100%)         
Created project in hogemysql
Loading composer repositories with package information
Updating dependencies (including require-dev)
Your requirements could not be resolved to an installable set of packages.

  Problem 1
    - cakephp/cakephp 3.4.7 requires ext-intl * -> the requested PHP extension intl is missing from your system.
    - cakephp/cakephp 3.4.6 requires ext-intl * -> the requested PHP extension intl is missing from your system.
    - cakephp/cakephp 3.4.5 requires ext-intl * -> the requested PHP extension intl is missing from your system.
    - cakephp/cakephp 3.4.4 requires ext-intl * -> the requested PHP extension intl is missing from your system.
    - cakephp/cakephp 3.4.3 requires ext-intl * -> the requested PHP extension intl is missing from your system.
    - cakephp/cakephp 3.4.2 requires lib-icu >=4.8 -> the requested linked library icu has the wrong version installed or is missing from your system, make sure to have the extension providing it.
    - cakephp/cakephp 3.4.1 requires lib-icu >=4.8 -> the requested linked library icu has the wrong version installed or is missing from your system, make sure to have the extension providing it.
    - cakephp/cakephp 3.4.0 requires lib-icu >=4.8 -> the requested linked library icu has the wrong version installed or is missing from your system, make sure to have the extension providing it.
    - Installation request for cakephp/cakephp 3.4.* -> satisfiable by cakephp/cakephp[3.4.0, 3.4.1, 3.4.2, 3.4.3, 3.4.4, 3.4.5, 3.4.6, 3.4.7].

とintlがないと言われている。
qiita.com

の手順でやってみた。

icu4cインストール(Unicode 関連の処理を行うためのオープンソースのライブラリ)

$ brew install icu4c

autoconfインストール(https://ja.wikipedia.org/wiki/Autotools#autoconf)
が、うまくいかない。

Error: No available formula with the name "icu4cautoconf" 
==> Searching for similarly named formulae...
Error: No similarly named formulae found.
==> Searching taps...
Error: No formulae found in taps.
==> You haven't updated Homebrew in a while.

brew updateしようとしたが

Error: /usr/local must be writable!


qiita.com

とありあえず

brew doctor

してみた。
それにしたがい

sudo chown -R $(whoami) /usr/local

をする。

brew update

が実行できたが

Error: update-report should not be called directly!


もう一度

brew install autoconf
$ sudo pecl update-channels
$ sudo pecl install intl 
sudo: pecl: command not found

遠回りしている気がしたので

brew search intl
intltool
homebrew/php/php53-intl    homebrew/php/php55-intl    homebrew/php/php71-intl
homebrew/php/php54-intl    homebrew/php/php56-intl    homebrew/php/php70-intl
brew install homebrew/php/php71-intl

webアプリのフォルダで

composer install

これでアクセスしたところ表示が500から

Could not load configuration file: /Applications/MAMP/htdocs/hogemysql/config/app.php

に変わった。
もう一度

composer install

したところ

$ composer install
Loading composer repositories with package information
Installing dependencies (including require-dev) from lock file
Nothing to install or update
Generating autoload files
> Cake\Composer\Installer\PluginInstaller::postAutoloadDump
> App\Console\Installer::postInstall
Created `config/app.php` file
Set Folder Permissions ? (Default to Y) [Y,n]? Y
Permissions set on /Applications/MAMP/htdocs/hogemysql/tmp/cache
Permissions set on /Applications/MAMP/htdocs/hogemysql/tmp/cache/models
Permissions set on /Applications/MAMP/htdocs/hogemysql/tmp/cache/persistent
Permissions set on /Applications/MAMP/htdocs/hogemysql/tmp/cache/views
Permissions set on /Applications/MAMP/htdocs/hogemysql/tmp/sessions
Permissions set on /Applications/MAMP/htdocs/hogemysql/tmp/tests
Permissions set on /Applications/MAMP/htdocs/hogemysql/tmp
Permissions set on /Applications/MAMP/htdocs/hogemysql/logs
Updated Security.salt value in config/app.php

となり、無事アクセスが成功した。


whoamiとは

whoami - Wikipedia

MySQL

phpMyAdminがつかえるとして以下話をする。

MySQLにパスワードを設定している場合は
phpMyAdmin/config.inc.php

$cfg['Servers'][$i]['user']          = '*****'; 
$cfg['Servers'][$i]['password']      = '****';

を設定する。

phpMyAdminでデータベース作成

mydata 照合順序 utf8_nicode_ci

テーブル作成

boards フィールド数4

フィールド設定

id INT PRIMARY A_I
name VARCHAR(255) Null
title VARCHAR
content TEXT
CREATE TABLE `mydata`.`boards` ( `id` INT NOT NULL AUTO_INCREMENT , `name` VARCHAR(255) NULL , `title` VARCHAR(255) NOT NULL , `content` TEXT NOT NULL , PRIMARY KEY (`id`)) ENGINE = InnoDB;

ダミーレコード入力

挿入で適当に数件入れる。

INSERT INTO `boards` (`id`, `name`, `title`, `content`) VALUES (NULL, 'poi', 'asdasd', 'fawefsfawefaewf');
INSERT INTO `boards` (`id`, `name`, `title`, `content`) VALUES (NULL, 'piopoi', 'asdasd', 'ddddddddddwwwwwssssxxxx');

CakePHPのデータベースファイルをMySQLに変更する

Config/app.php

    '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' => '****',
            'password' => '****',
            'database' => 'mydata',
            'encoding' => 'utf8',
            'timezone' => 'UTC',
            'flags' => [],
            'cacheMetadata' => true,
            'log' => false,
            'quoteIdentifiers' => false,
            'url' => env('DATABASE_URL', null),
        ],

表示用意

例によってコントローラ用意

<?php

namespace App\Controller;

class BoardsController extends AppController {
  public function index() {
    $data = $this->Boards->find('all');
    $this->set('data', $data);
  }
}

?>

エンティティとテーブル用意

<?php
  namespace App\Mode\Entity;

  use Cake\ORM\Entity;

  class Board extends Entity
  {
    protected $_accessible = [
      '*' => true,
      'id' => false
    ];
  }
?>
<?php
  namespace App\Model\Table;

  use Cake\ORM\Table;

  class BoardsTable extends Table {
    
  }

  ?>

ビューの作成
Template/Boards/index.ctp

<h1>DataBase</h1>

<table>
<tr>
  <th>ID</th>
  <th>Title</th>
  <th>Content</th>
</tr>

<?php
$arr = $data->toArray();
for ($i = 0;$i < count($arr);$i++) {
  echo $this->Html->tableCells(
      $arr[$i]->toArray(),
      ['style' => 'background-color:#f0f0f0'],
      ['style' => 'font-weight:bold'],
      true);
}
?>

</table>

おさらい

いままでのおさらい。

プロジェクト作成

mkdir hoge
php composer.phar create-project --prefer-dist cakephp/app hoge

Hello World

<?php
  namespace App\Controller;

  class HelloController extends AppController {
    public $autoRender = false;
    public function index() {
      echo "hello world!!";
    }
  }
?>

hello/other

<?php
  namespace App\Controller;

  class HelloController extends AppController {
    public $autoRender = false;
    public function index() {
      echo "hello, world!!";
    }
    public function other() {
      echo "hello, other world!!";
    }
  }
?>

フォワードとリダイレクション

<?php
  namespace App\Controller;

  class HelloController extends AppController {
    public $name = "Hello";
    public $autoRender = false;
    public function index() {
      echo "hello, world!!";
    }
    public function other() {
      echo "hello, other world!!";
    }

    // アクションを指定
    public function forw() {
      $this->setAction(other);
    }
    
  // ブラウザにベージ移動を依頼する
    public function red() {
      $this->redirect("/hello/other");
    }

  }
?>

テンプレート

作る場所の例
src/Template/Hello/index.ctp

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta http-equiv="content-type" content="text/html;
  charset=UTF-8">
  <title>Hello Page</title>
</head>

<body>
    <h1>midashi</h1>
    <p> hello hello </p>
</body>
</html>

コントローラ側でautoRenderをtrueにしてテンプレートを読み込む。

<?php
  namespace App\Controller;

  class HelloController extends AppController {
    public $name = "Hello";
    public $autoRender = true;
    public function index() {
      $this->viewBuilder()->autoLayout(false);
    }
  }
?>

autoLayoutをtrueにする場合、テンプレートは

   <h1>midashi</h1>
    <p> hello hello </p>

だけでよく、デフォルトのsrc/Template/Layout/default.ctp
が適用される。

レイアウト

スタイルシートを用意する。
webroot/css/cake.hello.css

body {
  background: #eee;
  color: #999;
  margin: 10px 8px
}

#header {
  font-size: 18pt;
  font-weight: bold;
  margin: 10px;
}

#content {
  background: #fff;
  color: #999;
  padding: 10px 25px 30px 25px;
  font-size: 14pt;
}

#footer {
  text-align: right;
  font-size: 12pt;
  margin: 10pt;
}

h1 {
  color: #aaa;
  font-size: 24pt;
  margin: 20pt 0pt 50pt 0pt;
}

cssを利用する側のテンプレートを書く
src/Template/Layout/hello.ctp

<!DOCTYPE html>
<html>
<head>
    <?= $this->Html->charset() ?>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>
        <?= $this->fetch('title') ?>
    </title>
    <?= $this->Html->meta('icon') ?>

    <?= $this->Html->css('cake.hello.css') ?>

    <?= $this->fetch('meta') ?>
    <?= $this->fetch('css') ?>
    <?= $this->fetch('script') ?>
</head>

<!-- fetchでコントローラの変数を取ってきている。 -->

<body>

<div id="container">
  <div id="header">header</div>

  <div id="content">
      <?=$this->fetch('content') ?>
  </div>

  <div id="footer">footer</div>

</body>
</html>

jsも使いたい場合、ファイルをwebroot/js/cake.hello/jsに用意し、

   <?= $this->Html->script('cake.hello.js') ?>

を追加する。

最後に、コントローラでレイアウトを指定する。

<?php
  namespace App\Controller;

  class HelloController extends AppController {
    public $name = "Hello";
    public $autoRender = true;
    public function index() {
      $this->ViewBuilder()->layout('Hello');
    }
  }
?>

エレメント

レイアウトにはめ込んで使える。Templete/Elementフォルダにいれておき、

 <?= $this->element('hoge') ?>

で読み込める。

値を渡す場合

 <?= $this->element('hoge', ['x'=>10,'y'=>5]) ?>

値の受け渡し

コントローラからテンプレートへ

      $this->set('poi',10);

テンプレート側は

  <p>
      <?= $poi ?>
    </p>

AppController->requestの連想配列

params 送信された値すべて
data POSTされた際の内容
query クエリー
url 送信アドレス
base ベースのディレクト
webroot webrootディレクト
here 現在のアドレス

フォームヘルパー

テンプレート側

  <p> ヘルパーを使ったフォームの送信</p>

    <p>
      <?= $result; ?>
    </p>

    <!-- FormHelperクラスを使ってformタグ生成 第1引数は値を保管するモデル名だが指定していないのでnull-->
    <?= $this->Form->create(null,
    ['type' => 'post',
    'url' => ['controller' => 'Hello', 'action' => 'index']]) ?>

    <!-- inputタグ生成 フィールド名を指定、HelloFormのところはモデル名を指定していればそれを入れる -->
    <?= $this->Form->text("HelloForm.text1") ?>

    <!-- 送信ボタンタグ -->
    <?= $this->Form->submit("送信") ?>

    <!-- タグの終了 -->
    <?= $this->Form->end(); ?>

コントローラ側

<?php
  namespace App\Controller;

  class HelloController extends AppController {

// 略

    public function index() {

// 略

      $result = "";

      if ($this->request->isPost()) {

        $result = "<pre>送信情報<br/>";

        foreach ($this->request->data['HelloForm'] as $key => $value) {
          $result .= $key . ' => ' . $value;
        }

        $result .= "</pre>";

      } else {
        $result = "送信してください";
      }
      $this->set("result", $result);
    }

// 略


  }
?>

モデル = テーブル + エンティティ

例としてBoardモデルを考える

モデル Board キャメル記法
データベーステーブル boards 小文字複数形 アンダースコア記法(クラスでないので)
エンティティ Board Board.php キャメル記法(クラスなので)
コントローラ BoardsController BoardController.php キャメル記法(クラスなので)
ビュー(テンプレート) Template/Boards index.ctp等を配置

SQLiteの用意

SQLite3で自前で作る。ダミーレコードもいれておく

$ sqlite3 mydata
sqlite> create table 'boards' ( 'id' integer primary key autoincrement, 'name' text not null, 'title' text, 'content' text);
sqlite> insert into 'boards' values (1,'name','test','test!');
sqlite> insert into 'boards' values (2,'name2','test2','test?');

.tables, select * from 'boards'等で確認

データベース設定

Config/app.php のDatasourcesをいじる

<?-
// 略
    'Datasources' => [
        'default' => [
            'className' => 'Cake\Database\Connection',
            'driver' => 'Cake\Database\Driver\Mysql', // ここをSqliteに
            'persistent' => false,
            'host' => 'localhost', // 消す
            //'port' => 'non_standard_port_number',
            'username' => 'my_app', // 消す
            'password' => 'secret', // 消す
            'database' => 'my_app', // ROOT . DS . 'db' . DS . 'mydata' とする(使うファイル名を、拡張子あるならそれをつけて)。DSはパス区切りを表す。
            'encoding' => 'utf8',
            'timezone' => 'UTC',
            'flags' => [],
            'cacheMetadata' => true,
            'log' => false,

            'quoteIdentifiers' => false,

            //'init' => ['SET GLOBAL innodb_stats_on_metadata = 0'],

            'url' => env('DATABASE_URL', null),
        ],

// 略

    ],
->

これでアプリ名にアクセス(例  ***/hoge)でwelcomeページをみて、下の方のdatabaseの項目が「CakePHP is able to connect to the database.」にチェックがついていることを確認する。

エンティティクラスの作成

src/Model/EntityにBoard.phpファイルを作成

<?php
namespace App\Model\Entity;

use Cake\ORM\Entity;

class Board extends Entity {
  // 値の一括代入用の設定 id以外のすべては一括代入可能
  protected $_accessible = [
    '*' => true,
    'id' => false
  ];
}

?>

テーブルクラスのファイルを作成

src/Model/TableにBoardsTable.phpファイルを作成

<?php 
  namespace App\Model\Table;

  use Cake\ORM\Table;

  class BoardsTable extends Table {
    
  }

 ?>

コントローラの作成

<?php
namespace App\Controller;

class BoardsController extends AppController {
  public function index() {
    $data = $this->Boards->find('all'); // $dataはQueryクラス
    $this->set('data', $data);
  }
}
?>

ビューの作成

src/Template内にBoardsフォルダを作成、index.ctpファイルを作る。

<h1> データ </h1>
<table>
  <thead>
    <tr>
      <th>ID</th>
      <th>NAME</th>
      <th>TITLE</th>
      <th>CONTENT</th>
    </tr>
  </thead>
  <tbody>
    <?php foreach ($data as $obj): ?> <!-- $objはBoardエンティティクラス -->
      <tr>
        <td> <?= $obj->id ?> </td>
        <td> <?= h($obj->name) ?></td>
        <td> <?= h($obj->title) ?></td>
        <td> <?= h($obj->content) ?></td>
      </tr>
    <?php endforeach; ?>
  </tbody>
</table>

HTMLヘルパーでテーブルを作る

<table>
  <thead>
    <tr>
      <th>ID</th>
      <th>NAME</th>
      <th>TITLE</th>
      <th>CONTENT</th>
    </tr>
  </thead>
  <?php
  $arr = $data->toArray();// 配列に取り出す
  for ($i = 0 ; $i < count($arr); $i++) {
    echo $this->Html->tableCells(
      $arr[$i]->toArray(),
      ['style' => 'background-color:#f0f0f0'],
      ['style' => 'font-weight:bold'],
      true);
  }
  ?>
</table>

技術英語

WWDCをみつつ

Existentials 存在に関する(実存的な)
Compilation コンパイル、編集物
Inference 推論
thunks サンク 遅延評価を受ける関数に受け渡す引数 
ストリーム (プログラミング) - Wikipedia

inception 開始、発端
Interruptible 中断可能、割り込み可能
subvert 倒す、破壊する、覆す
elapse 経過する、過ぎ去る

WWDC2017

iOS11の忘備録

まずQiitaを一読して後追いする。WWDC2017を個別にみていきたい。恐らくリンク先の堤さん等のまとめ(API Diffsから見る iOS 11 の新機能 #WWDC17 - Over&Out その後)
を読むほうが早い..。

以下作成中

レビュー催促ポップアップの規制

Apple、アプリ上でレビューを催促するポップアップを今後は規制
iphone-mania.jp

iOS10.3からSKStoreReviewController
これに一本化される。

MusicKit

iTuneの曲の再生、プレイリスト取得等
MusicKit - Apple Developer
qiita.com

DeviceCheck

qiita.com

アプリのデバイスごとの識別情報。アプリを消しても一緒に消えない個別情報。

MapKit機能追加

MKMarkerAnnotationViewが追加されたのが大きいような気がする。表示の優先順位とかもつけられるようになった。
qiita.com

WKWebView機能追加

cookie管理、カスタムリソース(端末内の画像とかをhtmlに入れられる)、コンテンツブロックが追加された。
qiita.com

Core ML

機械学習系、学習済みのものを使ったりできる。appleが幾つか学習済みデータのサンプルを以下で提供しているのでそれを使ってみるのが良いかも。
少し調べる必要がある。
d.hatena.ne.jp
Machine Learning - Apple Developer
Core ML | Apple Developer Documentation

Depth API

デュアルレンズを使った奥行き判定。AVCaptureDepthDataOutput。
d.hatena.ne.jp
AVCaptureDepthDataOutput - AVFoundation | Apple Developer Documentation

SiriKit機能追加

各種インテントが増えてる。公演のPDF参照。
INTransferMoneyIntent, INSearchForAccountsIntent, INCreateTaskListIntent, INAddTasksIntent, INSetTaskAttributeIntent, INSearchForNotebookItemsIntent,
INGetVisualCodeIntent,
developer.apple.com
SiriKit - Apple Developer
https://devstreaming-cdn.apple.com/videos/wwdc/2017/214bugobsy7xw94v/214/214_whats_new_in_sirikit.pdf

ReplayKit機能追加

RPScreenRecorderというデバイス画面の動画を取れるクラス(AVPlayerからはとれない。)にstartCaptureが追加された。
d.hatena.ne.jp
RPScreenRecorder - ReplayKit | Apple Developer Documentation

SceneKit機能追加

scncameracontroller 情報がない。
SCNCameraController - SceneKit | Apple Developer Documentation

ちなみにSCNCameraとは
SCNCamera - SceneKit | Apple Developer Documentation

ARKit

ARSCNViewやARSKViewは ARSessionを含む。Sessionを動かすにはconfigがいる。ARSessionConfiguration, ARWorldTrackingSessionConfiguration。
ARSession - ARKit | Apple Developer Documentation

WWDC2017ARKIT
developer.apple.com

ARKitはAVFoudationとCoreMotionを使う。ARSessionConfigを設定してARSessionをRunする。ARSessionはAVCaptureSessionとCMMotionManagerを使う。
現在のフレームがARFrame。
特定の位置等をARAnchorで付けたりできる。ARCameraにTracking stateなどの状態が入る(ARSessionから状態通知)。

シーン(場面)の理解としてどこが平面化の理解というのができる。configuration.planeDetection とかで指定しておく。hitTestが frame.hitTestでできる。

Renderingについては

SceneKit のARSCNView
SpriteKitのARSKView
メタルでCustom Renderingする
等がある。


dev.classmethod.jp


SceneKitはiOS8から使える簡易3D描画フレームワーク
qiita.com



サンプルコード
github.com
github.com


アニメーション

developer.apple.com

iOS10から導入されたUIViewPropertyAnimatorに
iOS11で
scrubsLinearly:、pausesOnCompletion:が加わる。

CALayerに.maskedCorners:CACornerMaskが加わる。

Foundation

developer.apple.com



キーパスが簡単に

 let age = ben[keyPath: \Kid.age]
 ben[keyPath: \Kid.nickname] = "Ben"

KVOも

let observation = mia.observe(\.age) {
}
Codableについて

初歩的知識

以下を参照した。
saruwakakun.com

  • display:inlineは大きさ変えられない。display:blockかdisplay:inline-blockにする必要あり。aタグ, spanタグ。
  • width:autoの決まり方 基本親要素まで広がる、%指定で親要素の何%かと言う決まり方になる(このときpadding, borderをつけているとはみ出るのでbox-sizing: border-box等をつける。)。
  • min-width, max-widthで縮小に拡大に制限をつけられる。
  • height:autoは中身の分の高さになる。%指定で親の高さがきまっていないときwidthなら親の親を辿ってブラウザの幅までいきつくがheightの場合は指定がきかなくなるので注意。

htmlを吐き出す4

何か形になってきた気が。とりあえず根本的にタグを定義してみた。
しかしdivとかを手で入れるようになってしまい面倒さは変わらないような気も。

import Data.List

main = print (display html)

type ClassName = String
-- data DIV a = DIV ClassName a deriving Show
-- data P a = P ClassName a deriving Show
--
-- display:: DIV a -> String
-- display (DIV name x) = name



type TagName = String
tag::TagName -> String -> String
tag name txt = "<"++name++">" ++ txt ++ "</"++name++">"

type AttributeName = String
type AttributeString = String
attr::AttributeName -> String -> AttributeString
attr name txt = name ++ "=" ++ txt


tagatt::TagName -> [AttributeString] -> String -> String
tagatt name att txt = "<" ++ name ++ " " ++ attstr ++ ">" ++ txt ++ "</"++name++">" where
  attstr = intercalate "" att

qua::String->String
qua txt = "'" ++ txt ++ "'"

data TAG = TAG TagName ClassName [ATTRIBUTE] [TAG] |Text String deriving Show
data ATTRIBUTE = Attribute AttributeName String deriving Show

class DISPLAY a where
  display:: a -> String

instance DISPLAY TAG where
  display (TAG tagName className attributes tags) = tagatt tagName (map display ([Attribute "class" (qua className)]++attributes)) (intercalate "" (map display tags))
  display (Text txt) = txt


instance DISPLAY ATTRIBUTE where
  display (Attribute name txt) = attr name txt


-----

html = TAG "html" "" [] htmlall

htmlall = [header, body]

header = TAG "header" "" [] []
body = TAG "body" "" [] [Text "hello"]


Styleタグを付けてみた。

import Data.List

main = putStr (display html)

type ClassName = String



type TagName = String
tag::TagName -> String -> String
tag name txt = "\n<"++name++">\n" ++ txt ++ "</"++name++">\n"

type AttributeName = String
type AttributeString = String
attr::AttributeName -> String -> AttributeString
attr name txt = name ++ "=" ++ txt


tagatt::TagName -> [AttributeString] -> String -> String
tagatt name att txt = "\n<" ++ name ++ " " ++ attstr ++ ">\n" ++ txt ++ "</"++name++">\n" where
  attstr = intercalate "" att

qua::String->String
qua txt = "'" ++ txt ++ "'"

data TAG = TAG TagName ClassName [ATTRIBUTE] [TAG] |Text String deriving Show
data ATTRIBUTE = Attribute AttributeName String deriving Show

type PropertyName = String
data STYLE = STYLECLASS [ClassName] [PROPERTY] | STYLETAG TagName [PROPERTY]
data PROPERTY = Property PropertyName String deriving Show

class DISPLAY a where
  display:: a -> String

instance DISPLAY TAG where
  display (TAG tagName className attributes tags) = tagatt tagName (map display ([Attribute "class" (qua className)]++attributes)) (intercalate "" (map display tags))
  display (Text txt) = txt

instance DISPLAY ATTRIBUTE where
  display (Attribute name txt) = attr name txt

instance DISPLAY PROPERTY where
  display (Property name txt) = "\t" ++ name ++ ":" ++ txt ++ ";\n"

instance DISPLAY STYLE where
  display (STYLECLASS classnames props) = intercalate "" (map (" ."++) classnames) ++ "{\n" ++ (intercalate "" (map display props))  ++ "\n}\n"
  display (STYLETAG tagname props) = tagname ++ "{\n" ++ (intercalate "" (map display props))  ++ "\n}\n"


-----

html = TAG "html" "" [] htmlall

htmlall = [header, body]

header = TAG "header" "" [] [style]
style = TAG "style" "" [] [Text (display css)]
body = TAG "body" "hoge" [] [Text "hello"]

css = STYLECLASS ["hoge"] [Property "background-color" "green"]


タグを幾つか定義してみた。これで大体がつくれるかもしれない。

import Data.List

main = putStr (display html)

type ClassName = String



type TagName = String
tag::TagName -> String -> String
tag name txt = "\n<"++name++">\n" ++ txt ++ "</"++name++">\n"

type AttributeName = String
type AttributeString = String
attr::AttributeName -> String -> AttributeString
attr name txt = name ++ "=" ++ txt


tagatt::TagName -> [AttributeString] -> String -> String
tagatt name att txt = "\n<" ++ name ++ " " ++ attstr ++ ">\n" ++ txt ++ "</"++name++">\n" where
  attstr = intercalate "" att

qua::String->String
qua txt = "'" ++ txt ++ "'"

data TAG = TAG TagName ClassName [ATTRIBUTE] [TAG] |Text String deriving Show
data ATTRIBUTE = Attribute AttributeName String deriving Show

type PropertyName = String
data STYLE = STYLECLASS [ClassName] [PROPERTY] | STYLETAG TagName [PROPERTY] | STYLEEMPTY
data PROPERTY = Property PropertyName String deriving Show

class DISPLAY a where
  display:: a -> String

instance DISPLAY TAG where
  display (TAG tagName className attributes tags) = tagatt tagName (map display ([Attribute "class" (qua className)]++attributes)) (intercalate "" (map display tags))
  display (Text txt) = txt

instance DISPLAY ATTRIBUTE where
  display (Attribute name txt) = attr name txt

instance DISPLAY PROPERTY where
  display (Property name txt) = "\t" ++ name ++ ":" ++ txt ++ ";\n"

instance DISPLAY STYLE where
  display (STYLECLASS classnames props) = intercalate "" (map (" ."++) classnames) ++ "{\n" ++ (intercalate "" (map display props))  ++ "\n}\n"
  display (STYLETAG tagname props) = tagname ++ "{\n" ++ (intercalate "" (map display props))  ++ "\n}\n"
  display (STYLEEMPTY) = ""


-----

html = htmlcommon htmlall

htmlcommon = _html "" [Attribute "lang" (qua "ja")]
metacommon = _meta "" [Attribute "charset" (qua "UTF-8")] []
htmlall = [headtag "title" (style css) , body]

_meta = TAG "meta"
_html = TAG "html"
_head = TAG "head"
_body = TAG "body"
_div = TAG "div"
_p = TAG "p"
_a href= \className -> TAG "a" className  [Attribute "href" (qua href)]
_title = TAG "title"

style css = TAG "style" "" [] [Text (display css)]

-- head
headtag title style = _head "" [] [metacommon,style, (_title "" [] [Text title])]

-- body
body = _body "hoge" [] [_div "box" [] [Text "Hello", _a "https://yahoo.co.jp" "" [Text "link"]]]

-- css
css = STYLECLASS ["hoge"] [Property "background-color" "green"]

-- template
templatehtml title css bodytag = htmlcommon [headtag title (style css), bodytag]

-- emptyhtml
emptyhtml = templatehtml "title" STYLEEMPTY (_body "" [] [])


gistにのっけた。
html haskell · GitHub