あじちゃんのブログ。備忘録。

〜SEもOLなんですかね?

CSVのデータを加工するときに使った関数の備忘録

改行とカンマで区切られたCSV文字列を想定し実施

f:id:azix:20180719203926p:plain

目的:与えられたCSV形式のデータから、頭2つのデータを配列として取り出す

  • こんな感じのフォームを準備
<form action="{{ action('よしなに') }}" method="よしなに">
    {{ csrf_field() }}
    <textarea name="csv" cols="30" rows="10" placeholder="CSV情報を入れてください"></textarea>
    <input type="submit" value="SEND">
    <pre>
例:
title-1, author-1, description-1
title-2, author-2, description-2
title-3, author-3, description-3
    </pre>
</form>
  • このフォームに例をそのままぶち込んで送信したものを加工する。
<?php

$csv = $request["csv"];

//改行ごとの配列
$item_groups = preg_split("/\n|\r\n|\r/", $csv);

//タイトルと著者の配列
$items = [];
$keys = ['title', 'author'];
foreach ($item_groups as $item_group) {
    $c = preg_split("/,/", $item_group); //カンマごとに配列に格納
    $chunk = array_chunk($c, 2)[0]; //前から2項目のみを配列に追加
    $changeKey = array_combine($keys, $chunk); //keyを変更
    array_push($items, $changeKey);
}

説明

  1. preg_split を使って、改行ごとに配列にする.
    正規表現\n|\r\n|\r で、改行コードを網羅.

  2. array_chunk を使って、目的のindexまでを取得し配列にする.
    これはindex[0][1]を取り出していると言うより、2個ずつ配列を分割している.
    今回はindex[0][1]が欲しかったので、2個ずつ取り出した初めの配列を使った.

  3. array_combine を使って、配列キーを変更する.

  4. array_push を使って、結果配列に追加していく.
    -array_push

🙂💬

特筆することはないけど、よく使う配列操作の関数は覚えておきたいなと思う.
あと、配列そのものに影響するのか、返り値が目的のものなのかというところも気をつけたい.

【Guzzle】POST時のoptionの設定仕方

APIの条件が以下のようになっていて、JSONでオプションを送ってくれと言われている場合。

条件

Method: POST
uri: /{ID} //対象のIDを指定
Media type: application/json //JSONで送ってねと言われている
contents: required (array of string) //IDに対して追加する対象
<?php

$base_url = "https://hoge"; //ダミーです
$uri = "/" . $ID;
$method = "POST";

$okomes = ['contents' => ['ビタミン', 'ミネラル', '食物繊維']];

//接続
$client = new Client($base_url);
$options = [
    'json' => $okomes, // ここにぶち込むと勝手にjsonにしてくれる
    'http_errors' => false,
    'headers' => [
        'Accept' => 'application/json',
        'Content-Type' => 'application/json'
    ]
]);
$response = $client->request($method, $uri, $options);
$response_contents_json = $response->getBody()->getcontents();


