なるの備忘録

エンジニアリングそして営業ができるエンジニアに向けて、日々学んだことをアウトプットしていきます。

【予約語に注意】FuelPHPでユーザ登録をしようとすると「Fuel\Core\Database_Exception [ 1064 (1064) ]: You have an error in your SQL syntax;」と出る

FuelPHPでユーザ登録をするとエラーが出る。

FuelPHPでユーザ登録をしようとすると以下のようなエラーが出た。

Fuel\Core\Database_Exception [ 1064 (1064) ]:
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'group, profile_fields, last_login, login_hash, created_at) VALUES ('test8', 'zGE' at line 1 [ INSERT INTO users (username, password, email, group, profile_fields, last_login, login_hash, created_at) VALUES ('test8', 'zGEG+uMfdUKF9EJ4dPFONfP4OKlu33BkVIr6wLUDa4M=', 'test8@mail.com', 1, 'a:0:{}', 0, '', 1556079498) ]

どうやらINSERT文自体が間違っているらしい。

直接DBでSQLを実行してみる

直接DBでSQLを実行してみるとここでもエラー。
一つ一つカラムを外していくと、どうやらgroupというカラムが原因のようだ。

カラム名予約語が使われているときは「`」で囲う

SELECT、DELETE、または BIGINT などの特定の語は、テーブル名やカラム名などの識別子として使用するために予約されており、特別な取り扱いが必要となる。
今回の場合は、カラム名として使用されている「group」が予約語のため(group byで使用)、エラーが起きていたよう。

※参考
dev.mysql.com

そんな時はカラム名を「`(バッククォート)」で囲めば解決。
今回の場合だと以下のように実施。

INSERT INTO users (username, password, email, `group`, profile_fields, last_login, login_hash, created_at) VALUES ('test8', 'zGEG+uMfdUKF9EJ4dPFONfP4OKlu33BkVIr6wLUDa4M=', 'test8@mail.com', 1, 'a:0:{}', 0, '', 1556079498)
gontora.hatenadiary.com

これで直接DBでSQL文を実行してみると、無事データ登録が出来た。

FuelPHPが自動的に生成しているSQL文での予約語対策

しかし今回のSQL文はFuelPHPが自動的に生成しているので、実際のコードを実施したときは依然エラーが出る。

調べてみるとどうやら、config/db.php 等で設定している、使用しているデータベース設定の identifierを以下のように設定する必要があるそう。

'identifier'   => '`',

これでカラム名がバッククォートで括られるように設定されるようだ。

db.phpファイル全体だとこんなイメージ。

<?php
return array(
    'active' => 'mysqli',
    'mysqli' => array(
        'type' => 'mysqli',
        'connection' =>array(
            'hostname'      => 'localhost',
            'database'      => 'framework',
            'username'      => 'root',
            'password'      => 'root',
            'persistent'    => false,
            'compress'      => false,
        ),
        'identifier'   => '`',
        'table_prefix'  => '',
        'charset'       => 'utf8',
        'caching'       => false,
        'profiling'     => true,
    ),
);

これで無事登録できました。
このへんはFuelPHPでもバージョンで違うよう。
最近のバージョンはデフォルトで設定されていないのかな?

※参考
teratail.com

「クラス名:nth-of-type(n)」で記載した場合、「クラスでn番目」ではなく、「要素でn番目」という数え方になる

「クラス名:nth-of-type(n)」で記載した場合、「クラスでn番目」ではなく、「要素でn番目」という数え方になる

「クラス名:nth-of-type(n)」で記載したときの挙動が気になったのでメモ。
以下の簡単なコードで動作を確認します。

簡単な動作確認用コード

HTML

<!DOCTYPE html>
<html lang="ja">
    <head>
        <link rel="stylesheet" href="style.css">
    </head>
    <body>
        <div>            
            <span class="a">その要素で1番目⇛aクラス</span>
            <span class="b">その要素で2番目⇛bクラス</span>
            <!-- クラスに適用されていたならこの要素は青色になる(class="a"の中で2番目のため)-->
            <span class="a">その要素で3番目⇛aクラス</span>
            <span class="b">その要素で4番目⇛bクラス</span>
            <!-- クラスに適用されていたならこの要素は青色になる(class="a"の中で3番目のため)-->
            <span class="a">その要素で5番目⇛aクラス</span>
            <span class="b">その要素で6番目⇛bクラス</span>
        </div>
    </body>
