20190524のlaravelに関する記事は13件です。

Docker で Laravel開発環境

Nginxのconfを作成する

server {
    listen  80;
    root /usr/share/nginx/laravel/public;
    index index.php index.html index.htm;
    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }
    location ~ ^/.+\.php(/|$) {
        fastcgi_pass laravel-container:9000;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }
}

DockerでPHP-FPMを作成する

FROM php:7.3-fpm-alpine
RUN apk add libzip-dev
RUN docker-php-ext-configure zip --with-libzip
RUN docker-php-ext-install pdo_mysql zip

docker-composeを作成する

version: "3.7"

services:

  laravel:
    build: .
    container_name: laravel-container
    working_dir: /usr/share/nginx/laravel
    networks:
      - laravel-docker
    volumes:
        - ./laravel:/usr/share/nginx/laravel

  nginx:
    image: nginx:1.16-alpine
    container_name: reverse-proxy
    working_dir: /usr/share/nginx/laravel
    networks:
      - laravel-docker
    ports:
        - "8080:80"
    volumes:
        - ./default.conf:/etc/nginx/conf.d/default.conf
        - ./laravel:/usr/share/nginx/laravel

  mysql:
    image: mysql:8.0
    container_name: mysql-server
    networks:
      - laravel-docker
    environment:
      - MYSQL_ROOT_PASSWORD=password
      - MYSQL_DATABASE=homestead
      - MYSQL_USER=homestead
      - MYSQL_PASSWORD=secret
    ports:
      - 3306:3306

  redis:
    image: redis:5.0-alpine
    container_name: redis-server
    networks:
      - laravel-docker
    ports:
      - 6379:6379

networks:
  laravel-docker:
    driver: bridge

詳細は下記(ハンズオン)

https://github.com/hexaforce/laravel-docker

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

HomesteadでRuby on Railsの環境構築

Homesteadはlaravelの開発環境を簡単に構築できるパッケージだが、Ruby on Railsで必要なソフトも入っているため、Homesteadを使用したRuby on Railsの環境を構築していく。

今回はMacで、使用するDBはMySQLとする。

Homesteadとは?

Laravel公式のboxで、Vgrantを使用することで仮想マシンにLaravelの開発環境を簡単に構築することができるパッケージです。
PHPやWebサーバ、その他のサーバソフトウェアをローカルマシンにインストールする必要なく、開発環境を構築できます。

導入されているソフトウェア

公式より以下のソフトが既に含まれています。(2019/5 現在)

  • Ubuntu 18.04
  • Git
  • PHP 7.3
  • PHP 7.2
  • PHP 7.1
  • Nginx
  • MySQL
  • lmmによるMySQLとMariaDBデータベーススナップショット
  • Sqlite3
  • PostgreSQL
  • Composer
  • Node (Yarn、Bower、Bower、Grunt、Gulpを含む)
  • Redis
  • Memcached
  • Beanstalkd
  • Mailhog
  • avahi
  • ngrok
  • Xdebug
  • XHProf / Tideways / XHGui
  • wp-cli
  • Minio

オプションで導入できるソフトウェア

  • Apache
  • Crystal & Lucky Framework
  • Dot Net Core
  • Elasticsearch
  • Go
  • MariaDB
  • MongoDB
  • Neo4j
  • Oh My Zsh
  • Ruby & Rails
  • Webdriver & Laravel Dusk Utilities
  • Zend Z-Ray

VirtualBoxとVagrantのインストール

VirtualBoxをインストール

仮想化ソフトは他にもいくつかあるそうですが「VirtualBox」を使用

インストールはこちらから >> https://www.virtualbox.org/

自分の使用しているOSを選択

スクリーンショット 2019-05-22 22.13.38.png

【注意】
「機能拡張がブロックされました」と表示されたら「システム環境設定」→「セキュリティとプライバシー」から読み込みを許可しましょう

Vagrantをインストール

Vagrantとは仮想化ソフト(VirtualBox)を使用し、コマンドを入力することで仮想環境を管理したり構築したりすることができるツールです。

インストールはこちらから >> https://www.vagrantup.com/

自分の使用しているOSを選択

スクリーンショット 2019-05-22 22.19.47.png

ダウンロードしたらバージョンを確認してみる。

$ vagrant --version
 Vagrant 2.2.4

これで2.2.4のVagrantがインストールされました。

Homesteadのboxをインストール

boxとはOSのディスクイメージファイルで、これを追加することで仮想環境を作成できる。

https://app.vagrantup.com/laravel/boxes/homestead

上記のリンクの公式を確認すると「laravel/homestead」があるのでこれを取得する。

VagrantCloudにあるboxを追加する場合は名前だけでも良い。

$ vagrant box add laravel/homestead

実行するとproviderは何かと聞かれるので「virtualbox」の「3」を選択する。
結構時間がかかるので終わるまで待つ。

$ vagrant box add laravel/homestead
==> box: Loading metadata for box 'laravel/homestead'
    box: URL: https://vagrantcloud.com/laravel/homestead
This box can work with multiple providers! The providers that it
can work with are listed below. Please review the list and choose
the provider you will be working with.

1) hyperv
2) parallels
3) virtualbox
4) vmware_desktop

Enter your choice: 3
==> box: Adding box 'laravel/homestead' (v7.2.1) for provider: virtualbox
    box: Downloading: https://vagrantcloud.com/laravel/boxes/homestead/versions/7.2.1/providers/virtualbox.box
    box: Download redirected to host: vagrantcloud-files-production.s3.amazonaws.com
==> box: Successfully added box 'laravel/homestead' (v7.2.1) for 'virtualbox'!

Successfulluyとなったので、以下のコマンドでboxがちゃんと追加されたか確認する。

$ vagrant box list
laravel/homestead (virtualbox, 7.2.1)

Homesteadのファイルをダウンロード

ダウンロードしたファイルは任意のディレクトで良いが、今回はホームディレクトリの直下にダウンロードするので移動しておく。

$ cd
$ pwd
/Users/ユーザー名

以下のコマンドでgithubからリポジトリをクローンします。

$ git clone https://github.com/laravel/homestead.git Homestead
Cloning into 'Homestead'...
remote: Enumerating objects: 59, done.
remote: Counting objects: 100% (59/59), done.
remote: Compressing objects: 100% (46/46), done.
remote: Total 3606 (delta 37), reused 22 (delta 13), pack-reused 3547
Receiving objects: 100% (3606/3606), 782.03 KiB | 863.00 KiB/s, done.
Resolving deltas: 100% (2190/2190), done.

Homesteadの初期化

HomesteadはHomestead.yamlというファイルに色々書くことで、任意の設定をすることができる。
Homestead.yamlは初期化することで生成される。

ダウンロードしたHomesteadディレクトリに移動する。
中に色々なファイルが入っているが、初期化をしていないのでHomestead.yamlが生成されていない。

$ cd Homestead/
$ ls
CHANGELOG.md        Vagrantfile     composer.lock       phpunit.xml.dist    scripts
Homestead.yaml.example  bin         init.bat        readme.md       src
LICENSE.txt     composer.json       init.sh         resources       tests

以下のコマンドで初期化する。

$ bash init.sh
Homestead initialized!
$ ls
CHANGELOG.md        LICENSE.txt     aliases         composer.lock       phpunit.xml.dist    scripts
Homestead.yaml      Vagrantfile     bin         init.bat        readme.md       src
Homestead.yaml.example  after.sh        composer.json       init.sh         resources       tests

Homestead initialized!と表示されたので、中を確認するとHomestead.yamlが生成されている。

SSH鍵のファイルの作成

ホストOSとゲストOSの通信はSSHで行うので、それに必要な鍵を作成する。

まずはホームディレクトリに移動して既に鍵があるかを確認。

$ cd
$ ls -la | grep .ssh

id_rsaid_rsa.pubが表示されれば、既にSSH鍵ファイルはあります。

無い場合は以下のコマンドで作成する。

$ ssh-keygen -t rsa

途中でEnter file in which to save the key (/Users/ユーザー名/.ssh/id_rsa):と保存するディレクトリを聞かれるので、そのままEnterを押す。

次にEnter passphraseとパスフレーズを求められるので任意のパスフレーズを設定する。
Enter same passphrase again:と再度確認を求められるので設定したパスフレーズを入力する。

$ ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/Users/ユーザー名/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /Users/ユーザー名/.ssh/id_rsa.
Your public key has been saved in /Users/ユーザー名/.ssh/id_rsa.pub.
The key fingerprint is:
...(以下省略)...

ファイルキーが作成されたので、先ほどのコマンドで確認する。

$ ls -la | grep .ssh

Homesteadの設定

Homestead(仮想マシン)の各設定は、初期化した時に生成したhomestead.yamlに記述します。

Homesteadのディレクトリに移動し、vimでHomestead.yamlを編集。

$ cd Homestead/
$ vim Homestead.yaml

