- 投稿日:2020-07-21T22:39:02+09:00
Laravelで多角形の内外判定を行うアルゴリズムの実装案
ユーザの住所が配達を承る範囲内かどうかを調べる必要があったので
実装を行っていましたところ,
https://www.nttpc.co.jp/technology/number_algorithm.html
にとてもよいアルゴリズムがあったのでこれをLaravel(PHP)で使えるようにしようと言うのが今回です.Crossing Number Algorithm
- 調べたい範囲の多角形と,点を用意します.
- 点から真横に線を伸ばす.
- 多角形内に点があれば多角形の辺との交差数は奇数,外なら偶数になる
ざっとこんなイメージですがいいですかね.詳しくはサイト読んでください.
特殊ケースが4つぐらいあるので,そこは気をつけないといけません.Laravelでの実装
多角形の準備
config\const.php
に判定したい多角形を準備します.
最初の座標と最後の座標は一緒にしてね.
下記の例だと,四角形だけど準備する点は5つです.今回はGoogleMapAPI使うので,latとlngで区別します.latをy軸(縦方向),lngをx軸(横方向)として捉えてます.
lng,latの順のほうが良かったな.数学っぽいし.config\const.php'DeliveryArea'=>[ ["lat"=>1.0,"lng"=>0.0], ["lat"=>2.0,"lng"=>0.0], ["lat"=>2.0,"lng"=>1.0], ["lat"=>1.0,"lng"=>1.0], ["lat"=>1.0,"lng"=>0.0], ]配達可能エリアとかそうそう変わらんだろってことで,constに指定.
config('const.DeliveryArea);
だけで配列として使えるから便利だよね~.ユーザの住所
これはGoogleMapAPIのGeoCodingを使います.詳しくは調べてネ.
- 言語を指定
- APIキーを指定(極秘事項です.気をつけてね)
- リクエスト出して,jsonをもらってくる.
- よしなに返す.
ここでは,arrayにして同時に返してます.受け取るときは,list関数で受け取ればいいかなと.
ああああ とか変な住所が入ってきたら,ZERO_RESULTが返ってくるらしいので,それで判定しました.Polygon.phppublic static function geo($addr) { mb_language("Japanese"); //文字コードの設定 mb_internal_encoding("UTF-8"); $address = $addr; if (config('app.debug')) { //テスト環境, ローカル環境用の記述 $myKey = "デバッグ用のキー"; } else { $myKey = "本番環境用のキー"; } $address = urlencode($address); $url = "https://maps.googleapis.com/maps/api/geocode/json?address=" . $address . "+CA&key=" . $myKey; $contents = file_get_contents($url); $jsonData = json_decode($contents, true); if($jsonData["status"]=="ZERO_RESULTS"){ $lat = null; $lng = null; }else{ $lat = $jsonData["results"][0]["geometry"]["location"]["lat"]; $lng = $jsonData["results"][0]["geometry"]["location"]["lng"]; } return array($lat, $lng); }内外判定
まんまあったのをPHPの形式に直しただけです.あと,geo関数でnull返したので,それを扱うときの条件式を追加.
あと,判定の結果がどうなのかtrueとfalseで返してます.
交点の数が知りたい場合は,$cnを返せばOKでした.Polygon.phppublic static function isPointinPolygon($point,$PolygonArray){ $cn = 0; if($point["lat"]==null){ $point["lat"]=0.0; } if($point["lng"]==null){ $point["lng"]=0.0; } for($i = 0; $i < count($PolygonArray) - 1; $i++){ // 上向きの辺。点Pがy軸方向について、始点と終点の間にある。ただし、終点は含まない。(ルール1) if( (($PolygonArray[$i]["lat"] <= $point["lat"]) && ($PolygonArray[$i+1]["lat"] > $point["lat"])) // 下向きの辺。点Pがy軸方向について、始点と終点の間にある。ただし、始点は含まない。(ルール2) || (($PolygonArray[$i]["lat"] > $point["lat"]) && ($PolygonArray[$i+1]["lat"] <= $point["lat"])) ){ // ルール1,ルール2を確認することで、ルール3も確認できている。 // 辺は点pよりも右側にある。ただし、重ならない。(ルール4) // 辺が点pと同じ高さになる位置を特定し、その時のxの値と点pのxの値を比較する。 $vt = ($point["lat"] - $PolygonArray[$i]["lat"]) / ($PolygonArray[$i+1]["lat"]- $PolygonArray[$i]["lat"]); if($point["lng"] < ($PolygonArray[$i]["lng"] + ($vt * ($PolygonArray[$i+1]["lng"] - $PolygonArray[$i]["lng"])))){ ++$cn; } } } if($cn%2 == 0){ return false;//偶数点だと外部 } else{ return true;//奇数点だと内部 } }実際の使い方
考えられる状況は,ECサイトでのカート機能とかかと.
ユーザの住所みて,配送料に追加するとか,割引するとかかなと.この場合は,latとlngをあとづけしたので既存ユーザのlatとlngのデータはnullになってる,けどaddrのデータはあるって人がいるのでこんなことしてるけど,普通は会員登録時とかマイページで情報編集したときにlatとlngを取る.
で,住所の文字列をgeo使ってlatとlngに変換して,ユーザ情報を保存.そのまま内外判定の関数に渡してます.
引数の1つ目はlatとlng要素の配列.
引数の2つ目は判定したいエリアの配列.trueかfalse返すので自分の好きなように処理して,bladeにかえしてます.
CartController.php<?php use App\Utils\Polygon as Polygon; // useはよしなに class CartController extends Controller { public function indexcart() { $Areaadd = 0; $message = ""; if( Auth::user()->lat == null || Auth::user()->lng == null){ list($lat,$lng) = Polygon::geo(Auth::user()->addr); if($lat == null || $lng == null){ //取得してもなお不正な場合 $message = "ちゃんと住所入れてくれ"; }else{ User::where('id',Auth::id())->update([ 'lat'=>$lat, 'lng'=>$lng ]); } } if(Polygon::isPointinPolygon(["lat"=>Auth::user()->lat,"lng"=>Auth::user()->lng],config('const.DeliveryArea')) == false) {// lat=1.5 lng=0.5とかなら範囲内 $Areaadd += 999999999; $message = "届けてやるぜ"; }else{// lat=0.0 lng=0.0は範囲外 $message = "すまん遠すぎる"; } return view('user.cart')->with('message',$message)->with('Areaadd',$Areaadd); } }Githubにも置いてます.
https://github.com/a-msy/laravel-utils/blob/master/Polygon.php
以上です.
- 投稿日:2020-07-21T22:20:14+09:00
PHP-MySQLi-Database-Classの解説 日本語訳
MysqliDb -- MySQLi のシンプルなラッパーの解説日本語訳
PHP-MySQLi-Database-Classは日本ではあまり知られていませんが、
githubでは☆2800スターを集めて世界中の人に使われているものとなります。本家githubはこちらから
https://github.com/ThingEngineer/PHP-MySQLi-Database-Class利用方法
このクラスを利用するには、まずMysqliDb.phpをプロジェクトにインポート。
require_once ('MysqliDb.php');
composerでの利用方法
composer経由でライブラリをインストールすることも可能です。
composer require thingengineer/mysqli-database-class:dev-master
初期化 (initialization)
デフォルトではutf8のcharsetが設定されているので、簡単な初期化が可能です。
$db = new MysqliDb ('host', 'username', 'password', 'databaseName');
高度な初期化
$db = new MysqliDb (Array ( 'host' => 'host', 'username' => 'username', 'password' => 'password', 'db'=> 'databaseName', 'port' => 3306, 'prefix' => 'my_', 'charset' => 'utf8'));テーブルの接頭辞、ポート、データベースのcharsetパラメータはオプションです。
charsetを設定すべきでない場合は、nullに設定します。
また、すでに接続されている mysqli オブジェクトを再利用することも可能です。$mysqli = new mysqli ('host', 'username', 'password', 'databaseName'); $db = new MysqliDb ($mysqli);オブジェクトの作成時にテーブルのプレフィックスが設定されていなかった場合は、
後から別の呼び出しでテーブルのプレフィックスを設定することができます。$db->setPrefix ('my_');mysqlへの接続が切断される場合、Mysqlidbは自動的に一度データベースに再接続しようとします。
この動作を無効にするには以下のようにしてください。$db->autoReconnect = false;すでに作成された mysqliDb オブジェクトを別のクラスや関数から取得する場合は以下のように設定します。
function init () { // db staying private here $db = new MysqliDb ('host', 'username', 'password', 'databaseName'); } function myfunc () { // obtain db object created in init () $db = MysqliDb::getInstance(); ... }複数のデータベース接続
複数のデータベースに接続する必要がある場合は、以下の方法で使用してください。
$db->addConnection('slave', Array ( 'host' => 'host', 'username' => 'username', 'password' => 'password', 'db'=> 'databaseName', 'port' => 3306, 'prefix' => 'my_', 'charset' => 'utf8') );データベースを選択するには connection() メソッドを使用します。
$users = $db->connection('slave')->get('users');オブジェクトのマッピング
dbObject.php は、モデル表現機能を提供するために mysqliDb の上に構築されたオブジェクトマッピングライブラリです。
挿入クエリ(Insert Query)
簡単な例
$data = Array ("login" => "admin", "firstName" => "John", "lastName" => 'Doe' ); $id = $db->insert ('users', $data); if($id) echo 'user was created. Id=' . $id;fuunction挿入
$data = Array ( 'login' => 'admin', 'active' => true, 'firstName' => 'John', 'lastName' => 'Doe', 'password' => $db->func('SHA1(?)',Array ("secretpassword+salt")), // password = SHA1('secretpassword+salt') 'createdAt' => $db->now(), // createdAt = NOW() 'expires' => $db->now('+1Y') // expires = NOW() + interval 1 year // Supported intervals [s]econd, [m]inute, [h]hour, [d]day, [M]onth, [Y]ear ); $id = $db->insert ('users', $data); if ($id) echo 'user was created. Id=' . $id; else echo 'insert failed: ' . $db->getLastError();INSERT ... ON DUPLICATE KEY UPDATE 構文
$data = Array ("login" => "admin", "firstName" => "John", "lastName" => 'Doe', "createdAt" => $db->now(), "updatedAt" => $db->now(), ); $updateColumns = Array ("updatedAt"); $lastInsertId = "id"; $db->onDuplicate($updateColumns, $lastInsertId); $id = $db->insert ('users', $data);複数のデータセットを一度に挿入
$data = Array( Array ("login" => "admin", "firstName" => "John", "lastName" => 'Doe' ), Array ("login" => "other", "firstName" => "Another", "lastName" => 'User', "password" => "very_cool_hash" ) ); $ids = $db->insertMulti('users', $data); if(!$ids) { echo 'insert failed: ' . $db->getLastError(); } else { echo 'new users inserted with following id\'s: ' . implode(', ', $ids); }すべてのデータセットが同じキーしか持たない場合は、単純化することができます。
$data = Array( Array ("admin", "John", "Doe"), Array ("other", "Another", "User") ); $keys = Array("login", "firstName", "lastName"); $ids = $db->insertMulti('users', $data, $keys); if(!$ids) { echo 'insert failed: ' . $db->getLastError(); } else { echo 'new users inserted with following id\'s: ' . implode(', ', $ids); }データ置換(REPLACE文)
Replace() メソッドは insert() と同じ API を実装しています。
データを更新する(UPDATE文)
$data = Array ( 'firstName' => 'Bobby', 'lastName' => 'Tables', 'editCount' => $db->inc(2), // editCount = editCount + 2; 'active' => $db->not() // active = !active; ); $db->where ('id', 1); if ($db->update ('users', $data)) echo $db->count . ' records were updated'; else echo 'update failed: ' . $db->getLastError();update() はリミットパラメータもサポートしています。
php:
$db->update ('users', $data, 10);
// Gives: UPDATE users SET ... LIMIT 10
データを取得する(SELECT文)
セレクト/ゲット関数が呼び出された後、金額または返された行は$count変数に格納されます。
$users = $db->get('users'); //contains an Array of all users $users = $db->get('users', 10); //contains an Array 10 usersまたはカスタムカラムを設定して選択します。関数を使用することもできます。
$cols = Array ("id", "name", "email"); $users = $db->get ("users", null, $cols); if ($db->count > 0) foreach ($users as $user) { print_r ($user); }一行だけを選択する
$db->where ("id", 1); $user = $db->getOne ("users"); echo $user['id']; $stats = $db->getOne ("users", "sum(id), count(*) as cnt"); echo "total ".$stats['cnt']. "users found";1つの列の値または関数の結果を選択
$count = $db->getValue ("users", "count(*)"); echo "{$count} users found";複数の行から1つの列の値または関数の結果を選択
$logins = $db->getValue ("users", "login", null); // select login from users $logins = $db->getValue ("users", "login", 5); // select login from users limit 5 foreach ($logins as $login) echo $login;データを追加する(INSERT文)
また、特定のテーブルに .CSV または .XML データを読み込むこともできます。
.csv データを挿入するには、以下の構文を使用します。$path_to_file = "/home/john/file.csv"; $db->loadData("users", $path_to_file);これは、/home/john/ (johnのホームディレクトリ)フォルダにfile.csvという.csvファイルをロードします。
オプションでオプションの配列を添付することもできます。有効なオプションは以下の通りです。Array( "fieldChar" => ';', // Char which separates the data "lineChar" => '\r\n', // Char which separates the lines "linesToIgnore" => 1 // Amount of lines to ignore at the beginning of the import );Attach
$options = Array("fieldChar" => ';', "lineChar" => '\r\n', "linesToIgnore" => 1); $db->loadData("users", "/home/john/file.csv", $options); // LOAD DATA ...DATAの代わりにLOCAL DATAを使用するように指定
$options = Array("fieldChar" => ';', "lineChar" => '\r\n', "linesToIgnore" => 1, "loadDataLocal" => true); $db->loadData("users", "/home/john/file.csv", $options); // LOAD DATA LOCAL ...XML挿入
XML データをテーブルにロードするには、loadXML メソッドを使用します。構文は loadData 構文と同じです。
$path_to_file = "/home/john/file.xml"; $db->loadXML("users", $path_to_file);オプションのパラメータを追加
Array( "linesToIgnore" => 0, // Amount of lines / rows to ignore at the beginning of the import "rowTag" => "<user>" // The tag which marks the beginning of an entry )使用例
$options = Array("linesToIgnore" => 0, "rowTag" => "<user>"): $path_to_file = "/home/john/file.xml"; $db->loadXML("users", $path_to_file, $options);ページネーション(Pagination)
ページ分割された結果を取得するには get() の代わりに paginate() を使用します。
$page = 1; // set page limit to 2 results per page. 20 by default $db->pageLimit = 2; $products = $db->arraybuilder()->paginate("products", $page); echo "showing $page out of " . $db->totalPages;MAP
純粋な配列で結果を取得するのではなく、必要なキーを含む連想配列で結果を取得することも可能です。get() で取得するフィールドが 2 つだけの場合は配列($k => $v)で、それ以外の場合は配列 ($k => 配列 ($v, $v)) で結果を返します。
$user = $db->map ('login')->ObjectBuilder()->getOne ('users', 'login, id'); Array ( [user1] => 1 ) $user = $db->map ('login')->ObjectBuilder()->getOne ('users', 'id,login,createdAt'); Array ( [user1] => stdClass Object ( [id] => 1 [login] => user1 [createdAt] => 2015-10-22 22:27:53 ) )リターン型の定義
MysqliDbは、3つの異なるフォーマットで結果を返すことができます。配列の配列、オブジェクトの配列、Json文字列です。返り値の型を選択するには、ArrayBuilder()、ObjectBuilder()、JsonBuilder()メソッドを使用します。ArrayBuilder() はデフォルトの戻り値の型であることに注意してください。
// Array return type $= $db->getOne("users"); echo $u['login']; // Object return type $u = $db->ObjectBuilder()->getOne("users"); echo $u->login; // Json return type $json = $db->JsonBuilder()->getOne("users");生のSQLクエリの実行
$users = $db->rawQuery('SELECT * from users where id >= ?', Array (10)); foreach ($users as $user) { print_r ($user); }長いifチェックを避けるために、生のクエリの選択結果を扱うためのヘルパー関数があります。
結果の1行を取得します。$user = $db->rawQueryOne ('select * from users where id=?', Array(10)); echo $user['login']; // Object return type $user = $db->ObjectBuilder()->rawQueryOne ('select * from users where id=?', Array(10)); echo $user->login;1カラムの値を文字列として取得
$password = $db->rawQueryValue ('select password from users where id=? limit 1', Array(10). echo "パスワードは {$password} です。 注意: rawQueryValue() が配列ではなく文字列を返すようにするには、 クエリの最後に 'limit 1' を追加しなければなりません。複数の行から1列の値を取得します。
$logins = $db->rawQueryValue ('select login from users limit 10'); foreach ($logins as $login) echo $login;応用例
$params = Array(1, 'admin'); $users = $db->rawQuery("SELECT id, firstName, lastName FROM users WHERE id = ? AND login = ?", $params); print_r($users); // contains Array of returned rows // will handle any SQL query $params = Array(10, 1, 10, 11, 2, 10); $q = "( SELECT a FROM t1 WHERE a = ? AND B = ? ORDER BY a LIMIT ? ) UNION ( SELECT a FROM t2 WHERE a = ? AND B = ? ORDER BY a LIMIT ? )"; $results = $db->rawQuery ($q, $params); print_r ($results); // contains Array of returned rows
- 投稿日:2020-07-21T22:20:14+09:00
PHP-MySQLi-Database-Classの解説
MysqliDb -- MySQLi のシンプルなラッパーの解説 日本語訳
PHP-MySQLi-Database-Classは日本ではあまり知られていませんが、
githubでは☆2800スターを集めて世界中の人に使われているものとなります。本家githubはこちらから
https://github.com/ThingEngineer/PHP-MySQLi-Database-Class利用方法
このクラスを利用するには、まずMysqliDb.phpをプロジェクトにインポート。
require_once ('MysqliDb.php');
composerでの利用方法
composer経由でライブラリをインストールすることも可能です。
composer require thingengineer/mysqli-database-class:dev-master
初期化 (initialization)
デフォルトではutf8のcharsetが設定されているので、簡単な初期化が可能です。
$db = new MysqliDb ('host', 'username', 'password', 'databaseName');
高度な初期化
$db = new MysqliDb (Array ( 'host' => 'host', 'username' => 'username', 'password' => 'password', 'db'=> 'databaseName', 'port' => 3306, 'prefix' => 'my_', 'charset' => 'utf8'));テーブルの接頭辞、ポート、データベースのcharsetパラメータはオプションです。
charsetを設定すべきでない場合は、nullに設定します。
また、すでに接続されている mysqli オブジェクトを再利用することも可能です。$mysqli = new mysqli ('host', 'username', 'password', 'databaseName'); $db = new MysqliDb ($mysqli);オブジェクトの作成時にテーブルのプレフィックスが設定されていなかった場合は、
後から別の呼び出しでテーブルのプレフィックスを設定することができます。$db->setPrefix ('my_');mysqlへの接続が切断される場合、Mysqlidbは自動的に一度データベースに再接続しようとします。
この動作を無効にするには以下のようにしてください。$db->autoReconnect = false;すでに作成された mysqliDb オブジェクトを別のクラスや関数から取得する場合は以下のように設定します。
function init () { // db staying private here $db = new MysqliDb ('host', 'username', 'password', 'databaseName'); } function myfunc () { // obtain db object created in init () $db = MysqliDb::getInstance(); ... }複数のデータベース接続
複数のデータベースに接続する必要がある場合は、以下の方法で使用してください。
$db->addConnection('slave', Array ( 'host' => 'host', 'username' => 'username', 'password' => 'password', 'db'=> 'databaseName', 'port' => 3306, 'prefix' => 'my_', 'charset' => 'utf8') );データベースを選択するには connection() メソッドを使用します。
$users = $db->connection('slave')->get('users');オブジェクトのマッピング
dbObject.php は、モデル表現機能を提供するために mysqliDb の上に構築されたオブジェクトマッピングライブラリです。
挿入クエリ(Insert Query)
簡単な例
$data = Array ("login" => "admin", "firstName" => "John", "lastName" => 'Doe' ); $id = $db->insert ('users', $data); if($id) echo 'user was created. Id=' . $id;fuunction挿入
$data = Array ( 'login' => 'admin', 'active' => true, 'firstName' => 'John', 'lastName' => 'Doe', 'password' => $db->func('SHA1(?)',Array ("secretpassword+salt")), // password = SHA1('secretpassword+salt') 'createdAt' => $db->now(), // createdAt = NOW() 'expires' => $db->now('+1Y') // expires = NOW() + interval 1 year // Supported intervals [s]econd, [m]inute, [h]hour, [d]day, [M]onth, [Y]ear ); $id = $db->insert ('users', $data); if ($id) echo 'user was created. Id=' . $id; else echo 'insert failed: ' . $db->getLastError();INSERT ... ON DUPLICATE KEY UPDATE 構文
$data = Array ("login" => "admin", "firstName" => "John", "lastName" => 'Doe', "createdAt" => $db->now(), "updatedAt" => $db->now(), ); $updateColumns = Array ("updatedAt"); $lastInsertId = "id"; $db->onDuplicate($updateColumns, $lastInsertId); $id = $db->insert ('users', $data);複数のデータセットを一度に挿入
$data = Array( Array ("login" => "admin", "firstName" => "John", "lastName" => 'Doe' ), Array ("login" => "other", "firstName" => "Another", "lastName" => 'User', "password" => "very_cool_hash" ) ); $ids = $db->insertMulti('users', $data); if(!$ids) { echo 'insert failed: ' . $db->getLastError(); } else { echo 'new users inserted with following id\'s: ' . implode(', ', $ids); }すべてのデータセットが同じキーしか持たない場合は、単純化することができます。
$data = Array( Array ("admin", "John", "Doe"), Array ("other", "Another", "User") ); $keys = Array("login", "firstName", "lastName"); $ids = $db->insertMulti('users', $data, $keys); if(!$ids) { echo 'insert failed: ' . $db->getLastError(); } else { echo 'new users inserted with following id\'s: ' . implode(', ', $ids); }データ置換(REPLACE文)
Replace() メソッドは insert() と同じ API を実装しています。
データを更新する(UPDATE文)
$data = Array ( 'firstName' => 'Bobby', 'lastName' => 'Tables', 'editCount' => $db->inc(2), // editCount = editCount + 2; 'active' => $db->not() // active = !active; ); $db->where ('id', 1); if ($db->update ('users', $data)) echo $db->count . ' records were updated'; else echo 'update failed: ' . $db->getLastError();update() はリミットパラメータもサポートしています。
php:
$db->update ('users', $data, 10);
// Gives: UPDATE users SET ... LIMIT 10
データを取得する(SELECT文)
セレクト/ゲット関数が呼び出された後、金額または返された行は$count変数に格納されます。
$users = $db->get('users'); //contains an Array of all users $users = $db->get('users', 10); //contains an Array 10 usersまたはカスタムカラムを設定して選択します。関数を使用することもできます。
$cols = Array ("id", "name", "email"); $users = $db->get ("users", null, $cols); if ($db->count > 0) foreach ($users as $user) { print_r ($user); }一行だけを選択する
$db->where ("id", 1); $user = $db->getOne ("users"); echo $user['id']; $stats = $db->getOne ("users", "sum(id), count(*) as cnt"); echo "total ".$stats['cnt']. "users found";1つの列の値または関数の結果を選択
$count = $db->getValue ("users", "count(*)"); echo "{$count} users found";複数の行から1つの列の値または関数の結果を選択
$logins = $db->getValue ("users", "login", null); // select login from users $logins = $db->getValue ("users", "login", 5); // select login from users limit 5 foreach ($logins as $login) echo $login;データを追加する(INSERT文)
また、特定のテーブルに .CSV または .XML データを読み込むこともできます。
.csv データを挿入するには、以下の構文を使用します。$path_to_file = "/home/john/file.csv"; $db->loadData("users", $path_to_file);これは、/home/john/ (johnのホームディレクトリ)フォルダにfile.csvという.csvファイルをロードします。
オプションでオプションの配列を添付することもできます。有効なオプションは以下の通りです。Array( "fieldChar" => ';', // Char which separates the data "lineChar" => '\r\n', // Char which separates the lines "linesToIgnore" => 1 // Amount of lines to ignore at the beginning of the import );Attach
$options = Array("fieldChar" => ';', "lineChar" => '\r\n', "linesToIgnore" => 1); $db->loadData("users", "/home/john/file.csv", $options); // LOAD DATA ...DATAの代わりにLOCAL DATAを使用するように指定
$options = Array("fieldChar" => ';', "lineChar" => '\r\n', "linesToIgnore" => 1, "loadDataLocal" => true); $db->loadData("users", "/home/john/file.csv", $options); // LOAD DATA LOCAL ...XML挿入
XML データをテーブルにロードするには、loadXML メソッドを使用します。構文は loadData 構文と同じです。
$path_to_file = "/home/john/file.xml"; $db->loadXML("users", $path_to_file);オプションのパラメータを追加
Array( "linesToIgnore" => 0, // Amount of lines / rows to ignore at the beginning of the import "rowTag" => "<user>" // The tag which marks the beginning of an entry )使用例
$options = Array("linesToIgnore" => 0, "rowTag" => "<user>"): $path_to_file = "/home/john/file.xml"; $db->loadXML("users", $path_to_file, $options);ページネーション(Pagination)
ページ分割された結果を取得するには get() の代わりに paginate() を使用します。
$page = 1; // set page limit to 2 results per page. 20 by default $db->pageLimit = 2; $products = $db->arraybuilder()->paginate("products", $page); echo "showing $page out of " . $db->totalPages;MAP
純粋な配列で結果を取得するのではなく、必要なキーを含む連想配列で結果を取得することも可能です。get() で取得するフィールドが 2 つだけの場合は配列($k => $v)で、それ以外の場合は配列 ($k => 配列 ($v, $v)) で結果を返します。
$user = $db->map ('login')->ObjectBuilder()->getOne ('users', 'login, id'); Array ( [user1] => 1 ) $user = $db->map ('login')->ObjectBuilder()->getOne ('users', 'id,login,createdAt'); Array ( [user1] => stdClass Object ( [id] => 1 [login] => user1 [createdAt] => 2015-10-22 22:27:53 ) )リターン型の定義
MysqliDbは、3つの異なるフォーマットで結果を返すことができます。配列の配列、オブジェクトの配列、Json文字列です。返り値の型を選択するには、ArrayBuilder()、ObjectBuilder()、JsonBuilder()メソッドを使用します。ArrayBuilder() はデフォルトの戻り値の型であることに注意してください。
// Array return type $= $db->getOne("users"); echo $u['login']; // Object return type $u = $db->ObjectBuilder()->getOne("users"); echo $u->login; // Json return type $json = $db->JsonBuilder()->getOne("users");生のSQLクエリの実行
$users = $db->rawQuery('SELECT * from users where id >= ?', Array (10)); foreach ($users as $user) { print_r ($user); }長いifチェックを避けるために、生のクエリの選択結果を扱うためのヘルパー関数があります。
結果の1行を取得します。$user = $db->rawQueryOne ('select * from users where id=?', Array(10)); echo $user['login']; // Object return type $user = $db->ObjectBuilder()->rawQueryOne ('select * from users where id=?', Array(10)); echo $user->login;1カラムの値を文字列として取得
$password = $db->rawQueryValue ('select password from users where id=? limit 1', Array(10). echo "パスワードは {$password} です。 注意: rawQueryValue() が配列ではなく文字列を返すようにするには、 クエリの最後に 'limit 1' を追加しなければなりません。複数の行から1列の値を取得します。
$logins = $db->rawQueryValue ('select login from users limit 10'); foreach ($logins as $login) echo $login;応用例
$params = Array(1, 'admin'); $users = $db->rawQuery("SELECT id, firstName, lastName FROM users WHERE id = ? AND login = ?", $params); print_r($users); // contains Array of returned rows // will handle any SQL query $params = Array(10, 1, 10, 11, 2, 10); $q = "( SELECT a FROM t1 WHERE a = ? AND B = ? ORDER BY a LIMIT ? ) UNION ( SELECT a FROM t2 WHERE a = ? AND B = ? ORDER BY a LIMIT ? )"; $results = $db->rawQuery ($q, $params); print_r ($results); // contains Array of returned rowsデータを取得する条件を設定する(WHERE句) & グループ化したデータを取得する条件を設定する(HAVING句)
where(), orWhere(), having(), orHaving() メソッドを使用すると、クエリの where と having の条件を指定することができます。where() でサポートされているすべての条件は、having() でも同様にサポートされています。
警告: カラム間の比較を行うためには、生のwhere条件のみをカラム名として使用するか、関数をバインド変数として渡すことはできません。
$db->where ('id', 1); $db->where ('login', 'admin'); $results = $db->get ('users'); // Gives: SELECT * FROM users WHERE id=1 AND login='admin';$db->where ('id', 1); $db->having ('login', 'admin'); $results = $db->get ('users'); // Gives: SELECT * FROM users WHERE id=1 HAVING login='admin';演算子を使用して、カラム間の比較
// 間違い $db->where ('lastLogin', 'createdAt'); // 正しい $db->where ('lastLogin = createdAt'); $results = $db->get ('users'); // Gives: SELECT * FROM users WHERE lastLogin = createdAt;$db->where ('id', 50, ">="); // or $db->where ('id', Array ('>=' => 50)); $results = $db->get ('users'); // Gives: SELECT * FROM users WHERE id >= 50;BETWEEN / NOT BETWEEN:
$db->where('id', Array (4, 20), 'BETWEEN'); // or $db->where ('id', Array ('BETWEEN' => Array(4, 20))); $results = $db->get('users'); // Gives: SELECT * FROM users WHERE id BETWEEN 4 AND 20IN / NOT IN:
$db->where('id', Array(1, 5, 27, -1, 'd'), 'IN'); // or $db->where('id', Array( 'IN' => Array(1, 5, 27, -1, 'd') ) ); $results = $db->get('users'); // Gives: SELECT * FROM users WHERE id IN (1, 5, 27, -1, 'd');OR CASE:
$db->where ('firstName', 'John'); $db->orWhere ('firstName', 'Peter'); $results = $db->get ('users'); // Gives: SELECT * FROM users WHERE firstName='John' OR firstName='peter'NULL比較
$db->where ("lastName", NULL, 'IS NOT'); $results = $db->get("users"); // Gives: SELECT * FROM users where lastName IS NOT NULLLIKE比較
$db->where ("fullName", 'John%', 'like'); $results = $db->get("users"); // Gives: SELECT * FROM users where fullName like 'John%'$db->where ("id != companyId"); $db->where ("DATE(createdAt) = DATE(lastLogin)"); $results = $db->get("users");Or raw condition with variables:
$db->where ("(id = ? or id = ?)", Array(6,2)); $db->where ("login","mike") $res = $db->get ("users"); // Gives: SELECT * FROM users WHERE (id = 6 or id = 2) and login='mike';ページネーション総数の例
$offset = 10; $count = 15; $users = $db->withTotalCount()->get('users', Array ($offset, $count)); echo "Showing {$count} from {$db->totalCount}";ページネーション総数の例
クエリーキーワード
LOW PRIORITY | DELAYED | HIGH PRIORITY | IGNORE およびその他の mysql キーワードを INSERT ()、REPLACE ()、GET ()、UPDATE ()、DELETE() メソッド、または FOR UPDATE | LOCK IN SHARE MODE に SELECT () に追加するには、以下のようにします。
$db->setQueryOption ('LOW_PRIORITY')->insert ($table, $param); // GIVES: INSERT LOW_PRIORITY INTO table ...$db->setQueryOption ('FOR UPDATE')->get ('users'); // GIVES: SELECT * FROM USERS FOR UPDATE;キーワードの配列を使用
$db->setQueryOption (Array('LOW_PRIORITY', 'IGNORE'))->insert ($table,$param); // GIVES: INSERT LOW_PRIORITY IGNORE INTO table ...同じようにキーワードはSELECTクエリでも使用できます。
$db->setQueryOption ('SQL_NO_CACHE'); $db->get("users"); // GIVES: SELECT SQL_NO_CACHE * FROM USERS;オプションで、メソッドチェーニングを使用して、何度もオブジェクトを参照せずに何度もどこを呼び出すことができます。
$results = $db ->where('id', 1) ->where('login', 'admin') ->get('users');データを削除する(DELETE文)
$db->where('id', 1); if($db->delete('users')) echo 'successfully deleted';取得するデータをソートする(ORDER BY句)
$db->orderBy("id","asc"); $db->orderBy("login","Desc"); $db->orderBy("RAND ()"); $results = $db->get('users'); // Gives: SELECT * FROM users ORDER BY id ASC,login DESC, RAND ();値で順番に並べる
$db->orderBy('userGroup', 'ASC', array('superuser', 'admin', 'users')); $db->get('users'); // Gives: SELECT * FROM users ORDER BY FIELD (userGroup, 'superuser', 'admin', 'users') ASC;setPrefix()の機能を使用していて、orderBy()メソッドでテーブル名を使用する必要がある場合は、
テーブル名が ``でエスケープされていることを確認してください。$db->setPrefix ("t_"); $db->orderBy ("users.id","asc"); $results = $db->get ('users'); // WRONG: That will give: SELECT * FROM t_users ORDER BY users.id ASC; $db->setPrefix ("t_"); $db->orderBy ("`users`.id", "asc"); $results = $db->get ('users'); // CORRECT: That will give: SELECT * FROM t_users ORDER BY t_users.id ASC;データをグループ化する(GROUP BY句)
$db->groupBy ("name"); $results = $db->get ('users'); // Gives: SELECT * FROM users GROUP BY name;内部結合を行う(INNER JOIN句)
$db->join("users u", "p.tenantID=u.tenantID", "LEFT"); $db->where("u.id", 6); $products = $db->get ("products p", null, "u.name, p.productName"); print_r ($products);結合文にAND条件を追加
$db->join("users u", "p.tenantID=u.tenantID", "LEFT"); $db->joinWhere("users u", "u.tenantID", 5); $products = $db->get ("products p", null, "u.name, p.productName"); print_r ($products); // Gives: SELECT u.login, p.productName FROM products p LEFT JOIN users u ON (p.tenantID=u.tenantID AND u.tenantID = 5)結合文にOR条件を追加
$db->join("users u", "p.tenantID=u.tenantID", "LEFT"); $db->joinOrWhere("users u", "u.tenantID", 5); $products = $db->get ("products p", null, "u.name, p.productName"); print_r ($products); // Gives: SELECT u.login, p.productName FROM products p LEFT JOIN users u ON (p.tenantID=u.tenantID OR u.tenantID = 5)プロパティ共有
プロパティをコピーすることも可能です。
$db->where ("agentId", 10); $db->where ("active", true); $customers = $db->copy (); $res = $customers->get ("customers", Array (10, 10)); // SELECT * FROM customers where agentId = 10 and active = 1 limit 10, 10 $cnt = $db->getValue ("customers", "count(id)"); echo "total records found: " . $cnt; // SELECT count(id) FROM users where agentId = 10 and active = 1サブクエリ
Subquery init
Subquery init without an alias to use in inserts/updates/where Eg. (select * from users)$sq = $db->subQuery(); $sq->get ("users"); A subquery with an alias specified to use in JOINs . Eg. (select * from users) sq $sq = $db->subQuery("sq"); $sq->get ("users"); Subquery in selects: $ids = $db->subQuery (); $ids->where ("qty", 2, ">"); $ids->get ("products", null, "userId"); $db->where ("id", $ids, 'in'); $res = $db->get ("users"); // Gives SELECT * FROM users WHERE id IN (SELECT userId FROM products WHERE qty > 2)MySQLサブクエリを使ったINSERT文
$userIdQ = $db->subQuery (); $userIdQ->where ("id", 6); $userIdQ->getOne ("users", "name"), $data = Array ( "productName" => "test product", "userId" => $userIdQ, "lastUpdated" => $db->now() ); $id = $db->insert ("products", $data); // Gives INSERT INTO PRODUCTS (productName, userId, lastUpdated) values ("test product", (SELECT name FROM users WHERE id = 6), NOW());MySQLサブクエリを使ったJOIN文
$usersQ = $db->subQuery ("u"); $usersQ->where ("active", 1); $usersQ->get ("users"); $db->join($usersQ, "p.userId=u.id", "LEFT"); $products = $db->get ("products p", null, "u.login, p.productName"); print_r ($products); // SELECT u.login, p.productName FROM products p LEFT JOIN (SELECT * FROM t_users WHERE active = 1) u on p.userId=u.id;EXISTS と NOT EXISTS
$sub = $db->subQuery(); $sub->where("company", 'testCompany'); $sub->get ("users", null, 'userId'); $db->where (null, $sub, 'exists'); $products = $db->get ("products"); // Gives SELECT * FROM products WHERE EXISTS (select userId from users where company='testCompany')Has
この関数の前に where メソッドを呼び出して指定した where 条件を満たす要素が少なくとも存在する場合に TRUE を返す便利な関数です。
$db->where("user", $user); $db->where("password", md5($password)); if($db->has("users")) { return "You are logged"; } else { return "Wrong user/password"; }Helper methods
データベースから切断
$db->disconnect();mysql の接続が切れた場合の再接続
if (!$db->ping()) $db->connect()最後に実行されたSQLクエリを取得します。この関数がSQLクエリを返すのはデバッグ目的のみであることに注意してください。
$db->get('users'); echo "Last executed query was ". $db->getLastQuery();テーブルが存在するかどうかをチェック
if ($db->tableExists ('users')) echo "hooray";mysqli_real_escape_string() wrapper:
$escaped = $db->escape ("' and 1=1");トランザクションヘルパー
トランザクションはinnoDBのテーブルで動作していることを覚えておいてください。挿入に失敗した場合は、トランザクションをロールバックします。
$db->startTransaction(); ... if (!$db->insert ('myTable', $insertData)) { //Error while saving, cancel new record $db->rollback(); } else { //OK $db->commit(); }エラーヘルパー
クエリを実行した後、エラーが発生したかどうかをチェックするオプションがあります。
MySQLのエラー文字列や、最後に実行したクエリのエラーコードを取得することができます。$db->where('login', 'admin')->update('users', ['firstName' => 'Jack']); if ($db->getLastErrno() === 0) echo 'Update succesfull'; else echo 'Update failed. Error: '. $db->getLastError();クエリ実行時間のベンチマーク
クエリの実行時間を追跡するためには、setTrace()関数を呼び出す必要があります。
$db->setTrace (true); // As a second parameter it is possible to define prefix of the path which should be striped from filename // $db->setTrace (true, $_SERVER['SERVER_ROOT']); $db->get("users"); $db->get("test"); print_r ($db->trace);[0] => Array ( [0] => SELECT * FROM t_users ORDER BY `id` ASC [1] => 0.0010669231414795 [2] => MysqliDb->get() >> file "/avb/work/PHP-MySQLi-Database-Class/tests.php" line #151 ) [1] => Array ( [0] => SELECT * FROM t_test [1] => 0.00069189071655273 [2] => MysqliDb->get() >> file "/avb/work/PHP-MySQLi-Database-Class/tests.php" line #152 )テーブルロック
テーブルをロックするには、setLockMethodと一緒にロックメソッドを使用します。
次の例では、書き込みアクセスのためにテーブルのユーザをロックします。$db->setLockMethod("WRITE")->lock("users");別のロックを呼び出すと、最初のロックが解除されます。
$db->unlock();以前にロックされていたテーブルのロックを解除します。複数のテーブルをロックするには、配列を使用します。
$db->setLockMethod("READ")->lock(array("users", "log"));これは、テーブルのユーザーとログをロックします。その後に*unlock()を使用するか、
テーブルがロックされたままになることを確認してください!
- 投稿日:2020-07-21T18:19:45+09:00
ウェブカツ!!が業界初のプログラミング漫画「はたらくプログラミング」を作ってしまった話
まえおき
どうも、最近運営しているプログラミングスクール「ウェブカツ!!」を売却しようとして「40億で売れる?」ってIT業界で有名なM&Aエージェントに相談してみたら「25億が現実的な落とし所ですねー。。」と渋い顔で言われてしまった、かずきちです。
一時、ベンチャー経営者やアンチがうちの生徒雇わない発言して物議を醸しましたが、一向にうちの生徒の内定報告いただいている状態で何よりです。
今年の秋口からは、うちの本が続々と出ます。
SNSマーケの口コミのみで、広告やSEOすらやってなかったので、もう
伸び代しかないですね。(ケイスケホンダ選手風)アクティブで一時期1500人超える勢いだったんですが、安っぽいアフィリエイターみたいな副業気分で学ぼうとしてる甘っちょろい人間も増えてたので、僕が相当生徒数削りました。事業やってて思うのは、やっぱ費用が安いと意識の安い人間が入りますね。
(安くしちゃえば1万人は超えるし、売り上げも上がるのは分かってますが、その分しょうもないエンジニア増やしてもなという。)因みにうちで身に付くレベルがどれかというと卒業したばかりの生徒達が作ったものを一部お見せするとこんな感じです。
ウェブカツ卒業生に仕事として頼んだ実際に世に出されるサービスをご紹介。
— かずきち@プログラミングスクール経営者 (@kazukichi3110) February 24, 2020
卒業するとこれくらいのものが作れるスキルがつくってこと。
ちなみに外部の別サービスとシステム連携までしてます。
要は仕事として十二分に頼めるレベルってことです。#ウェブカツ #ウェブカツ女性割引 pic.twitter.com/MWnH578PC0業界未経験のウェブカツ生徒達がチーム開発で作ったサービスが近々リリースされます
— かずきち@プログラミングスクール経営者 (@kazukichi3110) June 29, 2020
ビジネス要件、市場調査からプロとして本当に必要なものを教えてますが、もう未経験とは言わないよね、これ#Progate #テックアカデミー #techacademy#テックキャンプ#侍エンジニア塾#SkillHacks #デイトラ pic.twitter.com/qTCdXMEErmhttps://itengineer-scouter.com/
※このサービスは、今は余力がないので運営ほったらかしてますが、スクールや教育が増えれば今後確実に定量評価出来るものが必要になるんでコンテンツちゃんと考えれば伸ばせるやつ。
競合ではpaizaとかあって僕もやりましたが、あれってエンジニアとしてのお仕事で使う技術能力とはかなりかけ離れちゃってるんですよね。技術というより数学テストだし。うちは他スクールと違って、生徒に「作品」を作らせることはしてません。
だって、仕事としてお金もらってやってるのって
「商品」を作ること
ですから。趣味レベルのものを作ってもしょうがないんですよね。
「商品」として成り立つレベルが作れなきゃ。うちの生徒には元医師やらBIG4税理士法人、大手金融機関、大手メーカー勤めの高学歴な人〜中卒、40代主婦まで、地域は北海道から沖縄果てはフィリピン、マレーシア、インド、デンマークといったバリエーション豊かな人達が学んでいます。
(中卒も40代主婦もきちんと内定もらって今はエンジニアとしてバリバリやっているので、これからフリーランスで稼いでくれるのが楽しみです)余談ですが、最近テック〇〇の面談受けた人がまた入ってきたんですが、営業に
「都内に出てこれない人は本気度が低いから無理だよ」
と言われたそうです。(うちは地方でも内定決まっているというのに。。)
都内が案件多いとはいえ、斡旋して自分らの利益にしたいからとはいえ。ね。
まぁ、正社員の斡旋するだけで、年収の3割もらえるんで、一人100万以上入ってくるものね。
そりゃ、売り上げ主義でいけば都内就職者だけ扱いたいよね。「はたらくプログラミング」を作りたい!
前置き長くなりましたが、そんな中で今回うちの生徒(今は卒業生)で「ちょっと昔趣味で漫画描いてた」という人に
「はたらく細胞」みたいにプログラミング版を作りたいんだけど出来ない?
とお願いし、それがようやく完成。反響も上々なようで今回その製作の裏側をご紹介したいと思います。
【漫画】はたらくプログラミング 第1話 (1/5) pic.twitter.com/WI7ywZKty1
— とりたす (@yuudori) March 11, 2020amazonとboothで現在発売中です。
https://www.amazon.co.jp/dp/B087Z6J1RZ/ref=cm_sw_r_tw_dp_x_-qQfFbBE70Y32「はたらくプログラミング」を作ろうと思った経緯
僕はいわゆる「ガチエンジニア」じゃ決してありません。
技術自体が全く好きではありません。
異業種の営業マンからエンジニアに転向する際の独学で、このITエンジニア業界の
「教育能力なさすぎ」
「伝えるスキルなさすぎ」
「ビジネス、マーケティング能力なさすぎ」
の3拍子にイラッとし、その改革のためにスクールを立ち上げた(昔はただの動画サービスだったけど)わけですが、そんな中でずっと漫画で学べりゃ楽なのになぁ
と思っていました。
僕は漫画大好きなんですもの。字とか嫌い。
スクールも全て動画で教えているくらいですしね。が、漫画を書くスキルはもちろんないですし、そもそもどんな漫画にすりゃいいのか思いつかなかったんですね。
そんなある時、出会っちゃったわけですよ、あれに。「はたらく細胞」
ですよ。
これを読んだ瞬間、降りてきちゃったわけです。神が。
これだ!って感覚です。
「はたらく細胞」を
パインスパイアしよう!そう思ったわけです。
神の命です。「はたらく細胞」を
パクインスパイアしちゃいなさい。そういう神の命を頂いたわけです。
何をどういう順序でどういう世界観で伝えるか。それが重要だ。
とはいえ、「プログラミングを擬人化する」というところまではきたんですが(まぁ、調べたらそういう擬人化した漫画ちっくなものはありましたが)、それぞれをどう伝えるか悩みました。
実際、わかばちゃんシリーズであったりコード学園ってのがありましたが、どっちも僕が求めるものとは違ったんです。ちなみに僕はいわゆる「オタク」が好きそうな萌え系キャラが大嫌いです。
エンジニア界隈では好かれるでしょうが、僕のような一般人からしたら気持ち悪さしかないんですね。(申し訳ないけどそれが本音だよ)
だから、そんな擬人化キャラにはしたくなかったですし、わかばちゃんのような4コマ漫画では、はたらく細胞のように難解な専門知識を漫画としてストーリー仕立てで各キャラの個性や世界観も感じながら楽しみながら学習したい
という僕の堕落し甘えきった目的には到達できなかったんです。
だって、あれは漫画部分が一部あるだけの「解説本」ですし。
初心者の頃の僕はコードが出てきた段階で拒絶反応ですしね。
一番の初心者ってそっからなわけで。僕はエンジニアが大嫌いだ
そもそも、僕は異業種の人をエンジニアとして育ててこの業界に送り込みたいんです。
だって僕はエンジニア大嫌いなんですもの。
でも、
エンジニアは大好きなんです。
言ってること分かります?
営業やってた僕からすれば、エンジニアという職業は指動かしてるだけで金もらえるわ、
リモートも出来るわ、
ヘッドフォンしながら仕事出来るわ、
スマホいじりながら仕事出来るわ、
短期間で一気に報酬上げられるわ、
自動化して自分で金稼げるわ
で「天国」なんですよ。
エンジニアで月100万稼ぐのと営業で月100万稼ぐのじゃ天と地ほどの差な労力です。
女性ならライフステージによっても他の仕事より融通効きやすいだろうしね。
(女っ気なくてむさ苦しい現場が多いのが残念だけども。うちのスクールの女性比率はかなり高いので女性生徒からすると現場出てみて女性が少なすぎる現状にびっくりするみたいです。)でも、僕のQiitaやらTwitterやらにウジのように湧いてくるキモいエンジニアは嫌いなんですよ。
教え方下手くそなエンジニアも、ビジネスもわからない子供エンジニアも嫌いなんですよ。
商品より作品作りたがったり、顧客課題をすっぽかして技術情報だけで鼻息荒くしてるエンジニアも大嫌いなんですよ。だから、もうこの業界変えるには既存エンジニアより異業種のコミュケーション能力高い人や素養ある人に営業もビジネスも税務も法務も教えてエンジニアも並より上のスキル教える方が大事だと思っているわけです。
(最近、SNS訴訟に強い弁護士が教えてくれる法務部がうちのスクールに出来ました。営業部も日本で唯一大学で営業を学問として教えている生保で元億プレーヤーの花田敬さんに見てもらってます。)なので、そもそも
プログラミングって何それ?聞いたことあるくらいだけど
な人たちでも読みたくなるようなものを作りたかったんですね。
売れない営業マンが漫画喫茶で手にとって読めるレベルのやつが。
そんで、あわよくば「あ、プログラミングって面白そうかも」
と思ってくれりゃあ御の字っていう。
まぁ、とは言え、結構細かな技術部分の違いも入れて作ってるので、プログラミング学習中の人でもためになる内容になってます。
なので、各スクールさんで補助教材の1つとして使えたり、プログラミングが小学校必修となって親御さんなり教師がプログラミングがどんなものか学ぶ第一歩としても役立つと思います。
(実際に今有名な出版社さんから、うちの持ち出しなしで出版依頼も来てます)
世界観どうしよう
ターゲットも定まったところで世界観どうしようか悩みました。
ちなみにこの漫画は「漫画を読みながらWEBプログラミングの世界を学べる」ようにしたかったので、擬人化は
・HTML言語
・CSS言語
・JavaScript言語
・PHP言語
・SQL言語
を出そうと思ってました。
それぞれの言語の役割がざっくりイメージ出来て、自分たちが普段見ているHPが表示される中ではこんなやり取りが行われているんだという通信の流れもイメージできればいいなと。
(あとあとでRubyも出すことにしました。どんな登場でどんなキャラかは漫画でのお楽しみで)
まぁ、キャラの動かし方としては、二郎系インスパイアの感じにしかならんだろうなとは思っていたので、
あとは色々とやり取りを重ねていくうちに世界観が見えてくるようになりました。
HTML言語のキャラをざっくりどうするか
キャラ設定的なのどうするか考えていったんですが、
htmlはwebの根幹みたいなもんでしょう。
建築で言えば「基礎工事」や「家の骨組み」を作る人なわけなので、熱血漢なてやんでぇ大工職人
という感じになりました
まぁ、ベタですが変に凝ると初心者がそもそも入っていけない世界になっていっちゃうので、ベタな王道で行くことにしました。css言語のキャラをざっくりどうするか
cssは骨組みだけの簡素な家に外観つけて華やかにしていく美術さん的な感じですね。
ここらへんもベタに行きたかったので、お色気担当を入れることになり、お色気のある大人な美術担当の女性
にすることになりました。
ストーリー内でも、htmlが土台を作り、cssが装飾を行う。という実際のweb制作の仕組みと同じにしています。
(こんな女性が実際の現場にいて欲しいと切に願ってます)js言語のキャラをざっくりどうするか
これは、はたプロ(はたらくプログラミング)作りたい!ってちょろってツイートした時に
「言語を女性に全て擬人化したらこんなんだよね」
ってのが生徒からもらってたんで、それが採用されました。jsはまぁフロントやってる人なら分かりますが、javaなりphpなりといった言語と違って標準のオブジェクトをぶっ壊す事も出来てしまうし、型とか関係なく放り込めるし、
ある意味柔軟で自由奔放、ある意味で大雑把
みたいな言語なので、そのまま
自由奔放でガサツで未熟感のある女性
になりました。
たぶん、B型女性かO型でしょうね。
僕はA型なんで、たぶん合わないです。
(振り回されてみたい願望もあるけど)また、このjsちゃんをメインキャラに据える事にしました。
まぁ、うちのスクールがそもそも
バックも分かるフロントエンドエンジニア
を創出してるので、自然とjsメインになった感じです。
今後のテクノロジー成長の事も考えるとnodeもあるし、業務システムなどにある様な無機質な「システム」ではなく「サービス」としての価値勝負になっていき、UIリッチ、UXリッチでSPA化が当たり前になり、バックはAPIのみで簡素化されていく事を考えるとフロントエンド案件が今後どんどん増えていくのは必死ですしね。つづく
- 投稿日:2020-07-21T18:11:05+09:00
【超初心者用】Laravel用のサーバーを起動する
Apacheを使用しなくてもいい
Apacheは8000をリッスンしている。
Apacheを起動してブラウザに
localhost
を入力すると、ルートディレクトリを開くことになるので、設定しているファイルが開かれる。自分の場合は
top.php
というファイルが開かれる。Laravelを使うときにもサーバーをたちあげる必要あり
動画なので説明をみていると、MAMPを使っていたり、いきなりlocalhostにアクセスすることで
この画面が起動していましたが、自分はApacheを使用してサーバーを立ち上げていて、8000をlocalhostに設定していました。
なので当然上記の画面が表示されませんでした。
ポートを指定してサーバーを立ち上げる?!
ウェブ職人のためのPHPフレームワーク。というサイトにちゃんと便利なことも書いてありました。
http://laravel.jp/https://readouble.com/laravel/4.2/ja/quick.html
$ php artisan serve --port=8080後ろの
--port=8080
というのが8080をポート番号に指定する
ということらしい。
これにより、複数のサーバーを立てる場合はこのポート番号をかぶらないように指定すればいいみたいですね。
- 投稿日:2020-07-21T16:52:53+09:00
【超初心者用】Laravelのインストールがうまくいかなかった
comporserでlaravelをインストールしようとしたら
$ composer global require "laravel/installer"
Using version ^3.2 for laravel/installer ./composer.json has been updated 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 - Installation request for laravel/installer ^3.2 -> satisfiable by laravel/installer[v3.2.0]. - laravel/installer v3.2.0 requires ext-zip * -> the requested PHP extension zip is missing from your system. Installation failed, reverting ./composer.json to its original content.問題が発生しているらしい
./composer.json has been updated
なんかよくわからないが、バージョンが違うのかな。
先の方を読むと、
Installation request for laravel/installer ^3.2 -> satisfiable by laravel/installer[v3.2.0].
リクエストを
laravel/installer[v3.2.0]
に変えればいいよという感じですかね。
laravel/installer v3.2.0 requires ext-zip * -> the requested PHP extension zip is missing from your system
ここは、PHPのextensionのzipが見つからないということでしょうか。とりあえず、最初の方を試してみる。
laravel/installer[v3.2.0]で実行してもダメ
[InvalidArgumentException] Could not find a matching version of package laravel/installer[v3.2.0]. Check the package spelling, your version constraint and that the package is available in a stability which matches your minimum-stability (stable). require [--dev] [--prefer-source] [--prefer-dist] [--fixed] [--no-progress] [--no-suggest] [--no-update] [--no-scripts] [--update-no-dev] [--update-with-dependencies] [--update-with-all-dependencies] [--ignore-platform-reqs] [--prefer-stable] [--prefer-lowest] [--sort-packages] [-o|--optimize-autoloader] [-a|--classmap-authoritative] [--apcu-autoloader] [--] [<packages>]...ext-zipが足りない
laravel/installer v3.2.0 requires ext-zip * -> the requested PHP extension zip is missing from your system.
という記載があるので、
laravel/installer v3.2.
の要求に関してはext-zip
が必要だということですかね。とりあえずPHPをインストールし直した
$ brew install phpでインストールし直しました
できた!
$ composer global require "laravel/installer" Changed current directory to /Users/onoharamakoto/.composer Using version ^3.2 for laravel/installer ./composer.json has been updated Loading composer repositories with package information Updating dependencies (including require-dev) Package operations: 19 installs, 0 updates, 0 removals - Installing symfony/polyfill-php80 (v1.18.0): Downloading (100%) - Installing symfony/process (v5.1.2): Downloading (100%) - Installing symfony/polyfill-ctype (v1.18.0): Downloading (100%) - Installing symfony/filesystem (v5.1.2): Downloading (100%) - Installing symfony/polyfill-mbstring (v1.18.0): Downloading (100%) - Installing symfony/polyfill-intl-normalizer (v1.18.0): Downloading (100%) - Installing symfony/polyfill-intl-grapheme (v1.18.0): Downloading (100%) - Installing symfony/string (v5.1.2): Downloading (100%) - Installing psr/container (1.0.0): Downloading (100%) - Installing symfony/service-contracts (v2.1.3): Downloading (100%) - Installing symfony/polyfill-php73 (v1.18.0): Downloading (100%) - Installing symfony/console (v5.1.2): Downloading (100%) - Installing psr/http-message (1.0.1): Downloading (100%) - Installing psr/http-client (1.0.1): Downloading (100%) - Installing ralouphie/getallheaders (3.0.3): Downloading (100%) - Installing guzzlehttp/psr7 (1.6.1): Downloading (100%) - Installing guzzlehttp/promises (v1.3.1): Downloading (100%) - Installing guzzlehttp/guzzle (7.0.1): Downloading (100%) - Installing laravel/installer (v3.2.0): Downloading (100%) symfony/service-contracts suggests installing symfony/service-implementation symfony/console suggests installing symfony/event-dispatcher symfony/console suggests installing symfony/lock symfony/console suggests installing psr/log (For using the console logger) guzzlehttp/psr7 suggests installing zendframework/zend-httphandlerrunner (Emit PSR-7 responses) guzzlehttp/guzzle suggests installing psr/log (Required for using the Log middleware) Writing lock file Generating autoload files 11 packages you are using are looking for funding. Use the `composer fund` command to find out more!なんかエラーメッセージが消えました。
どうやらインストールできたようです。パスを通す
$ vim ~/.bashrc新しくファイルを作成して開きます。
下の記述を入れる。export PATH="$HOME/.composer/vendor/bin:$PATH"
:wq
で保存して終了する。次のコマンドを実行する
$ source ~/.bashrcここまで来たらLaravelのコマンドが使える
$ laravel Laravel Installer 3.2.0 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 -v|vv|vvv, --verbose Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug Available commands: help Displays help for a command list Lists commands new Create a new Laravel applicationエラーメッセージが出てません。動いているらしい。
ターミナルをいったん閉じると
zsh: command not found: laravelLaravelのコマンドは使えなくなるみたいです。
もう一度source ~/.bashrc
を実行してからやればまた使えるようになりました。結論
Problem 1 - Installation request for laravel/installer ^3.2 -> satisfiable by laravel/installer[v3.2.0]. - laravel/installer v3.2.0 requires ext-zip * -> the requested PHP extension zip is missing from your system.上記のようなエラーが出た場合は
1. PHPをインストールし直すbrew install php
2.composer global require "laravel/installer"
を実行してlaravelをインストールするこれで大丈夫みたいです。
真似しないようにお願いします
当方、かなりの素人です。何をやっても一つずつエラーが発生して前に進まないのです。
とりあえず作業を記録しています。自分向けに書いてます。できるだけ他の肩の記事を参考に処理を進めてください。大変なことになるかもしれませんので。
- 投稿日:2020-07-21T16:26:35+09:00
phpDocumentorでNo summary was found for this file.
TL;DR
PHP7.1以上のプロジェクトのドキュメントをphpDocumentor2で生成しようとしていませんか?GitHubのREADMEをきちんと読みましょう!
以下そこにたどり付くまでの記録です。
事象1
public const
がダメ?以下のファイルを
phpDocumentor
に突っ込むとNo summary was found for this file
というエラーが出るAwesome.php<?php /** * AwesomeなClassを定義するファイル */ namespace MyAwesome; /** * AwesomeなClass */ class Awesome { /** * PO は HOGEHOGE とする * * @var string */ public const PO = "HOGEHOGE"; }対処
検索
StackOverflow「phpDocブロックを2つ置けば解決する」
ググり方が下手なので、これ以外の情報は検索しても出てこなかった切り分け
定数のdocコメントを消してもダメ
Awesome.php<?php /** * AwesomeなClassを定義するファイル */ namespace MyAwesome; /** * AwesomeなClass */ class Awesome { public const PO = "HOGEHOGE"; }
定数ごと消すとOK
Awesome.php<?php /** * AwesomeなClassを定義するファイル */ namespace MyAwesome; /** * AwesomeなClass */ class Awesome { }
関数は定義してもOK
Awesome.php<?php /** * AwesomeなClassを定義するファイル */ namespace MyAwesome; /** * AwesomeなClass */ class Awesome { /** * po は HOGEHOGE * * @return string */ public function po(): string { return "HOGEHOGE"; } }
![]()
public const
をconst
にするとOKAwesome.php<?php /** * AwesomeなClassを定義するファイル */ namespace MyAwesome; /** * AwesomeなClass */ class Awesome { const PO = "HOGEHOGE"; }
![]()
public
を消すとdocコメントを付けてもOKAwesome.php<?php /** * AwesomeなClassを定義するファイル */ namespace MyAwesome; /** * AwesomeなClass */ class Awesome { /** * PO は HOGEHOGE とする * * @var string */ const PO = "HOGEHOGE"; }原因
オブジェクト定数のアクセス範囲を指定するとダメっぽい…?PHP 7.1から言語機能に追加されたはずでは……
事象2
nullable
な引数がダメ?以下のファイルを
phpDocumentor
に突っ込むとNo summary was found for this file
というエラーが出るAwesome2.php<?php /** * Awesome2 を定義するファイル */ namespace MyAwesome; use OtherPackage\OtherClass; /** * Awesomeなclassその2 */ class Awesome2 { /** * 何もしないコンストラクタ * * @param OtherClass|null $other */ public function __construct(?OtherClass $other) { } }対処
nullableじゃなくしてみる
Awesome2.php<?php /** * Awesome2 を定義するファイル */ namespace MyAwesome; use OtherPackage\OtherClass; /** * Awesomeなclassその2 */ class Awesome2 { /** * 何もしないコンストラクタ * * @param OtherClass $other */ public function __construct(OtherClass $other) { } }
デフォルト引数を指定してみる
Awesome2.php<?php /** * Awesome2 を定義するファイル */ namespace MyAwesome; use OtherPackage\OtherClass; /** * Awesomeなclassその2 */ class Awesome2 { /** * 何もしないコンストラクタ * * @param OtherClass|null $other */ public function __construct(OtherClass $other = null) { } }原因
nullable
な型指定がダメっぽい…?PHP 7.1から言語機能に追加されたはずでは……事象3
nullable
な返り値がダメ?以下のファイルを
phpDocumentor
に突っ込むとNo summary was found for this file
というエラーが出るAwesome3.php<?php /** * Awesome3 を定義するファイル */ namespace MyAwesome; /** * Awesomeなclassその3 */ class Awesome3 { /** * 名前を検証する * * @param string $name * @return string|null */ public function validate(string $name): ?string { if($name === "po"){ return null; }else{ return $name; } } }対処
![]()
mixed
にしてみるAwesome3.php<?php /** * Awesome3 を定義するファイル */ namespace MyAwesome; /** * Awesomeなclassその3 */ class Awesome3 { /** * 名前を検証する * * @param string $name * @return string|null */ public function validate(string $name) { if($name === "po"){ return null; }else{ return $name; } } }原因
nullable
な型指定がダメっぽい…?PHP 7.1から言語機能に追加されたはずでは……結論
「No summary was found for this file」というエラーメッセージに騙されましたが、単純にGitHubのREADMEに書いてある通りphpDocumentor2はPHP7.0までしか対応してないという話でした。~完~
おとなしくphpDocumentor3を待ちましょう。今RC版までリリースされています。
- 投稿日:2020-07-21T16:13:17+09:00
PHPとJavaScriptを使ったプルダウンを覚えたので記録しておく
PHPを使ったプルダウンを覚えたので記録しておく。
一部分を抜き出しているので非常にわかりにくいかもしれませんが...
PHP、JavaScript、Ajax、jsonを使用。PHPファイルその1
<select name="category" size="1" id="category"> <option value="大型犬" data-filter="大型犬">大型犬</option> <option value="中型犬" data-filter="中型犬">中型犬</option> <option value="小型犬" data-filter="小型犬">小型犬</option> </select> <select name="subcategory" size="1" id="subcategory"> </select>サブカテゴリにデータを入れていきます。
PHPファイルその2
<?php if(isset($_GET['category']) == true){ $category = $_GET['category']; } //json形式で項目を入力しておく if($category == '大型犬'){ $array = "[{\"name\": \"ゴールデンレトリバー\", \"value\": \"ゴールデンレトリバー\"},{\"name\": \"ラブラドールレトリバー\", \"value\": \"ラブラドールレトリバー\"},{\"name\": \"サモエド\", \"value\": \"サモエド\"}]"; }else if($category == '中型権'){ $array = "[{\"name\": \"コーギー\", \"value\": \"コーギー\"},{\"name\": \"柴犬\", \"value\": \"柴犬\"}]"; }else if($category == '小型犬'){ $array = "[{\"name\": \"チワワ\", \"value\": \"チワワ\"},{\"name\": \"マルチーズ\", \"value\": \"マルチーズ\"}]"; } header('Content-Type: application/json; charset=utf-8'); print($array);//カテゴリ設定 $('#category').on('change', function (event) { category(); }); }); //カテゴリ設定の関数 function category() { $.ajax({ url: '***ファイル名を入力***', type: 'GET', data: { category: $('#category').val(), select: 'subcategory', }, dataType: 'json', cashe: false }).done(function (data) { const target_number = event.target.value; const subcategory = $('#subcategory'); const data_sub = $('#category').children().eq(target_number).data(subcategory); subcategory.empty(); for (let i = 0; i < data.length; i++) { let option = $('<option></option>'); option.val(data[i]['value']); option.text(data[i]['name']); subcategory.append(option); } }).fail(function (data, textStatus, error) { alert('error'); }); }
- 投稿日:2020-07-21T15:41:49+09:00
PHPを使ったページネーション(ページング)を習得したので記録しておく
PHPを使った恐らく1番簡単なページネーション(ページング)を習得したので記録しておく
今回は複数の画像を表示することを想定。
一部分を抜き出してきたためやや分かりにくいがメモ程度に。
$_GET取得です。
デザインしやすいようリストを使用。//ページネーション設定 $perPage = 6;//最大表示画像数 $imgs = count($img);//画像数をカウント $maxPage = ceil($imgs / $perPage); if (!isset($_GET['page'])){ $page = 1; } else { $page = (int)$_GET['page']; } $startNo = ($page - 1) * $perPage; $img = array_slice($img, $startNo, $perPage, true); //ページネーション表示 if ($page > 1) {//最初以外のページにいる場合は最初のページをリンク表示 print('<li><a href="./index.php?page=1"><< first</a></li>'); } else if($page == 1){//最初のページにいる場合は表示しない print(''); } //全ページをリンク表示 for ($i = 1; $i <= $maxPage; $i++) { if ($i == $page) {//閲覧中のページはリンクなし print('<li>'.$i.'</li>'); } else {//それ以外のページはそのページへのリンクを貼る print('<li><a href="./index.php?page='.$i.'">'.$i.'</a></li>'); } } if ($page < $maxPage) {//最後以外のページにいる場合は最後のページをリンク表示 print('<li><a href="./index.php?page='.$maxPage.'">last >></a></li>'); } else if($page == $maxPage){//最後のページにいる場合は表示しない print(''); }CSS部分はこんな感じで中央寄せのページネーション。
a{ color: yellow; text-decoration: none; } li{ color: white; list-style: none; text-align: center; padding: 16px; display: inline-block; }
- 投稿日:2020-07-21T15:01:19+09:00
Laravel ルーティング情報を表示してくれるコマンド
- 投稿日:2020-07-21T12:17:52+09:00
[PHP on Windows] composer をインストーラから導入、プロキシ関連エラーが出たら手入力指定で回避できるかも
はじめに
企業内プロキシ配下の Windows10 に XAMPP + Composer を導入しました。
Composer-setup.exe から既定の設定でインストールしたとき、次のエラーで失敗しました。The "https://getcomposer.org/versions" file could not be downloaded: SSL operation failed with code 1. OpenSSL Error messages: error:1408F10B:SSL routines:ssl3_get_record:wrong version number Failed to enable crypto failed to open stream: operation failed Retrying...
エラーの原因はさまざまあるかもしれませんが、この現象を回避して無事インストールできたので一例として共有します。
環境
回避策
Composer-setup.exe インストーラーのウィザード画面で初期設定される、レジストリから読み出したプロキシ設定を、手入力したものへ変更します。
具体的には、Proxy Settings の画面で...
- Ignore settings from registry にチェックを入れます。Enter proxy url の初期設定が消え、Use a proxy...のチェックも消えます。
- Use a proxy server to connect to internet にチェックを入れます。Enter proxy url へ入力可能になります。
- Enter proxy url へプロキシサーバー情報を手入力します。(例 http://proxy.example.com:3128/)
- "Next >" で次の画面に進みます。
以上です
- 投稿日:2020-07-21T02:10:05+09:00
【Laravel】ロリポップ でComposer requireをするとPHP Fatal error: Out of memoryが出る場合にやったこと
原因
文字通りメモリ不足です。
つまりメモリがあれば良いわけなのですが、ロリポップではメモリを上限に設定してもPHP Fatal error: Out of memoryが出ます。
また、そもそもロリポップではphp.iniが変更できなかったりと制限があります。
$ composer require intervention/imageとかが普通にできないです。
そういえばcomposerでlaravelをインストールしようとした時もエラーが出たような・・・対処(正解かどうかはわからない)
個人的にやったことをまとめます。
僕はこのやり方で一応なんとかなったのですが、責任は追いません。
というか、もっと良い方法ありませんか...?
scpコマンドを使用して1回ローカルに落とす
$ scp -r -P[ポート番号] ドメイン名@ssh.lolipop.jp:web [ダウンロード先]scpコマンドはこちらの記事でわかりやすく解説してくださってます。
例えばこんな感じです。(macのデスクトップのhogeフォルダにコピーする場合)
$ scp -r -P1234 ×××@ssh.lolipop.jp:web ~/Desktop/hogeポート番号・パスワードが必要なので、そこはロリポップのメニューの「SSH」から見てみてください。
あと結構時間がかかります。ローカルでcomposerを使う
$ cd [ダウンロードしたフォルダのパス] $ composer require [パッケージ名]composerがcommand not foundの場合はインストールしましょう。
僕はこちらの記事を参考にしました。再びサーバーにコピー
$ scp -r -P[ポート番号] [ダウンロードしたいローカルのディレクトリパス] ドメイン名@ssh.lolipop.jp:upこれでwebディレクトリと同じ階層に、cpディレクトリが配置されました。
あとはwebディレクトリを削除し、cpディレクトリをwebにリネームすれば完了です。
$ mv web web2 (一応web2というディレクトリを作って今までのプロジェクトを保存しておく) $ rm web $ mv up webこれで一応完了なのですが、このあと画像をアップロードしたら画像がnot found(404)になるという事例が発生しました。
めちゃくちゃ焦りませした。。。
調べてみると、どうやらシンボリックを再作成する必要がありそうです。
ということで、
- 一旦public/storageを削除
- 再びシンボリックを作成
という処理をします。
# sshでログイン後・・・ $ cd web $ cd public $ rm storage $ cd ../ $ php artisan storage:linkこれで再びシンボリックが作成され、全ての工程が完了しました。。。
最後に・・・
きっともっと良い方法があるとは思うのですが(例えば手動でcomposer.jsonに追記して・・・とか)、僕の知識ではこれが一番安全でした。
そもそもレンタルサーバーでcomposerを使うのがいけないのかもしれませんね。
以上、Web初心者の苦労でした。
もっと良い方法あったらコメントお願いします!!!
- 投稿日:2020-07-21T02:10:05+09:00
【Laravel】ロリポップでComposer requireをするとPHP Fatal error: Out of memoryが出る場合にやったこと
原因
文字通りメモリ不足です。
つまりメモリがあれば良いわけなのですが、ロリポップではメモリを上限に設定してもPHP Fatal error: Out of memoryが出ます。
また、そもそもロリポップではphp.iniが変更できなかったりと制限があります。
$ composer require intervention/imageとかが普通にできないです。
そういえばcomposerでlaravelをインストールしようとした時もエラーが出たような・・・対処(正解かどうかはわからない)
個人的にやったことをまとめます。
僕はこのやり方で一応なんとかなったのですが、責任は追いません。
というか、もっと良い方法ありませんか...?
scpコマンドを使用して1回ローカルに落とす
$ scp -r -P[ポート番号] ドメイン名@ssh.lolipop.jp:web [ダウンロード先]scpコマンドはこちらの記事でわかりやすく解説してくださってます。
例えばこんな感じです。(macのデスクトップのhogeフォルダにコピーする場合)
$ scp -r -P1234 ×××@ssh.lolipop.jp:web ~/Desktop/hogeポート番号・パスワードが必要なので、そこはロリポップのメニューの「SSH」から見てみてください。
あと結構時間がかかります。ローカルでcomposerを使う
$ cd [ダウンロードしたフォルダのパス] $ composer require [パッケージ名]composerがcommand not foundの場合はインストールしましょう。
僕はこちらの記事を参考にしました。再びサーバーにコピー
$ scp -r -P[ポート番号] [ダウンロードしたいローカルのディレクトリパス] ドメイン名@ssh.lolipop.jp:upこれでwebディレクトリと同じ階層に、cpディレクトリが配置されました。
あとはwebディレクトリを削除し、cpディレクトリをwebにリネームすれば完了です。
$ mv web web2 (一応web2というディレクトリを作って今までのプロジェクトを保存しておく) $ rm web $ mv up webこれで一応完了なのですが、このあと画像をアップロードしたら画像がnot found(404)になるという事例が発生しました。
めちゃくちゃ焦りませした。。。
調べてみると、どうやらシンボリックを再作成する必要がありそうです。
ということで、
- 一旦public/storageを削除
- 再びシンボリックを作成
という処理をします。
# sshでログイン後・・・ $ cd web $ cd public $ rm storage $ cd ../ $ php artisan storage:linkこれで再びシンボリックが作成され、全ての工程が完了しました。。。
最後に・・・
きっともっと良い方法があるとは思うのですが(例えば手動でcomposer.jsonに追記して・・・とか)、僕の知識ではこれが一番安全でした。
そもそもレンタルサーバーでcomposerを使うのがいけないのかもしれませんね。
以上、Web初心者の苦労でした。
もっと良い方法あったらコメントお願いします!!!
- 投稿日:2020-07-21T00:21:12+09:00
Redis 安易になんでもSETしてたらGETできなくてハマった
サンプルコード
<?php namespace App\Controller\Component; use Cake\Controller\Component; use Cake\Core\Configure; use Predis\Client; class HogeCacheManagerComponent extends Component { /** @var object */ private $client; /** * initialize * * @param array $registory * @return void */ public function initialize(array $registory) { parent::initialize($registory); $this->client = new Client(Configure::read('Redis')); } /** * getCache method * * @param string $key * @return null|string */ public function getCache($key) { return $this->client->get($key); } /** * setCache method * * @param string $key * @param mixed $value * @return void */ public function setCache($key, $value, $expire = 600) { $this->client->set($key, json_encode($value)); $this->client->expire($key, $expire); } }テストコード
<?php namespace App\Test\TestCase\Controller\Component; use App\Controller\Component\HogeCacheManagerComponent; use Cake\Controller\ComponentRegistry; use Cake\TestSuite\TestCase; /** * App\Controller\Component\HogeCacheManagerComponent Test Case */ class HogeCacheManagerComponentTest extends TestCase { /** * Test subject * * @var \App\Controller\Component\HogeCacheManagerComponent */ private $HogeCacheManager; /** * setUp method * * @return void */ public function setUp() { parent::setUp(); $registry = new ComponentRegistry(); $this->HogeCacheManager = new HogeCacheManagerComponent($registry); } /** * tearDown method * * @return void */ public function tearDown() { unset($this->HogeCacheManager); parent::tearDown(); } /** * Test getCache method * * @return void */ public function testGetCache() { $this->assertEmpty($this->HogeCacheManager->getCache('fruits')); $this->HogeCacheManager->setCache('fruits', 'apple'); $this->assertSame('apple', str_replace('"', '', $this->HogeCacheManager->getCache('fruits'))); } /** * Test setCache method * * @return void */ public function testSetCache() { $this->assertEmpty($this->HogeCacheManager->getCache('animals')); $this->HogeCacheManager->setCache('animals', 'dog'); $this->assertSame('dog', str_replace('"', '', $this->HogeCacheManager->getCache('animals'))); } }SETの仕様
SET(key, value)
計算時間: O(1)
文字列値 value をキー key にセットします。文字列は1073741824バイト(1GB)以下でなければいけません。返り値
Status code replyを返す。引用元:http://redis.shibu.jp/commandreference/strings.html#command-SET
GETの仕様
GET(key)
計算時間: O(1)
指定したキー key に対応する値を取得します。もしキーが存在しなかったら特別な値 “nil” を返します。もしキーに対応する値が文字列型ではなかったらエラーが返ります。なぜなら GET は文字列型にしか対応していないからです。返り値
Bulk replyを返す。引用元:http://redis.shibu.jp/commandreference/strings.html#command-GET
ハマったこと
- SET時に keyを文字列以外の値にする
なぜハマったのか
- 上記に記されてるように、SETの仕様はバイト制限のみであり、型制限は設けられていない
- そのため、型を意識せずとも セットしたいkeyとvalueでセットできてしまう
ポイント
- SET時のkeyは 文字列型 にする
- 投稿日:2020-07-21T00:14:07+09:00
Laravel CRUD処理を使った投稿アプリを作成する その6 投稿編集機能
目的
- アプリを作成する上で基本となるCRUD処理を有したLaravelアプリをチュートリアル的に作成する方法をまとめる
実施環境
- ハードウェア環境
項目 情報 OS macOS Catalina(10.15.5) ハードウェア MacBook Pro (13-inch, 2020, Four Thunderbolt 3 ports) プロセッサ 2 GHz クアッドコアIntel Core i5 メモリ 32 GB 3733 MHz LPDDR4 グラフィックス Intel Iris Plus Graphics 1536 MB
- ソフトウェア環境
項目 情報 備考 PHP バージョン 7.4.3 Homwbrewを用いて導入 Laravel バージョン 7.0.8 commposerを用いてこちらの方法で導入→Mac Laravelの環境構築を行う MySQLバージョン 8.0.19 for osx10.13 on x86_64 Homwbrewを用いてこちらの方法で導入→Mac HomebrewでMySQLをインストールする 前提条件
- 実施環境に近い環境が構築されていること。
- 筆者は下記の方法で環境構築を行った。
前提情報
- DockerやAWSなどは使用せずにMacのローカルに実施環境と同じLaravel開発環境を構築して実施する。
- チュートリアルで実際に筆者が作成したソースコードをGitHubにて公開予定である。
- CRUD処理の作成完了を最短目標にしてバリデーションなどは後々設定することとする。
- 実施環境と同じ環境がDockerやAWSで用意できるなら都度読み替えていただければ実施が可能だと思う。
- 公式ドキュメントと一冊の技術書を元に本記事を記載する。
- Laravel 7.x
- PHPフレームワーク Laravel Webアプリケーション開発 バージョン5.5 LTS対応
- 本記事はシリーズとして内容を分割する予定である。記事のタグ「miriwo_laravelチュートリアル」を本シリーズの記事に付与するのでそのほかの記事がみたい方は活用していただきたい。
この記事の読後感
- 投稿内容を投稿後に編集することができる。
全ての記事(miriwo_laravelチュートリアル)を通した読後感
- Laravelアプリでログインなどのユーザ認証付き投稿アプリの作成ができる。
概要
- ルーティングの記載
- コントローラの記載
- ビューファイルの修正
- 確認
概要
ルーティングの記載
laravel_crudディレクトリで下記コマンドを実行してルーティングファイルを開く。
$ vi routes/web.php開いたファイルに下記の行を追記する。
laravel_crud/routes/web.phpRoute::get('/edit', 'ContentController@edit')->name('edit'); Route::post('/update', 'ContentController@update')->name('update');コントローラの記載
laravel_crudディレクトリで下記コマンドを実行して作成したコントローラファイルを開く。
$ vi app/Http/Controllers/ContentController.php下記の内容をクラス内に追記する。
laravel_crud/app/Http/Controllers/ContentController.phppublic function edit($content_id) { $contents_edit_query = Content::select('*'); $contents_edit_query->where('id', $content_id); $edit_contents = $contents_edit_query->get(); $edit_content = $edit_contents[0]; return view('contents.edit', [ 'edit_content' => $edit_content, ]); } public function update(Request $request) { $contents_update_query = Content::select('*'); $contents_update_query->where('id', $request['content_id']); $update_contents = $contents_update_query->get(); $update_content = $update_contents[0]; $update_content->content = $request['content']; $update_content->save(); return redirect('/output'); }記載後のコントローラファイルの内容を下記に記載する。
laravel_crud/app/Http/Controllers/ContentController.php<?php namespace App\Http\Controllers; use Illuminate\Http\Request; use App\Models\Content; class ContentController extends Controller { public function input() { return view('contents.input'); } public function save(Request $request) { $input_content = new Content(); $input_content->content = $request['content']; $input_content->save(); return redirect('/output'); } public function output() { $contents_get_query = Content::select('*'); $all_contents = $contents_get_query->get(); return view('contents.output', [ 'all_contents' => $all_contents, ]); } public function delete(Request $request) { $contents_delete_query = Content::select('*'); $contents_delete_query->where('id', $request['content_id']); $contents_delete_query->delete(); return redirect('/output'); } public function edit($content_id) { $contents_edit_query = Content::select('*'); $contents_edit_query->where('id', $content_id); $edit_contents = $contents_edit_query->get(); $edit_content = $edit_contents[0]; return view('contents.edit', [ 'edit_content' => $edit_content, ]); } public function update(Request $request) { $contents_update_query = Content::select('*'); $contents_update_query->where('id', $request['content_id']); $update_contents = $contents_update_query->get(); $update_content = $update_contents[0]; $update_content->content = $request['content']; $update_content->save(); return redirect('/output'); } }ビューファイルの作成と修正
laravel_crudディレクトリで下記コマンドを実行してビューファイルを作成する。
vi resources/views/contents/edit.blade.php
作成して開いたビューファイルに下記の内容を追記する。
laravel_crud/resources/views/contents/edit.blade.php<h1>edit</h1> <form action="{{route('update')}}" method="post"> @csrf <textarea name="content" cols="30" rows="10">{{$edit_content['content']}}</textarea> <input type="hidden" name="content_id" value="{{$edit_content['id']}}"> <input type="submit" value="送信"> </form>laravel_crudディレクトリで下記コマンドを実行してビューファイルを開く。
vi resources/views/contents/output.blade.php
開いたビューファイルに下記の内容を追記する。
laravel_crud/resources/views/contents/output.blade.php<h1>output</h1> @foreach ($all_contents as $item) <hr> <p>{{$item['content']}}</p> <form action="{{route('delete')}}" method="post"> @csrf <input type="hidden" name="content_id" value="{{$item['id']}}"> <input type="submit" value="削除"> </form> <a href="{{route('edit', ['content_id' => $item['id']])}}"> <button>編集</button> </a> @endforeach確認
laravel_crudディレクトリで下記コマンドを実行してローカルサーバを起動する。
$ php artisan serveブラウザで下記にアクセスする。
「編集」ボタンをクリックする。
下記の様に先に投稿した内容がすでに記載されているテキストボックスが出力される。
内容を任意の物に変更し、「送信」ボタンをクリックする。
下記ページにリダイレクトして、投稿内容が変更されていれば本記事の内容は完了である。
- 投稿日:2020-07-21T00:07:28+09:00
マイグレーション作成
今回やること
マイグレーション機能(データベースのバージョン管理)を使用して、phpMyAdminに作ったデータベース(mommy_book)にテーブルを作成する!
ポイント
migrationファイルの内容の中には、テーブルを作成する処理が含まれている
- up(): テーブル作成(バージョンアップ処理)
- down(): テーブル削除(ロールバック処理)
Laravelにはプロジェクト作成段階でユーザ認証が組み込まれてるようになっている
- ユーザ用のテーブルとパスワード再確認用テーブルを作成するmigrationファイルがデフォルトでdatabase/migrationの直下に保存されている
今回のMommy_bookアプリでは、デフォルトのユーザ用migrationファイル(Usersテーブル用)に加えて、Babiesテーブル、Vaccinesテーブル、Baby_checkupsテーブル、Baby_teethテーブル、Matanity_checkupsテーブル、Albumsテーブルを作るため6つのmigrationファイルを作成する。
流れ
- migrationファイルを作成
- テーブル定義書をもとにmigrationファイルを編集
- migrationを実行
- phpMyAdminのデータベースにテーブルが作成されているかを確認
ここでは、①デフォルトでテーブルを作る場合(Usersテーブル)と②自分でmigrationファイルを作る場合(ex. Babiesテーブル)の作成を説明します
①デフォルトでテーブルを作る場合(Usersテーブル)
1.migrationファイルは既にあるので、database/migrationの直下のcreate_users_table.phpを開く
[デフォルトではup()は以下の通り、down()はデフォルトのままなので省略]public function up() { Schema::create('users', function (Blueprint $table) { $table->increments('id'); $table->string('name'); $table->string('email')->unique(); $table->timestamp('email_verified_at')->nullable(); $table->string('password'); $table->rememberToken(); $table->timestamps(); }); }3.migrationを実行 (コマンドで)
php artisan migrate☆データベースにテーブルが作成できているので成功☆
②自分でmigrationファイルを作る場合(ex. Babiesテーブル)
- migrationファイルを作成
コマンドで、以下の通り(-createオプション:テーブル名は複数形で)
php artisan make:migration create_babies_table --create=babiesdatabase/migrationで作成したcreate_babies_table.phpを開く
[デフォルトではup()は以下の通り、down()はデフォルトのままなので省略]public function up() { Schema::create('tweets', function (Blueprint $table) { $table->id(); $table->timestamps(); }); }php artisan migrate☆データベースにテーブルが作成できているので成功☆
カラム設定で出てきたもの
ベースとなる書き方
型がintegerのときは、引数を取ることできないので注意!!!!Schema::create('テーブル名', function (Blueprint $table) { $table->カラムの型('カラム名', 引数) }nullのとき⇩
$table->カラムの型('カラム名', 引数)->nullable();メールアドレスなど値の重複を防ぎたいとき⇩
$table->カラムの型('カラム名', 引数)->unique();外部キー⇩
$table->foreign('外部キー名')->references('外部キーに対応する主キー名')->on('選択した主キーのテーブル名'); }timestamps()
有効(全体)桁数指定で、NULL値可能なcreated_atとupdated_atカラムを追加する
NULLが指定された場合は、デフォルト値が入るまとめ
以下の手順を繰り返す!!
1. migrationファイルを作成
2. テーブル定義書をもとにmigrationファイルを編集
3. migrationを実行
4. phpMyAdminのデータベースにテーブルが作成されているかを確認
- 投稿日:2020-07-21T00:06:55+09:00
PHP-数値を3桁ごとにカンマを付与する関数
number_format関数
数字を千位毎にグループ化してフォーマットする
<?php echo number_fornmat(1234567); //1,234,567laravelで使うときは下記のような感じで使う
$price = [1000, 2000, 3000,]; foreach ($price as $value){ <td>¥{{ number_format($value->price) }}</td> } 結果 ¥1,000 ¥2,000 ¥3,000余談ですが、勝手に小数点を含む数値」を四捨五入するので、第二引数に桁数を指定すれば小数点以下も表示できます。
<?php echo number_format(1234.567,2); // 1,234.57