</html>

CSS

.a:nth-of-type(1){
    background-color: red;
}
.a:nth-of-type(2){
    background-color: blue;
}
.a:nth-of-type(3){
    background-color: yellow;
}
.a:nth-of-type(4){
    background-color: green;
}

※nth-of-type(n)は、疑似クラスの一種で、 n番目のその種類の要素にスタイルを適用

実施結果

f:id:narunaru7638:20190422004455p:plain

まとめ

・「クラス名:nth-of-type(n)」で記載した場合、「クラスでn番目」ではなく、「要素でn番目」という数え方になる
・要素でn番目かつそのクラス名をもつものにスタイルが適用される
・「クラス名:nth-of-type(n)」で記載したときは、勘違いしやすいので注意(特に兄弟要素に同じ種類の要素があると間違えやすい)

コマンドラインでfuelPHPがインストールできないときの対策(syntax error near unexpected token `newline')

コマンドラインfuelPHPがインストールできないときの対策(syntax error near unexpected token `newline')

コマンドラインfuelPHPをインストールしようとしたら、以下のようなエラーがでました。

$ curl get.fuelphp.com/oil | sh
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   239  100   239    0     0    118      0  0:00:02  0:00:02 --:--:--   118
sh: line 1: syntax error near unexpected token `newline'
sh: line 1: `<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">'

解決策

以下のコマンドを実施して、このようにPCのPasswordを求められればOKです。

$ curl https://get.fuelphp.com/oil | sh
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   479  100   479    0     0    437      0  0:00:01  0:00:01 --:--:--   437
Password:

このコマンドの差分からして、どうやらhttpsで取得をしないといけないようですね。

Sassの変数と@mixinでレスポンシブデザインを作るときは@mixinの呼び出し順に注意

Sassの変数と@mixinで3パターンのレスポンシブデザインを作ろうとすると、CSSが適用されない

PC・タブレットスマホの3パターンのレスポンシブデザインをSassの変数と@mixinで作ろうとして、CSSがうまく適用されませんでした。
結論としては、Sassの変数と@mixinでレスポンシブデザインを作るときは、ブレイクポイントの変数の用意の仕方で、@mixinの呼び出し順が異なります。
これによって一見CSSが適用されていないように見えてしまいます。

そもそも「Sassの変数と@mixinを使ってレスポンシブデザイン」を作る方法は?

こちらに素晴らしく分かりやすいサイトがございますので、こちらを御覧ください。
www.tam-tam.co.jp

本題:@mixinの呼び出し順について

用意したブレイクポイントの変数

$breakpoints: (
  'sm': 'screen and (max-width: 414px)',
  'md': 'screen and (max-width: 768px)',
  'lg': 'screen and (max-width: 1000px)',
  'xl': 'screen and (max-width: 1200px)',
) !default;

用意したmixin

@mixin mq($breakpoint: md) {
  @media #{map-get($breakpoints, $breakpoint)} {
    @content;
  }
}

@mixinでメディアクエリを呼び出す

正しい呼び出し順

