Markdown テーブル セル内で改行を行う方法
Bootstrapについてゼロから学習
初学者がBootstrapについてゼロから学んだことを記述しています。
#Bootstrapとは
様々なブラウザや画面サイズに対応した本格的なWEBサイトを簡単に作ることができるWEBフレームワーク
である。
※WEBフレームワークは、WEBサイトの開発を容易にする「雛形」のこと
●Bootstrapのメリット
・個人開発〜大規模開発まで幅広い用途に対応
・レスポンシブデザイン
・テンプレートやプラグインによるカスタマイズ
等を簡単に実装することができ、短期間で本格的なWEBサイトを作成できる。
●デメリット
・独自のルールを学習する必要がある
・似たようなデザインになりやすい
・細かくカスタマイズすると逆に工数が増える
Bootstrapの機能
グリッドシステム
グリッドシステム=画面を縦に分割して、ブロックごとに図や文章を配置する手法で、画面サイズに合わせてコンテンツの幅と数を制御できる。
※縦に分割した列1つ1つをグリッドという
グリッドシステムでは、必ず全体を「container」または「container-fluid」というクラスで囲む
。
●containerを使用した場合
画面幅に応じて、コンテンツや余白の幅が自動で変わる。
ウィンドウ幅 | 内部コンテンツ幅 |
---|---|
576px未満 | ウィンドウ一杯 |
576〜768px未満 | 常に540px |
768〜992px未満 | 常に720px |
992〜1200px未満 | 常に960px |
1200px以上 | 常に1140px |
●container-fluidを使用した場合
画面幅に関係なく、常に画面いっぱいに広がる
●rowとcolを使う
内部コンテンツは、row(行)の中に、col(列)で作成する
<body><divclass="container"><!--全体をcontainerで囲む--><divclass="row"><!--rowでcolを囲む--><divclass="col"style="background":red;height:200px;">A</div><divclass="col"style="background":yellow;height:200px;">B</div><divclass="col"style="background":blue;height:200px;">C</div></div></div></body>
<body><divclass="container"><!--全体をcontainerで囲む--><divclass="row"><!--rowでcolを囲む--><!--colのあとに「-数字」で縦に12分割のうち、どれくらいの幅にするか指定する--><divclass="col−3"style="background":red;height:200px;">A</div><divclass="col-4"style="background":yellow;height:200px;">B</div><divclass="col-5"style="background":blue;height:200px;">C</div></div></div></body>
レスポンシブデザイン
横幅が長いPC画面と、横幅が短いスマホなどの画面では表示が変わる
ブレイクポイント
PC表示とスマホ表示が変わる境界線をブレイクポイントと言う。
一般的には、768px(col-md)でPC表示とスマホ表示を切り替える
0〜575px | 576〜767px | 768〜991px | 992〜1999px | 1200px以上 | |
---|---|---|---|---|---|
クラス | col | col-sm | col-md | col-lg | col-xl |
<body><divclass="container"><!--全体をcontainerで囲む--><divclass="row"><!--rowでcolを囲む--><!--col-md(768px)がブレイクポイントということ--><divclass="col-md−3"style="background":red;height:200px;">A</div><divclass="col-md-4"style="background":yellow;height:200px;">B</div><divclass="col-md-5"style="background":blue;height:200px;">C</div></div></div></body>
<body><divclass="container"><!--全体をcontainerで囲む--><divclass="row"><!--rowでcolを囲む--><!--col-md(768px)未満の時はそれぞれcol-4で、それ以上の時は3,4,5ということ)--><divclass="col-4 col-md−3"style="background":red;height:200px;">A</div><divclass="col-4 col-md-4"style="background":yellow;height:200px;">B</div><divclass="col-4 col-md-5"style="background":blue;height:200px;">C</div></div></div></body>
画面幅に応じた要素の非表示
class="d-●●-none"とすると、
●●pxの画面以上は、特定の要素を非表示
にできる。
0〜575px | 576〜767px | 768〜991px | 992〜1999px | 1200px以上 | |
---|---|---|---|---|---|
特定の要素を 非表示にするクラス | d-none | d-sm-none | d-md-none | d-lg-none | d-xl-none |
<body><divclass="container"><!--全体をcontainerで囲む--><divclass="row"><!--rowでcolを囲む--><!--md(768px)以上の時はそれぞれcol-4で、それ以上の時はA要素を非表示ということ)--><divclass="col-12 d-md-none"style="background":red;height:200px;">A</div><divclass="col-6 col-md-8"style="background":yellow;height:200px;">B</div><divclass="col-6 col-md-4"style="background":blue;height:200px;">C</div></div></div></body>
画面幅に応じた要素の表示
class="d-none d-●●-block"とすると、
●●pxの画面以上は、特定の要素を表示する
ことができる。
0〜575px | 576〜767px | 768〜991px | 992〜1999px | 1200px以上 | |
---|---|---|---|---|---|
特定の要素を 表示するクラス | d-block | d-sm-block | d-md-block | d-lg-block | d-xl-block |
<body><divclass="container"><!--全体をcontainerで囲む--><divclass="row"><!--rowでcolを囲む--><!--md(768px)未満の時はA要素を非表示で、768px以上の時はA要素を表示する)--><divclass="col-12 d-none d-md-block"style="background":red;height:200px;">A</div><divclass="col-8"style="background":yellow;height:200px;">B</div><divclass="col-4"style="background":blue;height:200px;">C</div></div></div></body>
②シンプルで見やすいテーブル
③デザインされたボタン
Bootstrapの仕組み
CSSとJavaScriptにより構成されている。
Bootstrapを使用するには
①ネット上のBootstrapファイルを読み込んで使う...CDN(Contents Delivery Network)
②ソースファイルをダウンロードして使う
③コンパイル済みのファイルをダウンロードして使う
※本記事では③を仕様
Bootstrapの読み込み
●HTMLの
タグ内にcssファイルのパスを記述●HTMLの直後にjsファイルのパスを記述
画像やブロック要素の調整
img-fluid
画像の幅をブロック幅に合わせて表示する
<img src="ファイル名" Class="img-fluid">
paddingとmargin
padding... class="p●-X"
margin... class="m●-X"
方向を指定する(●の部分)
|記述方法|t|r|b|l|x|y|無し|
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|間隔を開ける方向|上|右|下|左|上下|左右|上下左右|
記述方法 | 0 | 1 | 2 | 3 | 4 | 5 |
---|---|---|---|---|---|---|
間隔 | 0 | 0.25rem | 0.5rem | 1rem | 1.5rem | 3rem |
Bootstrap特有のclass
①左寄せ、中央寄せ、右寄せ
左寄せ... class="text-left"
中央寄せ... class="text-center"
右寄せ... class="text-right"
②見出し
h1... <h1></h1> または class="h1"
h2... <h2></h2> または class="h2"
③リスト
<li></li>のデフォルト設定の点を削除... class="list-unstyled"
リストでテキストを横並びにする... <ul class="list-inline">
<li class="list-inline-item"></li>
</ul>
④幅や高さの指定
幅や高さを指定するclass
幅を指定するclass
記述方法 | w-25 | w-50 | w-75 | w-100 | mw-100 | w-auto |
---|---|---|---|---|---|---|
意味 | width:25% | width:50% | width:75% | width:100% | width:100% | max-width:100% |
高さを指定するclass
記述方法 | h-25 | h-50 | h-75 | h-100 | mh-100 | h-auto |
---|---|---|---|---|---|---|
意味 | height:25% | height:50% | height:75% | height:100% | height:100% | max-height:100% |
※横幅、高さを%で指定した場合、親要素を100%とした時の割合で表示される
⑤float
グリッドシステムを無視して要素を横並びにする場合、
通常のHTML/CSSのようにfloatを使用
左寄せ... class="float-left"
※floatさせる要素自体に指定
右寄せ... class="float-right"
※floatさせる要素自体に指定
float解除... class="clear-fix"
※floatさせる要素全体を囲む親要素に指定
⑥ナビゲーションバーの型
「navbar」「navbar-expand-ブレイクポイント」の2つのclassを記述
<nav class="navbar navbar-expand-ブレイクポイント>
リストでナビゲーションバーを作成する場合は、ulに「navbar-nav」というclassを記述
<ul class="navber-nav">
liに「nav-item」、aに「nav-link」というclassを記述
<li class="nav-item"><a href="●●" class="nav-link>XXXX</a></li>
</ul>
</nav>ナビゲーションバーは<nav>で囲む
PHP入門
JavaやJavaScriptなどと並行して学習を進めており、基礎的な文法は省略しているところも多いが、初心者がゼロからphpに関して学習した内容を以下に記述しています。
PHPプログラミングの手順
①エディタを使用してプログラミングを記述
②任意の名前.phpで保存
③保存したphpファイルをサーバーへアップロード
環境構築
今回はMAMPをインストールして利用した。
PHPの書き方
<? php
ここにプログラミングを記述する
?>
出力の方法
echo "Hello World";
または、
print "Hello World";
改行したい場合
echo "1行目<br>2行目";
変数
変数名の前には$をつける
大文字と小文字は区別される
変数名の先頭に数字、_以外の数字は変数名に使えない
例)
$ABC $abc $Abc
代入
変数に値を代入するには「=」を使う
$a = 1;
$a = "文字列"; //文字列は「" "」で囲む
if文
if (条件) {処理内容}
例)もし$aが10より大きい場合は、Aと表示する
$a = 15;
if ($a > 10) {
echo "A";
}
elseif文
if (条件) {処理内容}
例)もし$aが10より大きい場合は、Aと表示する
そうでない場合で、$aが10未満の場合は、Bと表示する
$a = 15;
if ($a > 10) {
echo "A";
} elseif ($a < 10){
echo "B";
}
else文
if (条件) {処理内容}
例)もし$aが10より大きい場合は、Aと表示する
そうでない場合は、Bと表示する
$a = 15;
if ($a > 10) {
echo "A";
} else {
echo "B";
}
swich文
switch ($a) {
case〇〇 : 処理内容;
break;
}
配列
配列の書き方
$name = array("田中"、"高橋"、"斎藤");
または
$name[0] = "田中";
$name[1] = "高橋";
$name[2] = "斎藤";
要素の追加
$name = array("田中"、"高橋"、"斎藤");
$name[] = "新しい要素";
※$name[3]に新しい要素が追加される
値の更新
$name = array("田中"、"高橋"、"斎藤");
$name[0] = "加藤";
※田中→加藤
要素の削除
$name = array("田中"、"高橋"、"斎藤");
unset($name[0]);
※田中を削除
連想配列
例)普通の配列
$name = array("田中"、"高橋"、"斎藤");
例)連想配列
$name = array("名前1" => "田中"、"名前2" => "高橋"、"名前3" => "斎藤");
例)田中を呼び出す場合
echo $name["名前1"];
多次元配列
配列の各箱の中に、さらに小さな箱を入れて管理する方法
例)
$name = array(
array("田中","高橋"),
array("Bob","Emily"),
array("キム","パク"),
);
例)田中を呼び出す場合
echo $name[0][0];
多次元配列の値に、配列変数を指定することもできる
例)アジア配列、アメリカ配列を、カントリー配列に代入
$asia = array("日本","タイ");
$america = array("アメリカ","ブラジル");
$country = array($asia,$america);
例)日本を呼び出す場合
echo $country[0][0];
多次元連想配列
配列の各箱の中に小さな箱が入っており、各箱の添え字に別の文字列等を使って管理する方法
例)
$country = array(
"アジア" => array("東アジア" => "日本", "東南アジア" => "ブラジル"),
"アメリカ" => array("北米" => "アメリカ", "南米" => "ブラジル"),
"欧州" => array("西欧" => "フランス", "東欧" => "ロシア")
);
例)タイを呼び出す場合
echo $country["アジア"]["東南アジア"]
シングルクォーテーションとダブルクォーテーションの違い
文字列 | 計算式 | 変数 | 処理速度 | |
---|---|---|---|---|
シングルクォーテーション | そのまま文字列として表示 | そのまま文字列として表示 | そのまま文字列として表示 | 速い |
ダブルクォーテーション | そのまま文字列として表示 | そのまま文字列として表示 | 変数を展開して中身を表示 | 遅い |
[.]ドット
ドットは文字列の連結に使われる。
例)
$name = "田中";
$age = 25;
echo $name."さん(".$age.”歳)”
↓
田中さん(25歳)
関数
関数の書き方
function 関数名(引数1、引数2、引数3・・・){
処理1;
処理2;
return 戻り値;
}
foreach文
配列に格納した情報を順番に表示する
$配列変数名 = array(値0、値1、値2);
foreach($配列変数名 as $✕){
処理内容;}
例)
<?php
$a = array("山田","佐藤","鈴木");
foreach($a as $value){ //$aを$valueとして処理する的な意味
echo $value;
}
?>
↓
山田佐藤鈴木
foreachでキーを表示する方法
$配列変数名 = array(値0、値1、値2);
foreach($配列変数名 as $△ => $✕){
echo $△.$✕;}
例)
<?php
$a = array("山田","佐藤","鈴木");
foreach($a as $b => $c){ //$aを$b(キー)と$c(値)として処理する的な意味
echo $b.$c; //キーと値をそれぞれ表示
}
?>
↓
0山田1佐藤2鈴木
連想配列で各キーに名前をつける方法
例)
<?php
$a = array("【名前1】" => "山田","【名前2】" => "佐藤","【名前3】" => "鈴木");
foreach($a as $b => $c){ //$aを$b(キー)と$c(値)として処理する的な意味
echo $b.$c; //キーと値をそれぞれ表示
}
?>
↓
【名前1】山田【名前2】佐藤【名前3】鈴木
foreach文の多次元連想配列
$food
●$vegetable($groupkey)
↓($namekey/$eigoname) => ($nihonname)
・"carrot" => "にんじん"
・"tomato" => "トマト"
・"onion" => "たまねぎ"
●$fruit($groupkey)
↓($namekey/$eigoname) => ($nihonname)
・"apple" => "りんご"
・"orange" => "オレンジ"
・"grape" => "ぶどう"
<?php$food=array("vegetable"=>array("carrot"=>"にんじん","tomato"=>"トマト","onion"=>"たまねぎ"),"fruit"=>array("apple"=>"りんご","orange"=>"オレンジ","grape"=>"ぶどう");foreach($foodas$groupkey=>$namekey){echo"■".$groupkey."<br>";foreach($namekeyas$eigoname=>$nihonname){echo$eigoname.":"$nihonname."<br>";}echo"<br>";}?>
↓
■vegetable
carrot:にんじん
tomato:トマト
onion:たまねぎ
■fruit
apple:りんご
orange:オレンジ
grape:ぶどう
foreach文と配列とソート
例)
<?php
$a = array("d","c","b","a");
sort($a);
foreach($a as
$key => $value){ //$aを$valueとして処理する的な意味
echo $value."<br>";
}
?>
↓
a
b
c
d と表示される
rsort(変数)
例)配列$aの各値を降順に並べ替える
<?php
$a = array("d","c","b","a");
rsort($a);
foreach($a as
$key => $value){ //$aを$valueとして処理する的な意味
echo $value."<br>";
}
?>
↓
d
c
b
a と表示される(アルファベットの降順z→a)
ksort(変数)
例)配列$aの各キーを昇順に並べ替える
<?php
$a = array(
"1" => "d",
"2" => "c",
"3" => "b",
"4" => "a");
ksort($a);
foreach($a as $key => $value){ //$aを$valueとして処理する的な意味
echo $key.":".$value."
";
}
?>
↓
1:d
2:c
3:b
4:a と表示される
関数の書き方 | 並べ替えの基準 | 意味 |
---|---|---|
sort($配列変数) | 値(バリュー) | 配列変数の各値を昇順に並べ替え |
rsort($配列変数) | 値(バリュー) | 配列変数の各値を降順に並べ替え |
asort($配列変数) | 値(バリュー) | 配列変数の各値を昇順に並べ替え 連想配列において、各キーと値の関係を維持しつつソートする。 |
arsort($配列変数) | 値(バリュー) | 配列変数の各値を降順に並べ替え 連想配列において、各キーと値の関係を維持しつつソートする。 |
ksort($配列変数) | 添字(キー) | 配列変数の各値を昇順に並べ替え 連想配列において、各キーと値の関係を維持しつつソートする。 |
krsort($配列変数) | 添字(キー) | 配列変数の各値を降順順に並べ替え 連想配列において、各キーと値の関係を維持しつつソートする。 |
問い合わせフォームの作成
web上で問い合わせフォームが動く仕組み
①index.html(問い合わせ画面)ーーーユーザーが入力する
②mail_confirm.php(入力内容確認画面)
→不備があれば①へ戻り、入力やり直し
③insert.php(SQL分を記述)
④phpファイルから、データベースへ通信
HTMLから引き渡された情報がデータベースへ格納される。
(SQLのinset文)
問い合わせフォーム作成の手順
①設定ファイルの編集(やらないと、フォームから送信された文字列が文字化けしてデータベースに登録されてしまう)
②データベース上にtableを作成する
③HTMLとCSSを作成する
④phpファイルを作成する
PHP側でのPOSTの使い方
echo $_POST['箱の名前']; //index.htmlで作成したform内のname名前を、formの入力欄ごとに指定する必要がある。
処理の流れ(イメージ)
<formmethod="post"action="abc.php">名前<inputtype="text"name="箱の名前"> //①
<inputtype="submit"value="送信"> //②
</form>
↓ ↓ ↓ ①テキストボックスに名前が入力される
↓ ↓ ↓ ②送信ボタンがクリックされる index.htmlからabc.phpへ"箱の名前”の値が送られる
↓ ↓ ↓ ③引き渡されたPOSTをechoで出力する
echo$_POST['箱の名前'];//③入力された内容を表示して確認 <formaction="insert.php"method="post"> //フォームクリックされた場合、insert.phpへ送信<inputclass="submit"type="submit"value="送信する"> //送信ボタン<inputtype="hidden"value="<?php echo $_POST['箱の名前']; ?>"name="箱の名前"></form>
↓ ↓ ↓
↓ ↓ ↓ 上記で送信ボタンがクリックされると、入力された情報がinsert.phpに送信される。
↓ ↓ ↓
<?php mb_internal_encoding("utf-8");//①DBへ情報を格納する際の文字化けを防ぐ文$pdo=newPDO("mysql:dbname=lesson01;host=localhost;","サーバID","サーバpass");//③DBへ接続するための文$pdo->exec("insert into テーブル名(カラム名,カラム名)values
('".$_POST['箱の名前']."','".$_POST['箱の名前']."');");?>
↓ ↓ ↓ 今回はPDOというライブラリを使ってphp上でSQL文を書いている。
↓ ↓ ↓ ①DB接続をして
↓ ↓ ↓ ②insert文でデータベースに情報を格納する
データベース
PDOの使い方
mb_internal_encoding("utf8);
◆データベースと接続するための文
$pdo = new PDO("mysql:dbname=lesson01;host=localhost;" ,"root" ,"");
※mysql:dbname=lesson01 MySQLに接続し、データベース「lesson01」を利用するという意味
※host=localhost 通常はDB用のサーバー名を記述する。ローカル環境を使用している場合はこの記述。
※"root"," " サーバー接続する際のIDとパスワードを記述。
◆データベースにデータを格納するための文
$pdo -> exec("insert into テーブル名(カラム名,カラム名)values
('".$_POST['箱の名前']."','".$_POST['箱の名前']."');"); //DBへ送るための情報
◆データベースからデータを取り出すための文
$stmt = $pdo -> query("select * from テーブル名");
※PDO実行時に気をつけること
①select文を使うときは
$stmt = $pdo -> query("sql文");
②insert文、update文、delete文を使うときは
$pdo -> exec("sql文");
データベースから取得した情報を表示させる文の例
while($row=$stmt->fetch()){echo$row[`取り出すデータのカラム名`];echo$row[`取り出すデータのカラム名`];echo$row[`取り出すデータのカラム名`];}//またはforeach($stmtas$row){echo$row[`取り出すデータのカラム名`];echo$row[`取り出すデータのカラム名`];echo$row[`取り出すデータのカラム名`];}//※rowは「行」のこと//※stmtは「statement/声明」の略//※fetchは「go and get/取ってくる」こと
リダイレクト
あるwebページから自動的に他のwebページに移動すること。
PHPでリダイレクトを使用する場合は、下記のheader関数を使用する
header("Location: URL または 相対パス");
session
sessionとは、ページを飛び越えて情報を引き継ぐ技術
これまでのPOST通信は、form内にPOSTの記述をすることで、
2つのページ間で情報を引き継ぐことが可能
sessionでは、複数のページ(ファイル)間で情報を引き継ぐことが可能
sessionの書き方
session_start;
sessionを使う場合、ファイル内にsession_start;と記述する必要がある。
session_start;以降はsessionが有効になる。
$_SESSION['任意の変数名'] = "文字列等";
sessionでは、このように任意の変数に文字列等を代入できる。
echo $_SESSION['任意の変数名'];
一度、sessionに代入した文字列等は、どのファイル(ページ)でもsession_start;を記述した後であればechoなどで出力することができる。
sessionー同じファイル内で出力する場合
<?phpsession_start();//①session_start以降はsessionが有効になる。$_SESSION['name']="山田太郎";//②$_SESSION['〇〇'] = "△△";//△△を〇〇に代入するという意味。(=サーバーに保存する)echo$_SESSION['name'];?>
sessionー複数のファイルで出力する場合
<?phpsession_start();//①session_start以降はsessionが有効になる。$_SESSION['name']="山田太郎";//②$_SESSION['〇〇'] = "△△";//△△を〇〇に代入するという意味。(=サーバーに保存する)
<?phpsession_start();//他のページでもsession_startと記述すれば、そのセッションを使用できる。echo$_SESSION['name'];//②で保存したSessionをechoで表示する。 ?>
特定のセッション変数の削除
unset($_SESSION['削除するセッション変数名']);
すべてのセッション変数の削除
session_destroy();
cookie
webサイトを訪問したユーザー情報を一時的に保存する仕組み。
cookieはブラウザに保存されている。
cookie | session | |
---|---|---|
保存場所 | ブラウザ | サーバー |
有効時間 | コード内で自由に設定 | 「php.ini」で設定(デフォルトは、24分) |
削除方法 | 有効期限を現在の時間よりも前の時間に設定することで、cookieを削除することができる。 | session_destroy(); または、ブラウザを閉じたときに自動的に削除される。 |
使用例 | ログインフォームにおいて、「ログイン情報を保持する」 にチェックを入れると、ログアウトしても、ログインに必要なメールやパスワードが フォームに入力されたままになる。 | ログイン状態において、ページ間(=ファイル間)で情報を引き継ぐ。 |
cookieの使い方
setcookie(クッキーにつける名前,保存したいもの,有効期限);
※有効期限の書き方:1週間の場合→time()+60*60*24*7
クッキーを削除したい場合:time()-1と記述する
cookieー同じファイル内で出力する場合
<?phpsetcookie(name,"保存したいもの",time()+60*60*24*7);//nameという配列に、"保存したいもの"を格納する。保存期間は1週間echo$_COOKIE['name'];//配列に格納した"保存したいもの"を出力。?>
cookieー複数のファイルで出力する場合
<?phpsetcookie(name,"保存したいもの",time()+60*60*24*7);//nameという配列に、"保存したいもの"を格納する。保存期間は1週間?>
<?phpecho$_COOKIE['name'];//配列に格納した"保存したいもの"を出力。?>
empty
ある配列や変数が空であるかを判定する
if(empty(変数)){処理内容;}
※空や0、NULLである場合はTrueを返し、それ以外はFalseを返す
<?phpsession_start();$_SESSION['mail']="〇〇@gmail.com";?>
<?phpsession_start();if(empty($_SESSION['name'])){//nameには何もセットされていないので、条件式はtrueとなり、echoが実行される。echo"nameは空です";}session_destroy();?>
isset
ある変数や配列に値がセットされていて、かつNULLでないかを判定する
if(isset(変数)){処理内容;}
※値がセットされている場合や、空や0の場合はtrueを返し、NULLがセットされている場合はFalseを返す。
<?phpsession_start();$_SESSION['name']="山田太郎";$_SESSION['mail']="〇〇@gmail.com";?>
<?phpsession_start();if(isset($_SESSION['name'])){//nameに山田太郎がセットされているので、条件式はtrueとなり、echoが実行される。echo"セッションあり";}session_destroy();?>
バリデーション
問い合わせフォームや会員登録などの際に、各入力項目に適した内容が入力されているかどうかチェックすること
正規表現
特定の文字列のパターンを文字や記号で表現する手法
正規表現の使い方
■\dは、1つの半角数字(0123456789)を意味する「メタ文字」
例)電話番号090-0000-0000の正規表現
\d\d\d-\d\d\d\d-\d\d\d\d
■文字の個数を限定するときは、{n,m}や{n}というメタ文字(量指定子)を使用する
例)電話番号090-0000-0000
03-0000-0000
043-000-0000
01234-0-0000 の正規表現
\d{2,5}-\d{1,4}-\d{4}
■「AまたはBのいずれか1文字」を表す場合は[AB]と書く
※文字数制限はなく、[ABC]であれば、「AまたはBまたはCのいずれか1文字」となる。
例)英数字またはアンダースコア
[a-z0-9_]
■「〜が1文字、または無し」を表す場合は?を使う
■「任意の1文字」を表す場合は.を使う
■「任意の文字が1文字以上」を表す場合+を使う
■[任意の文字が0文字以上」を表す場合*を使う
■「/」をエスケープする場合**を使う
■正規表現に( )を使うと、囲まれた部分がキャプチャされ、連番がつけられる。
■英単語を構成する文字(大文字も小文字も両方)を表す場合は\wを使う
■半角スペースやタブ文字、改行文字など、目に見えない「空白文字全般」を表すメタ文字\s
■「A以外の任意の文字」を表す場合は[^A]と書く
■タブ文字を表すメタ文字\t
■「文字列ABCまたは文字列CDF」のor条件を表す場合はABC|DEFと書く
■行頭を表すアンカー^
■行末を表すアンカー$
■「英単語ABCだけ」を表す場合は\bABC\bと書く
■(肯定の)後読み
abcの「直後の位置」を表す場合は(?<=abc)と書く
■(肯定の)先読み
abcの「直前の位置」を表す場合は(?=abc)と書く
■(否定の)後読み
「abc以外の文字列の直後」を表す場合は(?<!abc)と書く
■(否定の)先読み
「abc以外の文字列の直後」を表す場合は(?!abc)と書く
■「( )でキャプチャされた1番目の文字列」を表す場合は、\1書く
正規表現を使ったバリデーション
■PHPの場合
if(preg_match("/チェック方法/",チェック対象の変数)){処理内容;}
■HTML5
<input type="XXX" name="XXX" pattern="チェック方法">
正規表現の使用例(PHP)
<?php$abc=012;if(preg_match("/^[0-9]+$/",$abc)){echo'数値です';}else{echo'数値ではありません';}?>
<?php$mail="yamada@gmail.com";if(preg_match("/^[a-z0-9._%+-]+@[a-z0-9.-]¥.[a-z]{2,3}$/",$mail)){echo'正しいメールアドレスです';}else{echo'正しいメールアドレスの形ではありません';}?>
<?php$tel="090-1234-5678";if(preg_match("/^[0-9]{2,4}-[0-9]{2,4}-[0-9]{3,4}$/",$tel)){echo'正しい電話番号です';}else{echo'正しい電話番号の形ではありません';}?>
<?php$zip="100-0013";if(preg_match("/^[0-9]{3}-[0-9]{4}$/",$zip)){echo'正しい郵便番号です';}else{echo'正しい郵便番号の形ではありません';}?>
<?php$zip="1000013";if(preg_match("/^[0-9]{7}+$/",$zip)){echo'正しい郵便番号です';}else{echo'正しい郵便番号の形ではありません';}?>
<?php$pass="pass1234";if(preg_match("/^[a-zA-Z0-9]{6,8}+$/",$pass)){echo'正しいパスワードです';}else{echo'正しいパスワードの形ではありません';}?>
<?php$a="あいうえお";if(preg_match("/^[あ-んア-ケ一-龠]+$/u",$a)){echo'全角文字です';}else{echo'全角文字ではありません';}//全角文字をUTF-8の文字コードで指定したい時は、終わりの部分を「+$/」ではなく「+$/u」にする。?>
<body><formaction="XXX"method="post"><inputtype="text"name="XXX"pattern="^[a-z0-9._ %+-]+@[a-z0-9.-]+¥.[a-z]{2,3}$"></form></body>
PHPで正規表現を行うタイミング
①HTMLのフォームで入力された情報が、PHPファイルへPOST通信で引き渡される。
②POST通信で引き渡された情報をpreg_matchでチェックする。
③チェック結果が正しい場合→insert文でデータベースに格納
④チェック結果が正しくない場合→エラーメッセージ画面へリンク
HTMLで正規表現を行うタイミング
①index.htmlのform内のpatternでチェックする。
②チェック結果が正しい場合→HTMLのフォームで入力された情報が、PHPファイルへPOST通信で引き渡される。
③チェック結果が正しくない場合→フォーム画面でエラーメッセージを表示
④insert文でデータベースに格納
画像のアップロード方法
①formに<input type="file">を記述
②form内でアップロードした画像ファイルはデータベースに格納せずに、
「move_uploaded_file(XXX,XXX);」という関数を使用し、指定したファイルへ移動
③データベースにvarcharで画像用のカラムを作成
④データベースの画像カラムには「移動先のファイルのパス」と「画像のファイル名」を格納
⑤画像を表示させる際は、<img src="XXXX">のXXXXに、
「移動先のファイルのパス」と「画像のファイル名」を記述
<body><formmethod="post"action="upload.php"enctype="multipart/form-data"><!--ファイルをアップロードする際は「enctype="multipart/form-data"」を記述する--><inputtype="hidden"name="max_file_size"value="5000000"/><!--アップロードするファイルサイズの上限(5,000,000バイト(5メガバイト))--><inputtype="file"name="upfile"size="50"/><!--ファイルを選択ボタンができる--><!--通常はサーバにアップロードするために、ここにFTP接続をするための関数を記述する--><inputtype="submit"value="アップロード"/></form></body>
<?php$temp_pic_name=$_FILES['upfile']['tmp_name'];//POSTでアップロードされた「upfile」はサーバー上に一時保存されている。 //一時保存されているファイル名を取得し、$temp_pic_nameに代入$original_pic_name=$_FILES['upfile']['name'];//サーバーに一時保存された「upfile」の本当のファイル名を取得し、$original_pic_nameに代入 move_uploaded_file($temp_pic_name,'./image/'.$original_pic_name);//アップロードされたファイルをサーバー上の一時保存領域からimageフォルダへ移動?>
move_uploaded_file
アップロードしたファイルが有効なアップロードであるかどうか確認する関数。
有効な場合は指定子たファイルの移動先に移動される。
返り値として、有効だった場合はTRUE、有効ではない場合は移動されずFALSEを返す。
move_uploaded_file(アップロードしたファイル名,ファイルの移動先);
prepared statement
予め(=prepared)SQL文の型を記述しておく手法。
PDOでデータベース接続しselect文を実行する際にセキュリティを高めるために必要な方法。
place holder
prepared statementを使用する際に使われる手法で、prepared statementのSQL文の型の中に記述する。疑問符型と名前型がある。
rand();
ランダムな数字を発生させる。
rand(最小値、最大値);
最小値から最大値の間でランダムな数字を発生させる。
例)サイコロのプログラムを作る場合、最小値:1、最大値:6
ー>(アロー演算子
左辺から右辺を取り出す
オブジェクト指向
クラスの書き方
classクラス名{public$変数名;//プロパティpublicfunction__construct(引数){//コンストラクタ(クラスがインスタンス化されてからはじめに呼び出される関数)実行する処理;}publicfunctionメソッド名(){実行する処理;}}$インスタンス名=newクラス名("引数");
継承
継承とは、あるクラスのプロパティやメソッドを引き継ぎ、クラスを拡張することphp:継承の書き方
class 子クラス名 extends 親クラス名{
子クラス独自のプロパティやメソッドの追加のほか、
この中で親クラスで定義したプロパティやメソッドの上書き(オーバーライド)
}
ファイルの読み込み
PHPでは、外部の別ファイルの中身を呼び出すことができる。
構文 | 処理内容 |
---|---|
require | ファイルが読み込めない場合「」が出てその場で処理が終了する。 |
require_once | ファイルが読み込めない場合「」が出てその場で処理が終了する。 さらに、一度読み込んだファイルは読み込みができない。 |
include | ファイルが読み込めない場合「」が出るが処理は継続する。 |
include_once | ファイルが読み込めない場合「」が出るが処理は継続する。 さらに、一度読み込んだファイルは読み込みができない。 |
◆requieでファイルを読み込むプログラムの例
<?phpclassName{//Nameクラスprivate$name;//フィールドの宣言publicfunction__construct($name){//コンストラクタ$this->name=$name;//nameフィールドに引数nameを代入}publicfunctionAisatsu(){//Aisatsuメソッドreturn"私の名前は".$this->name."です。";//戻り値}}?>
↓↓↓requireでname.phpを読み込む↓↓↓
<?phprequire"name.php";//requireでname/phpを読み込み//読み込めない場合は「fatal error」が出てその場で処理が終了する。$instance=newName("");//読み込んだName型のインスタンスの生成echo$instance->Aisatsu();//メソッド呼び出し?>
カプセル化
クラス内部のプロパティにprivateを使い、クラス外部からアクセスできなくすること
PHPのプロパティやメソッドには3タイプの権限がつけられる
|権限|説明|
|:-:|:-:|
|public|どこからでも利用(参照)できる
※メソッドには基本的に「public」を使う|
|private|同一クラス内しか利用(参照)できない
※プロパティには基本的に「private」を使う|
|protected|親クラス、継承クラスからしか利用(参照)できない
※基本的に親クラスのプロパティで使う|
getterとsetter
カプセル化されたプロパティには、getterやsetterというメソッドを利用することで
間接的にアクセスできるようになる。
//getter--------------------functiongetプロパティ名(){return$this->プロパティ名;}//setter--------------------functionsetプロパティ名(引数){$this->プロパティ名=引数;}
初心者がソフトウェアテストについて学んだこと(ホワイトボックス、ブラックボックス等)
プログラミングを学習し始めて間もない初学者がソフトウェアテストについて学んだことをいかに記述しています。
以下の書籍で学習した内容のまとめです。(1〜3章まで)
高橋寿一『知識ゼロから学ぶソフトウェアテスト』翔泳社
https://www.amazon.co.jp/dp/B00HQ7S5CA/ref=cm_sw_em_r_mt_dp_U_LgFfEbBB2SVR7
テストケースは膨大なので、完全なテストは存在しない
テストは限られた時間内でもすべての機能をテストしなくては行けないので、どの手法を用いるべきか常に考えるべき
ホワイトボックステスト
全てのソフトウェアテストの基礎となる手法。
プログラムの論理構造が正しいかテストする。ソフトウェアの使用が間違っていて発生するバグは発見できない。
制御パステスト法
制御パスは命令と条件分岐の組み合わせのこと。
制御パスの総数はとても多いので、以下の手法を用いて、網羅する基準にしたがって実施する。
■ステートメントカバレッジ手法
カバレッジ(カバー(網羅)してる範囲、テストが終わった範囲)
ステートメント(命令文)
命令文をテストする手法で、条件分岐でのバグは発見できない、非常に弱いテスト手法
■ブランチカバレッジ手法
分岐コードに対して、判定がTRUE、FALSEの結果を少なくとも1回ずつ持つようにテストケースを書く手法
網羅するという点では優れているが、テストケースの数が増えるのが難点
■カバレッジ基準
一般の商用ソフトウェアなら60%〜90%で十分だが、人命に関わるソフトウェアなら100%、つまりソフトウェアによる。
■テスト駆動開発(TDD/Test-Driven Development)
①赤:小さい動作しないテストを書く
②緑:そのテストを通すコードを書く
③リファクタリング:コードをきれいにする
TDDで開発するとテストを書く時間がないとか言うことにならない。
ブラックボックステスト
プログラムを1種のブラックボックスに見立てて、ソースコードを見ずに様々な入力を行ってテストする手法
・ソフトウェアの4つの振る舞い
●入力を処理する
●出力を処理する
●計算を行う
●データを保存する
この4つの動きしかしないので、この4つの振る舞いをテストすれば良い。
★同値分割法・協会分析法(ブラックボックステストの基本)
4つの振る舞いのうち、入力処理と出力処理をソフトウェアが正しく処理しているかテストする。
ユーザーからの入力だけでなく、ネットワーク経由のデータの受信など様々な入力も含む
■同値分割法
入力領域を同値クラスと言う部分集合に分割して、その部分集合に含まれる値を等価とみなす作業
例:
入力A:1〜5まで入力可
入力B:1〜5まで入力可
出力C:A ✕ B
6 __ __ __ __ __
5| |
4| |
3| 有効同値 | 無効同値
2| |
1|__ __ __ __ __|
0 1 2 3 4 5 6
【有効同値のテストケース】 A=3、B=4 |
---|
【無効同値のテストケース】 A= 6、B= 6 A= 6、B= 6 A=-1、B=-1 A= 0、B= 0 |
⭐0は特別な数値でバグになりやすいので必ずテストする
■境界値分析法
「境界」(無効同値と有効同値の間、有効同値と有効同値の間)
プログラム上、境界には必ず条件分が必要で、その条件分の間違いを境界分析法でチェックする。
●包括関係バグ
> と >= の間違い
●On-Offポイント法
境界値のバグを見つけるために、境界のどの値をチェックするか考える手法
有効同値 | 無効同値 | 境界値 | |
---|---|---|---|
入力A | 1から5 | 0以下6以上 | 0,1,5,6 |
入力B | 1から5 | 0以下6以上 | 0,1,5,6 |
【テストケース】
●0 0は特別な数値でバグになりやすいので必ずテストする
●1 有効な値の下限
●3 有効な値の真ん中
●5 有効な値の上限
●6 無効な値の下限
■ディシジョンテーブルテスト
すべての入力の組み合わせを表にして、その入力に対する動作、出力を明記する。
多数の入力処理に対して、多数の出力処理をテストするというような手法。
■状態遷移テスト
状態(state)、遷移(transition)
状態遷移マトリックスという表をさくせいして、ソフトウェアがその項目道理動作しているかチェックする手法
期待していない状態に遷移するバグ、ある状態からある状態に遷移できないバグが発見できる。
※状態の数が多いと、モデルが複雑すぎて、モデリングに時間がかかるしテスト項目も多すぎるという問題点がある
■ランダムテスト
何ら考えもなしに入力や操作を行う手法。
(アドホックテスト、アドリブテスト、モンキーテストなどとも呼ばれる)
★ブラックボックステストまとめ
●入力ダイアログボクスがあれば「境界値テスト」を行う※まず行う
●復数の入力ダイアログボクスがあれば「デシジョンテーブルテスト」を行う
●ダイアログボックスの遷移があれば「状態遷移テスト」を行う
Vue.jsドキュメントのスロットで躓いた箇所についての覚書①
はじめに
最近Vue.jsを学習中です。
Vuetifyに手を出した際にスロットに関する理解が不十分であることに気づいたので、Vue.js公式ドキュメントを一通り読みながら動かしてみようと思ったのですが、いくつか躓いた点があるので残しておきます。(※2020/1/8時点の内容です。)
Vue.js最近触り始めたよーって方の参考になれば幸いです。
※できるだけ分かりやすく書きますが完全に初心者向けの内容というわけではないので、完全初心者の方は公式ドキュメントの「基本的な使い方」あたりを見てからの方が理解できると思います。
ちなみにVue.jsの初学者向けの書籍としては猫本がおすすめです。
事前準備
試しで動かすためにVueCLI4でプロジェクトのひな型を作ります。
1. VueCLI4をインストールする。 ※参考
npm install -g @vue/cli
2. プロジェクトを作りたいディレクトリでcreate
する。 ※参考
vue create my-app
上記のコマンド実行後にプロジェクトの構成を聞かれますが、default
でOKです。
? Please pick a preset: (Use arrow keys)
> default (babel, eslint)
Manually select features
しばらく待ってひな形のプロジェクトの完成です。
3. サーバを立ち上げる
以下のようにディレクトリを変更して、サーバを起動するように促されますので、言われた通りにコマンドを実行します。
�🎉 Successfully created project my-app.
�👉 Get started with the following commands:
$ cd my-app
$ npm run serve
以下のように表示されたらサーバが立ち上がっているのでhttp://localhost:8080/
にブラウザからアクセスします。
(VSCodeの場合はCtrl
を押しながらクリックするとブラウザで開けて便利!)
DONE Compiled successfully in 6349ms
App running at:
- Local: http://localhost:8080/
- Network: http://192.168.100.100:8080/
以下のような画面が表示されていればOKです。
ちなみにサーバの停止はVSCodeの場合、Ctrl
+C
でできます。
以下が出力されるのでy
を入力すればOKです。
バッチ ジョブを終了しますか (Y/N)?
基本的に作業中は立ち上げっぱなしで問題ないです。
※VSCode自体を閉じても停止します。
4. ソースを修正する
自動で出力されたソースを修正して、この後の動作確認を行いやすくします。
対象のファイルを以下のように修正します。
<template><divid="app"><HelloWorld/></div></template><script>importHelloWorldfrom"./components/HelloWorld.vue";exportdefault{name:"app",components:{HelloWorld}};</script>
<template><div>Slot Practice</div></template><script>exportdefault{name:"HelloWorld"};</script>
かなりスッキリしました。
再度ブラウザでhttp://localhost:8080/
を開くと「Slot Practice」が左上に表示されているだけであることを確認してください。
ちなみに構成としてはApp.vue
が親コンポーネント、HelloWorld.vue
が子コンポーネントとなっています。
Slotはざっくり言うと親が子のコンポーネントを呼び出す際にデータなどを与える仕組みだと思うので、親と子の関係がある点を抑えておくとよいかと思います。
躓いた点
スロットコンテンツ
①url
が見つからない
とりあえず載ってる通りに修正したら最初っから詰まりました。
※コンポーネントの名前は変えるのがめんどくさかったのでHelloWorld
のままにしてます。
分かりにくければnavigation-link
に読み替えてもらえればと思います。
<template><divid="app"><HelloWorldurl="/profile">
Your Profile
</HelloWorld></div></template><script>importHelloWorldfrom"./components/HelloWorld.vue";exportdefault{name:"app",components:{HelloWorld}};</script>
<template><av-bind:href="url"class="nav-link"><slot></slot></a></template><script>exportdefault{name:"HelloWorld"};</script>
上記のように修正ところ、VSCode上ではエラーなどはなかったのですが、Chrome上でエラーが発生していました。
(ChormeのデベロッパーツールはF12
で開けます。便利!)
エラーの内容は以下です。
ごちゃごちゃ書いてありますが、要は以下の2点です。
・「url
が使われているが、定義されていない」
・「src/components/HelloWorld.vueが原因」
①解決
HelloWorld.vue
でhref
属性にv-bind
しているurl
が定義されていないことが原因でした。
なのでdata
を追加して、urlに適当に値を設定してあげます。
<template><av-bind:href="url"class="nav-link"><slot></slot></a></template><script>exportdefault{name:"HelloWorld",data(){return{url:"https://www.google.com/"};}};</script>
ちなみにコンポーネントのdataオプションは関数である必要があります。 ※参考
上記に修正したところ、Chorme上のエラーが消えて、「Your Profile」がリンクになり、「https://www.google.com/」
を開けるようになりました。
②<font-awesome-icon>
が見つからない
親側(App.vue)で子コンポーネントタグの中にコンポーネントも含むことができるよの説明の中で、Font awesomeが使われていました。
とりあえず以下のように修正。
<template><divid="app"><HelloWorldurl="/profile"><!-- コンポーネントを使ってアイコンを追加 --><font-awesome-iconname="user"></font-awesome-icon>Your Profile
</HelloWorld></div></template><script>importHelloWorldfrom"./components/HelloWorld.vue";exportdefault{name:"app",components:{HelloWorld}};</script>
上記の修正を行ってChormeを確認したところ、以下のようなエラーが発生していました。font-awesome-icon
が見つからないとのこと。
②解決
ググって一番上にあった以下の記事を参考に、Font awesomeをinstall
します。
Font awesome を Vue.js で使ってみよう
※installコマンドを実行する前にサーバを停止します。
> npm install --save @fortawesome/fontawesome-svg-core
> npm install --save @fortawesome/free-solid-svg-icons
> npm install --save @fortawesome/vue-fontawesome
更に先ほどの記事を参考にsrc/main.js
を以下のように修正します。
importVuefrom'vue'importAppfrom'./App.vue'import{library}from'@fortawesome/fontawesome-svg-core'import{faCoffee}from'@fortawesome/free-solid-svg-icons'import{FontAwesomeIcon}from'@fortawesome/vue-fontawesome'library.add(faCoffee)Vue.component('font-awesome-icon',FontAwesomeIcon)Vue.config.productionTip=falsenewVue({render:h=>h(App),}).$mount('#app')
この状態で再度サーバを立ち上げて、ブラウザで確認します。
新たに以下のエラーが出ていました。。。
1つ目のエラーについて、とりあえず先ほどの参考記事の下の方まで確認すると、ここで<font-awesome-icon icon="coffee" />
としている部分を見つけました。name
ではなくicon
を指定するようです。
また、公式Githubの使用方法にも同様にicon
を指定している記述がありました。App.vue
を以下のように修正します。
<template><divid="app"><HelloWorldurl="/profile"><!-- コンポーネントを使ってアイコンを追加 --><font-awesome-iconicon="user"></font-awesome-icon>Your Profile
</HelloWorld></div></template><script>importHelloWorldfrom"./components/HelloWorld.vue";exportdefault{name:"app",components:{HelloWorld}};</script>
ブラウザを確認すると1つ目のエラーがなくなっていることを確認できました。
2つ目のエラーについては、なかなか原因が分からなかったのですが、先程の公式Githubの使用方法をよく確認すると、src/App.vue
でuser-secret
のアイコンを使用するために、src/main.js
において{ faUserSecret }
をimportしていることに気づきました。
どうやら使用したいアイコンによってimportするアイコンを指定する必要があるようです。
これに倣って、main.js
のimport部分とadd部分を修正します。
importVuefrom'vue'importAppfrom'./App.vue'import{library}from'@fortawesome/fontawesome-svg-core'import{faUser}from'@fortawesome/free-solid-svg-icons'import{FontAwesomeIcon}from'@fortawesome/vue-fontawesome'library.add(faUser)Vue.component('font-awesome-icon',FontAwesomeIcon)Vue.config.productionTip=falsenewVue({render:h=>h(App),}).$mount('#app')
上記の修正後、Chormeでエラーが出ていないことと、画面上でユーザーのアイコンが表示されていることを確認できました。
続く
長くなってしまったので次回に続きます。
崩れたレイアウトの調査方法
趣味でiOSアプリ開発をかじっていた自分が、改めてiOS開発を勉強し始めた際に、曖昧に理解していたところや知らなかったところをメモしています。いつか書き直します。
参考文献
この記事は以下の書籍の情報を参考にして執筆しました。
レイアウトが崩れる原因
レイアウトが一意に定まっていない、曖昧なレイアウト。
意図しない制約が反映されてしまう、制約のコンフリクトがある。
曖昧なレイアウト
レイアウトが曖昧かどうか調べる
hasAmbiguousLayout()を用いてレイアウトが曖昧かどうか調べることができる。
view.hasAmbiguousLayout
下記のようにviewの制約を設定している途中で実行するとtrueが帰ってくる。
hasAmbiguousLayout()がtrueの状態ではviewは表示されない。
letview1=UIView.init(frame:CGRect.init(x:0,y:0,width:300,height:250))view1.backgroundColor=.redview1.translatesAutoresizingMaskIntoConstraints=falseview.addSubview(view1)view1.topAnchor.constraint(equalTo:view.topAnchor,constant:200).isActive=trueview1.leadingAnchor.constraint(equalTo:view.leadingAnchor,constant:100).isActive=trueview1.widthAnchor.constraint(equalToConstant:200).isActive=trueprint(view1.hasAmbiguousLayout)// trueview1.heightAnchor.constraint(equalToConstant:200).isActive=trueprint(view1.hasAmbiguousLayout)// false
制約のコンフリクト
制約のコンフリクトはレイアウトエンジンによって自動的に不必要な制約が削除されることによって解決されるが、意図しないレイアウトとなることがあるのでレイアウトが崩れてしまうことがある。
制約のコンフリクトをデバッグする
例として意図的に制約のコンフリクトを発生させる。
letview1=UIView.init(frame:CGRect.init(x:0,y:0,width:300,height:250))view1.backgroundColor=.redview1.translatesAutoresizingMaskIntoConstraints=falseview.addSubview(view1)view1.topAnchor.constraint(equalTo:view.topAnchor,constant:200).isActive=true// 同じ要素かつ値が違う制約を宣言して制約をコンフリクトさせるview1.leadingAnchor.constraint(equalTo:view.leadingAnchor,constant:100).isActive=trueview1.leadingAnchor.constraint(equalTo:view.leadingAnchor,constant:200).isActive=trueview1.widthAnchor.constraint(equalToConstant:200).isActive=trueview1.heightAnchor.constraint(equalToConstant:200).isActive=true
エラーメッセージを読み解いて確認
実行時のエラーメッセージにコンフリクトした制約の概要が記載されている。
VisualFormatLanguage形式で記載されている。
[16824:2982179] [LayoutConstraints] Unable to simultaneously satisfy constraints.
Probably at least one of the constraints in the following list is one you don't want.
Try this:
(1) look at each constraint and try to figure out which you don't expect;
(2) find the code that added the unwanted constraint or constraints and fix it.
(
"<NSLayoutConstraint:0x600003802a30 H:|-(100)-[UIView:0x7fde9f408970] (active, names: '|':UIView:0x7fde9f40be70 )>",
"<NSLayoutConstraint:0x600003802a80 H:|-(200)-[UIView:0x7fde9f408970] (active, names: '|':UIView:0x7fde9f40be70 )>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x600003802a80 H:|-(200)-[UIView:0x7fde9f408970] (active, names: '|':UIView:0x7fde9f40be70 )>
Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKitCore/UIView.h> may also be helpful.
ビューデバッガーで確認
ビューデバッガーでの表示。画面左からの距離の制約が2つあることがわかる。
それぞれ[右クリック]→[Print Discripption of ~]で制約を表示させると値を確認できる。
Printing description of $21:
<NSLayoutConstraint:0x600003802a30 H:|-(100)-[UIView:0x7fde9f408970] (active, names: '|':UIView:0x7fde9f40be70 )>
Printing description of $22:
<NSLayoutConstraint:0x600003802a80 H:|-(200)-[UIView:0x7fde9f408970] (active, names: '|':UIView:0x7fde9f40be70 )>
VisualFormatLanguageを読みやすくするツール
https://www.wtfautolayout.com/
Viewの名称
indentiferなどに部品の名称を設定することでエラーメッセージの「0x7fde9f408970」こういうのを読みやすくできる。
レイアウト実装パターン
趣味でiOSアプリ開発をかじっていた自分が、改めてiOS開発を勉強し始めた際に、曖昧に理解していたところや知らなかったところをメモしています。いつか書き直します。
参考文献
この記事は以下の書籍の情報を参考にして執筆しました。
いくつかレイアウトの実装方法について書いてます
グループ化
UIの部品をUIViewによりグループ化し、中身のコンテンツの大きさにより高さと幅が下辺となるviewを作る。
IB上ではUILayoutGuideが使用できないのでUIViewで空間を作る。
ただし、空間の色を透明にすると描画処理が重くなってしまうので、出来れば色を指定した方がいい。
下記の例のviewは、x座標と上からの距離のみ指定されているが制約エラーは出ていない。
これは中身のviewにより高さと幅が決まっているためである。
まず高さのみ制約を見ると、コンテンツの高さ+制約で高さが求められている。
横幅も同じようになっている。
中身の部品はグループ化に使っているviewまたは互いに対して制約を指定しているので、画面を横にしても位置関係が変わることはない。
しかし今のレイアウトではコンテンツが入らない時に画像が隠れてしまう。
はみ出した時に画像だけは画面に入るように制約を加えてみる。
親view.width >= view.widthとなるように制約を加える。
関係を >= とすることでコンテンツが小さい時は親viewのwidthに依存しないようにした。
ラベルのTrailing Spaceの制約の優先度を下げて表示を行う。
同一幅のオブジェクト
幅を等しくするオブジェクトを全て選択して、EqualWidthを選択。
オブジェクト間の幅を等しくしたい場合
viewを2つ定義してAとBの間BとCの間に設置し、それぞれボタンとくっつける制約を定義する。
(ついでに高さをボタンと揃える)
最後にview同士の幅を等しくして終わり。
トルツメパターン
トルツメ : 不用なインターフェースを削除してその間のスペースを詰めること。
UITextViewを取り除きたい。
トルツメ失敗パターン
viewから消した場合
textView.removeFromSuperview()
非表示にした場合
textView.isHidden=true
viewから取り除ける場合のトルツメ
viewから消す場合はトルツメできた。
非表示にする場合はできない。
viewから取り除けない場合のトルツメ
再利用を前提としていてオブジェクトを取り除きたくない場合、Content Sizeに高さが依存しているオブジェクトであれば、コンテンツをnilにすることでトルツメできるようになる。
labelを取り除く場合
label.text=nil
imageの場合
imaageView.image=nil
StackViewを使った時のトルツメ
imageView.isHidden=true
UIStackViewを使ったレイアウト
ダメな例
まとめて選択してStackViewにしようとする。
StackViewは部品を一方向に揃えるのでレイアウトか崩れた。
小さな組み合わせからまとめる
縦方向横方向に並べる部品を細分化して小さなものからStackにしていく。
それぞれのStackViewの設定
一番大きなStack
・AlignmentをFillではなくcenterにすることで各要素の幅を別々に設定できるようにした。
・DiscributuonをFillにすることでどんな画面でも最大の幅で表示するようにした。
・Spacingで各要素の間隔を取っている。
画像をstackをまとめているstack
・AlignmentをTopにすることで文章が長くなっても画像が一番上に来るようにした。
・画像とstackの幅の比率を1:2に設定した。
・DiscributuonをFill Prportionallyにすることで画像の比率を崩さないようにした。
星の画像をまとめているstack
・DiscributuonをEqual Spacingにしたが、他のどの設定でも良かった。
・Spacingで間隔を空けている。
・AlignmentをFillとして全ての星の画像の比率を1:1にしているが、今回はwidthを等しくする制約をつけているので、高さの制約が必要となった。
widthを等しくする制約を消してstackViewの設定だけで実装しようとした時のレイアウト。
犬ラベルと説明textViewをまとめているstack
・Alignment、Discributuon共にFillにして横幅いっぱいに表示するようにした。
・textViewのscrolling Enabledをチェックマークを外して全文表示するようにしている。
コンテンツの高さに合わせてスクロールするView
画面を横にした時にコンテンツの高さだけスクロールできるViewを作る。
Scroll View の中に View を設置し中に部品を置く。
Viewの制約を追加する。
FrameLayoutGuideに対して、幅を等しくする制約を与える。
ContentLayoutGuideの上下左右と等しくする制約を設定して完成。
現在の仕様ではキーボードを表示した時に一番下のtextFieldが隠れてしまう。
キーボードを表示した時に上にスクロールしてずらす処理を実装する。
importUIKitclassViewController2:UIViewController,UITextFieldDelegate{@IBOutletweakvarbottomConstraint:NSLayoutConstraint!@IBOutletweakvarscrollView:UIScrollView!@IBOutletweakvartextField1:UITextField!@IBOutletweakvartextField2:UITextField!@IBOutletweakvartextField3:UITextField!@IBOutletweakvartextField4:UITextField!overridefuncviewDidLoad(){super.viewDidLoad()textField1.delegate=selftextField2.delegate=selftextField3.delegate=selftextField4.delegate=selfNotificationCenter.default.addObserver(self,selector:#selector(handleKeyboardWillShow(_:)),name:UIResponder.keyboardWillShowNotification,object:nil)NotificationCenter.default.addObserver(self,selector:#selector(handleKeyboardWillHide(_:)),name:UIResponder.keyboardWillHideNotification,object:nil)}@objcfunchandleKeyboardWillShow(_notification:Notification){guardletuserInfo=notification.userInfoas?[String:Any]else{return}guardletkeyboardInfo=userInfo[UIResponder.keyboardFrameBeginUserInfoKey]as?NSValueelse{return}guardletduration=userInfo[UIResponder.keyboardAnimationDurationUserInfoKey]as?Doubleelse{return}scrollIndicatorInsets(height:keyboardInfo.cgRectValue.size.height,duration:duration)}funcscrollIndicatorInsets(height:CGFloat,duration:Double){letcontentInsets=UIEdgeInsets(top:0,left:0,bottom:height,right:0)UIView.animate(withDuration:duration){self.scrollView.contentInset=contentInsetsself.scrollView.scrollIndicatorInsets=contentInsetsself.view.layoutIfNeeded()}}@objcfunchandleKeyboardWillHide(_notification:Notification){scrollView.contentInset=.zeroscrollView.scrollIndicatorInsets=.zero}functextFieldShouldReturn(_textField:UITextField)->Bool{// キーボードを閉じるtextField.resignFirstResponder()returntrue}}
コンテンツの大きさに合わせたTableView
TableViewCellクラスを作成してxibファイルと紐づける。
importUIKitclassTableViewCell:UITableViewCell{@IBOutletweakvarlabel:UILabel!@IBOutletweakvartextView:UITextView!funcsetCell(label:String,text:String){self.label.text=labelself.textView.text=text}}
tableViewを作る。先ほど作成したカスタムセルを呼び出す。
importUIKitclassViewController2:UIViewController,UITableViewDelegate,UITableViewDataSource{// 表示するデータletdisplayList=[["1","hoge\nhoge\nhoge"],["2","fuga\nfuga"],["3","piyo"],["4","a\naa\naaa"]]@IBOutletweakvartableView:UITableView!overridefuncviewDidLoad(){super.viewDidLoad()tableView.register(UINib(nibName:"TableViewCell",bundle:nil),forCellReuseIdentifier:"TableViewCell")}overridefuncdidReceiveMemoryWarning(){super.didReceiveMemoryWarning()}// セルの個数を指定するデリゲートメソッド(必須)functableView(_tableView:UITableView,numberOfRowsInSectionsection:Int)->Int{returndisplayList.count}// セルに値を設定するデータソースメソッド(必須)functableView(_tableView:UITableView,cellForRowAtindexPath:IndexPath)->UITableViewCell{// セルを取得するletcell=tableView.dequeueReusableCell(withIdentifier:"TableViewCell")as!TableViewCellcell.setCell(label:displayList[indexPath.row][0],text:displayList[indexPath.row][1])returncell}}
トレイトコレクションとレイアウト
趣味でiOSアプリ開発をかじっていた自分が、改めてiOS開発を勉強し始めた際に、曖昧に理解していたところや知らなかったところをメモしています。いつか書き直します。
参考文献
この記事は以下の書籍の情報を参考にして執筆しました。
トレイトコレクション
トレイトコレクションは表示に関わるアプリの状態管理をしていて、レイアウトを決定するための情報を提供してくれる。
トレイトコレクションの状態に合わせてレイアウトを変更することで柔軟なレイアウトを作れる。
トレイトコレクションはスクリーンで定義されウィンドウからビューコントローラに渡されていく。
UITraitCollectionのプロパティ
プロパティ | 型 | 役割 | 値 |
---|---|---|---|
displayScale | CGFlat | 表示スケール | 非Retina:1.0, Retina:2.0, 指定なし:0.0 |
horizontalSizeClass | UIUserInterfaceSizeClass | 水平方向の抽象的なサイズ | Unspecified, Compact, Regular |
verticalSizeClass | UIUserInterfaceSizeClass | 垂直方向の抽象的なサイズ | Unspecified, Compact, Regular |
userInterfaceIdiom | UIUserInterfaceIdiom | 端末種別 | Unspecified, Phone, Pad, TV |
forceTouchCapability | UIForceTouchCapability | 3Dタッチフラグ | Unknown, Unavailable, Availavle |
サイズクラス
端末と向き | 高さ | 幅 |
---|---|---|
iPad縦 | Regular | Regular |
iPad横 | Regular | Regular |
iPhone縦 | Regular | Compact |
iPhone横 | Compact | Compact |
iPhonePlus縦 | Regular | Compact |
iPhonePlus横 | Compact | Regular |
UITraitCollectionを比較する
containsTraits(: )メソッドを呼び出して比較する。
引数のトレイトコレクションを含んでいればtrueを返す。
// HorizontalSizeClass = Regular という値のみを持つトレイトコレクションを作成letregularWidthTrait=UITraitCollection(horizontalSizeClass:.compact)// self.traitCollection.HorizontalSizeClass == Compact の時trueを返すprint(self.traitCollection.containsTraits(in:regularWidthTrait))// true
UITraitCollectionを合成する
init(traitsFrom: )を用いて、トレイトコレクッションの配列を合成したトレイトコレクションを生成できる。
下記の例ではビューコントローラーの持つトレイトコレクションのhorizontalSizeClassをregularに上書きしたトレイトコレクションを生成する例。
letregularWidthTrait=UITraitCollection(horizontalSizeClass:.regular)letoverrideTraitCollection=UITraitCollection(traitsFrom:[self.traitCollection,regularWidthTrait])
端末の回転挙動を扱う
端末の回転挙動は以下の4つのステップに分かれている。
最初のセットアップ時にUITraitEnvironmentプロトコルとUIContentContainerプロトコルで定義されたメソッドたちが呼び出され、これらのメソッド内で回転挙動を扱うことができる
willTransition
トレイトコレクションが変化する直前かつ端末の回転時サイズクラスが変化する時に呼び出される。
サイズが変化しない場合、180°回転時やiPadのように縦横のsizeが同じ場合は呼ばれない。
トレイトコレクションはボトムアップに変更されていくので、トレイトコレクションの変更を子ビューコントローラに反映させる為にオーバーライドするときはsuperを呼ぶ必要がある。
viewWillTransition
アプリを表示しているウィンドウの大きさが変化する直前に呼ばれる。
トレイトコレクションの変更に関係せず表示画面サイズが変更されるときに呼び出されるので180°回転時やiPadでも呼び出される。
このメソッドも変更を子ビューコントローラに反映させる為にオーバーライドするときはsuperを呼ぶ必要がある。
taritCollectionDidChange
トレイトコレクションが変化した直後またトレイトコレクションがセットされた後に呼び出される。
アプリ起動時やビューコントローラが初めてロードされた時も呼び出される。
このメソッドも変更を子ビューコントローラに反映させる為にオーバーライドするときはsuperを呼ぶ必要がある。
端末回転時のアニメーション
端末回転時にレイアウトを変更するだけなら上記3つのどのメソッド内に処理を書いても問題はないが、アニメーションと同期してオブジェクトを動かす場合はwillTransition,viewWillTransitionを使う。
overridefuncviewWillTransition(tosize:CGSize,withcoordinator:UIViewControllerTransitionCoordinator){super.viewWillTransition(to:size,with:coordinator)coordinator.animate(alongsideTransition:{contextinif(size.width<=size.height){// 縦画面レイアウト用にアニメーションさせたい処理print("tate")}else{// 横画面レイアウト用にアニメーションさせたい処理print("yoko")}},completion:nil)}
各オブジェクトごとにサイズクラスを適用する
下記のように設定するとWidthがRegular、HeightがCompactの時のみオブジェクトが適用される。
プログラミング言語(ruby)学んでみて
プログラミング言語に初めて触れました。
ルービー、サファイアと聞くと美しい宝石を思い浮かべます。
ですが、学びが浅すぎて、まだrubyのもつ言語の美しさに気付けていません。。
マークアップ言語とrubyの初歩を学んだばかりですが、自分なりに感じたことを述べます。数ヶ月経つとrubyという言語に対する感じ方も変わってくると思いますので。
プログラミングを学んでからまだ数日しか経っていない、本当の初学者としての受講生の気持ちに寄り添えるように、アウトプットとして残しておきます。
まず、
暗記しようとしないほうがいいのかも、ということです。
初めて出てくる単語やルールを全てくまなく覚えようとすると精神的負荷が高い。
本質的な部分を学ぶ労力が削がれる気がしました。
ですので、理解に重点を置いて、単語やルールは出てきた度に慣れながら覚えていこうと思います。
次に、
いま何をやっているかが分からくなりそうになる、ということです。
木を見て森を見ず、という言葉がありますがまさにそうでした。
でも、森を見すぎても分からないので、林を見つつ、木をこなしていきたいと思います。
森 ⇄ 林 ⇄ 木
お手本をただただ模写するのでは学習効果が薄い気がしています。
自分なりにコードの区切りや意味を唱えながら一行づつ打ち出すべきなのかもしれません。
いま学んでいる時の感情や考えを忘れず今後に生かしていきたいと思います。
終わり。
Railsチュートリアル 第13章 ユーザーのマイクロポスト - 基本的な画像アップロード
作成中のアプリケーションから、画像アップローダー「CarrierWave」を使えるようにする
画像投稿機能を実装するために必要な画像アップローダーとして、今回は、「CarieerWave」という画像アップローダーを用います。CarrierWaveをRailsアプリケーションで用いるためには、Railsアプリケーション側にcarrierwave
というgemが必要となります。
早速Gemfile
を更新していきましょう。
source 'https://rubygems.org'
gem 'rails', '5.1.6'
gem 'bcrypt', '3.1.12'
gem 'faker', '1.7.3'
+ gem 'carrierwave', '1.2.2'
+ gem 'mini_magick', '4.7.0'
gem 'will_paginate', '3.1.6'
...略
group :production do
gem 'pg', '0.20.0'
+ gem 'fog', '1.42'
end
...略
とりあえず現時点で必要になるのはcarrierwave
のみです。mini_magickや
fog`というgemは、今後追加していく機能で使用するgemです。
Gemfileを更新したので、当然ながらbundle install
を実行する必要があります。
# bundle install
...略
Fetching gem metadata from https://rubygems.org/........
Fetching gem metadata from https://rubygems.org/.
Resolving dependencies....
...略
Fetching mime-types-data 3.2019.1009
Installing mime-types-data 3.2019.1009
Fetching mime-types 3.3.1
Installing mime-types 3.3.1
Fetching carrierwave 1.2.2
Installing carrierwave 1.2.2
...略
Fetching mini_magick 4.7.0
Installing mini_magick 4.7.0
...略
Bundle complete! 29 Gemfile dependencies, 88 gems now installed.
Gems in the group production were not installed.
Bundled gems are installed into `/usr/local/bundle`
bundle install
は特に問題なく完了できたようです。
Railsのジェネレーターで画像アップローダーを生成する
# rails generate uploader Picture
Running via Spring preloader in process 15235
create app/uploaders/picture_uploader.rb
少なくともcarrierwave
(または他の画像アップローダー)gemがインストールされていないと、rails generate uploader
コマンドは正常に完了しません。
アップロードされた画像をMicropostモデルに関連付けるようにする
マイクロポストに画像を関連付けるために必要な属性の追加
マイクロポストの画像投稿機能は「画像はマイクロポストに紐付けされる」という実装内容になるため、アップロードされた画像はMicropostモデルに関連付けられるのが自然な実装モデルです。実際には、「RDB上microposts
テーブルのpicture
カラムに、アップロードされた画像のファイル名を格納する」という形の実装をします。picture
カラムにはファイル名が入るので、型はstring
となります。
picture
カラムを追加した新たなマイクロポストのデータモデルは、以下のようになります。
データモデルに変更を加えたので、対応するマイグレーションファイルの生成、ならびに生成したマイグレーションのRDBへの適用が必要となります。なお今回は、生成したマイグレーションファイルの内容に手を加える部分はありません。
# rails generate migration add_picture_to_microposts picture:string
Running via Spring preloader in process 15244
invoke active_record
create db/migrate/20200105225338_add_picture_to_microposts.rb
# rails db:migrate
== [timestamp] AddPictureToMicroposts: migrating ===========================
-- add_column(:microposts, :picture, :string)
-> 0.0183s
== [timestamp] AddPictureToMicroposts: migrated (0.0199s) ==================
Micropostモデル側でCarrierWaveを使うために必要な実装
画像と関連付けたモデルをCarrierWave側に伝えるためには、モデル側でmount_uploader
メソッドを呼び出します。mount_uploader
の第1引数は「属性名を指すシンボル」、第2引数は「アップローダーのクラス名」を取ります。例えば「モデル側の属性名がpicture
、アップローダー名がPictureUploader
」であれば、mount_uploader
メソッドは以下のように呼び出されます。
mount_uploader:picture,PictureUploader
app/models/micropost.rb
全体の変更内容は以下のようになります。
class Micropost < ApplicationRecord
belongs_to :user
default_scope -> { order(created_at: :desc) }
+ mount_uploader :picture, PictureUploader
validates :user_id, presence: true
validates :content, presence: true, length: { maximum: 140 }
end
現時点で、テストスイートは全体が成功するはずです。
# rails test
Running via Spring preloader in process 15277
Started with run options --seed 12165
61/61: [=================================] 100% Time: 00:00:13, Time: 00:00:13
Finished in 13.04142s
61 tests, 329 assertions, 0 failures, 0 errors, 0 skips
マイクロポスト投稿フォームに画像アップローダーを追加する
Homeページに画像アップローダーを表示させるためには、マイクロポスト投稿フォームに画像アップローダーを追加するのが自然です。このような場合に使うのはfile_field
メソッドとなります。早速app/views/shared/_micropost_form.html.erb
に画像アップローダーの実装を追加しましょう。
<%= form_for(@micropost) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<div class="field">
<%= f.text_area :content, placeholder: "Compose new micropost..." %>
</div>
<%= f.submit "Post", class: "btn btn-primary" %>
+ <span class="picture">
+ <%= f.file_field :picture %>
+ </span>
<% end %>
MicropostモデルのWebから更新できる属性に、新たにpicture
を追加する
Webから画像をアップロードしてマイクロポストに紐付けられるようにするためには、Micropostコントローラーで用いているStrong Parameters機能で、Webからの更新を許可するパラメーターにpicture
を追加する必要があります。変更対象のファイルはapp/controllers/microposts_controller.rb
ですね。
class MicropostsController < ApplicationController
...略
private
def micropost_params
- params.require(:micropost).permit(:content)
+ params.require(:micropost).permit(:content, :picture)
end
...略
end
マイクロポストの画像表示を追加する
マイクロポストに画像を関連付けても、その画像がフィード画面に表示されないのでは意味がありません。というわけで、Micropostパーシャル側にも「マイクロポストの画像表示」のための新たな実装が必要となります。Micropostパーシャルの実体であるapp/views/microposts/_micropost.html.erb
は、以下のように変更していきます。
<li id="micropost-<%= micropost.id %>">
<%= link_to gravatar_for(micropost.user, size: 50), micropost.user %>
<span class="user"><%= link_to micropost.user.name, micropost.user %></span>
- <span class="content"><%= micropost.content %></span>
+ <span class="content">
+ <%= micropost.content %>
+ <%= image_tag micropost.picture.url if micropost.picture? %>
+ </span>
<span class="timestamp">
Posted <%= time_ago_in_words(micropost.created_at) %> ago.
<% if current_user?(micropost.user) %>
<%= link_to "delete", micropost, method: :delete, data: { confirm: "You sure?" } %>
<% end %>
</span>
</li>
「マイクロポストに画像が関連付けられていなければ、画像を表示する部分の描画そのものを行わない」というのがポイントです。「マイクロポストに画像が関連付けられているか否か」というのは、picture?
というメソッドの戻り値によってわかるようになっています。
picture?
メソッドは、CarrierWaveによって自動的に生成されるメソッドです。メソッド名は、モデル側で定義した画像の属性名をもとにして、CarrierWaveによって自動的に決定されます。
【Vuex】同じmutationsが多数繰り返されるエラーが発生していたら確認した方がいいこと
はじめに
先日、こちらの記事を書きました。
【Vuex】mapState, mapGetters, mapMutations, mapActionsの最低限の使い方まとめ - Qiita
上記に関連して、記事を書こうと思ったきっかけになったエラーについても記録として残しておこうと思います。
以下のように同じmutationsが繰り返されていたら怪しんでみて下さい
環境
OS:macOS Catalina 10.15.1Vue:2.6.10vuex:3.1.2
エラー原因
computed
プロパティ内に...mapMutations
を書いてしまっている。
methods
プロパティ内に書くのが正しいです。
ダメな例
//...computed:{...mapMutations(['anyMutation',]),},methods:{anyMethod(){this.anyMutation()}}//..
良い例
//..methods:{...mapMutations(['anyMutation',]),anyMethod(){this.anyMutation()}}//..
これで無事読み込まれます。
おわりに
最後まで読んで頂きありがとうございました
どなたかの参考になれば幸いです
画面幅に合わせて可変する正方形を作りたい
はじめに
レスポンシブ対応のウェブページを作っているときに、画面幅に合わせて可変する正方形が必要になったので、調べて実装しました。
今後、使い回しが効きそうだったので備忘録として残しておきます。
固定サイズの正方形を作る
<divclass="square"></div><style>.square{width:100px;height:100px;background-color:red;}</style>
こうですね。
わかりやすく赤色の正方形です。
横方向を画面幅に合わせて可変させる
<divclass="square"></div><style>.square{width:50%; <=変更しましたheight:100px;background-color:red;}</style>
この状態で、画面幅をいじると、四角形の横幅が変化します。
正方形にする
<divclass="square"><divclass="inner"></div></div><style>.square{width:50%;height:100px;background-color:red;}.inner{width:0px;height:0px;}
四角形の中に、高さ・幅とも0のdivを入れました。
この中に入れたdivにpadding-bottomを設定します。
.inner{width:0px;height:0px;padding-bottom:100%;<=追加}
marginやpaddingを%で指定する場合、親要素の幅から計算されます。
topやbottomでも親要素の幅が基準になります。
なので赤い四角形の幅が500pxだった場合、padding-bottom 100%も500pxになるわけです。
最後に赤い四角形の高さ指定を外してあげれば、完成です。
完成形
<divclass="square"><divclass="inner"></div></div><style>.square{width:50%;background-color:red;}.inner{width:0px;height:0px;padding-bottom:100%;}
画面幅に合わせて可変する正方形の完成です。
Amplifyのqueryでfilterするときのand orなどの書き方
書いた経緯
Amplify で自動生成されたqueryのDocsをみていて、自動でandとかcontainsとか自動されていて便利だなと思いつつ、andとorとかの書き方がわからずググっていたのですがすぐみつからず、ああかなこうかなと書いてわかったので同じ感じでまよった方のために共有するため書きました。よくよく定義をみたら当たり前の書き方でした。
記事の対象の方
- Amplify触り始めて、queryの書き方で試行錯誤している人(私)
既知とする条件(書かないこと)
- Amplifyの使い方
- graphqlとは?
本文
以下のようなtypeを定義したとします。
typeUser@model{id: ID!lastName: String!firstName: String!createdAt: AWSDateTime}
amplifyが自動で以下のUserリストをとるqueryを作成してくれます。
# by amplifylistUsers(filter: ModelUserFilterInputlimit: IntnextToken: String):ModelUserConnection
filter: ModelUserFilterInput
の定義は以下が自動生成されています。
# by AmplifytypeModelUserFilterInput{id: ModelIDInputlastName: ModelStringInputfirstName: ModelStringInputcreatedAt: ModelStringInputand: [ModelUserFilterInput]or: [ModelUserFilterInput]not: ModelUserFilterInput}
ここで以下のシンプルなフィルター使用したqueryを書きます。
# 自分で定義querylistUsers($input:ModelUserFilterInput){listUsers(filter: $input){items{firstNamelastNamecreatedAt}}}
そして変数に値を入力します。まずシンプルなものです。
fistNameにTaro
が含まれるものを取得します。
# 自分で定義{"input":{"firstName":{"contains":"Taro"}}}
結果
{"data":{"listUsers":{"items":[{"firstName":"Taro","lastName":"Yamada","createdAt":"2020-01-09T15:37:22.819Z"}]}}}
and or を使ったquery
以下のように書きます。Docsの定義をみるかぎり[ModelUserFilterInput]
とあるので配列を与えるので
以下のようになります。
{"input":{"and":[#andを先に書く!{"firstName":{"contains":"T"}},{"lastName":{"eq":"Yamada"}}]}}
結果は先ほどと同じです。
同様にor
は
{"input":{"or":[{"firstName":{"contains":"T"}},{"firstName":{"contains":"K"}}]}}
で結果は同じです。
以上です。
蛇足
本文とあんまり関係ないですが、and
とかor
をさきにかくと関数みたいなのにeq
とかは違うのが感覚的に迷いました。
Clojureなら(関数 値)
で一貫してますが
;includesのあとにfirstName
(and
(includes?
(.firstName "T")
(=
(.lastName "Yamada"))
graphqlの場合はcontainsは変数のあと、andは先にくるのが感覚的に分かり難かったです。
#amplifyの場合 containsはfirstNameのあと
"and": [
{
"firstName": {
"contains": "T"
}
},
{
"lastName": {
"eq": "Yamada"
}
}
]
【クラウド初心者向け】お客様の選択による分岐と外線転送
概要
- お客様の選択した数字により処理が分岐します。
- 繰り返しは3回とします。
- あらかじめ指定した番号の外線に発信します。
使用ユーザー
- IAMユーザー
手順
AWSにサインインします。
- アカウント、ユーザー名、パスワードを入力してサインインします。
アカウント内(IAM)で作成したユーザーを使用してコンソールにサインインする
- アカウント、ユーザー名、パスワードを入力してサインインします。
『AWSマネジメントコンソール』画面にある「サービスを検索」にConnectと入力し、検索結果から《Amazon Connect》をクリックし、Amazon Connect コンソール(https://console.aws.amazon.com/connect/)を開きます。
Amazon Connectの案内音声を人間の音声に変更で作成した問い合わせフローをクリックします。
左側メニューの「操作」から《顧客の入力を取得する》をフロー部分にドラッグ&ドロップし、オブジェクト同志を矢印で接続後に《顧客の入力を取得する》のタイトル部分をクリックします。
右側に「プロンプトの再生」画面が表示されるので、以下の項目を選択、入力して《別の条件の追加》を3回クリックします。
- テキスト読み上げまたはチャットテキスト:選択します。
- テキストの入力:選択し、音声案内する文言を入力します。
顧客の入力を取得するの説明
タイムアウト
入力しない時間がタイムアウトの設定に設定した秒数経過した場合に発生します。
デフォルト
入力値(オプション)として想定していない番号が入力された場合に発生します。
左側メニューの「終了/ハングアップ」から《切断/ハングアップ》をフロー部分にドラッグ&ドロップし、オブジェクト同志を矢印で接続します。
左側メニューの「操作」から《プロンプトの再生》をフロー部分にドラッグ&ドロップし、オブジェクト同志を矢印で接続後に《顧客の入力を取得する》のタイトル部分をクリックします。
右側に「プロンプトの再生」画面が表示されるので、以下の項目を選択、入力して《Save》をクリックします。
- テキスト読み上げまたはチャットテキスト:選択します。
- テキストの入力:選択し、音声案内する文言を入力します。
左側メニューの「操作」から《プロンプトの再生》をフロー部分にドラッグ&ドロップし、オブジェクト同志を矢印で接続後に《プロンプトの再生》のタイトル部分をクリックします。
左側メニューの「終了/転送」から《電話番号への転送》をフロー部分にドラッグ&ドロップし、オブジェクト同志を矢印で接続後に《電話番号への転送》のタイトル部分をクリックします。
右側に「電話番号への転送」画面が表示されるので、以下の項目を選択、入力します。
- 国コード:転送先の国コード
- 電話番号:頭の0を除いた転送先の電話番号
下にスクロールして、以下の項目を選択して《Save》をクリックします。
- 「Caller ID番号」を選択
- 「インスタンスから番号」を選択しますを選択
- ダイアログボックスをクリックして番号を選択
目次に戻る
【C#】SQLのBulkInsertでファイルにアクセスできなかったのでC#で自作した話(初心者)
「ちょろいっすよ!」
私は入社2年目の駆け出し技術者です。
ある日上司がSQL初心者の私に頼み事をしてきました。
上司「ちょっと相談があるんやけど、、、」
上司「今、DBにこんなテーブルがあるんだけど、」
TABLE1
ID | 名称 | サービスID |
---|---|---|
1 | 名前A | 3 |
2 | 名前B | 2 |
3 | 名前C | 2 |
上司「本来このテーブルのサービスIDカラムに対応するサービス名称があるんだけど、
使わんから、このCSVの対応表だけ作って終わりにしたんや」
1,サービスA
2,サービスB
3,サービスC
4,サービスD
5,サービスE
上司「でもやっぱりサービス名称これから使いそうやから、JOINで取れるようにCSVから対応表通りのテーブルを作ってくれない?」
上司「クライアント側にはCSVは定期的に変更してもいいって言っているから、テーブル作成するスクリプトやらなんやらをタスクスケジューラで定期実行してな」
私「よくある話ですね。多分SQLのBulkInsert使えば一発なんでちょろいっすよwww」
ちょろいはずだった・・・
私「よーし、ちゃっちゃとSQL書いちゃおー」
私「まずはテーブル作成して、」
CREATETABLESERVICE_TABLE(Service_IDintnotnull,Service_Namevarchar(102)notnull);
私「あとはBulkInsertして終いや!」
私「定期実行するから頭でTRUNCATEしとこ。」
TRUNCATETABLESERVICE_TABLEBULKINSERTSERVICE_TABLEFROM'C:\hoge\Service.csv'WITH(FIELDTERMINATOR=',',ROWTERMINATOR='\n');
私「あとは"C:\hoge"にService.csvを置いて、、、実行!」
私「、、、え!?」
ファイル"C:\hoge\Service.csv"を開けなかったので、一括読み込みできません。
私「なんでや、、、」
悪戦苦闘
この後、ググりながらhogeフォルダのセキュリティ設定やDB側の設定をいじってみたのですが、1時間かけても結局できませんでした。
SQLサーバ認証を用いているとファイルのアクセス権がーとかBulkInsertで指定するパスはDBサーバ上のパスでーとかいろいろ書いてあり、もう何が本当かもわからなくなりました。
ちなみにこの作業は別のサーバ上で行いたかったのでDBサーバ上にcsvファイル置いてーはできません。
もしかしたら、わかる人がやれば一瞬なのかもしれません。
設定でなんとかなるよっていう方はコメントでご教授お願いします。
めんどくさくなった
私「めんどくさいなー。帰ってゲームしたいなー」
私「もうC#でBulkInsertと同じことするコンソールアプリ作ったほうが早くね?(やけくそ)」
私「そのアプリのexeをタスクスケジューラで定期実行したら同じじゃん!(天才)」
私「まずはデータクラスを作って」
classServiceData{/// <summary>/// サービスID/// </summary>publicintServiceID{get;set;}/// <summary>/// サービス名称/// </summary>publicstringServiceName{get;set;}}
私「SQLServer操作クラスを作るか。今回の機能的にこれくらいあればいいかな」
usingSystem;usingSystem.Collections.Generic;usingSystem.Data.SqlClient;namespaceBulkInsertApp{publicclassMSSqlManager{privateSqlConnectionsqlConnection;privateSqlTransactionsqlTransaction;/// <summary>/// 接続文字列生成/// </summary>/// <returns>接続文字列</returns>privatestringGetConnectionString(){stringconnectionString=null;stringuserId="<SQL認証のユーザ名>";stringpassword="<SQL認証のパスワード>";stringdbname="<DB名>";stringdbpath="<DBサーバアドレス>";connectionString="Persist Security Info=False;"+"User ID = "+userId+"; Password = "+password+"; Initial Catalog = "+dbname+"; Data Source = "+dbpath;}returnconnectionString;}publicMSSqlManager(){try{stringconnectString=GetConnectionString();this.sqlConnection=newSqlConnection(connectString);this.sqlConnection.Open();}catch(Exceptionex){Console.WriteLine(ex.Message);throw;}}publicvoidClose(){try{this.sqlConnection.Close();this.sqlConnection.Dispose();}catch(Exceptionex){Console.WriteLine(ex.Message);throw;}}publicvoidBeginTran(){try{this.sqlTransaction=this.sqlConnection.BeginTransaction();}catch(Exceptionex){Console.WriteLine(ex.Message);throw;}}publicvoidCommitTran(){try{if(this.sqlTransaction.Connection!=null){this.sqlTransaction.Commit();this.sqlTransaction.Dispose();}}catch(Exceptionex){Console.WriteLine(ex.Message);throw;}}publicvoidRollBack(){try{if(this.sqlTransaction.Connection!=null){this.sqlTransaction.Rollback();this.sqlTransaction.Dispose();}}catch(Exceptionex){Console.WriteLine(ex.Message);throw;}}publicvoidExecuteInsert(stringquery,Dictionary<string,Object>paramDict){SqlCommandsqlCom=newSqlCommand();try{//クエリー送信先、トランザクションの指定sqlCom.Connection=this.sqlConnection;sqlCom.Transaction=this.sqlTransaction;sqlCom.CommandText=query;foreach(KeyValuePair<string,Object>iteminparamDict){sqlCom.Parameters.Add(newSqlParameter(item.Key,item.Value));}// SQLを実行sqlCom.ExecuteNonQuery();}catch(Exceptionex){Console.WriteLine(ex.Message);throw;}}publicvoidExecuteQuery(stringquery){try{SqlCommandsqlCom=newSqlCommand();sqlCom.Connection=this.sqlConnection;sqlCom.Transaction=this.sqlTransaction;sqlCom.CommandText=query;sqlCom.ExecuteNonQuery();}catch(Exceptionex){Console.WriteLine(ex.Message);throw;}}}}
私「あとはCSV読み込み→テーブルTruncate→CSVデータInsertすれば終いや!」
usingSystem;usingSystem.Collections.Generic;usingSystem.Data.SqlClient;usingSystem.IO;usingSystem.Text;namespaceBulkInsertApp{publicclassServiceBulk{publicvoidServiceBulkManager(){List<ServiceData>ServiceDataList=CSVDataGet();TruncateTable();BulkInsert(ServiceDataList);}privateList<ServiceData>CSVDataGet(){List<ServiceData>retList=newList<ServiceData>();StreamReadersr=newStreamReader(@"C:\hoge\Service.csv",Encoding.GetEncoding("Shift_JIS"));try{while(!sr.EndOfStream){ServiceDataServiceData=newServiceData();stringline=sr.ReadLine();string[]values=line.Split(',');List<string>items=newList<string>();items.AddRange(values);if(items.Count==2){ServiceData.ServiceID=int.Parse(items[0]);ServiceData.ServiceName=items[1];retList.Add(ServiceData);}}}catch(Exceptione){Console.WriteLine(e.Message);}finally{sr.Close();}returnretList;}privatevoidTruncateTable(){MSSqlManagermanager=newMSSqlManager();try{manager.BeginTran();stringquery="TRUNCATE TABLE SERVICE_TABLE";manager.ExecuteQuery(query);manager.CommitTran();}catch(SqlExceptionsqle){stringerror="Number: "+sqle.Number+" Message: "+sqle.Message;Console.WriteLine(error);manager.RollBack();throw;}catch(Exceptionex){Console.WriteLine(ex.Message);throw;}finally{manager.Close();}}privatevoidBulkInsert(List<ServiceData>listData){MSSqlManagermanager=newMSSqlManager();try{manager.BeginTran();foreach(ServiceDatadatainlistData){stringsqlstr="INSERT INTO SERVICE_TABLE "+"(Service_ID, ServiceName)"+" values "+"(@Service_ID, @Service_Name)";Dictionary<string,Object>paramDict=newDictionary<string,object>();paramDict.Add("@Service_ID",data.ServiceID);paramDict.Add("@Service_Name",data.ServiceName);manager.ExecuteInsert(sqlstr,paramDict);}manager.CommitTran();}catch(SqlExceptionsqle){stringerror="Number: "+sqle.Number+" Message: "+sqle.Message;Console.WriteLine(error);manager.RollBack();throw;}catch(Exceptionex){Console.WriteLine(ex.Message);throw;}finally{manager.Close();}}}}
私「あとはこいつをメインから呼び出せばええんや」
usingSystem;usingSystem.Collections.Generic;usingSystem.Text;usingSystem.Threading.Tasks;namespaceBulkInsertApp{classProgram{publicstaticvoidMain(string[]args){ServiceBulksb=newServiceBulk();sb.ServiceBulkManager();}}}
私「よっしゃできたやで」
私「ビルドして実行や!よしテーブル見てみよう!」
SERVICE_TABLE
Service_ID | Service_Name |
---|---|
1 | サービスA |
2 | サービスB |
3 | サービスC |
4 | サービスD |
5 | サービスE |
私「よっしゃOKや!」
私「できましたよー。これを実行してくださいー!」
上司「ありがとうやで。(なんでこいつexe渡してきたんや?まぁできてるならいいか)」
あとがき
最後まで読んでいただきありがとうございます。
業務内容に関わる箇所や処理等、都合により一部割愛しております。
まだまだ経験が浅いのでクソみたいなコードです。(StringBuilder使え)
コメントでコードレビューお願い致します
Railsで開発した個人アプリにDockerを導入する手順と最低限の知識
Railsで開発した個人アプリに、後からDockerを導入しました。
その時知識不足なせいでハマってしまった場面があったので、自分の中で整理してアウトプットすることを目的にこの記事を書き残します。
ちなみに、以下の記事を主に参考にさせていただきました。
DockerをMacにインストールする
Docker + Rails + Puma + Nginx + MySQL
RailsアプリにDockerを導入する手順+事前知識
まずは事前知識として、これは知っておいたほうがいいというものを簡単に書いていきます。
事前知識 - Docker関係
Docker(ドッカー)
※1.軽量な仮想化環境を実現するためのツール。
OS やアプリケーションを設定したものを丸ごと実行イメージとして保存できるので、Docker が導入されている別のマシンにそのまま持って行くことができる。
実行環境をテキストファイルとして共有できるのでとても便利。
※1.仮想化環境とは、コンピュータ上にソフトウェアによって仮想的に構築されたコンピュータ(仮想マシン)が備える仕様や機能の総体のこと。
Dockerイメージ
Dockerイメージは、コンテナを起動させるためのベースとなるもの(オブジェクト指向でいうと「クラス」にあたる)
テキストファイル(Dockerfile)からビルドされる。(後に記述)
DockerHub(Docker向けのコンテナ共有サービス)では、既に多くのイメージが公開されている。
Dockerコンテナ
Dockerのコンテナは、 Dockerイメージを元に作成される仮想環境の実行部分(オブジェクト指向でいうと「インスタンス」にあたる)
原則1コンテナ1アプリ。
Dockerfile(ドッカーファイル)
指定したベースのDockerイメージに加える変更を記述するファイル。
Dockerfileを使うことでオリジナルのDockerイメージを作成することができる。
docker-compose(ドッカーコンポーズ)
複数のコンテナから構成されるアプリケーションで、Dockerイメージのビルドや各コンテナの起動・停止などをより簡単に行えるようにするツール。
docker-composeを使用する際は「docker-compose.yml」が必要になる。
事前知識 - サーバ関係
ミドルウェア
OSとアプリケーションの間に入り、中間的な処理を行うソフトウェアのこと。
ー 例 ー
- Webサーバ
- Apache、NginXなど
- APサーバ
- Puma
- Unicornなど
- DBサーバ
- MySQL
- PostgreSQLなど
Nginx(エンジンエックス)
webサーバの一つ。
Apacheよりも処理能力が高い。
puma(プーマ)
※1.Rackという機能を提供するためのアプリケーションサーバ。
webサーバの1つでもある。
※1.RackとはWeb サーバと Rubyやフレームワークをつなぐ最小のインタフェースを提供するもの。
Docker導入手順
① Docker for Macを公式サイトからインストール、そして起動
公式サイトで会員登録を済ませた後、Docker for Macをダウンロードしインストール。
インストールが終わったら、Dockerを起動しておく。
(MACの画面上部にDockerのマークが出れば起動できてる証拠)
②作成済みのアプリケーションフォルダの直下に「Dockerfile」、「docker-compose.yml」ファイルを新しく作成する。
フォルダ構成
- 既存のRailsアプリフォルダ
- app
- bin
- config
- db
- ・・・
- Dockerfile
- docker-compose.yml
③Dockerfileに記述する(アプリケーションフォルダ直下)
FROMruby:2.5.1RUNapt-getupdate&&\apt-getinstall-ymysql-clientnodejsvim--no-install-recommends&&\rm-rf/var/lib/apt/lists/*RUNmkdir/myproject
WORKDIR /myprojectADDGemfile/myproject/GemfileADDGemfile.lock/myproject/Gemfile.lockRUNgeminstallbundlerRUNbundleinstallADD./myprojectRUNmkdir-ptmp/sockets
④docker-compose.ymlに記述する(アプリケーションフォルダ直下)
version:'2'services:db:image:mysql:5.6environment:-./environments/db.envvolumes:-mysql-data:/var/lib/mysqlports:-"4306:3306"app:build:.command:bundle exec puma -C config/puma.rbvolumes:-.:/myproject-public-data:/myproject/public-tmp-data:/myproject/tmp-log-data:/myproject/logweb:build:context:containers/nginxvolumes:-public-data:/myproject/public-tmp-data:/myproject/tmpports:-80:80volumes:mysql-data:public-data:tmp-data:log-data:
⑤アプリケーションフォルダ直下に「environments」フォルダを作成、さらにenvironmentsフォルダ直下に「db.env」ファイルを作成する。
- 既存のRailsアプリフォルダ
- app
- bin
- config
- db
- environments
- db.env
- ・・・
- Dockerfile
- docker-compose.yml
⑥db.envを編集
MYSQL_ROOT_PASSWORD=password
MYSQL_USER=user
MYSQL_PASSWORD=password
⑦database.ymlを編集
default: &default
adapter: mysql2
encoding: utf8
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
username: <%= ENV.fetch('MYSQL_USER') { 'root' } %>
password: <%= ENV.fetch('MYSQL_PASSWORD') { 'root' } %>
host: db
⑧アプリケーションフォルダ直下に「containers」フォルダを作成、さらにcontainersフォルダ直下に「nginx」フォルダを作成する。
フォルダ構成
- 既存のRailsアプリフォルダ
- app
- bin
- config
- containers
- nginx
- db
- environments
- db.env
- ・・・
- Dockerfile
- docker-compose.yml
⑨作成したnginxフォルダ直下に「Dockerfile」、「nginx.conf」ファイルを作成する。
- 既存のRailsアプリフォルダ
- app
- bin
- config
- containers
- nginx
- Dockerfile
- nginx.conf
- nginx
- db
- environments
- db.env
- ・・・
- Dockerfile
- docker-compose.yml
⑩Dockerfileに記述する(containers/nginxフォルダ直下)
FROMnginx:1.15.8RUNrm-f/etc/nginx/conf.d/*ADDnginx.conf/etc/nginx/conf.d/myproject.confCMD/usr/sbin/nginx-g'daemon off;'-c/etc/nginx/nginx.conf
⑪nginx.confに記述する(containers/nginxフォルダ直下)
upstream myproject {
server unix:///myproject/tmp/sockets/puma.sock;
}
server {
listen 80;
server_name 13.112.60.229;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
root /myproject/public;
client_max_body_size 100m;
error_page 404 /404.html;
error_page 505 502 503 504 /500.html;
try_files $uri/index.html $uri @myproject;
keepalive_timeout 5;
location @myproject {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_pass http://myproject;
}
}
⑫puma.rbを編集
app_root=File.expand_path("../..",__FILE__)bind"unix://#{app_root}/tmp/sockets/puma.sock"stdout_redirect"#{app_root}/log/puma.stdout.log","#{app_root}/log/puma.stderr.log",true
⑬ターミナルでコマンドを実行
ファイルの準備が整ったら、最後にターミナル上でコマンドを実行。
(railsアプリケーションフォルダ内で実行する)
イメージを構築する
$docker-compose build
railsのコンテナを作成し、データベースの作成処理を行う
$docker-compose run --rm app rake db:create db:migrate
全てのコンテナを構築・起動する
$docker-compose up
上記の流れが終わったあとlocalhostにアクセスすると、しっかり確認することができました。
ちなみに今回書きまとめたものは、DBもDockerで管理することになりますが、DBはローカルのものを参照したいという場合、以下の記事が参考になるかと思います。
既存のRailsアプリをDocker化し、ローカルのDBに接続する方法
(おまけ)
Dockerfileに記述できるコマンド一覧
コマンド | 意味 |
---|---|
FROM | ベースとなるイメージ |
RUN | docker build 時に実行するコマンド |
CMD | docker run 時に実行するコマンド |
ENTRYPOINT | docker run 時に実行するコマンド |
MAINTAINER | 作者情報 |
LABEL | ラベル情報(メタデータ) |
EXPOSE | 公開ポート番号 |
ENV | 環境変数 |
ARG | 一時変数 |
COPY | ホストからコンテナへのファイルコピー |
ADD | ファイル/ディレクトリの追加 |
VOLUME | ボリュームのマウント |
USER | 実行ユーザ |
SHELL | シェル指定 |
WORKDIR | ワークディレクトリ |
ONBUILD | ビルド時に実行するコマンド |
STOPSIGNAL | コンテナ終了時に送信されるシグナル |
HEALTHCHECK | ヘルスチェック |
ターミナル上で実行できるdocker-composeコマンド一覧
コマンド | 意味 |
---|---|
build | サービスの構築または再構築 |
config | compose ファイルの確認と表示 |
create | サービスの作成 |
down | コンテナ・ネットワーク・イメージ・ボリュームの停止と削除 |
events | コンテナからリアルタイムにイベントを受信 |
help | コマンド上でヘルプを表示 |
kill | コンテナを kill (強制停止) |
logs | コンテナの出力を表示 |
pause | サービスを一時停止 |
port | ポートに割り当てる公開用ポートを表示 |
ps | コンテナ一覧 |
pull | サービス用イメージの取得 |
restart | サービスの再起動 |
rm | 停止中のコンテナを削除 |
run | 1度だけコマンドを実行 |
scale | サービス用コンテナの数を指定ド |
start | サービスの開始 |
stop | サービスの停止 |
up | コンテナの作成と開始 |
version | Docker Compose のバージョン情報を表示 |
【Win/Mac】自分が日常的によく使うコマンド(コピペ派の人)
私が日頃、普段使っているPCのコマンド操作です。大それた内容ではないです。分からない時、ggて、何度も見た先人のページに辿りつくんだけど、短い羅列なのにすぐ忘れる。入力が面倒臭いから書くね...(随時更新)
役にたつかもしれない人
・ビギナー(初心者)、コマンド操作より手動(マウス)操作の方が慣れている。
・コマンド入力よりコピペ(手動)派例: 1. GitHubからアプリをダウンロードする時はgit cloneするよりDownload ZIPする
2. ダウンロードしたアプリは自分の目で見て手動管理したい人
・どのディレクトリ(階層)からでも実行出来る。
D&D = コマンドウィンドウにドラッグ&ドロップ
Mac - ターミナル
コマンド | 用途 |
---|---|
killall Finder | USB抜く時とか |
xattr -rc .appをD&D | 「壊れているため開けません」を開く |
open -n + D&D | 同じアプリを複数起動 |
cd ~/ | ホームディレクトリに移動 |
cd D&D | そのディレクトリへ移動 |
sudo D&D | root権限で実行 |
Windows - コマンドプロンプト
コマンド | 用途 |
---|---|
cd D&D | そのディレクトリへ移動 |
h: | Hドライブへ移動 |
Laravel-Enum 導入
概要?
Laravel-Enum の使い方をまとめておこうと思い。記事を書く所存。
準備
laraevl のバージョン
$php artisan --versionLaravel Framework 5.8.16
使えるようにする
以下のコマンドを実行すると、Laravel 上で Enum(列挙型)が使用できるようになる。
Enumって、ラジオボタンとかセレクトボックスの中身とかに使えて便利だと思う。
$composer require bensampo/laravel-enum
使いたい
コマンドからクラスを作成する
コマンドを実行して、Enum クラスを作成する
$php artisan make:enum TestText
Enum created successfully.
正常に作成すると、app/Enums
のしたにTestText.php
ファイルが作成される.
作成したクラスを以下のように編集する。
<?phpnamespaceApp\Enums;finalclassTestTextextendsEnum{constTEST="test";constTEXT="text";}
日本語化対応もできる
app/resources/lang/ja/
にenums.php
を作成するよ。
<?php// php artisan で作成したクラスuseApp\Enums\TestText;return[TestText::class=>[TestText::TEST=>'テスト',TestText::TEXT=>'テキスト',],];
ただ上記のファイルの恩恵を受けるためには、app/config/app.php
のlocale
を日本語に設定しておく必要があるよ。
<?phpreturn[// 略'locale'=>'ja',// 略];
とりあえず View で使ってみる。
例えば、ラジオボタンとか。toSelectArray
が key=>value
で返してくれるので便利。
これはlalavel-enum
のメソッド。便利。
<divclass="input-group col-12 col-md-6">{{Form::label("test_list_label","テストラジオ",['class'=>'required'])}}<divclass="radios">@foreach(\App\Enums\TestText::toSelectArray()as$value=>$item)<divclass="radio">{{Form::radio('test_list_item',$value,$value==='test',['id'=>"test_list_item--{$value}",])}}{{Form::label("test_list_item--{$value}",$item,[])}}</div>@endforeach</div></div>
Mysql のデータベースのあれこれもあとで書くんよ
初投稿
OSS活用勉強会でQiita入門というMarkdown勉強会に参加してみたので、自分でもちょっと書いてみた。
まずは自己紹介など・・・
Qiita初めての記事は、Qiita入門イベントに参加してみたレポートになります。
あ、申し遅れました。長野県伊那市で電子黒板の販売や、ネットワーク構築などを生業とする会社の一人親方なんぞしている「鄭 喆敏(てい あきとし)」と申します。
1973年8月生まれの在日コリアン3世(但し日本語しか喋れません)
そう、今世間で「氷河期世代」とされている40代後半の人間です。
某書店員・某家電販売員・某カメラメーカー修理センター電話対応員・某カメラメーカー修理センター作業員(MOドライブとか音楽プレイヤーとかの修理してました)という職歴を経て、伊那市の公立校(小中21校)でのPC更新計画策定に関わり(iPad大量導入へと繋がります)教育ICT分野にコミットし始めました。その活動の中で、ブームになり始めたIoTと関わるようになり、それと同時に地方でのエンジニアの圧倒的な少なさに直面。それを解決すべく(今から考えるとかなり無茶してますが)2017年から地元で、「IoTで地域課題解決にチャレンジ」を掲げハッカソンの開催などを行っています。(2019年は諸事情により開催できず)
現在は、CoderDojo伊那のチャンピオン(代表の意味)をやったり、「Code for」の地元ブリゲード(消防団 ここでは地方組織の意)立ち上げ準備をしています。
今後どうするか・・・
今後はあくまで地元を拠点に、IoTやAIの活用の追求・地域に眠る様々な情報のオープンデータ化や活用、地域全体の情報リテラシーの底上げなどに係るあらゆることに関与していこうとしています。
学習記録 その20(24日目)
学習記録(24日目)
勉強開始:12/7(土)〜
教材等:
・大重美幸『詳細! Python3 入門ノート』(ソーテック社、2017年):12/19(木)読了
・Progate Python講座(全5コース):12/21(土)終了
・Andreas C. Müller、Sarah Guido『(邦題)Pythonではじめる機械学習』(オライリージャパン、2017年):12月23日(土)読了
・Kaggle : Real or Not? NLP with Disaster Tweets:12月28日(土)投稿〜1月3日(金)まで調整
・Wes Mckinney『(邦題)Pythonによるデータ分析入門』(オライリージャパン、2018年):1月4日(土)〜
『Pythonによるデータ分析入門』
p.346 10章 データの集約とグループ演算 まで読み終わり。
9章 プロットと可視化
・matplotlib, seabornといったデータ可視化ライブラリの解説
線種のような設定要素についてはDocString(関数名 + '?')で見られる。
(matplotlibをas pltでインポートしているなら、plt.plot?のように使う。)
・基本はmatplotlibとし、必要に応じてpandasやseabornのようなアドオンライブラリを用いるとよい。
importmatplotlib.pyplotaspltfig=plt.figure()#プロット機能が含まれるオブジェクト。
ax1=fig.add_subplot(1,1,1)#プロットするためにはサブプロットを1つ以上追加する。
#以下、図の形式や入力データについて記述
・できること概要
余白の調整、軸の共有、タイトル、凡例及び表示位置の調整(loc='best'で最適位置)、
ラベル回転表示(rotation)、注釈の追加(annotate)、図の追加(add_patch)、
matplotlibのデフォルト値設定(rcメソッド)
props={'title':'namae no ikkatsu settei','xlabel':'aiueo'}ax.set(**props)
・DataFrameにもplotメソッドがある。データフレームにそのまま使える。
s.value_counts().plot.bar()#barhで横棒
・seabornパッケージを使用すると、プロットの前に集計や要約を要するデータを容易に可視化できる。
引数のdataにはデータを、xやyにはデータフレームの行と列の名前を指定する、
・ヒストグラム:棒グラフの一種、値の頻度を離散データとして表示
・密度プロット:観測データを生み出したと推定される連続確率分布から生成される。
通常、この分布をカーネルという正規分布などのシンプルな和として近似する方法をとっている。
そのため、密度プロットは「カーネル密度推定(KDE)プロット」とも呼ばれる。(plot.kde)
・すごいよく使いそうなメソッド
seaborn.distplot(ヒストグラムと密度推定のプロットを同時に作成できる)
seaborn.regplot(散布図を作成し、線形回帰による回帰直線をあてはめる)
seaborn.pairplot(各要素ずつを比較した散布図行列を一括で可視化できる)
10章 データの集約とグループ演算
・pandasのgroupbyメソッド
データセット同士の要素を組み合わせて任意の処理が実行できる(ものと理解。)
・グループ演算プロセスは 分離(split)−適用(apply)−結合(combine)の流れ。
・1つのデータセットに対しても、複数の要素を指定できる。
任意の値について抜き出し、処理(平均、カウント等)をした後、再度グループ化できる?
・ディクショナリを用いたマッピング情報を使用して分類もできる。
・groupbyメソッドの関数(count, sum, mean, median...)基本的な算術計算は網羅してそう。
・groupbyでデータを集約した際につく名前は、タプルを渡すことで変更できる。
as_index = Falseでインデックスなしも指定できる。
・applyは、オブジェクトを分離し、それぞれのピースに渡された関数を適用し、その後結合する。
applyに渡す関数はプログラマが自分で実装する必要があるため、想像力が求められる。
・ピボットテーブルとクロス集計。データフレームの関数でもgroupbyでも実装dけいる。
これらを扱えるようになると、データクリーニングやモデリング、統計分析に役立つ。