- 投稿日:2020-07-06T20:13:34+09:00
PHPでWebスクレイピングをしCSVファイルに書き出す方法
コード全体
index.php<?php require_once("./phpQuery-onefile.php"); $file = fopen("data.csv", "w"); $html = file_get_contents("URL"); for($i=0;$i<100;$i++){ $title[$i] = phpQuery::newDocument($html)->find("h3:eq($i)")->text(); $content[$i] = phpQuery::newDocument($html)->find(".content:eq($i)")->text(); fputs($file, $title[$i].$content[$i]."\n");} fclose($file); ?>情報をURLから取得
phpQueryを読み込む
index.php// phpQueryを読み込む require_once("./phpQuery-onefile.php"); // 情報を取得したいURLを指定 $html = file_get_contents("URL"); // 取得したい部分を指定しテキスト化を繰り返す for($i=0;$i<100;$i++){ $title[$i] = phpQuery::newDocument($html)->find("h3:eq($i)")->text(); $content[$i] = phpQuery::newDocument($html)->find(".content:eq($i)")->text(); }:eq($i)でi番目の情報を指定できる。
CSVに変換
index.php$file = fopen("data.csv", "w"); // 省略 fputs($file, $title[$i].$content[$i]."\n");} fclose($file);(参考)phpでウェブスクレイピング
- 投稿日:2020-07-06T18:54:17+09:00
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をインストールする 記載例
下記の様に記載することで当該カラムのデフォルト値を指定することができる。
$table->データ型('カラム名', オプション)->default(デフォルト値に設定する文字列や値);
- 投稿日:2020-07-06T17:54:40+09:00
yoast seo をカスタマイズするちょっとした方法
wordpressサイトの構築において、SEO系のプラグインを使用する場合、
代表的なものとして、「Yoast SEO」「All in One SEO Pack」があげられるのではないでしょうか。Yoast SEOを使用した場合に、「個別ページ」「投稿ページ」「アーカイブページ」など、meta設定やrobotsの設定を一括で指定するができます。
また、それそれの編集ページで個別に調整することもできます。しかし、個別に調整したい投稿が、全投稿のうち10件あったとした場合(10件の調整内容は同じとする)、10件それぞれに管理画面から編集していてはめんどくさい。
調べたら、フィルターをかましたら、諸々PHPで上書きできるようでした。管理的にもこちらのほうがよさそうなのかも〜。
メモがてらに、いくつか書き留めておきます。メタタグ
title
add_filter( 'wpseo_title', 'custom_title' ); function custom_title($title) { //条件分岐 if ( is_page('about') ) { return '会社概要'; } return $title; }description
add_filter( 'wpseo_metadesc', 'custom_metadesc' ); function custom_metadesc($metadesc) { //条件分岐 if ( is_page('about') ) { return '会社概要をご紹介いたします。'; } return $metadesc; }robots
add_filter( 'wpseo_robots', 'custom_robots' ); function custom_robots($robots) { //条件分岐 if ( is_single('test') ) { return 'noindex,nofollow'; } return $robots; }OGタグ
og_site_name
add_filter( 'wpseo_opengraph_site_name', 'custom_og_site_name' ); function custom_og_site_name($site_name) { //条件分岐 if ( is_page('about') ) { return '企業サイト'; } return $site_name; }og_site_title
add_filter( 'wpseo_opengraph_title', 'custom_og_title' ); function custom_og_title($title) { //条件分岐 if ( is_page('about') ) { return '会社概要'; } return $title; }og_site_desc
add_filter( 'wpseo_opengraph_desc', 'custom_og_desc' ); function custom_og_desc($desc) { //条件分岐 if ( is_page('about') ) { return '会社概要をご紹介いたします。'; } return $desc; }参照サイト
- 投稿日:2020-07-06T17:43:21+09:00
【初心者向け】【PHP】FizzBuzz問題
今回はphpでFizzBuzz問題を書きました。と言っても前回とほとんどおんなじようなコードです。
FizzBuzz問題とは?
1から100まで順に数えて出力して行き、3で割り切れる数は「Fizz」5で割り切れる数は「Buzz」両方で割り切れる数は「FizzBuzz」と出力する、ようにプログラムを書く問題です。
これが書けるか書けないかでプログラマー志願者を仕分けられるようになったようです。実際今でも使われていますから押さえておいて損はないと思います。FizzBuzz詳細
私が書いたコード
sample.php<?php $i = 0; for($i = 1; $i < 100; $i++) { if($i % 15 === 0) { print "FizzBuzz!<br />"; } else if ($i % 5 === 0) { print "Buzz<br />"; } else if ($i % 3 === 0) { print "Fizz<br />"; } else { print $i."<br />"; } } ?>書く順番
前回同様、ifは条件が厳しいものから順番に書いていった方が良いです。今回の問題だと"Fizz"や"Buzz"を表示させるifを先に書いてしまうと3と5の倍数の数字がif文を通過するとき、3の倍数をFizzに置き換えるところで条件を満たしてしまうのでその先の処理は行わないからです。
- 投稿日:2020-07-06T17:08:45+09:00
Virtualbox, Vagrant, AnsibleでLAMP環境を構築
仮想環境の構成と要件
仮想環境の構成
ホストOS
- macOS Mojave (10.14.x)
構成
- CentOS 7
- PHP 7
- MySQL 5.6
- Apache 2.4
要件
- ドキュメントルート配下のファイルを、ホスト(PC)とゲスト(仮想環境)で共有する
- ホストのブラウザで、ゲストに設置したHTMLファイルがウェブページとして見られるところを目指す
使うソフトウェア・ツール
- Virtualbox
- Vagrant
- Ansible
構築
必要なソフトウェアをインストール
Virtualbox
公式サイトから最新版をダウンロードして、インストール。
(この記事の時点では 5.2.18)Oracle VM VirtualBox
https://www.virtualbox.org/Vagrant
公式サイトから最新版をダウンロードして、インストール。
(この記事の時点では 2.1.2)Vagrant by HashiCorp
https://www.vagrantup.com/インストールが完了したら、ターミナルでコマンドを実行して、インストールがされているかを確認。
# インストール後の確認 $ vagrant -v Vagrant 2.1.2Ansible
こちらはターミナルでコマンドを実行してインストール。
# インストール $ brew install ansible # インストール後の確認 $ ansible --version ansible 2.6.0Vagrantの設定
新しくVagrantを作成
任意のディレクトリに移動して、そこに仮想環境を構築していく。
下記のコマンドを実行すると、Vagrantfileが作成される。これが、Vagrantの設定ファイルになる。
# Vagrantを初期化 $ vagrant initVagrantfileに、仮想環境の設定を記述
Vagrantfileでは、作成する仮想環境のOSや、割り当てるメモリ、ホストとのディレクトリ共有設定などの設定ができる。
今回変更した箇所は、以下の通り。
OSにCentOS7を指定
Vagrantでは、boxという単位で環境を管理している。
今回は、CentOS7を構築するので、以下のように変更する。# 元の記述 config.vm.box = "base" # boxに centos/7 を指定 config.vm.box = "centos/7"固定ID:192.168.33.10でアクセスできるようにする
# 以下記述のコメントアウトを外す config.vm.network "private_network", ip: "192.168.33.10"ホストとゲストのディレクトリを共有する
ソースコードをホストとゲストで共有するために、ディレクトリの共有する記述をする。
以下の記述では、Vagrantfileと同じ階層にある htdocsディレクトリと、CentOS(ゲスト)の /var/www/htmlディレクトリを同期させている。なお、パーミッションは雑に777としているが、適宜変更すること。
# ディレクトリの共有の記述を書き換え # 元の記述(コメントアウトされている) # config.vm.synced_folder "../data", "/vagrant_data" # 変更後 config.vm.synced_folder "./htdocs", "/var/www/html", :mount_options => [ "dmode=777", "fmode=777" ]仮想環境に割り当てるメモリを変更
仮想環境に割り当てるメモリを変更する。
あまり大きくしてもマシン全体が重たくなるだけなので、今回は大幅に減らして256MBとする。# 元の記述(コメントアウトされている) # config.vm.provider "virtualbox" do |vb| # # Display the VirtualBox GUI when booting the machine # vb.gui = true # # # Customize the amount of memory on the VM: # vb.memory = "1024" # end # 変更後(コメントアウトを外して、値を変更) config.vm.provider "virtualbox" do |vb| # # Display the VirtualBox GUI when booting the machine # vb.gui = true # # # Customize the amount of memory on the VM: vb.memory = "256" endAnsible設定のための記述を追加
Ansibleを使うための記述を追加する。
# 以下の記述を、最終行の `end` の手前に追記 config.vm.provision "ansible" do |ansible| # 設定を適用する対象のサーバーの指定を記述するファイルの指定 ansible.playbook = "ansible/playbook.yml" # サーバーの設定をカスタマイズするためのレシピを記述する設定ファイルの指定 ansible.inventory_path = "ansible/hosts" ansible.limit = 'all' endAnsibleの設定
次に、Ansibleの設定ファイルを作成し、記述していく。
ansible/hosts を作成
まずは、設定を適用する対象のサーバーの指定を記述するファイルを作成する。
今回は、ansible/hosts
というファイルを新規に作成して、以下の記述を行う。[vagrant] 192.168.33.10ansible/playbook.yml を作成
次に、サーバーの設定をしていく設定ファイルを作成する。
今回記述した内容は、以下の通り。各項目で何をしているかはコメントで記載している。
ansible/playbook.yml--- - hosts: all sudo: yes vars: # MySQLのユーザーとパスワードを、変数に格納 mysql_user_name: vagrant mysql_user_password: vagrant tasks: # SELinux停止 - name: SELinuxのDisable設定 selinux: state=disabled # ロケールの設定 - name: add ja_JP.UTF-8 to locale shell: localedef -f UTF-8 -i ja_JP /usr/lib/locale/ja_JP.UTF-8 - name: set locale shell: localectl set-locale LANG=ja_JP.utf8 when: ansible_env.LANG | default('') != 'ja_JP.UTF-8' - name: set timezone to Asia/Tokyo timezone: name: Asia/Tokyo # Apacheをインストール - name: Install Apacheをインストール yum: name=httpd - name: Apacheを起動 service: name=httpd state=started enabled=yes - name: .htaccessを有効にする replace: dest=/etc/httpd/conf/httpd.conf regexp='AllowOverride None' replace='AllowOverride All' # PHP7.1をインストール - name: yum install epel-repease yum: name=epel-release state=installed - name: add remi-repo repository command: rpm -ih http://rpms.famillecollet.com/enterprise/remi-release-7.rpm creates=/etc/yum.repos.d/remi.repo - name: PHP7.1をインストール yum: name={{ item }} enablerepo=remi,remi-php71 state=installed with_items: - php - php-devel - php-fpm - php-mbstring - php-mcrypt - php-mysqlnd - php-pdo - php-xml - name: PHPをタイムゾーンの設定 replace: > dest=/etc/php.ini regexp="^;date\.timezone =" replace="date.timezone = Asia/Tokyo" # MySQL5.6 - name: MySQL5.6のリポジトリを追加 command: > yum -y install http://dev.mysql.com/get/mysql-community-release-el6-5.noarch.rpm creates=/etc/yum.repos.d/mysql-community.repo - name: MySQLをインストール yum: name={{item}} with_items: - mysql-server - MySQL-python - name: MySQLを起動 service: name=mysqld state=started enabled=yes - name: MySQLのユーザーを追加 mysql_user: name={{ mysql_user_name }} password={{ mysql_user_password }} priv=*.*:ALL # Apache再起動 - name: Apache再起動 service: name=httpd state=restartedゲストOSを起動して、動作確認
ゲストOSを起動して、動作確認する。
ゲストOSを起動
Vagrantを起動する。
起動すると、ここまで設定してきた内容を勝手に読み込んで、サーバーの構築を進めてくれる。# Vagrantを起動 $ vagrant up問題なく進んでいけば、最後に以下のようなメッセージがでて、入力画面にもどるはず。
PLAY RECAP ********************************************************************* 192.168.33.10 : ok=16 changed=15 unreachable=0 failed=0動作確認
ホストOSの
/htdocs/
配下にphpinfoを出力するファイルを配置して、ゲストOSに同期され、実際にブラウザで表示できることを確認する。ファイルを作成
/htdocs/info.php<?php phpinfo(); ?>ブラウザでアクセス
以下のURLにアクセスします。
http://192.168.33.10/info.phpPHPに関する情報が表示されれば、OK。
環境を停止・破棄
仮想環境はメモリを常に使用する。ゲストOSを利用しないときはサーバーを停止しておくこともできる。
# Vagrantを停止(サーバーを停止) $ vagrant haltまた、構築した環境が不要になった場合は、以下のコマンドでゲストOSを破棄できる。
# Vagrantを破棄(サーバーを廃棄) $ vagrant destroy
- 投稿日:2020-07-06T11:24:58+09:00
Laravel で FromRequest のバリデーションをテストする
Laravel の FormRequest クラスを利用すると各フィールドのバリデーションルールを array の形で定義することができます。
<?php namespace App\Http\Requests\UserRegistration; use Illuminate\Foundation\Http\FormRequest; class UserRegistrationFormRequest extends FormRequest { public function rules(): array { return [ 'name' => [ 'required', 'string', 'min:2', 'regex:/^[A-Za-z0-9]+$/', ], 'password' => [ 'required', 'string', 'min:8', 'regex:/[a-z]/', 'regex:/[A-Z]/', 'regex:/[0-9]/', 'regex:/@$!%*#?&/', ], ]; } }一つ一つのルールをテストするメリットは特にないと思いますが、上記のような複数ルールの組み合わせやカスタムバリデーションを検証するために Unit Test を作成する際の Tips を紹介します。
テストコード
ベースとなるメソッドは Stack Overflow から拝借しています(というか、この記事の要点はこの方法の紹介です!)。
これをベースに汎用的な FormRequest 用の TestCase クラスを作ってみます。<?php namespace Tests\Unit\App\Requests\Base; use Illuminate\Foundation\Testing\TestCase; abstract class BaseFormRequestTestCase extends TestCase { /** * @var array */ protected $rules; /** * @var \Validator */ protected $validator; public function setUp(): void { parent::setUp(); $this->setRules(); $this->validator = $this->app['validator']; } /** * 子クラスで Request Class が持つ rules を set する。 */ abstract protected function setRules(): void; protected function getFieldValidator($field, $value) { return $this->validator->make( [$field => $value], [$field => $this->rules[$field]] ); } protected function validateField($field, $value) { return $this->getFieldValidator($field, $value)->passes(); } }これを継承した形で TestCase を作成すれば比較的シンプルにバリデーションのテストを書くことができます。
<?php namespace Tests\Unit\App\Requests\UserRegistration\UserRegistrationFormRequest; use App\Http\Requests\UserRegistration\UserRegistrationFormRequest; use Tests\Unit\App\Requests\Base\BaseFormRequestTestCase; class UserRegistrationFormRequestTest extends BaseFormRequestTestCase { protected function setRules(): void { $this->rules = (new UserRegistrationFormRequest())->rules(); } public function testNameRules() { $this->assertFalse($this->validateField('name', null)); $this->assertFalse($this->validateField('name', 'a')); $this->assertTrue($this->validateField('name', 'ab')); $this->assertTrue($this->validateField('name', 'AB')); $this->assertTrue($this->validateField('name', '01')); $this->assertTrue($this->validateField('name', 'aA0')); $this->assertFalse($this->validateField('name', 'ab@')); $this->assertFalse($this->validateField('name', 'ab cd')); } public function testPasswordRules() { $this->assertFalse($this->validateField('password', null)); $this->assertFalse($this->validateField('password', 'abAB01@')); $this->assertTrue($this->validateField('password', 'abAB01@$')); $this->assertFalse($this->validateField('password', 'abcABC012')); $this->assertFalse($this->validateField('password', 'ABC012@$!')); $this->assertFalse($this->validateField('password', '012@$!abc')); $this->assertFalse($this->validateField('password', '@$!abcABC')); $this->assertFalse($this->validateField('password', 'ab AB 01 @$')); } }
- 投稿日:2020-07-06T02:27:17+09:00
docker-composeで、nginx、php、mysqlの環境を作成してみた
私は初心者です。間違っていたりもっと良いやり方がありましたら教えていただけるとありがたいです
こちらのリンクにコードを置きました
参考
- docker-composeでPHPとMySQLを連携させてみる - Qiita
- https://hub.docker.com/_/php
- https://hub.docker.com/_/mysql
- FuelPHPでのMySQL接続時にThe server requested authentication method unknown to the client [caching_sha2_password] となった場合に対処してみた - Qiita
- Docker Laravel Mysql: could not find driver - Stack Overflow
docker-compose.ymlversion: "3" services: web: image: nginx ports: - "8080:80" volumes: # ホストのdefault.confを同期 - ./default.conf:/etc/nginx/conf.d/default.conf # ホストの./myappフォルダを同期 - ./myapp:/var/www/html depends_on: - php php: build: . volumes: # ホストの./myappフォルダを同期 - ./myapp:/var/www/html db: image: mysql # PDOでhostを指定するときにこのコンテナ名を使う container_name: mysql # MySQL8.0でのデフォルトの認証方式が「caching_sha2_password」なので変更する # 設定しないと "The server requested authentication method unknown to the client" とエラーになる command: --default-authentication-plugin=mysql_native_password environment: # 設定必須、rootパスワード - MYSQL_ROOT_PASSWORD=root # この設定はオプション、イメージの起動時に作成されるデータベース名 - MYSQL_DATABASE=sampledefault.confserver { listen 80; listen [::]:80; server_name localhost; root /var/www/html; location / { index index.php index.html; } location ~ \.php$ { fastcgi_pass php:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } }DockerfileFROM php:7-fpm # 拡張モジュールをインストール RUN docker-php-ext-install pdo pdo_mysqlmyapp/index.php<?php try { echo (new PDO( 'mysql:host=mysql;dbname=sample;charset=utf8mb4', 'root', 'root', [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, ] )) ->query('select concat(\'MySQL Version :\', version()) v') ->fetch()['v']; } catch (PDOException $e) { echo $e->getMessage(); }以上です。m(_ _)m
- 投稿日:2020-07-06T01:33:00+09:00
データ型とは
データ型とは
データ型とは データの性質のこと。
主に「整数型/浮動小数点型」「文字列型」「NULL型」「論理型」があります。整数型(integer) / 浮動小数点型(float)
整数型は整数を、浮動小数点型は小数を扱う形式です。
index.php<?php $int_a = 123; $int_b = +123; // $int_aと同じ。普通は+はつけずに書く $int_c = -123; // 負の数は「-」をつける $float = 0.123; // 小数 ?>$int_a , $int_b , $int_c のデータ型は整数型、 $floatのデータ型は浮動小数点型となります。
文字列型(string)
文字を扱う形式です。
"(ダブルクオーテーション)又は'(シングルクオーテーション)で囲むと、文字列型として扱われます。index.php<?php $int_a = 123; // これは「整数型」です。 $string_a = '123'; // これは「文字列型」です。 $string_b = '山田花子'; ?>NULL型(null)
NULLは値を持たないことを表す形式です。
値はnullしかありません。index.php<?php var_dump($undefined); ?>を実行すると、「Notice: Undefined variable: undefined」が出て来ます。
これは、「undefinedという変数は定義されていない」というエラーです。
このように何も値を代入していない変数の値などにNULLが使われます。論理値型(boolean)(ブーリアン型)
論理型はtrue(真)又はfalse(偽)の2つの値を持つ形式です。
この値は、TRUE または FALSE のどちらかになります。index.php<?php $bool_true = true; // 値trueを$bool_trueに代入する $bool_false = false; // 値falseを$bool_trueに代入する ?>あとがき
基本的なものだけまとめました。
- 投稿日:2020-07-06T00:37:33+09:00
Docker Laravel6のアプリにユーザ認証機能を付与する
目的
- 環境構築と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 前提条件
- 下記の記事を参考にDockerを用いたLaravelアプリの作成が行われていること。
前提情報
- 特になし
読後感
- Laravelアプリにauthを用いたユーザ認証機能を付与することができる。
概要
- Dockerのphpコンテナに入る
- DBの作成と設定
- ライブラリのインストール
- Authファイルの取得
- 確認
詳細
Dockerのphpコンテナに入る
下記コマンドを実行してDockerの起動しているコンテナの一覧を表示する。
$ docker psPHPのコンテナを探し下記コマンドを実行する。
$ docker exec -it phpコンテナの名前 bashDockerコンテナ内で下記コマンドを実行してnginxのドキュメントルートに移動する。
$ cd /usr/share/nginx/html/appDBの設定
Dockerコンテナ内のappディレクトリで下記コマンドを実行して.envファイルを開く。
$ vi .envDBの記載を下記の様に修正・追記を行う。
/usr/share/nginx/html/app/.envDB_CONNECTION=mysql DB_HOST=mariadb DB_PORT=3306 DB_DATABASE=laravel DB_USERNAME=laravel DB_PASSWORD=larapass記載後の.envファイルの内容を下記に記載する。
/usr/share/nginx/html/app/.envAPP_NAME=Laravel APP_ENV=local APP_KEY=base64:3aQ51W/eAA0ICIpKCYhAygUc1SCWOcKBL9Sijrn8iOQ= APP_DEBUG=true APP_URL=http://localhost LOG_CHANNEL=stack DB_CONNECTION=mysql DB_HOST=mariadb DB_PORT=3306 DB_DATABASE=laravel DB_USERNAME=laravel DB_PASSWORD=larapass BROADCAST_DRIVER=log CACHE_DRIVER=file QUEUE_CONNECTION=sync SESSION_DRIVER=file SESSION_LIFETIME=120 REDIS_HOST=127.0.0.1 REDIS_PASSWORD=null REDIS_PORT=6379 MAIL_DRIVER=smtp MAIL_HOST=smtp.mailtrap.io MAIL_PORT=2525 MAIL_USERNAME=null MAIL_PASSWORD=null MAIL_ENCRYPTION=null MAIL_FROM_ADDRESS=null MAIL_FROM_NAME="${APP_NAME}" AWS_ACCESS_KEY_ID= AWS_SECRET_ACCESS_KEY= AWS_DEFAULT_REGION=us-east-1 AWS_BUCKET= PUSHER_APP_ID= PUSHER_APP_KEY= PUSHER_APP_SECRET= PUSHER_APP_CLUSTER=mt1 MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}" MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"ライブラリのインストール
Dockerコンテナ内のappディレクトリで下記コマンドを実行してライブラリを取得する。(ライブラリのバージョン指定
1.*
を行わず実行するとエラーになる。バージョン指定をせずエラーになった話はこちら→Laravel 6 $ composer require laravel/uiを実行するとエラーが発生する)$ composer require laravel/ui 1.*Authファイルの取得
Dockerコンテナ内のappディレクトリで下記コマンドを実行してAuthに必要なファイルを取得する。
$ php artisan ui bootstrap --authDockerコンテナ内で下記コマンド実行してnvmをインストールする。
$ curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.34.0/install.sh | bashDockerコンテナ内で下記コマンドを実行してnode.jsとyarnをインストールする。
$ . ~/.nvm/nvm.sh && nvm install node && npm i -g yarnDockerコンテナ内で下記コマンドを実行して必要なCSSファイルをインストールする。
$ npm install && npm run dev確認
下記にアクセスし、Laravelのホーム画面が出力されることを確認する。
「REGISTER」をクリックする。
下記の画面が出力されることを確認する。
Dockerコンテナ内の
/usr/share/nginx/html/app
ディレクトリに移動し下記コマンドを実行する。$ php artisan migrate各認証情報を入力し「Registar」をクリックする。
下記の様に初期登録とログインすることができればユーザ認証機能の付与は完了である。
参考文献
- 投稿日:2020-07-06T00:13:20+09:00
Laravelでページネーション
前提条件
eclipseでLaravel開発環境を構築する。デバッグでブレークポイントをつけて止める。(WindowsもVagrantもdockerも)
本記事は上記が完了している前提で書かれています
プロジェクトの作成もapacheの設定も上記で行っていますLaravelでデータベースを操作する(クエリビルダ編)
本記事は上記が完了している前提で書かれています
本記事は上記で作成したフォルダとファイルを使用しますサービスクラス修正
ここで修正するサービスクラスは
Laravelでデータベースを操作する(クエリビルダ編)
で作成したものです
(1) /sample/app/Services/Interfaces/Table2Service.php修正
selectメソッドの引数修正
引数に$limit = null, $page = null, $sort = null
追加Table2Service.php‥‥ public function select($id, $varchar_col, $int_col, $datetime_col, $date_col, $time_col, $limit = null, $page = null, $sort = null); ‥‥(2) /sample/tests/Services/Impl/Table2ServiceImpl.php修正
selectメソッドの引数修正
引数に$limit = null, $page = null, $sort = null
追加Tests\Services\Impl\Table2ServiceImpl.php‥‥ public function select($id, $varchar_col, $int_col, $datetime_col, $date_col, $time_col, $limit = null, $page = null, $sort = null) { } ‥‥(3) /sample/app/Services/Impl/Table2ServiceImpl.php修正
selectメソッド修正App\Services\Impl\Table2ServiceImpl.php‥‥ public function select($id, $varchar_col, $int_col, $datetime_col, $date_col, $time_col, $limit = null, $page = null, $sort = null) { $columns = [ 'table1.id as table1_id', 'table1.varchar_col as table1_varchar_col', 'table1.int_col as table1_int_col', 'table1.datetime_col as table1_datetime_col', 'table1.date_col as table1_date_col', 'table1.time_col as table1_time_col', 'table2.id as table2_id', 'table2.varchar_col as table2_varchar_col', 'table2.int_col as table2_int_col', 'table2.datetime_col as table2_datetime_col', 'table2.date_col as table2_date_col', 'table2.time_col as table2_time_col', 'table3.id as table3_id', 'table3.varchar_col as table3_varchar_col', 'table3.int_col as table3_int_col', 'table3.datetime_col as table3_datetime_col', 'table3.date_col as table3_date_col', 'table3.time_col as table3_time_col', ]; $db = DB::table('table2') ->leftJoin('table1', 'table2.table1_id', '=', 'table1.id') ->leftJoin('table3', 'table2.id', '=', 'table3.table2_id') ->select($columns); if (!is_null($id)) { $db->where('table2.id', '=', $id); } if (!is_null($varchar_col)) { $db->where('table2.varchar_col', 'like', '%'. addcslashes($varchar_col, '\\_%') . '%'); } if (!is_null($int_col)) { $db->where('table2.int_col', '=', $int_col); } if (!is_null($datetime_col)) { $db->where('table2.datetime_col', '=', $datetime_col); } if (!is_null($date_col)) { $db->where('table2.date_col', '=', $date_col); } if (!is_null($time_col)) { $db->where('table2.time_col', '=', $time_col); } if (!is_null($sort)) { $sortCol = ['table2.id', 'table2.varchar_col', 'table2.int_col', 'table2.datetime_col', 'table2.date_col', 'table2.time_col']; $db->orderBy($sortCol[$sort]); } if (!is_null($page) && !is_null($limit)) { $recordList = $db->paginate($limit, $columns, 'page', $page); } else { $recordList = $db->get(); } return $recordList; } ‥‥大きな修正は$db->paginateメソッドを追加したことです
paginateメソッドの
第1引数は1ページに表示する件数です。
第2引数はselectするカラムです。
今回は
DB::table('table2')
‥‥
->select($columns);
で取得するカラムを指定しているので意味ないです
第3引数はページ番号が送信されてくるHTTPリクエストパラメーター名です。
第4引数はページ番号です。select文ではこの引数-1がoffsetになります
第2引数から第4引数は省略できます。省略した場合、第2引数は[*]、第3引数は'page'、第4引数はnullになり、ページ番号は第3引数名のHTTPパラメーター値になります(第3引数、第4引数を省略すれば、pageという名前のHTTPパラメーター値となる)
今回はクエリビルダを使いましたが、paginateメソッドはEloquentでも使えます
Laravelでデータベースを操作する(Eloquent編)
でEloquentを使うサービスクラスを作成しました。そこではgetメソッドをつかってselectしましたが、getメソッドの部分を今回と同じpaginateメソッドに変更すれば、Eloquentでページネーションできます。クエリビルダのpaginateメソッドもEloquentのpaginateメソッドも引数は同じですフォームリクエストの修正
ここで修正するフォームリクエストは
Laravelでデータベースを操作する(クエリビルダ編)
で作成したものです
/sample/app/Http/Requests/Table2Request.php修正Table2Request.php‥‥ public function rules() { ‥‥ return [ 'id' => [$idRequire, 'numeric', 'max:18446744073709551615'], 'table1_id' => ['nullable', 'numeric', 'max:18446744073709551615'], 'varchar_col' => ['nullable', 'max:255'], 'int_col' => ['nullable', 'integer', 'max:2147483647'], 'datetime_col' => ['nullable', 'date_format:Y-m-d H:i:s'], 'date_col' => ['nullable', 'date_format:Y-m-d'], 'time_col' => ['nullable', 'date_format:H:i:s'], 'limit' => ['nullable', 'integer', 'min:1', 'max:200'], 'page' => ['nullable', 'integer', 'min:1', 'max:2147483647'], 'sort' => ['nullable', 'integer', 'min:0', 'max:5'], ]; } ‥‥limit、page、sortの入力制限を追加しました
Controllerにメソッド追加
(1) /sample/app/Http/Controllers/SampleController.phpにpaginateQueryBuilderメソッドを追記
フォームリクエスト、サービスクラスのuse文は
Laravelでデータベースを操作する(クエリビルダ編)
で書きましたSampleController.phppublic function paginateQueryBuilder(Table2Request $request, Table2Service $table2Service) { if (is_null($request->session()->get('errors'))) { $request->flash(); } $id = $request->input('id'); $varchar_col = $request->input('varchar_col'); $int_col = $request->input('int_col'); $datetime_col = $request->input('datetime_col'); $date_col = $request->input('date_col'); $time_col = $request->input('time_col'); $limit = $request->input('limit') ?? 5; $page = $request->input('page') ?? 1; $sort = $request->input('sort') ?? 0; $recordList = null; if (is_null($request->session()->get('errors'))) { $recordList = $table2Service->select($id, $varchar_col, $int_col, $datetime_col, $date_col, $time_col, $limit, $page, $sort); } $data = [ 'recordList' => $recordList, 'id' => $id, 'varchar_col' => $varchar_col, 'int_col' => $int_col, 'datetime_col' => $datetime_col, 'date_col' => $date_col, 'time_col' => $time_col, 'limit' => $limit, 'page' => $page, 'sort' => $sort ]; return view('sample.paginate', $data); }(2) /sample/routes/web.phpに下記を追記
Route::get('sample/paginate-query-builder', 'SampleController@paginateQueryBuilder');
viewの作成
(1) ページネーションビューの作成
ページネーションビューとは前のページへリンク、次のページへリンク、ページ番号リンクを描画するビューです
コマンドラインで
cd sample
php artisan vendor:publish --tag=laravel-pagination
xdebugの設定をしているとeclipseが実行していいですかというプロンプトを出すのでOKを押します
eclipseプロジェクトを右クリック→リフレッシュ
resources/views/vendor/paginationフォルダが現れます。そのフォルダの中に5つファイルができています
その中のbootstrap-4.blade.phpが今回使うページネーションビューになります。
ページネーションビューを独自のデザインにする場合、bootstrap-4.blade.phpを修正してください
今回修正したサービスクラスで使ったpaginateメソッドの戻り値(LengthAwarePaginatorクラスのインスタンス)がデフォルトで使用するページネーションビューがpagination::bootstrap-4です。
LengthAwarePaginator::defaultViewメソッドでデフォルトビューを変えることができます。また、デフォルトビューを変えなくても、後程使うlinksメソッドの第1引数にビュー名を渡すことでもカスタムページネーションビューを使用できます(2) /sample/resources/views/sample/paginate.blade.phpファイル作成
paginate.blade.php<html> <head> <title>sample</title> <style> .sample-table { border-collapse:collapse; white-space: nowrap; border: 1px solid #000000; } .sample-table thead { background-color: #33CCFF; color: #FFFFFF; font-weight: bold; } .sample-table td { padding-left:10px; padding-right:10px; border: 1px solid #000000; } .pagination li { display: inline-block; } </style> </head> <body> <form action="{{ url('sample/paginate-query-builder') }}" method="get"> @error('id') @foreach ($errors->get('id') as $error) <div style="color:red;">{{ $error }}</div> @endforeach @enderror <div>id<input type="text" name="id" value="{{ old('id') }}"></div> @error('varchar_col') @foreach ($errors->get('varchar_col') as $error) <div style="color:red;">{{ $error }}</div> @endforeach @enderror <div>varchar_col<input type="text" name="varchar_col" value="{{ old('varchar_col') }}"></div> @error('int_col') @foreach ($errors->get('int_col') as $error) <div style="color:red;">{{ $error }}</div> @endforeach @enderror <div>int_col<input type="text" name="int_col" value="{{ old('int_col') }}"></div> @error('datetime_col') @foreach ($errors->get('datetime_col') as $error) <div style="color:red;">{{ $error }}</div> @endforeach @enderror <div>datetime_col<input type="text" name="datetime_col" value="{{ old('datetime_col') }}"></div> @error('date_col') @foreach ($errors->get('date_col') as $error) <div style="color:red;">{{ $error }}</div> @endforeach @enderror <div>date_col<input type="text" name="date_col" value="{{ old('date_col') }}"></div> @error('time_col') @foreach ($errors->get('time_col') as $error) <div style="color:red;">{{ $error }}</div> @endforeach @enderror <div>time_col<input type="text" name="time_col" value="{{ old('time_col') }}"></div> @error('limit') @foreach ($errors->get('limit') as $error) <div style="color:red;">{{ $error }}</div> @endforeach @enderror <div>1ページ表示件数<input type="text" name="limit" value="{{ old('limit', 5) }}"></div> <input type="submit" > </form> <br> @isset($recordList) @if ($recordList->total() === 0) <div> 検索結果は0件です </div> @else <table class="sample-table"> <thead> <tr> <td colspan=6>table1</td> <td colspan=6>table2</td> <td colspan=6>table3</td> </tr> <tr> <td>id</td> <td>varchar_col</td> <td>int_col</td> <td>datetime_col</td> <td>date_col</td> <td>time_col</td> <td><a href="{{ $recordList->appends([ 'id' => $id, 'varchar_col' => $varchar_col, 'int_col' => $int_col, 'datetime_col' => $datetime_col, 'date_col' => $date_col, 'time_col' => $time_col, 'limit' => $limit, 'page' => $page, 'sort' => 0]) ->url($recordList->currentPage()) }}" >id</a></td> <td><a href="{{ $recordList->appends([ 'id' => $id, 'varchar_col' => $varchar_col, 'int_col' => $int_col, 'datetime_col' => $datetime_col, 'date_col' => $date_col, 'time_col' => $time_col, 'limit' => $limit, 'page' => $page, 'sort' => 1]) ->url($recordList->currentPage()) }}" >varchar_col</a></td> <td><a href="{{ $recordList->appends([ 'id' => $id, 'varchar_col' => $varchar_col, 'int_col' => $int_col, 'datetime_col' => $datetime_col, 'date_col' => $date_col, 'time_col' => $time_col, 'limit' => $limit, 'page' => $page, 'sort' => 2]) ->url($recordList->currentPage()) }}" >int_col</a></td> <td><a href="{{ $recordList->appends([ 'id' => $id, 'varchar_col' => $varchar_col, 'int_col' => $int_col, 'datetime_col' => $datetime_col, 'date_col' => $date_col, 'time_col' => $time_col, 'limit' => $limit, 'page' => $page, 'sort' => 3]) ->url($recordList->currentPage()) }}" >datetime_col</a></td> <td><a href="{{ $recordList->appends([ 'id' => $id, 'varchar_col' => $varchar_col, 'int_col' => $int_col, 'datetime_col' => $datetime_col, 'date_col' => $date_col, 'time_col' => $time_col, 'limit' => $limit, 'page' => $page, 'sort' => 4]) ->url($recordList->currentPage()) }}" >date_col</a></td> <td><a href="{{ $recordList->appends([ 'id' => $id, 'varchar_col' => $varchar_col, 'int_col' => $int_col, 'datetime_col' => $datetime_col, 'date_col' => $date_col, 'time_col' => $time_col, 'limit' => $limit, 'page' => $page, 'sort' => 5]) ->url($recordList->currentPage()) }}" >time_col</a></td> <td>id</td> <td>varchar_col</td> <td>int_col</td> <td>datetime_col</td> <td>date_col</td> <td>time_col</td> </tr> </thead> <tbody> @foreach ($recordList as $record) <tr> <td>{{ $record->table1_id }}</td> <td>{{ $record->table1_varchar_col }}</td> <td>{{ $record->table1_int_col }}</td> <td>{{ $record->table1_datetime_col }}</td> <td>{{ $record->table1_date_col }}</td> <td>{{ $record->table1_time_col }}</td> <td>{{ $record->table2_id }}</td> <td>{{ $record->table2_varchar_col }}</td> <td>{{ $record->table2_int_col }}</td> <td>{{ $record->table2_datetime_col }}</td> <td>{{ $record->table2_date_col }}</td> <td>{{ $record->table2_time_col }}</td> <td>{{ $record->table3_id }}</td> <td>{{ $record->table3_varchar_col }}</td> <td>{{ $record->table3_int_col }}</td> <td>{{ $record->table3_datetime_col }}</td> <td>{{ $record->table3_date_col }}</td> <td>{{ $record->table3_time_col }}</td> </tr> @endforeach </tbody> </table> @endif @endisset @isset($recordList) {{ $recordList->appends([ 'id' => $id, 'varchar_col' => $varchar_col, 'int_col' => $int_col, 'datetime_col' => $datetime_col, 'date_col' => $date_col, 'time_col' => $time_col, 'limit' => $limit, 'page' => $page, 'sort' => $sort ]) ->links() }} @endisset </body> </html>thead->tr->tdタグ内のaタグのhref属性では
$recordList->appends()->url()
を実行してます。$recordList
はLengthAwarePaginatorクラスのインスタンスです。
$recordList->currentPage()
は現在のページ番号を返します
url($recordList->currentPage())は$recordList->currentPage()
ページのURLを返します。
$recordList->appends
はurl()が返すURLに付加するクエリ文字列です
よく見ていただくと、appendsメソッドに渡している配列のsort要素の値を変えていますpaginate.blade.php下部に書いた
$recordList->appends()->links()
は先ほど生成したbootstrap-4.blade.phpを描画します
linksメソッドの第1引数にビュー名を渡すことでbootstrap-4.blade.phpではないカスタムページネーションビューを描画することもできます
appendsメソッドは先ほど説明した通りページリンクURLに付加するクエリ文字列です動作確認
http://localhost/laravelSample/sample/paginate-query-builder
にアクセスすると画面下部にページリンクが描画されていますPOSTに対応してみる
今作成したものはGETメソッドに対応したものでした。
多くの場合、検索はGETメソッドで大丈夫でしょうが、
検索条件がたくさん設置され、長い文字列カラムが検索条件に入っている場合など、GETメソッドにした場合、URLの文字列制限に引っかかり、URLのクエリ文字列が途中で切れてしまうこともあります
そのような事情で検索をPOSTメソッドで実装した場合に対応してみましょう(1) まず、resources/views/sample/paginate.blade.phpのformタグのmethod属性値をpostに変え、sample/routes/web.phpに定義した'sample/paginate-query-builder'のルーティングをRoute::getからRoute::match(['get', 'post']に変更します(今回は動作確認でsample/paginate-query-builderに直リンクするためgetも許容しておく)
(2) resources/views/vendor/pagination/bootstrap-4.blade.php修正
@if ($paginator->hasPages())
直下(2行目)に下記を追記@php $___paginatorHiddenFunc = function ($name, $value) use (&$___paginatorHiddenFunc) { if (is_array($value)) { foreach ($value as $k => $v) { $___paginatorHiddenFunc($name . '[' . $k . ']', $v); } } else { echo '<input type="hidden" name="' . htmlspecialchars($name, ENT_QUOTES) . '" value="' . htmlspecialchars($value, ENT_QUOTES) . '">'; } }; $___paginatorQueryList = null; parse_str(parse_url($paginator->url(1), PHP_URL_QUERY), $___paginatorQueryList); @endphpやっていることは2つです
type属性値がhiddenのinputタグを出力するメソッドを定義している($___paginatorHiddenFunc
)
1ページ目のページリンクのクエリ文字列を配列として取得している($___paginatorQueryList
)bootstrap-4.blade.phpにはaタグが3つ書いてあります
前のページへリンク、ページ番号リンク、次のページへリンクです
これらをformタグに直します前のページへリンク
<form action="{{ $paginator->path() }}" method="post"> @csrf @foreach ($___paginatorQueryList as $___paginatorQueryName => $___paginatorQueryValue) @if ($___paginatorQueryName === $paginator->getPageName()) @php $___paginatorHiddenFunc($___paginatorQueryName, $paginator->currentPage() - 1); @endphp @elseif ($___paginatorQueryName !== '_token') @php $___paginatorHiddenFunc($___paginatorQueryName, $___paginatorQueryValue); @endphp @endif @endforeach <input type="submit" value="‹"> </form>ページ番号リンク
<form action="{{ $paginator->path() }}" method="post"> @csrf @foreach ($___paginatorQueryList as $___paginatorQueryName => $___paginatorQueryValue) @if ($___paginatorQueryName === $paginator->getPageName()) @php $___paginatorHiddenFunc($___paginatorQueryName, $page); @endphp @elseif ($___paginatorQueryName !== '_token') @php $___paginatorHiddenFunc($___paginatorQueryName, $___paginatorQueryValue); @endphp @endif @endforeach <input type="submit" value="{{$page}}"> </form>次のページへリンク
<form action="{{ $paginator->path() }}" method="post"> @csrf @foreach ($___paginatorQueryList as $___paginatorQueryName => $___paginatorQueryValue) @if ($___paginatorQueryName === $paginator->getPageName()) @php $___paginatorHiddenFunc($___paginatorQueryName, $paginator->currentPage() + 1); @endphp @elseif ($___paginatorQueryName !== '_token') @php $___paginatorHiddenFunc($___paginatorQueryName, $___paginatorQueryValue); @endphp @endif @endforeach <input type="submit" value="›"> </form>やっていることは
配列として取得した1ページ目のページリンクのクエリ文字列($___paginatorQueryList
)をループし
type属性値がhiddenのinputタグを出力するメソッド($___paginatorHiddenFunc
)を実行しているだけです(3) resources/views/sample/paginate.blade.phpファイル作成
thead->tr->tdタグ内のaタグをformタグに変更します<form action="{{ $recordList->path() }}" method="post"> @csrf <input type="hidden" name="id" value="{{ $id }}"> <input type="hidden" name="varchar_col" value="{{ $varchar_col }}"> <input type="hidden" name="int_col" value="{{ $int_col }}"> <input type="hidden" name="datetime_col" value="{{ $datetime_col }}"> <input type="hidden" name="date_col" value="{{ $date_col }}"> <input type="hidden" name="time_col" value="{{ $time_col }}"> <input type="hidden" name="limit" value="{{ $limit }}"> <input type="hidden" name="sort" value="0">{{-- ここは各カラムの番号にする --}} <input type="hidden" name="page" value="{{ $page }}"> <input type="submit" value="id">{{-- ここは各カラム名にする --}} </form>動作確認
http://localhost/laravelSample/sample/paginate-query-builder
にアクセスします
ページリンクをクリックするとPOST送信できました
見た目は自由にCSSで変えてください