.container {
  width: $site-width;

  @include mq(md) {//画面サイズが768pxまでの場合、styleを適用
    width: 90%;
  }

  @include mq() {//画面サイズが414pxまでの場合、styleを適用
    width: 80%;
  }

誤った呼び出し順

.container {
  width: $site-width;

  @include mq() {//画面サイズが414pxまでの場合、styleを適用
    width: 80%;
  }

  //mq() で呼び出して適用したstyleが上書きされてしまう
  @include mq(md) {//画面サイズが768pxまでの場合、styleを適用
    width: 90%;
  }

まとめ

今回は用意したブレイクポイントの変数は「 'sm': 'screen and (max-width: 414px)',」のように「 max-width」で条件を定義しています。
この場合は、あとからstyleが上書きされないように、PC⇛タブレットスマホの順に@mixinを呼び出します。
そのためブレイクポイントの変数を「min-width」で定義した場合は、@mixinの呼び出し順は今回と逆になります。

yarnでnode-sassのライブラリを使うと「An output directory must be specified when compiling a directory」とエラーが出る

単なる打ち間違いですが、わりとハマってしまったのでメモ。

jsonファイルの中身

{
  "name": "test",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "build-css": "node-sass --include-path scss scss/style.scss css/style.css",
    "watch-css": "nodemon -e scss -x \"npm run build-css\""
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "node-sass": "^4.11.0",
    "nodemon": "^1.18.11"
  }
}

node-sassのライブラリをbuild-cssというコマンドを作成して実施しようとしています。

ターミナルでの実行およびエラー画面

$ yarn build-css
yarn run v1.15.2
$ node-sass --include-path scss scss/style.scss css/style.css
An output directory must be specified when compiling a directory
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

yarnでbuild-cssを実行。
「An output directory must be specified when compiling a directory」、すなわち「ディレクトリをコンパイルするときは、出力ディレクトリを指定する必要があります。」と怒られていますね。

結論

・出力するディレクトリではなく、読み取る側のディレクトリ名が間違っていました。
「誤:sccsディレクトリ内にstyle.scssを格納」⇛「正:scssディレクトリ内にstyle.scssを格納」

エラーメッセージに引っ張られすぎた…

CSSのアニメーション機能を使って、扉から飛び出すように画像を表示させる

せっかく学習したのでCSS3のアニメーション機能を使って、扉から飛び出すような画像表示機能を作ってみます。

動作イメージ

最初は扉のような画像が表示されています。
f:id:narunaru7638:20190416230842p:plain

扉にカーソルを重ねると勢いよく扉が開きます。
f:id:narunaru7638:20190416230859p:plain

直後に勢いよく画像が飛び出してきます。
f:id:narunaru7638:20190416230905p:plain

カーソルを画像から離すと画像は小さくなり、扉は閉まります。
f:id:narunaru7638:20190416230930p:plain

論よりコード

HTML

<!DOCTYPE html>
<html lang="ja">
    <head>
        <link rel="stylesheet" href="style.css">
    </head>
    <body>
        <div id="main">
            <!--  疑似要素:after,:beforeを付けるためにimgタグをspanタグで囲う   -->
            <!--  imgタグのような閉じタグが無い要素は疑似要素が使えない  -->
            <span class="wrap-img"><img src="img/image.png" alt=""></span>
        </div>
    </body>    
</html>

CSS

#main{
    padding: 200px;
}
.wrap-img{
    display: block;
    width: 800px;
    height: 800px;
    position: relative;
    z-index: 0;
    visibility: middle;
    box-sizing: border-box;
    transition: all .3s;
}
/*疑似要素:before,:after*/
/*html上には無いが、要素の前後に要素があるようにできる*/
/*htmlを汚さずにデザインのための要素を付けることが可能*/
.wrap-img::before,
.wrap-img::after{   
    position: absolute;
    /* 画像より手前に表示するため   */
    z-index: 1;
    display: block;
    content: '';
    box-sizing: border-box;
    top: 0;
    /* 親要素の半分の大きさの扉のため*/
    width: 50%;
    height: 100%;
    background-color: rgba(208, 162, 67, 1);
    border: rgba(128, 0, 0, 1) 2px solid;
    box-sizing: border-box;
    /* 0.1秒待った後に0.3秒かけてwidthが変化する(扉が閉まる)   */
    transition: width .3s ease .1s;
}
/*左側の扉となる要素*/
.wrap-img::before{
    left: 0;
}
/*右側の扉となる要素*/
.wrap-img::after{
    right: 0;
}
.wrap-img:hover::before,
.wrap-img:hover::after{
    cursor: pointer;
    /*カーソルを重ねるとwidthを0にする(扉が開く)*/
    width: 0;
    /* 0秒待った後に0.3秒かけてwidthが変化する   */
    transition: width .3s ease 0s;
}
img{
    box-sizing: border-box;
    display: block;
}
img{
    /* カーソルを重ねていないときの画像は小さく   */
    transform: scale(0.8, 0.8);
    transform: all .1s;
}
img:hover{
    cursor: pointer;
    /*  カーソルを重ねると画像は大きくなる   */
    transform: scale(1.2, 1.2);
    transition: transform .2s ease .1s;
}