🙂💬
GETだとパラメータに打ち込むことができたけど、POSTだとそれができずoptionに突っ込む必要があった。
その時にform_paramsを使ってbodyに打ち込むとBadRequest飛んできたりしてはまってしまった。
(bodyにぶち込むとWarnningでそもそもリクエストが飛ばないなど問題ありありでした。
公式ドキュメントはちゃんと読もう。
Guzzle-公式ドキュメント

【HTML】checkbox のチェックを付けていない時もパラメータを送る

  • checkbox のチェックが付いていない場合、 name も value も送信されない
<!-- 
    チェックされた場合は on が送信されるが、
    チェックされていない場合は何も送信されない。
 -->
<input type="checkbox" name="test" value="on">
  • name属性が同じ場合、後に書かれたものが優先的に送信される
<!-- 
hidden 属性で、 vlaue に off を設定しておくと、
(1)が送信され、(2)は送信されない。
 -->
<!-- (1) --><input type="hidden" name="test" value="off">
<!-- (2) --><input type="checkbox" name="test" value="on">
<!-- 
以下の場合、 test には最初(1)の off が設定されているが、
(2)の checked により value が(2)のものに上書きされ、 on が送信される。
 -->
<!-- (1) --><input type="hidden" name="test" value="off">
<!-- (2) --><input type="checkbox" name="test" value="on" checked>

🙂💬 分岐処理いっぱい書くことになるんだったら、これでサクッとやっちゃう方が私は好き。

【Laravel】メンテナンスモードの切替

Maintenance Mode

メンテナンスモードの切替が標準搭載されている

メンテナンスモード有効

$ php artisan down

Application is now in maintenance mode.

メンテナンスモード無効

$ php artisan up

Application is now live.

この時のメンテナンス画面は resources/views/errors/503.blade.php が使われる
上記ファイルがない場合の画面はこれ
f:id:azix:20180705143434p:plain

IP制限をかけることもできる 

指定したIPからのアクセスの場合は正常に画面を表示する
設定は.envからカンマ区切りで指定できる

#メンテナンス時のアクセス許可IP
MAINTENANCE_IP=IPaddress1,IPaddress2,IPaddress3

env("PARAMETER") といった形の .env で定義した値が読み込めなく(Nullに)なる

2018/07/02

ローカルログイン画面からログインできない件

起こったこと: env("PARAMETER") といった形の .env で定義した値が読み込めなく(Nullに)なる事象が発生していた。

原因1:configキャッシュの作り直しをするため php artisan config:cache コマンドを実行し、キャッシュが固定されたため。

原因2:5.2以降の仕様で、キャッシュがある時は、 config/*.php 以外の場所で使われる env() は無効化される。(NULLになる)

解決方法:以下のコマンドを実行

# キャッシュファイルの場所まで移動
$ pwd
~projectdir/bootstrap/cache

# configのキャッシュファイルを削除
$ ls -l
-rw-r--r--  1 user_name  46682944  16560  6 28 16:43 config.php
$ rm -f config.php

Upgrading To 5.2.0 From 5.1 > Configuration

Caching And Env
If you are using the config:cache command during deployment, you must make sure that you are only calling the env function from within your configuration files, and not from anywhere else in your application.

If you are calling env from within your application, it is strongly recommended you add proper configuration values to your configuration files and call env from that location instead, allowing you to convert your env calls to config calls.

正規表現考える

<?php

$str = "/content/hoge/fuga/piyo/ドメイン/hoge.html";
$regular1 = "/\/content\/(.*?)\/(.*?)\/(.*?)\//"; //[/content/hoge/fuga/piyo/]
$regular2 = "/^\/([^\/]*\/){4}/"; //[/content/hoge/fuga/piyo/]
$regular3 = "/^\/((.*?)\/){4}/"; //[/content/hoge/fuga/piyo/]

preg_match($regular1, $str, $matches1);
preg_match($regular2, $str, $matches2);
preg_match($regular3, $str, $matches3);


echo "元: ".$str.PHP_EOL;
echo PHP_EOL;
echo "正規表現: ".$regular1.PHP_EOL;
echo "パターン全体にマッチしたテキスト: ".$matches1[0];
echo PHP_EOL;
echo PHP_EOL;

echo PHP_EOL;
echo "正規表現: ".$regular2.PHP_EOL;
echo "パターン全体にマッチしたテキスト: ".$matches2[0];
echo PHP_EOL;
echo PHP_EOL;

echo PHP_EOL;
echo "正規表現: ".$regular3.PHP_EOL;
echo "パターン全体にマッチしたテキスト: ".$matches3[0];
echo PHP_EOL;
echo PHP_EOL;

パターンマッチを確認

matches
matches を指定した場合、検索結果が代入されます。 $matches[0] にはパターン全体にマッチしたテキストが代入され、 $matches[1] には 1 番目のキャプチャ用サブパターンにマッチした 文字列が代入され、といったようになります。

1. 正規表現: /\/content\/(.?)\/(.?)\/(.*?)\//

Array
(
    [0] => /content/hoge/fuga/piyo/
    [1] => hoge
    [2] => fuga
    [3] => piyo
)

2. 正規表現: /^\/([^\/]*\/){4}/

Array
(
    [0] => /content/hoge/fuga/piyo/
    [1] => piyo/
)

3. 正規表現: /^\/((.*?)\/){4}/

Array
(
    [0] => /content/hoge/fuga/piyo/
    [1] => piyo/
    [2] => piyo
)

【Laravel】クエリビルダーでスペース区切りの複数ワード検索を行う

所感とか

所感

🤪 考えるのすごい時間かかったのに、寝たら一瞬で思いついた. 睡眠は大事.

大事だと思ったこと

  • ワードをどの要素にどういう条件で絞り込むのかを明確にすること
  • はじめに目的とするSQLを書いてみること
  • 要素ごとにまとめてwhere句を作っていくこと
  • 正規表現は何パターンか覚えておきたいところ

ポイント

  • 半角スペースを全角スペースにする: mb_convert_kana($request->words, 's');
  • スペースごとに配列に格納: preg_split('/[\s]+/', $request->words);
  • Illuminate\Support\Collectionで配列要素全てに処理を追加: Collection::make($strArry)->map(function($p){return "%".$p."%";})->toArray();
  • それぞれごとにwhere句を形成する: $query->where(function($query)use(...){}); を複数使うとこでまとまったwhere句を形成できる
  • 最初に受け取ったinputを引き出せる: $request->session()->getOldInput()

ソース

// 検索ワード[aaa bbb ccc] の場合

 select * from `products`
 where (`title` like "%aaa%" and `title` like "%bbb%" and `title` like "%ccc%")
       or (`description` like "%aaa%" and `description` like "%bbb%" and `description` like "%ccc%");
  • Model(Search.php)
<?php

static function search(Request $request)
{
    $products = self::query();
    $hasParam = true;
    $search_words;

    if(isset($request->words)) {
        //検索ワードを分割
        if(isset($request->words)) {
            //半角スペースを全角スペースにする
            $request->words = mb_convert_kana($request->words, 's');
            //スペースごとに配列に格納
            $strArry = preg_split('/[\s]+/', $request->words);

            //use Illuminate\Support\Collectionで配列要素全てにワイルドカード(%)を追加
            //$pが配列の要素ひとつずつになる. その要素に処理をして,returnで元の要素と入れ替えるイメージ
            $search_words = Collection::make($strArry)->map(function($p)
            {
                return "%" . $p . "%";
            })->toArray();
        }
        $count = count($search_words);

        //title, descriptionそれぞれごとにwhere句を形成
        $products = $products
            ->where(function($query)use($search_words){
                foreach($search_words as $search_word) {
                    $query->where('title', 'like', $search_word);
                }
            })
            ->orwhere(function($query)use($search_words){
                foreach($search_words as $search_word) {
                    $query->where('description', 'like', $search_word);
                }
            });
    }
    else {
        $hasParam = false;
        $products = $products;
    }

    $result = [];

    //初期表示にメッセージが出ないようにする
    if($products->count() <= 0 && $hasParam){
        $result['message'] = "検索結果は0件です";
    } else {
        $result['message'] = "";
    }

    $result['products'] = $products;

    return $result;
}
  • Controller(Controller.php)
<?php

public function index(Request $request)
{
    $products = Search::search($request);

    $message = $products['message'];
    $products = $products['products'];

    if($message) {
        //検索結果が0件の場合
        return view('index', [
            'products' => $products,
            'inputs' => array_merge($request->input(), $request->session()->getOldInput()),
            'message' => $message
        ]);
    }
    
    //検索結果が1件以上の場合
    return view('akashic-game.products.index', [
        'products' => $products,
        'inputs' => array_merge($request->input(), $request->session()->getOldInput()),
        'message' => $message
    ]);
}
  • View(index.blade.php)
@if (isset($message))
  <p>{{ $message }}</p>
@else

<form action="{{ action('Controller@index') }}" method="GET">
  <fieldset>
    <div>
      <input type="text" name="words" value="@if(!empty($inputs['words'])){{ $inputs['words'] }}@endif">
    </div>
    <button type="submit">検索</button>
  </fieldset>
</form>

<div>
@forelse($items as $item)
  <li>{{ $item->title }} : {{ $item->description }}</li>
@endforeach
</div>