下記がHomestead.yamlのデフォルトのです。

Homestead.yaml
---
ip: "192.168.10.10"     # IPアドレス
memory: 2048            # 割り当てるメモリ
cpus: 2                 # 割り当てるCPU
provider: virtualbox    # 使用するプロバイダ

# SSH公開鍵のパス
authorize: ~/.ssh/id_rsa.pub

# SSH秘密鍵のパス
keys:
    - ~/.ssh/id_rsa

# 共有ディレクトリの設定
# map: ホストマシン側で共有したいディレクトリ
# to: ゲストマシン側で共有したいディレクトリ
folders:
    - map: ~/code
      to: /home/vagrant/cod


# Nginxサイトの設定
# map: アクセスするドメイン名の設定
# to: ゲストマシンNginxのドキュメントルートの設定
sites:
    - map: homestead.test
      to: /home/vagrant/code/public

# 使用するDB名
databases:
    - homestead

# ports:
#     - send: 50000
#       to: 5000
#     - send: 7777
#       to: 777
#       protocol: udp

# blackfire:
#     - id: foo
#       token: bar
#       client-id: foo
#       client-token: bar

rails serverは3000なので、コメントアウトを外して新しく記述する。

ports:
    - send: 3000
      to: 3000

それ以外はデフォルトのままで使用しますが、共有ディレクトリの設定や、ドキュメントルートの設定などの変更が可能です。

デフォルトのfoldersだとホストマシンのホームディレクトリ直下にcodeディレクトリが指定されていますが、現在codeディレクトリがないので作成しておきます。

今後プロジェクトフォルダを作成したときは、このcodeディレクトリのなかに入ることになります。

$ mkdir ~/code

【注意】
sitesプロパティをHomestead boxのプロビジョニング後に変更した場合、仮想マシンのNginx設定を更新するため、vagrant reload --provisionを再実行する必要があります。

ホスト名の設定

IPアドレス192.168.10.10homestead.testというドメイン名で設定してあり、hostsファイルに追記することで、Webブラウザでhttp://homestead.testにアクセスすることができる。

MacとLinuxでは/etc/hostsにファイルがあるので追加していく。
アクセス権がないと保存できないので、sudoをつけて192.168.10.10 homestead.appを追記する。

$ sudo vim /etc/hosts

##
# Host Database
#
# localhost is used to configure the loopback interface
# when the system is booting.  Do not change this entry.
##
127.0.0.1       localhost
255.255.255.255 broadcasthost
::1             localhost

192.168.10.10 homestead.test

Vagrant Boxの実行

各種設定が終わったら仮想マシンを起動します。

Homesteadのディレクトリ内にVagrantfileがあるので、違うディレクトリにいる場合は移動します。

$ pwd
/Users/ユーザー名/Homestead

下記のコマンドで仮想マシンを起動する。

$ vagrant up
Bringing machine 'homestead-7' up with 'virtualbox' provider...
==> homestead-7: Importing base box 'laravel/homestead'...
==> homestead-7: Matching MAC address for NAT networking...
==> homestead-7: Checking if box 'laravel/homestead' version '7.2.1' is up to date...
==> homestead-7: Setting the name of the VM: homestead-7
==> homestead-7: Clearing any previously set network interfaces...
...(以下省略)...

以下のコマンドで起動できているかを確認。

$ vagrant status
Current machine states:

homestead-7               running (virtualbox)

The VM is running. To stop this VM, you can run `vagrant halt` to
shut it down forcefully, or you can run `vagrant suspend` to simply
suspend the virtual machine. In either case, to restart it again,
simply run `vagrant up`.

running (virtualbox)となっているので起動できていることが確認できます。

あとはsshコマンドで仮想マシンに入ります。

$ vagrant ssh
Welcome to Ubuntu 18.04.2 LTS (GNU/Linux 4.15.0-47-generic x86_64)

Thanks for using
 _                               _                 _
