Laravel + vue-router vue SPAページのRouting @vueJS inside Laravel

基本

app.jsで記述したpathをlaravel側のweb.phpにも記述。その際、returnするviewはvueの起点ページにする。

Route::get('/profile', function() {
  return view('home');
});

→ home.blade.phpにvue componentのprofileがある場合、profileがレンダリングされた状態で開ける。

ただしcomponentがnestされている場合...

@app.js

const routes = [
  { path: '/profile', component: Profile,
    children: [
      {
        path: '/follow', component: Follows,   ・・・
      },
      {
        path: 'activity', component: Activity  ・・・
      }
    ]
  },

 

@web.php

Route::get('/follow', function() {   ・・・
  return view('home');
});

Route::get('/profile/activity', function() {  ・・・
  return view('home');
});

 

@親component

<router-link to="/follow">Following</router-link>   ・・・

<router-link to="/profile/activity">Activity</router-link>  ・・・

 

activityはprofileページからrouter-linkを通した場合開けるが、ページリロードの場合、component profile, activityともにレンダリングされない。

/profile/activityがrouter-viewに反映されない。

一方、child componentのfollowはpathを/followとし、root path化するとリロード経由でもレンダリングされる。

 

child componentをリロード経由で表示させたいならpathをrootにする(pathをnestできない???純粋なVue SPAならこの制約外。)

 

nestされたpathのrest化に成功

  • 問題点だったもの

vue関連を含むapp.jsの読み込み方法に問題があった

app.blade.php内にて下記のように記述

<script src='js/app.js'></script>…×

相対path表記だったため、例えば/profile/activityをロードするとapp.jsがprofile/js/app.jsになりnot foundになる。

こちらに訂正⇒ <script src="{{ asset('js/app.js') }}"></script>…〇

絶対path表記に変更

 

 new issue:

laravel側のparameter付きroute と vue側のrouteがぶつかる

VM314:65702 Uncaught TypeError: Cannot redefine property: $router 

 

layoutを設定したapp.blade.php内で読み込んだjavascriptファイル内にajaxリクエストをするscriptがあり、この影響でparameter付きroute時にエラーが発生していた。

error: [Deprecation] Synchronous

XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/. 

error: Uncaught TypeError: Cannot redefine property: $router

具体的には以下をコメントアウトしてエラーが除けた

app.blade.php内(layoutを設定していたファイル)

$.get("skin-config.html", function (data) {
  if (!$('body').hasClass('no-skin-config'))
  $('body').append(data);
});

参考:

laracasts.com

SPA with Vue.js and Laravel: Routing Basics

mattstauffer.co

SPA with Vue.js and Laravel: Routing Basics

 

  • router-linkにparameterとさらにもう一層nestされたroute

<router-link :to="{ path: '/user/' + user.name + '/follow' }" >

<router-link :to="{ path: '/user/' + user.name + '/activity' }" >

computed: {
  user() {
    return this.$store.state.user.user;  /* define param */
  }
},

@app.js

const routes = [

  {   path: '/user/:userName', name: 'user', component: Profile,
    children: [
      {
        path: '', component: Activity  /* /user/param */
      },
      {
        path: 'follow', component: Follows    /* /user/param/follow */
      },
      {
        path: 'activity', component: Activity    /* /user/param/activity */
      }
  ]
},

Vue chips いろいろ

  • htmlタグ内では{{ }}は使わないで v-bindまたはコロンで下記のように記述

data() {

    return {

        img: "http://~~~~"

    }

}

<img :src='img'>

 

  • セミコロンの取り扱い

セミコロンなし → static 

<router-link to="hoge">

セミコロンあり → dynamic

<router-link :to="foo">

computed: {
  foo() {
    regrgergs

  }

 

 

  • vuexでstateを設定した後、各componentでstateを呼び出したいとき

ページがレンダリングした時に同時に取得したいならcomputed

created()でstateの値を入れた場合、

data() {
    hoge : this.$store.state.~~~~

}

では値が取得できない。タイミングの問題???

computed: {

    hoge() {

        this.$store.state.~~~~

    }

}

* ここで 無駄にdataにhogeを作っておくとcomputedが反映されないので注意

イベント発動時にstateを取得したい場合、

sendMessage() {
  const message = {
    messageText: this.messageText,
    user: this.$store.state.user.user.name
  };

}

直接値をthis.$store.state.user.user.nameから参照できる

Laravel Database Seed

  • create a Seed file  

php artisan make:seeder UsersSeeder

  • register Seed file

@DatabaseSeeder.php

use Illuminate\Database\Seeder;

class DatabaseSeeder extends Seeder
{
public function run()
{
$this->call(UsersSeeder::class);
}
}

  • define UsersSeeder.php

use Illuminate\Database\Seeder;
use App\User;

class UsersSeeder extends Seeder
{

public function run()
{
$user = new User();
$user->name = "test";
$user->email = "test@test.com";
$user->password = bcrypt("testtest");
$user->save();
}
}

  • execute

php artisan db:seed

Laravel Migration file 操作

php artisan make:migration create_messages_table --create="messages"

 

Schema::create付きのmigration fileが生成される。

 

function up

php artisan migrate した時の動作

funciton down 

php artisan migrate:rollback した時の動作

 

migrateをやり直したい

php artisan migrate:rollback (データベースごと消える)

一旦migrateしたmigration file は直接編集できない。rollback後なら編集可。

データベースのデータを残したままmigrationを編集したい

→ 上書き編集用のmigration file を作成する ファイル名はやりたい編集の内容が分かりやすいようにする。

php artisan make:migration create_add_subject_column_to_messages_table --table="messages"

→ function up に

Schema::table('messages', function (Blueprint $table) {
    $table->string('subject');
});

php artisan migrate

→ messages tableにsubject columnが付与される。

 

php artisan migrate 

Base table or views already exists: 1050 .....(error)

phpmyadminから対象tableを削除して再度migrate

 

* php artisan migrate で error が発生したら composer dump-autoload 

Laravel 5.4 Database Structure

Relationships

 

f:id:monteecristoo:20170513231001p:plain

model A: User

protected $fillable = [ DBのカラム]

 public function messages) {

    return $this->hasMany(Message::class);

model B: Message

protected $fillable = [ DBのカラム] foreign_key は登録しなくてOK

public function users() {
   return $this->belongsTo(User::class);

}

DB_B 側に foreign_keyを設定(この場合user_id)

 

tinkerの操作

userを作成した状態で...

$user=App\User::find(1)->messages()->create(['message'=>'test from tinker'])

=> App\Message {#703
message: "test from tinker",
user_id: 1,
updated_at: "2017-05-13 13:35:31",
created_at: "2017-05-13 13:35:31",
id: 1,
}

 

*messagesのカラムにid, timestamps, foreign_key以外設定しなかった場合

= protected $fillable を設定していない場合

$user=App\User::find(1)->messages()->create()

ERROR

$user=App\User::find(1)->messages()->create([])

=> App\Message {#678
user_id: 1,
updated_at: "2017-05-13 20:22:52",
created_at: "2017-05-13 20:22:52",
id: 1,
}

f:id:monteecristoo:20170513224408p:plain

Max section4 lecture21

model A: Post

public function categories() {
    return $this->belongsToMany(Category::class)

}

model B: Category

public function posts() {
    return $this->belongsToMany(Post::class)

}

table: A table: B ともにforeign_keyなし

  • create intermediate table

php artisan make:migration create_category_post_table --create="category_post"

intermediate table 内に foreign_keyを作る

$table=>integer('category_id');

$table=>integer('post_id');

category, post tableの各々にデータを作成

  • category, post の各関係をcategory_postにデータ作成

それぞれのORMインスタンスを生成後attach()

$post = App\Post::find(5)

$category = App\Category::find(8)

$post->categories()->attach($category)

特定の$postを特定の$categoryにattach

tinker上で

$post=App\Post::find(1)->categories()

=> Illuminate\Database\Eloquent\Collection {#710
all: [
App\Category {#708
id: 1,
created_at: null,
updated_at: null,
pivot: Illuminate\Database\Eloquent\Relations\Pivot {#693
post_id: 1,
category_id: 1,
},
},
],
}
>>> $user=App\User::find(2)->categories
=> Illuminate\Database\Eloquent\Collection {#715
all: [
App\Category {#719
id: 3,
created_at: null,
updated_at: null,
pivot: Illuminate\Database\Eloquent\Relations\Pivot {#707
post_id: 2,
category_id: 3,
},
},
App\Category {#716
id: 2,
created_at: null,
updated_at: null,
pivot: Illuminate\Database\Eloquent\Relations\Pivot {#678
post_id: 2,
category_id: 2,
},
},
],
}

$post=App\Post::find(2)->caetegories()->orderBy('id')->get()

 

f:id:monteecristoo:20170513225021p:plain

 

f:id:monteecristoo:20170513225421p:plain

 

 

f:id:monteecristoo:20170513225615p:plain

Vue 2 debugger

f:id:monteecristoo:20170511205150j:plain

stateのツリーのトップフォルダが各stateが所属するjsファイルになる。

例えば...

▼ user: Object

 ▶ user: Object

▼ stream: Object

 ▶ messages: Array

 ▶ streamGroup: Array

の場合、userはuser.js、messages, streamGroupはstream.jsに記述してある。

cloud9上のLaravelアプリケーション内のnode server(今回はredis)とsocket.ioでLaravelアプリケーション内のVueJSからwebsocket通信をするとき

updated: 2018/7/9

 

node_server側

プロジェクト直下にmkdir node_server

npm init → entry point は server.js

npm install redis express socket.io

@/node_server/server.js

var app = require('express')();
var server = require('http').Server(app);
var io = require('socket.io')(server);
var redis = require('redis');

server.listen(8081);
io.on('connection', function(socket) {
console.log('New client connected');
});

 

node_serverの動作確認は...

@node_server terminalから

>>> node server.js

errorが来なければOK.

 

Vuejs側

npm install vue-socket.io --save

@app.js

import VueSocketio from 'vue-socket.io';

Vue.use(VueSocketio, 'cloud9のaddress:8081'));

@hoge.vue

<template>
<div>
<h1>SOckeIo</h1>
</div>
</template>

<script>
export default {
sockets: {

}
}
</script>

 

ここでmake:authをしているとsocket通信がmiddleware->'auth'ではじかれるのでその場合は、middleware->'auth'がかからないルーティングをweb.phpに作って...

Vue.use(VueSocketio, 'cloud9のaddress/test:8081')); とする。

ここで Corsエラー

XMLHttpRequest cannot load /socket.io/?EIO=3&transport=polling&t=LliUlhx. Redirect from 'socket.io/?EIO=3&transport=polling&t=LliUlhx' to '/socket.io?EIO=3&transport=polling&t=LliUlhx' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin '' is therefore not allowed access.

ドメインのトップはauthから外さなきゃダメ???

Corsエラーと同時にnode_server側でも以下のエラーメッセージ

events.js:137
throw er; // Unhandled 'error' event
^

Error: Redis connection to localhost:6379 failed - connect ECONNREFUSED 127.0.0.1:6379

コネクト拒否エラーが出た場合、redisサーバーが動いていない、もしくは正しくインストールできていないので

ターミナルでredis-serverを起動するか確認

 

コースエラー →→ redisサーバーが動いていない

ソケット通信が発信されているがエラー →→ ポートやアドレスの設定が間違っている

---------------------------------------------------------------------------------------------------------

親ページがhttpsだとsocketはMixed ContentでVueで実装したcomponentが全てブロックされる。SSL/TLS通信に対応さえる必要がある。

→ トップページにmiddleware->('auth')をかませるとVueのコンテンツがhttpsで読み込まれる。

locslhost上のlaravelならそのままwebsocket通信でMix Contentsに引っかからない???

bladeTemplate内でのscriptの読み込みは...

{{ secure_asset('path') }} ですること。{{ asset('path') }} だとhttpになりはじかれる。

-----------------------------------------------------------------------------------------------------

CORS対策

middlewareを作る

php artisan make:middleware Cors

 edit Cors middleware

@\app\Http\Middleware\Cors.php

public function handle($request, Closure $next)

{

return $next($request)

->header('Access-Control-Allow-Origin', '*')  // set allowed domein

->header('Access-Control-Allow-Methods', 'GET, POST, PUT, PATCH, DELETE, OPTIONS')

->header('Access-Control-Allow-Headers', 'Content-Type, Authorization');

}

register Cors middleware

@\App\Http\Kernel

protected $middleware = [

\App\Http\Middleware\Cors::class

]

 

---mindSpace 4_CORS Laravel + Angular 2 Vue.js 2

マニュアルで作ってもよいけど laravel-corsというpackageもある。

github.com

------------------------------------------------------------------------------

 

 

server.jsでnode_serverのcloud9接続portを指定するときの注意

port番号は8081,8082にすること。これらがデフォルトで解放されているポート(8080はメインアプリ用)

参考:

https://socket.io/get-started/chat/docs.c9.io

https://socket.io/get-started/chat/

 

 server.jsの動作確認用

server.listen(8081, function(){
console.log('Listening on Port 8081');
});

app.get('/', function(req, res){
res.send('<h1>Hello world</h1>');
});

ドメイン:8081でHello worldが表示される

io.on('connection', function(socket) {
console.log('New client connected');
});

 

-------------------------------------------------------------------Amitav 25#9Vue2&Laravel5.3

 

stackoverflow.com