ポイントまとめ

・疑似要素:before,:afterを使うことで、htmlを汚さずにデザインのための要素を付けることが可能
・imgタグのような閉じタグが無い要素は疑似要素が使えない
・疑似要素のwidthを50%にし、positionを調整、z-indexで画像の手前に持ってくることで扉のように見せる
・扉にカーソルを重ねたらtransitionでwidthを0に変化させる(待ち時間や変化の早さを指定可能)
・扉が空いたら画像が飛び出てくるようにtransitionで画像の大きさが変化する早さを調整

基本的なクロージャの実践例の「モジュールパターン」は何が起きているの?

なんとなくクロージャーは分かったけど…

JavaScriptのスコープの概念」や「クロージャーのメリット」は理解したけど、いまいち典型的なクロージャーのコードで何が起きているか分からなかったので調べてみました。

典型的なクロージャーのコードと分からんポイント

var module = (function() {//分からないポイント①: functionの前に"("がついて、function全体が()で囲われている
    var count = 0;

    return {
        increment: function() {//分からないポイント②:セミコロンの隣のfunctionという見慣れない記述
            count++;
        },
        show: function() {
            console.log(count);
        }
    };

})();//分からないポイント③:最後の謎の何も入っていない()

//分からないポイント④:〇〇.関数名();でよく分からんけど関数を呼べる?
module.show(); // 0

module.increment();
module.show(); // 1

console.log(count); // undefined

だいたいこのあたりがよく分からないポイントだと思います。

要点1:クロージャーは即時関数を使って記載されている

典型的なクロージャーのコードは即時関数というものを使って記載されています。
即時関数は、関数を定義すると同時に実行するための構文。

基本的な書き方

(function () {
    //処理
}());

引数と返り値

var result = (function (param1, param2) {
    return param1 + param2;
}(1, 2));

console.log(result); //3

つまり「変数module」に、関数を定義したと同時にその「関数を実行した結果」が入っていることが分かります。ここでいう「関数を実行した結果」とは「returnの中身」ですね。
「console.log(module);」を実施すると「increment」と「show」という関数が入っているのが分かると思います。

var module = (function() {//分からないポイント①: functionの前に"("がついて、function全体が()で囲われている
    var count = 0;

    return {//分からんポイント②:returnに関数が入ってる
        increment: function() {//分からないポイント②:セミコロンの隣のfunctionという見慣れない記述
            count++;
        },
        show: function() {
            console.log(count);
        }
    };

})();//分からないポイント③:最後の謎の何も入っていない()

//分からないポイント④:〇〇.関数名();でよく分からんけど関数を呼べる?
module.show(); // 0

module.increment();
module.show(); // 1

console.log(module);//incrementとshowという関数が入っているのが分かる

console.log(count); // undefined

開発ツールで見てみるとincrementとshowという関数が確かに入っていますね。
f:id:narunaru7638:20190416000953p:plain

これで「分からないポイント①」と「分からないポイント③」は理解できたと思います。

要点2:JavaScriptで扱うものはすべてオブジェクトかオブジェクトのように使える

JavaScriptで扱うものはすべてオブジェクトかオブジェクトのように使えます。
オブジェクトにはプロパティとメソッドがあります。

オブジェクトの作り方と利用例

//testHumanというオブジェクトを作成
var testHuman = {
    firstName: "Hoge",
    lastName: "Fuga",
    sayHello: function(){ console.log("Hello") }// メソッドを作成
};

console.log(testHuman["firstName"]);  // Hoge
console.log(testHuman["lastName"]);  // Fuga
testHuman.sayHello();// Hello メソッドを実施

上記のtestHumanオブジェクトのsayHelloメソッド作成と同様の方法で、moduleオブジェクトのincrementメソッドとshowメソッドを作成していることが分かります。testHuman.sayHello();と同様の方法で、「module.increment();」「module.show(); 」を実施していることが分かります。
これで「分からないポイント②」と「分からないポイント④」は理解できたと思います。