| |                             | |               | |
| |__   ___  _ __ ___   ___  ___| |_ ___  __ _  __| |
| '_ \ / _ \| '_ ` _ \ / _ \/ __| __/ _ \/ _` |/ _` |
| | | | (_) | | | | | |  __/\__ \ ||  __/ (_| | (_| |
|_| |_|\___/|_| |_| |_|\___||___/\__\___|\__,_|\__,_|

* Homestead 8.4.0 released!
* Settler v7.2.1 released! Make sure you update

0 packages can be updated.
0 updates are security updates.


Last login: Thu May 24 08:54:14 2019 from 10.0.2.2
vagrant@homestead:~$ 

無事に仮想マシンに入れたので、あとはRailsの環境を構築していきます。

Ruby on Railsの環境を構築

Homesteadが立ち上がったのであとは必要なソフトなどを入れていくが、既にあるのがほとんどなのでrbenv等を入れていく。

必要なライブラリをインストール

Ubuntu自体をアップデート(最新化)します。

$ sudo apt update 

今回はMysqlを使用するので、必要な関連パッケージをインストール

$ sudo apt install mysql-server mysql-client
$ sudo apt install libmysqlclient-dev

Rubyインストール

rbenvをインストール

rbenvとは、Rubyの「インストール」と「バージョン切替」を簡単におこなえるようにするためのツールです。

Gitを使ってrbenvをインストールします

$ git clone https://github.com/sstephenson/rbenv.git ~/.rbenv
Cloning into '/home/vagrant/.rbenv'...
remote: Enumerating objects: 15, done.
remote: Counting objects: 100% (15/15), done.
remote: Compressing objects: 100% (11/11), done.
remote: Total 2759 (delta 4), reused 8 (delta 4), pack-reused 2744
Receiving objects: 100% (2759/2759), 528.92 KiB | 874.00 KiB/s, done.
Resolving deltas: 100% (1724/1724), done.

インストールできたらrbenvコマンドが使えるように設定する

$ echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile
$ echo 'eval "$(rbenv init -)"' >> ~/.bash_profile
$ exec $SHELL -l

rbenvコマンドが使えるようになったか確認する

$ rbenv --version
rbenv 1.1.2-2-g4e92322

Rubyをビルドするために使うプラグインの「ruby-build」をインストール

$ git clone https://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build
Cloning into '/home/vagrant/.rbenv/plugins/ruby-build'...
remote: Enumerating objects: 38, done.
remote: Counting objects: 100% (38/38), done.
remote: Compressing objects: 100% (25/25), done.
remote: Total 9750 (delta 14), reused 29 (delta 8), pack-reused 9712
Receiving objects: 100% (9750/9750), 2.08 MiB | 2.10 MiB/s, done.
Resolving deltas: 100% (6340/6340), done.

インストールできるRubyのバージョンを確認する

$ rbenv install --list
Available versions:
  1.8.5-p52
  1.8.5-p113
  1.8.5-p114
  1.8.5-p115
  1.8.5-p231
  1.8.6
  1.8.6-p36
  1.8.6-p110
  1.8.6-p111
  1.8.6-p114

...(途中省略)...

  2.5.4
  2.5.5
  2.6.0-dev
  2.6.0-preview1
  2.6.0-preview2
  2.6.0-preview3
  2.6.0-rc1
  2.6.0-rc2
  2.6.0
  2.6.1
  2.6.2
  2.6.3
  2.7.0-dev
  jruby-1.5.6
  jruby-1.6.3

...(以下省略)...

バージョンを指定してRubyをインストール。
終わったら仮想マシンにインストールされているRubyのバージョンを確認します。

$ rbenv install -v 2.6.3
/tmp/ruby-build.20190524115043.18071 ~
Downloading ruby-2.6.3.tar.bz2...
-> https://cache.ruby-lang.org/pub/ruby/2.6/ruby-2.6.3.tar.bz2
Installing ruby-2.6.3...
/tmp/ruby-build.20190524115043.18071/ruby-2.6.3 /tmp/ruby-build.20190524115043.18071 ~
checking for ruby... /home/vagrant/.rbenv/shims/ruby
config.guess already exists
config.sub already exists
checking build system type... x86_64-pc-linux-gnu

...(以下省略)...

$ rbenv versions
* system (set by /home/vagrant/.rbenv/version)
  2.6.3

インストールされているのを確認できたら、仮想マシン全体で有効にするRubyのバージョンを指定する。

ディレクトリごとに指定する場合はglobalではなく、有効にしたいディレクトリでlocalを指定する。

$ rbenv global 2.6.3
$ rbenv versions
  system
* 2.6.3 (set by /home/vagrant/.rbenv/version)

アスタリスクが移動しました。
ちゃんと最新バージョンがインストールされたかを確認

$ ruby -v
ruby 2.6.3p62 (2019-04-16 revision 67580) [x86_64-linux]

bundlerのインストール

bundlerはプロジェクトごとで使うgemを、インストールしたり使用したりする。
どのバージョンが必要なのかは、プロジェクトフォルダにあるGemfileを読み取りることで実行される。

bundlerはRubyGemsからインストールできるのでgemコマンドでインストールする。
bundleコマンドが使えるようになるので確認する。

$ gem install bundler
Fetching bundler-2.0.1.gem
Successfully installed bundler-2.0.1
Parsing documentation for bundler-2.0.1
Installing ri documentation for bundler-2.0.1
Done installing documentation for bundler after 2 seconds

$ bundle -v
Bundler version 2.0.1

Ruby on Railsのインストール

Ruby on Railsは、gemコマンドでインストールする。
最新ではないバージョンを指定したい場合は-vオプションをつけて指定。

インストールが終わったらrailsコマンドが使用できるので確認する。

$ gem install rails
Fetching i18n-1.6.0.gem
Fetching rack-2.0.7.gem

...(途中省略)...

Removing ruby (1:2.5.1) ...
Removing ruby2.5 (2.5.1-1ubuntu1.2) ...
Removing libruby2.5:amd64 (2.5.1-1ubuntu1.2) ...
Removing rake (12.3.1-1) ...
Removing ruby-test-unit (3.2.5-1) ...
Processing triggers for libc-bin (2.27-3ubuntu1) ...
Processing triggers for man-db (2.8.3-2ubuntu0.1) ...

$ rails -v
Rails 5.2.3

Railsアプリを作成

Homestead.yamlで共有ディレクトリの設定がすでにできているので、codeディレクトリ内にファイルを作る。

$ cd
$ cd code/

今回は例としてtest_appというプロジェクトファイルを作成します。

プロジェクトファイルはrails newというコマンドで作成でき、-dオプションで使用するデータベースを指定できます。

オプションを指定しない場合は「SQLite」というデータベースがデフォルトで使用されますが、今回は「Mysql」を使用するので以下のコマンドでファイルを作成します。

$ rails new test_app -d mysql
      create
      create  README.md
      create  Rakefile
      create  .ruby-version
      create  config.ru
      create  .gitignore
      create  Gemfile
         run  git init from "."
Initialized empty Git repository in /home/vagrant/code/test_app/.git/
      create  package.json
      create  app

...(途中省略)...

Using spring-watcher-listen 2.0.1
Using turbolinks-source 5.2.0
Using turbolinks 5.2.0
Using uglifier 4.1.20
Using web-console 3.7.0
Bundle complete! 18 Gemfile dependencies, 78 gems now installed.
Use `bundle info [gemname]` to see where a bundled gem is installed.
         run  bundle exec spring binstub --all
* bin/rake: spring inserted
* bin/rails: spring inserted

$ ls
test_app

確認するとtest_appというファイルが作成されています。

Railsサーバーの起動

Railsサーバーはプロジェクトフォルダに移動してrails sコマンドで起動できます。

しかしVagrant環境で仮想マシンを起動している場合は、rails s -b 0.0.0.0というコマンドでRailsサーバーを起動させます。

localホスト以外からはアクセスできないため、-b 0.0.0.0オプションをつけて全てのIPアドレスを許可します。

$ cd test_app/
$ rails s -b 0.0.0.0
=> Booting Puma
=> Rails 5.2.3 application starting in development
=> Run `rails server -h` for more startup options
Puma starting in single mode...
* Version 3.12.1 (ruby 2.6.3-p62), codename: Llamas in Pajamas
* Min threads: 5, max threads: 5
* Environment: development
* Listening on tcp://0.0.0.0:3000
Use Ctrl-C to stop

このように表示されれば無事にサーバーが起動したことになります。
サーバーを停止したいときはCtrl + cで停止することできます。

ブラウザでアクセス

ドメイン名の設定もデフォルトでしてあるので、ブラウザにはhomestead.test:3000でアクセスできます。

Mysqlのパスワードを設定

ブラウザにアクセスすると以下のようなエラーが出ました。
スクリーンショット 2019-05-24 22.06.15.png

これはRailsアプリがMysqlにhomesteadユーザーでログインしようとした結果、「パスワードがない」と言われていることが原因です。

  • データベース : homestead
  • ユーザー名 : homestead
  • パスワード : secret

Homesteadでは上記のようなデフォルトの設定があるので、データベースの設定ファイルにパスワードを記述します。

【注意】
サーバーを起動しているタブではコマンド操作ができないので、新たにタブを増やし再度sshで仮想マシンに接続します。

データベースの設定ファイルはconfigディレクトリの中にdatabase.ymlという名前で入っています。

$ ls config/
application.rb  credentials.yml.enc  environments  master.key  spring.rb
boot.rb     database.yml         initializers  puma.rb     storage.yml
cable.yml   environment.rb       locales       routes.rb

$ vim config/database.yml

vimで開きpasswordの所にsecretを追記して保存します。

database.yml
# MySQL. Versions 5.1.10 and up are supported.
#
# Install the MySQL driver
#   gem install mysql2
#
# Ensure the MySQL gem is defined in your Gemfile
#   gem 'mysql2'
#
# And be sure to use new-style password hashing:
#   https://dev.mysql.com/doc/refman/5.7/en/password-hashing.html
#
default: &default
  adapter: mysql2
  encoding: utf8
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: root
  password: secret
  socket: /var/run/mysqld/mysqld.sock

development:
  <<: *default
  database: test_app_development

# Warning: The database defined as "test" will be erased and
# re-generated from your development database when you run "rake".
# Do not set this db to the same as development or production.
test:
  <<: *default
  database: test_app_test

保存したらサーバーを一度停止し、再起動してからブラウザにアクセスしてみます。

データベース作成

再びアクセスしてみると先ほどのエラーはなくなりましたが、違うエラーが出てきました。
スクリーンショット 2019-05-24 22.22.00.png

これはUnknown database 'test_app_development'とでていて、test_app_developmentというデータベースが無いよと注意されています。

Railsにはrails db:createというコマンド存在していて、database.ymlに記述されている情報を元に、データベースを作成してくれます。

これらはデフォルトで

  • プロジェクトフォルダ名_development
  • プロジェクトフォルダ名_test

という2つのデータベース名が記述されているので特に変更はせずに、先ほどのrails db:createコマンドを実行して上記の2つのデータベースを作成します。

$ rails db:create
Created database 'test_app_development'
Created database 'test_app_test'

データベースが作成されたので再度ブラウザにアクセスしてみます。

スクリーンショット 2019-05-24 22.42.57.png

上記のように表示されれば成功です。これで問題なくアクセスができました。

あとはアプリケーション制作

これでHomesteadを使用したRuby on Railsの環境を構築できました。
あとは作成したフォルダでアプリケーションを作ってみてください。

おまけ(gitのブランチ名の表示)

デフォルトだとブランチ名は表示されていないが、設定すれば表示される

vagrant@homestead:~/code/test_app$
vagrant@homestead ~/code/test_app (master *)
$

gitのブランチ名の表示をしたい場合は以下の処理を.bash_profileもしくは.bashrcに追記する。

.bash_profileか.bashrcに追記
if [ -f /etc/bash_completion ]; then
    . /etc/bash_completion
fi
if [ -f /etc/bash_completion.d/git-prompt ]; then
    export PS1='\[\033[01;32m\]\u@\h\[\033[01;33m\] \w$(__git_ps1) \n\[\033[01;34m\]\$\[\033[00m\] '
else
    export PS1='\[\033[01;32m\]\u@\h\[\033[01;33m\] \w \n\[\033[01;34m\]\$\[\033[00m\] '
fi

追記したら変更を反映させる

vagrant@homestead:~/code/test_app$ source ~/.bashrc

vagrant@homestead ~/code/test_app (master *)
$

参考記事

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[雑メモ]Socialiteとabraham/twitteroauthで複数アカウントでツイート

ログインと登録がTwitterからのみのアプリを作成していて、
こちらを参考にabraham TwitterOAuthと連携してみたものの、アクセストークンの取得がややこしい
Socialiteで簡単にログインと登録しつつ、取れるのでそれを用いてつぶやいてみる
Socialiteで参考にしたのはこちら

Socialiteで登録・ログイン→トークン取得→TwitterOAuthでツイートの流れ

LoginController.php
class LoginController extends Controller
{
    use AuthenticatesUsers;

    public function __construct()
    {
        $this->middleware('guest')->except('logout');
    }

    /**
     * 認証ページヘユーザーをリダイレクト
     *
     * @return \Illuminate\Http\Response
     */
    public function redirectToProvider()
    {
        return Socialite::driver('twitter')->redirect();
    }

    /**
     * ユーザーのアクセストークンを取得する
     *
     * @return \Illuminate\Http\Response
     */
    public function handleProviderCallback()
    {

        try {
            $twitter_user = Socialite::driver('twitter')->user();
            //アクセストークン取得
            $token = $twitter_user->token;
            $token_secret = $twitter_user->tokenSecret;

            if ($twitter_user) {
                //ユーザーの取得または生成
                $user = User::firstOrCreate(['twitter_id' => $twitter_user->id]);
                //最新状態に更新
                $user->update(
                    [
                        'twitter_name' => $twitter_user->name,
                        'twitter_nickname' => $twitter_user->twitter_nickname,
                        'twitter_avatar_original' => $twitter_user->avatar_original,
                        'twitter_oauth_token' => $token,
                        'twitter_oauth_token_secret' => $token_secret
                    ]
                );
                Auth::login($user, true);
                return redirect()->route('activity.index')->with('success', 'ログインしました');
            }
        } catch (Exception $e) {
            return redirect()->route('top')->with('error', 'Twitterアカウント取得に失敗しました');
        }

        return redirect()->route('top')->with('erorr', 'エラーが発生しました。再度お試しください');
    }

    public function logout()
    {
        Auth::logout();
        return redirect()->route('top')->with('success', 'ログアウトしました');
    }
}

あとはログイン後のページでつぶやいてやる

Hoge.php
public function tweet()
{
        $user = Auth::user();

        $twitter_user = new TwitterOAuth(
            config('twitter.consumer_key'),
            config('twitter.consumer_secret'),
            $user->twitter_oauth_token,
            $user->twitter_oauth_token_secret
        );
        //ツイートする
        $res = $twitter_user->post("statuses/update", [
            "status" => 'ツイート内容'
        ]);
}

だいぶスッキリしました

アクセストークンはセッションに入れるのと、保存するのどっちが良いのか...
こちらはServiceProviderを作成して、Facadeで呼び出せるようにしているけど、アクセストークンが変わる場合のうまい書き方が思いつかない

なにかアドバイスあればください

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

51歳からのプログラミング 備忘 吹き出し的なもの

吹き出し的なもの(以下、吹き出しという)を作ってみた。

入力欄を空欄で入力した時に、
吹き出しで「未入力です」ってアナウンスが
フェードインして入る、って感じで。

・ 吹き出しを、cssで用意
・ 吹き出しのcssは、<input の後の <span に設定
・ 吹き出しのcssは、最初は非表示にしとく(display:none)
・ 吹き出したいときに、表示する(ここでは、submit時)

そんな感じで作れそうだったので作った。

表示位置の設定と、フェードインアウト,
入力時には非表示状態、をコードしてるので、
ちょっと長いのが残念。

完成コードはこれ
でも、吹き出しをフェードアウトさせるところが気に入らない。いつか直そう。

//------- jquery ----------
<script>
  $(function(){
    var position,width;
    var $form=$('form');
    var $inp =$('input[name="inp"]');
    var $sp  =$('span[name="sp"]');

    $form.submit(function(){
      if(!$inp.val()){
        position=$inp.offset();
        width   =$inp.width();
        $sp.text('未入力です');
        $sp.css('display','inline');
        $sp.offset({top :(position.top-1),
                    left:(position.left+width+10),
                  });
        $sp.hide().fadeIn(100);
        return false;
      }
    });

    $inp.on('keypress',function(){
      $sp.fadeOut(100);
    });
  });
</script>
//----------------------------


//---------- css -------------
<style>
  .tip    {display:none;
           color:white;
           background:blue;
           border-radius:5px;
           }
</style>
//----------------------------


//--------- html -------------
<form action="test" method="post">
  {{csrf_field()}} // これはlaravel仕様です
  <input name="inp">
 <span name="sp" class="tip"></span>
</form>

コードを打つだけで楽しい。
心が躍るような楽しさ。
こんな楽しいことがあったんだ。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

PHP(Laravel) でエンドポイントをつくって、 Nuxt.js に渡す

// この記事は、 note に投稿した記事の再掲です。

ディレクトリ構成

Nuxt.js, Laravel 別々にディレクトリを作成し、それぞれ個別のプロジェクトとして扱います

- nuxt-project  # Nuxt.js
  - Nuxt のファイルたち

- laravel-project  # Laravel
  - Laravel のファイルたち

Laravel をさわる

はじめに、 Laravel を使ってエンドポイントを作る

Laravel をインストール

下記のコマンドを実行してインストールができる

$ cd /your/project/directory
$ composer create-project laravel/laravel <project-name>

パーミッションを変更

インストールしたら、 Laravel の storage ディレクトリと bootstrap/cache ディレクトリのパーミッションを 777 に変更する

ディレクトリパーミッション
Laravelをインストールした後に、多少のパーミッションの設定が必要です。storage 下と bootstrap/cache ディレクトリをWebサーバから書き込み可能にしてください。設定しないとLaravelは正しく実行されません。Homestead仮想マシンを使用する場合は、あらかじめ設定されています。

https://readouble.com/laravel/5.7/ja/installation.html#configuration

routes/api.php にエンドポイントの記述を追加

http://localhost:8000/api でアクセスできるようになる

Route::get('/api', function(){
 $nokura = array(
   [
     'title' => '主役じゃない方の僕ら',
     'story' => 'モブキャラ4人のギャグコメディ'
   ],
   [
     'title' => 'イデアの眷属',
     'story' => 'スーツの人たちがたくさん出てくる'
   ],
 );
 $array = array();
 foreach($nokura as $item) {
     $title = $item['title'];
     $story = $item['story'];
     $arr = array(
       'title' => $title,
       'story' => $story
     );
     array_push($array, $arr);
 }
 return $array;
});

Laravel を起動する

http://localhost:8000/api にエンドポイントができているはず

$ php artisan serve

次に、Nuxt.js をさわる

さきほど作った Laravel のエンドポイントから、Nuxt.js を使って情報を取得する

Nuxt.js をインストール

色々聞かれるので、 axios をインストールすると良い

$ yarn create nuxt-app <my-project>

axios を追加

インストール時に追加済なら飛ばします

$ yarn add -D @nuxtjs/axios

proxy-module を追加

$ yarn add -D @nuxtjs/proxy

nuxt.config.js に設定を追加

/api でアクセスしたら
開発環境の場合は http://localhost:8000/api
本番環境の場合は https://production-url/api
を表示してね という設定です

module.exports = {
  dev: (process.env.NODE_ENV !== 'production'),
  modules: [
    '@nuxtjs/axios',
    '@nuxtjs/proxy',
  ],
  proxy: {
    '/api': (this.dev) ? 'http://localhost:8000' : 'https://production-url'
  },
  axios: {
  },
}

情報を取得する

Laravel で作成したエンドポイントを asyncData() で叩くと
routes/api.php に記述した内容が取得できる

index.vue
<template lang="pug">
div
  pre {{apiPost}}
</template>

<script>
export default {
  async asyncData({ app }) {
    let data = await app.$axios.$get('/api')
    return { apiPost: data }
  },
}
</script>

おわり

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

LaravelでMySQLへのデータ挿入時にエラーが出た場合の対処法

はじめに

LaravelのSeederでテストデータを入力しようとした際に、次のエラーが発生した。

SQLSTATE[HY000]: General error: 1364 Field 'カラム名' doesn't have a default value

NOT NULLであるフィールドにNULLをInsertした事によりエラーが出たようだ。
今回はこの警告を無効化することで対処する。

環境

  • Laravel 5.5.45
  • MySQL 5.7.26

対処法

config/database.phpstrictの値をfalseに設定する。

database.php
'mysql' => [
    // 略
    // 'strict' => true,
    'strict' => false,
    // 略
],

原因

stricttrueになっていると、次のようにsql_modeが設定される。

mysql> select @@GLOBAL.sql_mode;
 +---------------------------------------------------------------------------------------+
 | @@GLOBAL.sql_mode                                                                     |
 +---------------------------------------------------------------------------------------+
 | STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION |
 +---------------------------------------------------------------------------------------+
 1 row in set (0.00 sec)

sql_modeSTRICT_TRANS_TABLESが設定されていると、無効な値が挿入された場合にエラーを出すようになる。

参考

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Laravelで投稿アプリの機能を作成 ~ログインカスタマイズ編Ⅰ~

はじめに

【30分クッキング】Laravelで投稿アプリの機能を作成のCRUD編、リレーション編に引き続き、
今回はできる限り工程を取らずに、自分のページに遷移させていく方法を実装いたしましたので
紹介していきたいと思います

前提

・前回のデータを元に修正していくので、一緒にデータを作りたい方は
下記から見ることをお勧めします
https://qiita.com/ProgramingDai/items/cf6944f9cd0ac08f4e3e
https://qiita.com/ProgramingDai/items/249acc8894079ee58268

・今回はできる限り工数を割くため、既存のLoginCotrollerとlogin.blade.phpを利用します

実装イメージ

{root}/post
↓
未認証
↓
{root}/login
↓
認証後
↓
{root}/post
↓
ログアウト
↓
{root}/login

実装レシピ

1.ログイン後のリダイレクト先変更

/app/Http/Controllers/Auth/LoginController.php
// 中略
// protected $redirectTo = '/home'; // デフォルトリダイレクト先
protected $redirectTo = '/post'; // 変更後リダイレクト先
// 中略

2.ログアウト後のリダイレクト先変更
今回はUserController.phpを新たに作成して実装します

php artisan make:controller UserController

/app/Http/Controllers/UserController.php
namespace App\Http\Controllers;

use Illuminate\Http\Request;
// 追加
use Illuminate\Support\Facades\Auth;

class UserController extends Controller
{
    // ログアウト遷移先変更
    public function getLogout(Request $request){
        Auth::logout();
        return redirect()->route('login');
    }
}

3.ルーティング設定

/routes/web.php
// 中略
Route::get('/logout', 'UserController@getLogout')->name('user.logout');

4.ビューの修正
デフォルトでの「login.blade.php」の中身を全て変更していきます。

/resources/views/auth/login.blade.php
@extends('layouts.postapp')

@section('content')
@section('maincopy', 'ログインしてください')

<form method="POST" action="{{ route('login') }}">
    {{ csrf_field() }}
    @if ($errors->has('email'))
        {{ $errors->first('email') }}
    @endif
    <input type="text" class="form" name="email" placeholder="メールアドレス">

    @if ($errors->has('password'))
        {{ $errors->first('password') }}
    @endif
    <input type="password" class="form" name="password" placeholder="パスワード">
    <input type="submit" class="create" value="ログイン">
</form>
@endsection

5.新規登録とログアウトリンクの切り分け表示
ログインするためには新規登録画面とログアウトできるリンクが必要です
@if(Auth::check())で現在認証中か否かを判定することができます

このページのどこでもいいので下記コードを追加してください

/resources/views/layouts/postapp.blade.php
@if(Auth::check())
<!--認証中なら-->
<a href="{{ route('user.logout') }}"><img src="{{ asset('img/logout.svg') }}" class="add" alt="ログアウト"></a>
@else
<!--未認証なら-->
<a href="{{route('register')}}"><img src="{{ asset('img/user.svg') }}" class="add" alt="ユーザー登録"></a>
@endif

※imgの部分は通常のリンク文字にしてもOKです
※ボタンUIはこちらのサイトから無料でダウンロードしました
https://www.ikonate.com/

あとがき

こんな感じ自動生成されるをページを利用すれば、遷移を変更していくだけで
オリジナルログイン画面の実装ができます。ログイン周りはこの他にも、「login.blade.php」を使わず
ビュー自体もオリジナルで実装する方法もありますので、興味があれば調べてみてください。
次回はregister(新規登録)周りのカスタマイズを実装していく予定ですので、ぜひ。

Laravelで投稿アプリの機能を作成
~CRUD編~
https://qiita.com/ProgramingDai/items/cf6944f9cd0ac08f4e3e
~リレーション編~
https://qiita.com/ProgramingDai/items/249acc8894079ee58268
~ログインカスタマイズ編Ⅰ~
https://qiita.com/ProgramingDai/items/fee669e5a8cf67f0e38e
~ログインカスタマイズ編Ⅱ~
https://qiita.com/ProgramingDai/items/4fe2e3cc90987356c9c4

参考書籍: PHPフレームワーク Laravel入門
https://blog.hiroyuki90.com/articles/laravel-books/

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Laravelで投稿アプリの機能を作成 ~ログインカスタマイズ編~

はじめに

【30分クッキング】Laravelで投稿アプリの機能を作成のCRUD編、リレーション編に引き続き、
今回はできる限り工程を取らずに、自分のページに遷移させていく方法を実装いたしましたので
紹介していきたいと思います

前提

・前回のデータを元に修正していくので、一緒にデータを作りたい方は
下記から見ることをお勧めします
https://qiita.com/ProgramingDai/items/cf6944f9cd0ac08f4e3e
https://qiita.com/ProgramingDai/items/249acc8894079ee58268

・今回はできる限り工数を割くため、既存のLoginCotrollerとlogin.blade.phpを利用します

実装イメージ

{root}/post
↓
未認証
↓
{root}/login
↓
認証後
↓
{root}/post
↓
ログアウト
↓
{root}/login

実装レシピ

1.ログイン後のリダイレクト先変更

/app/Http/Controllers/Auth/LoginController.php
// 中略
// protected $redirectTo = '/home'; // デフォルトリダイレクト先
protected $redirectTo = '/post'; // 変更後リダイレクト先
// 中略

2.ログアウト後のリダイレクト先変更
今回はUserController.phpを新たに作成して実装します

php artisan make:controller UserController

/app/Http/Controllers/UserController.php
namespace App\Http\Controllers;

use Illuminate\Http\Request;
// 追加
use Illuminate\Support\Facades\Auth;

class UserController extends Controller
{
    // ログアウト遷移先変更
    public function getLogout(Request $request){
        Auth::logout();
        return redirect()->route('login');
    }
}

3.ルーティング設定

/routes/web.php
// 中略
Route::get('/logout', 'UserController@getLogout')->name('user.logout');

4.ビューの修正
デフォルトでの「login.blade.php」の中身を全て変更していきます。

/resources/views/auth/login.blade.php
@extends('layouts.postapp')

@section('content')
@section('maincopy', 'ログインしてください')

<form method="POST" action="{{ route('login') }}">
    {{ csrf_field() }}
    @if ($errors->has('email'))
        {{ $errors->first('email') }}
    @endif
    <input type="text" class="form" name="email" placeholder="メールアドレス">

    @if ($errors->has('password'))
        {{ $errors->first('password') }}
    @endif
    <input type="password" class="form" name="password" placeholder="パスワード">
    <input type="submit" class="create" value="ログイン">
</form>
@endsection

5.新規登録とログアウトリンクの切り分け表示
ログインするためには新規登録画面とログアウトできるリンクが必要です
@if(Auth::check())で現在認証中か否かを判定することができます

このページのどこでもいいので下記コードを追加してください

/resources/views/layouts/postapp.blade.php
@if(Auth::check())
<!--認証中なら-->
<a href="{{ route('user.logout') }}"><img src="{{ asset('img/logout.svg') }}" class="add" alt="ログアウト"></a>
@else
<!--未認証なら-->
<a href="{{route('register')}}"><img src="{{ asset('img/user.svg') }}" class="add" alt="ユーザー登録"></a>
@endif

※imgの部分は通常のリンク文字にしてもOKです
※ボタンUIはこちらのサイトから無料でダウンロードしました
https://www.ikonate.com/

あとがき

こんな感じ自動生成されるをページを利用すれば、遷移を変更していくだけで
オリジナルログイン画面の実装ができます。ログイン周りはこの他にも、「login.blade.php」を使わず
ビュー自体もオリジナルで実装する方法もありますので、興味があれば調べてみてください。
次回はregister(新規登録)周りのカスタマイズを実装していく予定ですので、ぜひ。

Laravelで投稿アプリの機能を作成
~CRUD編~
https://qiita.com/ProgramingDai/items/cf6944f9cd0ac08f4e3e
~リレーション編~
https://qiita.com/ProgramingDai/items/249acc8894079ee58268
~ログインカスタマイズ編~
https://qiita.com/ProgramingDai/items/fee669e5a8cf67f0e38e

参考書籍: PHPフレームワーク Laravel入門
https://blog.hiroyuki90.com/articles/laravel-books/

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

LaravelでbrongsToManyしてみた。3 <タグから関連記事を取得>

  1. 中間テーブルの構成を作成
  2. 関連したタグを取得
  3. コレ
  4. まだあるかも。。

※前回までの物がない人は一読を推奨します。

タグの選択(ボタン要素を追加)

index.blade.php

<a href="twiite?tag={{ $tag }}" style="color: inherit">
    <p style="display: inline-block; margin-left: 10px; border: 1px solid 
    #5fa; max-width: 100px">
        {{ $tag }}
    </p>
</a>

タグの項目をaタグで囲んでみました。
今回はルートを通してないので、クエリでタグを持たせたいと思います。
ここでのリンクは例えば「https: //localhost:8080/twiite?tag=令和」などです。

クエリーデータを取得する場合以下があります。

$_GET['tag'];//html上
や
__construct(Request $request){
    $request->tag;
}//php上
などです。

ModelにbelongsToManyを追加

記事からやったのとまったく逆をやればいいのです。そう単純な話なのです。
ただ、attacheに関しては中間テーブルに記録する作業をタグからする意味も必要もないので、
そこは違うところです。あくまで今回は記事取得になります。
Tag.php に追加

public function twiites()
{
    return $this->belongsToMany(Twiite::class);
}

前と逆ですね。。これで、中間テーブルを使うことができます。

TwiiteController.php

public function index(Request $request)
    {
//省略...
+        if(!empty($request->tag)){//タグ情報がクエリで来ている場合。(検索)
+          $oneTagRecorde = $this->tag->where('name', $request->tag)
+            ->first();//タグを押してここに入るので、一意で一つしかないと予想される。
+          $twiiteList = $oneTagRecorde->twiites()
+            ->orderby('twiite_id')
+            ->get();//リレーションからタグに対応するツイートを全取得。
+        }
+        else{
          $twiiteList = $this->twiite->where('user_id',$userId)
            ->orderby('created_at','desc')
            ->get();//ツイート全件取得
+        }
//省略...  
        return view('index', compact('twiiteList', 'userId'));//index view
    }

処理を通常時の全レコード取得から、特定タグ情報が入ったものだけに変更します。
ここで、送ったクエリデータを判定し、何か入っていれば、タグ検索を
入っていなければ、通常の全レコード取得をするという流れになります。
その後の処理は前と待ったく同じです。。

投稿一覧 選択タグ色付けなど

選択して、関連記事が表示されるときに、
そのアクションを検知して、選択されているタグが赤くなるようにしてみますか。。
そして、どんな順番だろうと、選択タグが先頭に来るようにしましょう。

TwiiteController.phpのindex()

public function index(Request $request)
    {

       foreach($twiiteList as $twiiteRecord){
           $tags = $twiiteRecord->tags()->orderby('tag_id')->get();//中間テーブル経由でタグのrecordを取得
           $tagName = [];
+          $exchangeArray = 0;//先頭になるタグ名の番号
           foreach($tags as $tagRecord){//タグも複数あるので、繰り返す。
              $tagName[] = $tagRecord->name;//取得してきたレコードのid

+             if($request->tag === $tagRecord->name)//タグ名が選択タグと一致
+                $exchangeArray = count($tagName) - 1;//現在保存されているタグの場所n番目
           }

+          if($exchangeArray != 0){//先頭入れ替え
+            $name = $tagName[0];
+            $tagName[0] = $tagName[$exchangeArray];
+            $tagName[$exchangeArray] = $name;
+          }

           $twiiteRecord['tags'] = $tagName;//送るデータに追加(同foreachで回すため)
         }
         return view('index', compact('twiiteList', 'userId'));//index view
    }

検索タグがあれば、その番号を保存しておいて、先頭と入れ替える
という処理を追加。
そのほかデータの取得などは前々回と同じことなので、コメントアウトと、前のを見てください。
index.blade.php

<?php $first = true; ?>
@foreach($twiite->tags as $tag)
<a href="twiite?tag={{ $tag }} " style="
      <?php echo !empty($_GET['tag']) & $first ?
       'color: red' : 'color: inherit'?>
">
   <?php $first = false; ?>
   <p style="display: inline-block; margin-left: 10px; border: 1px solid #5fa; max-width: 200px">
      {{ $tag }}
   </p>
</a>
@endforeach

先頭に検索タグを持ってきたので、foreachのループ一回目だけ行いたいので、
$first = true;とかしています。
方法は好きなやり方で、やってください。
今回は三項演算子を使って、ifをしています。
ここでの条件は、クエリにタグ情報があるか? かつ 一回目か(初期のtrueか)?
これで、なければそのまま黒字に、あれば、先頭だけ赤文字になります。

完成

一通りやりたい機能は達成できました。
- 記事にタグを追加して保存、そのリレーション。
- 中間テーブルから関連タグを取得してきて、表示。
- タグからの記事検索。
- 検索結果の表示結果整形。

基本はもう動きますね。ただ、コードが汚いのと、長いので、まだ改良はできますが、
まあ、良しとしましょう。。w
今回一連の記事の流れは以上、記事とタグの中間テーブルが使いてぇという内容です。完結!

こちらに動かした動画がありますので、どうぞ参考に。
※音無しです。
今回のコード
gitに挙げてますので、どんどん使ってください。issueしていただいても結構ですよー。
本場で働いているので、まあ、答えられる範囲で答えます。では。。

次回は

あるかも。。一通り削除とかも付けてみようか?なんて思ってます。
ちょっと動かしておくのも面白いかと。。。
やるかわからないですw

ーー追記ーー
本記事シリーズの完成版はこちら。gitの管理をしっかりしました。
https://github.com/175B005/vueLaravel

また違うのをやっていくので、ここのブランチはvue.jsで追加していく用です。
belongstomanyというブランチでここまでを残しておきますので、
どうぞよろしくお願いします。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

LaravelでbrongsToManyしてみた。2 <関連したタグを取得>

  1. 中間テーブルの構成を作成
  2. コレ
  3. タグから関連記事を取得

※基本的な内容は前回の記事にあるので、要参照です。

今回の追加 Controllerファイルindex内+index.blade.phpのみ

追加範囲全部↓

TwiiteController.php

public function index(Request $request)
    {
        $userId = Auth::id();//ログイン中のid

        $twiiteList = $this->twiite->where('user_id',$userId)
            ->orderby('created_at','desc')
            ->get();//ツイート全件取得

+        foreach($twiiteList as $twiiteRecord){
+
+          $tags = $twiiteRecord->tags()->orderby('tag_id')->get();//中間テーブル経由でタグのrecordを取得
+
+          $tagName = [];
+          foreach($tags as $tagRecord){//タグも複数あるので、繰り返す。
+            $tagName[] = $tagRecord->name;//取得してきたレコードのid
+          }
+          $twiiteRecord['tags'] = $tagName;//送るデータに追加(同foreachで回すため)
+        }

        return view('index', compact('twiiteList', 'userId'));//index view
    }

index.php

    <h1>ーーーあなたのツイート一覧ーーー</h1>

      @foreach ($twiiteList as $twiite)
      <div style="border: 1px solid #000; display: block; width: 400px; margin-top: 2px">
        <p style="display: inline-block">{{ $twiite->contents }}</p>
      </div>
+        @foreach($twiite->tags as $tag)
+          <p style="display: inline-block; margin-left: 10px; border: 1px solid #5fa; width: 100px">{{ $tag }}</p>
+        @endforeach

      @endforeach

追加分のgitlink

belongsToMany型のオブジェクト取得からのタグ取得。

$tags = $twiiteRecord->tags()->orderby('tag_id')->get();
//インスタンスオブジェクトからorderby()->get()をして、中間テーブルに対応する
//タグのデータをすべて取得してきました。

要するに、attacheでやっていた扱い方と全く一緒。
getすればrecordが取得できるぜ。というお話です。

全件のタグを取得

foreachで回しているので、記事全件から一件ずつタグを見に行く。
さらにタグは複数あると想定されるので、(そうじゃなきゃやらないw)
タグの取得後に、記事のデータに付随させて送りたかったので、
foreachで回して、対応した記事に配列として追加。
あとはコメントアウトで細かく見てください。

direction1.jpg

別で送れますが、別で送ると、整合性がなくなる可能性がありますし、
何より細かい作業するようになると、一度に扱えた方が便利です。

タグを表示

cssは面倒なので書いてません。インラインで申し訳ない。。
記事の中に入れて持ってきたので、foreach内でタグの数だけ表示をしています。

次回は

次回は逆の取得をします。タグをクリックすると、その関連記事が出てくるようにしたいと思います。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

LaravelでbrongsToManyしてみた。

環境

  • Laravel5.6
  • mysql5.7
  • nginx
  • composer
  • php

今回やること

  1. 多対多の中間テーブルを作り、attachをすること。
  2. 記事に紐づくタグを作る。
  3. 大したことはやってないです。確認程度に眺めてください。

使用メソッド

  • belongsToMany
  • attach
  • firstOrCreate

作るDB構成

記事 --- 中間テーブル --- タグ
--- id ---
id ---> twiite_id ---
user_id tag_id <--- id
contents --- ---
--- --- name
time time time

端的に言うと---

--twiite table--

id user_id contents tag1 tag2 tag3 tag4 tag5
1 1 1コメやったぜ first --- --- --- ---
2 1 laravelの記事を書いています。 laravel mysql php composer framework
3 2 ホンダ シビッグ(車) ほんだし ビッグ(だし) ほんだし ホンダ 本田 --- ---

と管理すると、無駄な枠がいくつもできてしまいますよね。。
そして、5コと設定したら、DBを変えるまで、5コです。
これでは、変更があってもすぐに対応できませんので分けて管理します。

やっていく。。

※プロジェクトがある前提で進めます。

今回作るプロジェクトはこれ
(vendorファイルと.envがそのままなので、消してからcomposer install してください。)

必要なファイルを作成

php artisan make:model -mrc <記事名>
php artisan make:model -mrc <タグ名>
php artisan make:migrate <中間テーブル名>

複数記事と複数タグのリレーションをします。
必要そうなマイグレーションファイルやコントローラなども面倒なので、オプション付けて、一緒に作ってしまいましょう。
中間テーブルはテーブルを作成できれば、あとはいらないので、付属ファイルは作らないでOK。

まずはDBを整える

<日付>_<記事名>table.php

//<記事名> = twiite
class CreateTwiitesTable extends Migration
{

    public function up()
    {
        Schema::create('twiites', function (Blueprint $table) {
            $table->increments('id');
            $table->Integer('user_id')->unsigned();
            $table->string('contents');
            $table->timestamps();
        });
    }

    public function down()
    {
        Schema::dropIfExists('twiites');
    }
}

<日付>_<タグ名>table.php

//<タグ名> = tag
class CreateTagsTable extends Migration
{

    public function up()
    {
        Schema::create('tags', function (Blueprint $table) {
            $table->increments('id');
            $table->string('name', 20);
            $table->timestamps();
        });
    }

    public function down()
    {
        Schema::dropIfExists('tags');
    }
}

<日付>_<中間テーブル名>table.php

<中間テーブル名> = twiitetag
class CreateTwiiteTagTable extends Migration
{

    public function up()
    {
        Schema::create('tag_twiite', function (Blueprint $table) {
            $table->increments('id');
            $table->integer('twiite_id');
            $table->integer('tag_id');
        });
    }

    public function down()
    {
        Schema::dropIfExists('tag_twiite');
    }
}

マイグレーションファイルはこれで完成です。では、

php artisan migrate 

エラーが起きていなければ成功です。DBでも確認しましょう。

mysql -u ユーザ名 -p
Password:*******

mysql>use DB名
mysql>show tables;

table に先ほどのテーブルが作られていれば、成功。

desc table <テーブル名>;

これで、テーブルの制約が確認できますよ。

ルートを通します。

routes\web.php に追加

Route::resource('/twiite', TwiiteController::class,['except' => ['show', 'create']]);

詳細の場所は好きにしてください。exceptで今回使わないので、除去しています。

表示を整えます。

超適当に機能だけを付けています。

<html>
<head>
    <meta charset="utf-8">
    <title>多:多</title>
</head>
<body>
    <form method="post">
        {{ csrf_field() }}
        <input style="width:400px; height:100px" name="contents"><!--本文-->
    <input style="width:300px; height:30px" name="writelineTags"
        placeholder="「,」で区切って、タグ付けする(上限5コ)"><!--タグ文字列-->
    <input type="hidden" value=<?= $userId; ?> name="user_id"><!--ログイン中のid-->
        <button>投稿</button>
    </form>
    <h1>ーーーあなたのツイート一覧ーーー</h1>
    <div style="border: 1px solid #000; display: box; width: 400px">
      @foreach ($twiiteList as $twiite)
      <p>{{ $twiite->contents }}</p><!--渡されたツイートデータ(なければ実行なし)-->
      @endforeach
    </div>
</body>
</html>

Modelを作る

リレーションの設定は、DB個別でもできます。
直接sql文をたたくか、マイグレーションフィルに外部キーを設定でもできます。
が、しかし、せっかくフレームワークを使っているので、
生かさなければ!!
modelにて、その流れを肩代わりしてくれます。
外部キーなどをつくるわけではないので、そこは間違えないように!!

<記事名>.php

class Twiite extends Model
{
    protected $fillable = [
        'user_id',
        'contents'
    ];

    protected $dates = [
        'created_at',
        'updated_at'
    ];

   public function tags()
    {
        return $this->belongsToMany(Tag::class);
    }
}

外部キーがあれば、第二引数に設定したものが外部キーとして扱える。
今回はないが、リレーション相手のtagテーブルのidを保存しておきたいため、
idは外部キーではなく、indexの主キーでのアクセスとなる。

今回のこのページで作っているのは、一方的なリレーションになるので、
tagからのhasmanyは無い。後で続編予定。。そこで、作る。。

現状できないこと
  • タグ情報から関連する記事を取得できない。
  • タグを独自で作ったり、削除ができない。というか全く扱えないw

Controller を作る

最後に作るのはコントローラ!

最後でなくてもいいんだけど、DBの入出力と、フロントの表示が整ってから、必要なデータの処理を
する方が、わかりやすいと思うんだ。。。

<記事>Controller.php

use App\Twiite;
use App\Tag;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;

class TwiiteController extends Controller
{
    protected $twiite;

    public function __construct(Twiite $twiite){
        $this->middleware('auth');//ユーザ認証
        $this->twiite = $twiite;//twiiteクラスのインスタンス化
    }

    public function index(Request $request)
    {
        $userId = Auth::id();//ログイン中のid

        $twiiteList = $this->twiite->where('user_id',$userId)
            ->orderby('created_at','desc')
            ->get();//ユーザのtwiite全取得

        return view('index', compact('twiiteList', 'userId'));//index view
    }

    public function store(Request $request)
    {
      $userId = Auth::id();//ログイン中のid
      $inputs = $request->all();//リクエスト全て

      if(!empty($inputs['writelineTags'])){
        $tags = $this->setTagDivide($inputs['writelineTags']);//文字列を配列に分割「,」
        $tag_ids = $this->getIds($tags);//分割したタグを作り(またはカウントを追加し、)、そのidを取得
      }

      $this->twiite->contents = $inputs['contents'];//contentsデータを追加
      $twiite = $this->twiite->create($inputs);//twiiteデータ一件を作成&一件のデータを持つmodelのオブジェ 
 クト取得
      $twiite->tags()->attach($tag_ids);//中間テーブルに格納

      return redirect()->to('twiite');//indexへリダイレクト
    }

    public function setTagDivide($tagstring){
      $tags = explode(',',$tagstring);//文字列から特定の文字に応じて区切り、配列として格納。
      return $tags;//Is Array.
    }

    public function getIds($tags){
      $tagClass = new Tag();//tagを扱うクラスをインスタンス化
      $recodes = [];//帰り値の初期化
      $count = 5;
      foreach($tags as $tag){
        $count--;//カウント
        if($count <= 0) exit;//上限を超える場合は強制退場

        $aleadyTag = $tagClass->firstOrCreate(['name' => $tag]);//あれば取得、なければ作成。
        $aleadyTag->increment('counts');
        $recodes[] = $aleadyTag->id;
      }
         // dd($recodes);//tag_id,tag_id,tag_id..
        return $recodes;
    }
}

※Authはユーザ認証のメソッドです。
ユーザーは一人ではないので、そのidなどを判定するために使っています。
処理にはAuthやmidlewereなどは直接関係ないです。

見る人が見ると、「はあ?」と怒られてしまいそうな記述ですが、
急ぎ説明用に作ったものなので、ご容赦を。。

とりあえず、それぞれ横に書いてあるdirectionの通りの意味です。
詳細は自分で調べてください。

今回重要なのは、ここ。

      $twiite = $this->twiite->create($inputs);
      $twiite->tags()->attach($tag_ids);

$this->twiiteは、いわばnew Twiite() やTwiite::Classで作れるもののことで、モデルクラスをインスタンス化したものです。
createメソッドは返り値が追加したデータを持つ、モデルクラスのオブジェクトなので、
今回は1件のデータをattributeに持つ、オブジェクトになります。

当然モデルクラスにデータが入っているだけなので、インスタンスとは何ら機能に変化はありません。
そこから、先ほど<記事名>.phpで行った、tags()というメソッドを使い、
アタッチをしています。。
attacheを扱っているのは<記事名>クラスなので、その(指定がなければidになる)id、
attacheで送るデータは()内に入った、タグのid。

attacheメソッドは引数が配列データで送れるので、その場合は、複数個中間テーブルに保存されることになります。
ex)記事1個目にタグが複数ある場合。

twiite_id tag_id
1 1
1 2
1 3
1 4
2 4

こんな感じで、中間テーブルが同一の記事idに複数一気に作成されます。

中間テーブルの利用。

登録をしただけじゃ、何の意味もないので、これを呼び出す必要もあります。
が、今回はこのへんで! 次回の記事に続きを書いていきますので、そちらも見てください。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

LaravelでbrongsToManyしてみた。1 <中間テーブルの構成を作成・一方向からのリレーション>

  1. コレ
  2. 関連したタグを取得
  3. タグから関連記事を取得

環境

  • Laravel5.6
  • mysql5.7
  • nginx
  • composer
  • php

今回やること

  1. 多対多の中間テーブルを作り、attachをすること。
  2. 記事に紐づくタグを作る。
  3. 大したことはやってないです。確認程度に眺めてください。

使用メソッド

  • belongsToMany
  • attach
  • firstOrCreate

作るDB構成

記事 --- 中間テーブル --- タグ
--- id ---
id ---> twiite_id ---
user_id tag_id <--- id
contents --- ---
--- --- name
time time time

端的に言うと---

--twiite table--

id user_id contents tag1 tag2 tag3 tag4 tag5
1 1 1コメやったぜ first --- --- --- ---
2 1 laravelの記事を書いています。 laravel mysql php composer framework
3 2 ホンダ シビッグ(車) ほんだし ビッグ(だし) ほんだし ホンダ 本田 --- ---

と管理すると、無駄な枠がいくつもできてしまいますよね。。
そして、5コと設定したら、DBを変えるまで、5コです。
これでは、変更があってもすぐに対応できませんので分けて管理します。

やっていく。。

※プロジェクトがある前提で進めます。

今回作るプロジェクトはこれ
(vendorファイルと.envがそのままなので、消してからcomposer install してください。)

必要なファイルを作成

php artisan make:model -mrc <記事名>
php artisan make:model -mrc <タグ名>
php artisan make:migrate <中間テーブル名>

複数記事と複数タグのリレーションをします。
必要そうなマイグレーションファイルやコントローラなども面倒なので、オプション付けて、一緒に作ってしまいましょう。
中間テーブルはテーブルを作成できれば、あとはいらないので、付属ファイルは作らないでOK。

まずはDBを整える

<日付>_<記事名>table.php

//<記事名> = twiite
class CreateTwiitesTable extends Migration
{

    public function up()
    {
        Schema::create('twiites', function (Blueprint $table) {
            $table->increments('id');
            $table->Integer('user_id')->unsigned();
            $table->string('contents');
            $table->timestamps();
        });
    }

    public function down()
    {
        Schema::dropIfExists('twiites');
    }
}

<日付>_<タグ名>table.php

//<タグ名> = tag
class CreateTagsTable extends Migration
{

    public function up()
    {
        Schema::create('tags', function (Blueprint $table) {
            $table->increments('id');
            $table->string('name', 20);
            $table->timestamps();
        });
    }

    public function down()
    {
        Schema::dropIfExists('tags');
    }
}

<日付>_<中間テーブル名>table.php

<中間テーブル名> = twiitetag
class CreateTwiiteTagTable extends Migration
{

    public function up()
    {
        Schema::create('tag_twiite', function (Blueprint $table) {
            $table->increments('id');
            $table->integer('twiite_id');
            $table->integer('tag_id');
        });
    }

    public function down()
    {
        Schema::dropIfExists('tag_twiite');
    }
}

マイグレーションファイルはこれで完成です。では、

php artisan migrate 

エラーが起きていなければ成功です。DBでも確認しましょう。

mysql -u ユーザ名 -p
Password:*******

mysql>use DB名
mysql>show tables;

table に先ほどのテーブルが作られていれば、成功。

desc table <テーブル名>;

これで、テーブルの制約が確認できますよ。

ルートを通します。

routes\web.php に追加

Route::resource('/twiite', TwiiteController::class,['except' => ['show', 'create']]);

詳細の場所は好きにしてください。exceptで今回使わないので、除去しています。

表示を整えます。

超適当に機能だけを付けています。

<html>
<head>
    <meta charset="utf-8">
    <title>多:多</title>
</head>
<body>
    <form method="post">
        {{ csrf_field() }}
        <input style="width:400px; height:100px" name="contents"><!--本文-->
    <input style="width:300px; height:30px" name="writelineTags"
        placeholder="「,」で区切って、タグ付けする(上限5コ)"><!--タグ文字列-->
    <input type="hidden" value=<?= $userId; ?> name="user_id"><!--ログイン中のid-->
        <button>投稿</button>
    </form>
    <h1>ーーーあなたのツイート一覧ーーー</h1>
    <div style="border: 1px solid #000; display: box; width: 400px">
      @foreach ($twiiteList as $twiite)
      <p>{{ $twiite->contents }}</p><!--渡されたツイートデータ(なければ実行なし)-->
      @endforeach
    </div>
</body>
</html>

Modelを作る

リレーションの設定は、DB個別でもできます。
直接sql文をたたくか、マイグレーションフィルに外部キーを設定でもできます。
が、しかし、せっかくフレームワークを使っているので、
生かさなければ!!
modelにて、その流れを肩代わりしてくれます。
外部キーなどをつくるわけではないので、そこは間違えないように!!

<記事名>.php

class Twiite extends Model
{
    protected $fillable = [
        'user_id',
        'contents'
    ];

    protected $dates = [
        'created_at',
        'updated_at'
    ];

   public function tags()
    {
        return $this->belongsToMany(Tag::class);
    }
}

外部キーがあれば、第二引数に設定したものが外部キーとして扱える。
今回はないが、リレーション相手のtagテーブルのidを保存しておきたいため、
idは外部キーではなく、indexの主キーでのアクセスとなる。

今回のこのページで作っているのは、一方的なリレーションになるので、
tagからのhasmanyは無い。後で続編予定。。そこで、作る。。

現状できないこと
  • タグ情報から関連する記事を取得できない。
  • タグを独自で作ったり、削除ができない。というか全く扱えないw
  • 空文字の入力への対応ができない。
  • ほぼヴァリデーションしてないので、ガタガタ。。
  • 複数同じタグを入力できてしまう。カウントも増えるので、不正が可能。

Controller を作る

最後に作るのはコントローラ!

最後でなくてもいいんだけど、DBの入出力と、フロントの表示が整ってから、必要なデータの処理を
する方が、わかりやすいと思うんだ。。。

<記事>Controller.php

use App\Twiite;
use App\Tag;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;

class TwiiteController extends Controller
{
    protected $twiite;

    public function __construct(Twiite $twiite){
        $this->middleware('auth');//ユーザ認証
        $this->twiite = $twiite;//twiiteクラスのインスタンス化
    }

    public function index(Request $request)
    {
        $userId = Auth::id();//ログイン中のid

        $twiiteList = $this->twiite->where('user_id',$userId)
            ->orderby('created_at','desc')
            ->get();//ユーザのtwiite全取得

        return view('index', compact('twiiteList', 'userId'));//index view
    }

    public function store(Request $request)
    {
      $userId = Auth::id();//ログイン中のid
      $inputs = $request->all();//リクエスト全て

      if(!empty($inputs['writelineTags'])){
        $tags = $this->setTagDivide($inputs['writelineTags']);//文字列を配列に分割「,」
        $tag_ids = $this->getIds($tags);//分割したタグを作り(またはカウントを追加し、)、そのidを取得
      }

      $this->twiite->contents = $inputs['contents'];//contentsデータを追加
      $twiite = $this->twiite->create($inputs);//twiiteデータ一件を作成&一件のデータを持つmodelのオブジェ 
 クト取得
      $twiite->tags()->attach($tag_ids);//中間テーブルに格納

      return redirect()->to('twiite');//indexへリダイレクト
    }

    public function setTagDivide($tagstring){
      $tags = explode(',',$tagstring);//文字列から特定の文字に応じて区切り、配列として格納。
      return $tags;//Is Array.
    }

    public function getIds($tags){
      $tagClass = new Tag();//tagを扱うクラスをインスタンス化
      $recodes = [];//帰り値の初期化
      $count = 5;
      foreach($tags as $tag){
        $count--;//カウント
        if($count <= 0) exit;//上限を超える場合は強制退場

        $aleadyTag = $tagClass->firstOrCreate(['name' => $tag]);//あれば取得、なければ作成。
        $aleadyTag->increment('counts');
        $recodes[] = $aleadyTag->id;
      }
         // dd($recodes);//tag_id,tag_id,tag_id..
        return $recodes;
    }
}

※Authはユーザ認証のメソッドです。
ユーザーは一人ではないので、そのidなどを判定するために使っています。
処理にはAuthやmidlewereなどは直接関係ないです。

見る人が見ると、「はあ?」と怒られてしまいそうな記述ですが、
急ぎ説明用に作ったものなので、ご容赦を。。

とりあえず、それぞれ横に書いてあるdirectionの通りの意味です。
詳細は自分で調べてください。

今回重要なのは、ここ。

      $twiite = $this->twiite->create($inputs);
      $twiite->tags()->attach($tag_ids);

$this->twiiteは、いわばnew Twiite() やTwiite::Classで作れるもののことで、モデルクラスをインスタンス化したものです。
createメソッドは返り値が追加したデータを持つ、モデルクラスのオブジェクトなので、
今回は1件のデータをattributeに持つ、オブジェクトになります。

当然モデルクラスにデータが入っているだけなので、インスタンスとは何ら機能に変化はありません。
そこから、先ほど<記事名>.phpで行った、tags()というメソッドを使い、
アタッチをしています。。
attacheを扱っているのは<記事名>クラスなので、その(指定がなければidになる)id、
attacheで送るデータは()内に入った、タグのid。

attacheメソッドは引数が配列データで送れるので、その場合は、複数個中間テーブルに保存されることになります。
ex)記事1個目にタグが複数ある場合。

twiite_id tag_id
1 1
1 2
1 3
1 4
2 4

こんな感じで、中間テーブルが同一の記事idに複数一気に作成されます。

中間テーブルの利用。

登録をしただけじゃ、何の意味もないので、これを呼び出す必要もあります。
が、今回はこのへんで! 次回の記事に続きを書いていきますので、こちら(次)も見てください。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

laravelのインストール

laravelのインストール
composer が入った後Laravelを作成する際
通常の解説では

laravel new hogehoge

としてたが、うまくいかないことがある事とダウングレードすることから

composer create-project laravel/laravel:5.5 hogehoge

にしたほうがいい。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む