チームで開発する際のGithubを用いた開発フロー

チーム開発する際は、複数人で作業する為、一人称でデプロイするのとは異なる。開発規模が大きくなれば、なおさら複数人で協力して開発していくことになろう。そこで、開発フローについて考察したい。
以下はGithubを用いた開発手法だ。

1. githubでissueを発行
2. issueの番号でブランチを切る
3. 開発
4. commit, push
5. プルリク
6. 配置

まず前提としてGithubもしくはGithub Enterpriseのアカウントがあることが必要になります。ない場合は、sign upしましょう。

https://github.com/

1. githubでissueを発行
Githubにログインし、submit new issueでissueを発行します。

issueを発行すると番号が附番されます。下の例では#2となっています。

2. issueの番号でブランチを切る
clone or downloadからgit cloneします。

コマンドラインの操作

// git cloneする
[vagrant@localhost sample]$ git clone https://github.com/githubix/bengoshi_chat.git
Initialized empty Git repository in /home/vagrant/local/sample/bengoshi_chat/.git/
remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 53 (delta 0), reused 2 (delta 0), pack-reused 50
Unpacking objects: 100% (53/53), done.

// cloneされたかフォルダを確認
[vagrant@localhost sample]$ ls
bengoshi_chat

// ディレクトリに移動
[vagrant@localhost sample]$ cd bengoshi_chat
[vagrant@localhost bengoshi_chat]$ ls
README.md  config  lib  node  public_html

// ブランチを確認
[vagrant@localhost bengoshi_chat]$ git branch
* chat

chatというブランチが出来ています。

gitで開発していく場合には、git cloneしたブランチではなく、作業用ブランチを作成して作業していきます。それを「ブランチを切る」と言います。
gitのブランチを作成するには git branch hogehoge と打ちます。
早速やってみましょう。

[vagrant@localhost bengoshi_chat]$ git branch
* chat
// branchを切ります
[vagrant@localhost bengoshi_chat]$ git branch newbranch
// branchを確認
[vagrant@localhost bengoshi_chat]$ git branch
* chat
  newbranch

新しくnewbranchが出来ましたが、branchはchatのままです。branchの切り替えはcheckoutを使います。ホテルのチェックアウトと同じイメージです。

// newbranchに切り替えます
[vagrant@localhost bengoshi_chat]$ git checkout newbranch
Switched to branch 'newbranch'
// 確認すると、newbranchになっているのがわかります
[vagrant@localhost bengoshi_chat]$ git branch
  chat
* newbranch

続いて、fileを修正します。ここではサンプルとして、テキストを修正します。

※社会通念上、不適切と思われる相談内容は、<b>こちら</b>にユーザ名および内容をご連絡ください。

git add してstatusを見ると、状態がわかります。

// git add . とします。
[vagrant@localhost bengoshi_chat]$ git add .
// statusを確認すると、どのブランチ、ファイルか表示されます。
[vagrant@localhost bengoshi_chat]$ git status
# On branch newbranch
# Changes to be committed:
#   (use "git reset HEAD ..." to unstage)
#
#       modified:   public_html/index.php
#

続いて、commitして、pushします。

[vagrant@localhost bengoshi_chat]$ git commit -m "text modify"
[newbranch f7b8b29] text modify
 Committer: vagrant 
Your name and email address were configured automatically based
on your username and hostname. Please check that they are accurate.
You can suppress this message by setting them explicitly:

    git config --global user.name "Your Name"
    git config --global user.email you@example.com

If the identity used for this commit is wrong, you can fix it with:

    git commit --amend --author='Your Name '

 1 files changed, 1 insertions(+), 1 deletions(-)

// pushします。
[vagrant@localhost bengoshi_chat]$ git push origin newbranch
error: The requested URL returned error: 403 Forbidden while accessing https://github.com/githubix/bengoshi_chat.git/info/refs

fatal: HTTP request failed

あれ、よくわかんなくなってきた。。

reactでcomponentの引数を渡す

reactでcomponentの引数を渡したい時があると思いますので、そのサンプルを書きます。

Counterという関数。propsを受け取り、そのcolorを書きます。{props.color}

function Counter(props){
		return <div>0 {props.color}</div>
	}

渡す方です。

<div>
			<Counter color="blue"/>
			<Counter color="yellow"/>
			<Counter color="red"/>
		</div>,

繋げてみます。

(() => {

		function Counter(props){
		return <div>0 {props.color}</div>
	}

		ReactDOM.render(
		<div>
			<Counter color="blue"/>
			<Counter color="yellow"/>
			<Counter color="red"/>
		</div>,
			document.getElementById('root')
		);
	})();

うまく引き継がれました。

それをdivタグのsytleの属性に渡します。
backgroundColor:props.colorとすることで、props.colorを背景色に指定しています。

function Counter(props){
		return <div style={{backgroundColor:props.color}}>0</div>
	}

フレームワークの勉強方法を考えてみる

PHPのLaravelというフレームワークを学習したいとして、学習手順について考えてみたいと思います。
まず、大きくわけて以下のような考え方があると思います。

1. 必要な箇所のみWebで調べて、実装する
2. ドットインストールなど、学習サイトで基礎を勉強する
3. フレームワークの本を買って、本に沿って勉強する
4. フレームワークの勉強会に参加する
5. フレームワークの公式サイトから、ドキュメントを全部読む
6. 自分自身でフレームワークを触りながら、プロダクトを作って勉強する
7. フレームワークのgithub issuesを読む
8. フレームワークのossにコミットする

1. 必要な箇所のみWebで調べて、実装する
Googleで、調べたい内容のキーワードで検索をして、上位表示されているページの記事を複数読んで、ローカルでテストして動かします。
基本はこれの繰り返しで良いと思います。何故なら、最も効率的に時間を使えるから。
例えば、laravelのログイン機能の実装を調べたいとすれば、「laravel ログイン機能」と入力すれば、関連記事がずらずらと表示されます。1位表示されるということは、それだけ価値のある情報とみなされているので、素直にそれを読めばいいと思います。実際に、殆どこれで解決できるような気がします。

「laravel ログイン機能」で1位表示されている機能
https://www.ritolab.com/entry/51

2. ドットインストールなど、学習サイトで基礎を勉強する
フレームワークをゼロから学ぶ必要がある場合は、ドットインストールのレッスンがおススメです。フレームワークの基本的な機能を説明しているので、短時間で基礎を一通り学べます。
▽ドットインストール
https://dotinstall.com/
▽Laravel5.5
https://dotinstall.com/lessons/basic_laravel_v2
ただし、注意が必要なのは、レッスンの代表の田口元がマンパワーでつくってるので、内容が古いということがあります。Laravelは最新版が5.7ですが、まだ5.5なので、最新更新日を注意しなければなりません。また、フレームワークでも、phpとrailsぐらいしかなく、pythonやjavaなどその他の言語のコンテンツはあまりないので、その辺を勉強したい場合は、ドットインストールにはありません。
因みに私は、4,380レッスン完了して、全受講者中9位です。一時期、2位でした。プレミアム会員は月額980円なので費用対効果はいいと思います。

3. フレームワークの本を買って、本に沿って勉強する
本屋で、幾つか見て、自分に合いそうな本を買って勉強する方法です。私の場合、昔はこれが主流でしたが、最近はほとんど本は買いません。なぜなら、(1)情報が最新でない、(2)Webの方が見やすい、(3)持ち運びが重いから。本の出版だと、やはり少し前の情報なんですね。なので、お金だして買った割に、情報が古いとちょっとがっかりします。また、紙よりもwebの方が見やすい・使いやすいんですね。ソースコードなのどは、やはり、Web上で見た方がやりやすい。そして、なにより、持ち運びが重い。自宅よりも外で作業している時間の方が長いので、軽い方がいいです。

ただし、webで勉強したことを本屋で確認する、というのはよくやってます。

4. フレームワークの勉強会に参加する
LTの講師は、大体第一線のエンジニアが立つので、どれ位の知識が必要なのか、という意味では参考になりますが、これは、微妙ですね。なぜなら、勉強会に出たからといって、コーディングのスキルはあがらないから。
単純に、他社のオフィスに行けるのが楽しい、というのもあり、私は、一応、connpassとtechplayはチェックしていますが、そんなに勉強会には時間を割いていません。
https://connpass.com/
https://techplay.jp/
余裕ができたら、もっと勉強会に参加したいと思っています。

5. フレームワークの公式サイトから、ドキュメントを全部読む
これは凄いおススメ。teratailで質問すると、よく、公式のドキュメントを全部読め、と返ってくるが、周りのエンジニアでもスーパーエンジニアのような人は、何か課題があった時には、関連する記事を直ぐに公式のドキュメントをひっぱってくる。また、自分でカスタマイズする際にも、スキルのある人は、公式ドキュメントを良く読んでいる印象があります。
laravelのドキュメント
https://readouble.com/laravel/
難点としては、読むのに骨がおれる、時間がかかり大変、ということです。直接関係なさそうな記事も読まなければいけないため、長時間読み続けると、モチベーションが段々下がってきます。なので、細切れで学ぶなど工夫が必要かも。これは今後もやっていきたいですね。

6. 自分自身でフレームワークを触りながら、プロダクトを作って勉強する
これは最も重要かもしれません。自分でローカルで環境を作って、動かしながら、理解していく事が最重要だと思います。
ただし、これは、前工程に時間がかかる、という難点があります。
フレームワークを触る前に、つくるプロダクトの基本設計、詳細設計、画面設計、画面遷移、フロント部分などある程度つくっておかなければならないという点です。フレームワークの簡単な動作なら、別にデフォルトをインストールして基本動作を確認すれば良いですが、実践的な学習となると、それなりの設計がされたプロダクトでないと意味ありません。そのため、設計からキチンとやっていく必要があり、時間がかかる覚悟をしなければなりません。

7. フレームワークのgithub issuesを読む
最新の情報は、公式ではなく、githubでやりとりされているので、githubを見る癖をつけた方がいいですね。
https://github.com/laravel/laravel

8. フレームワークのossにコミットする
ここまでくれば、特にいうことはないでしょう。というか、このレベルまで早くいきたい。

ということで、つらつらと書いてきましたが、纏めると、効率的な学習法があるかもしれませんが、きちんとやるのであればフレームワークの学習には時間がかかる、ということでしょうか。
おススメの方法があったら教えてください。

お問い合わせ

reactで使う関数の基本構文

クリックするとアラートが表示される関数をreactで書きたいとします。
アラートはシンプルに書きます。

function showMessage(){
		alert('Hello');
	} 

これをreact内に書くとき。
onClick={showMessage}で呼び出します。その際に、onClick=”showMessage”だとstringと認識されるため、{}を指定してあげてください。

<div id="root"></div>
	<script type="text/babel">
		(() => {

		function showMessage(){
		alert('Hello');
	} 

		ReactDOM.render(
			<div className="box" onClick={showMessage}></div>,
			document.getElementById('root')
		);
	})();
	</script>

では、ブラウザで表示を確認します。

JSX

constで変数を渡すこともできます。

<script type="text/babel">
		(() => {

		const name = 'engineer';
		ReactDOM.render(
			<p>Hello! {name.toUpperCase()}</p>,
			document.getElementById('root')
		);
	})();
	</script>

こうですね。

readctDOM.renderの中でタグを複数書くとエラーになる

<div id="root"></div>
	<script type="text/babel">
		(() => {

		const name = 'engineer';
		ReactDOM.render(
			<p>hello</p><p>world</p>,
			document.getElementById('root')
		);
	})();
	</script>

divタグで囲うとエラーが消える。

React

A JavaScript library for building user interfaces
react
https://reactjs.org/

chromeにreact developer toolを入れます。

拡張管理を押下。
ファイルのURLへのアクセスを許可する をonにする

reactの公式より、try reactを押下
https://raw.githubusercontent.com/reactjs/reactjs.org/master/static/html/single-file-example.html

このscriptタグの箇所をコピペ

<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script>

htmlの中に入れていきます。

<!DOCTYPE html>
<html lang="ja">
<head>
	 <meta charset="UTF-8">
	 <title>React</title>
	 <link rel="stylesheet" href="css/styles.css">
	 <script src="https://unpkg.com/react@16/umd/react.development.js"></script>
    <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
    <script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script>
</head>
<body>
	<script type="text/babel">
		
	</script>
</body>
</html>

reactを書いていきます。

<div id="root"></div>
	<script type="text/babel">
		(() => {
		ReactDOM.render(
			<p>Hello!</p>,
			document.getElementById('root')
		);
	})();
	</script>

reactでは、(() => {})();と書く。もはやfunctionは省略。変わった書き方だ。
document.getByElementは上手くいってます。

auth.php Language file

Introduction
This is not original Laravel official documentaion. This page include into readouble.com to show original English content of Japanese translation.

return [

    /*
    |--------------------------------------------------------------------------
    | Authentication Language Lines
    |--------------------------------------------------------------------------
    |
    | The following language lines are used during authentication for various
    | messages that we need to display to the user. You are free to modify
    | these language lines according to your application's requirements.
    |
    */

    'failed' => 'These credentials do not match our records.',
    'throttle' => 'Too many login attempts. Please try again in :seconds seconds.',

];

return [

    /*
    |--------------------------------------------------------------------------
    | Pagination Language Lines
    |--------------------------------------------------------------------------
    |
    | The following language lines are used by the paginator library to build
    | the simple pagination links. You are free to change them to anything
    | you want to customize your views to better match your application.
    |
    */

    'previous' => '&laquo; Previous',
    'next' => 'Next &raquo;',

 'password' => 'Passwords must be at least six characters and match the confirmation.',
    'reset' => 'Your password has been reset!',
    'sent' => 'We have e-mailed your password reset link!',
    'token' => 'This password reset token is invalid.',
    'user' => "We can't find a user with that e-mail address.",
 'accepted'             => 'The :attribute must be accepted.',
    'active_url'           => 'The :attribute is not a valid URL.',
    'after'                => 'The :attribute must be a date after :date.',
    'after_or_equal'       => 'The :attribute must be a date after or equal to :date.',
    'alpha'                => 'The :attribute may only contain letters.',
    'alpha_dash'           => 'The :attribute may only contain letters, numbers, and dashes.',
    'alpha_num'            => 'The :attribute may only contain letters and numbers.',
    'array'                => 'The :attribute must be an array.',
    'before'               => 'The :attribute must be a date before :date.',
    'before_or_equal'      => 'The :attribute must be a date before or equal to :date.',
    'between'              => [
        'numeric' => 'The :attribute must be between :min and :max.',
        'file'    => 'The :attribute must be between :min and :max kilobytes.',
        'string'  => 'The :attribute must be between :min and :max characters.',
        'array'   => 'The :attribute must have between :min and :max items.',
    ],
    'boolean'              => 'The :attribute field must be true or false.',
    'confirmed'            => 'The :attribute confirmation does not match.',
    'date'                 => 'The :attribute is not a valid date.',
    'date_format'          => 'The :attribute does not match the format :format.',
    'different'            => 'The :attribute and :other must be different.',
    'digits'               => 'The :attribute must be :digits digits.',
    'digits_between'       => 'The :attribute must be between :min and :max digits.',
    'dimensions'           => 'The :attribute has invalid image dimensions.',
    'distinct'             => 'The :attribute field has a duplicate value.',
    'email'                => 'The :attribute must be a valid email address.',
    'exists'               => 'The selected :attribute is invalid.',
    'file'                 => 'The :attribute must be a file.',
    'filled'               => 'The :attribute field must have a value.',
    'image'                => 'The :attribute must be an image.',
    'in'                   => 'The selected :attribute is invalid.',
    'in_array'             => 'The :attribute field does not exist in :other.',
    'integer'              => 'The :attribute must be an integer.',
    'ip'                   => 'The :attribute must be a valid IP address.',
    'ipv4'                 => 'The :attribute must be a valid IPv4 address.',
    'ipv6'                 => 'The :attribute must be a valid IPv6 address.',
    'json'                 => 'The :attribute must be a valid JSON string.',
    'max'                  => [
        'numeric' => 'The :attribute may not be greater than :max.',
        'file'    => 'The :attribute may not be greater than :max kilobytes.',
        'string'  => 'The :attribute may not be greater than :max characters.',
        'array'   => 'The :attribute may not have more than :max items.',
    ],
    'mimes'                => 'The :attribute must be a file of type: :values.',
    'mimetypes'            => 'The :attribute must be a file of type: :values.',
    'min'                  => [
        'numeric' => 'The :attribute must be at least :min.',
        'file'    => 'The :attribute must be at least :min kilobytes.',
        'string'  => 'The :attribute must be at least :min characters.',
        'array'   => 'The :attribute must have at least :min items.',
    ],
    'not_in'               => 'The selected :attribute is invalid.',
    'numeric'              => 'The :attribute must be a number.',
    'present'              => 'The :attribute field must be present.',
    'regex'                => 'The :attribute format is invalid.',
    'required'             => 'The :attribute field is required.',
    'required_if'          => 'The :attribute field is required when :other is :value.',
    'required_unless'      => 'The :attribute field is required unless :other is in :values.',
    'required_with'        => 'The :attribute field is required when :values is present.',
    'required_with_all'    => 'The :attribute field is required when :values is present.',
    'required_without'     => 'The :attribute field is required when :values is not present.',
    'required_without_all' => 'The :attribute field is required when none of :values are present.',
    'same'                 => 'The :attribute and :other must match.',
    'size'                 => [
        'numeric' => 'The :attribute must be :size.',
        'file'    => 'The :attribute must be :size kilobytes.',
        'string'  => 'The :attribute must be :size characters.',
        'array'   => 'The :attribute must contain :size items.',
    ],
    'string'               => 'The :attribute must be a string.',
    'timezone'             => 'The :attribute must be a valid zone.',
    'unique'               => 'The :attribute has already been taken.',
    'uploaded'             => 'The :attribute failed to upload.',
    'url'                  => 'The :attribute format is invalid.',

    /*
    |--------------------------------------------------------------------------
    | Custom Validation Language Lines
    |--------------------------------------------------------------------------
    |
    | Here you may specify custom validation messages for attributes using the
    | convention "attribute.rule" to name the lines. This makes it quick to
    | specify a specific custom language line for a given attribute rule.
    |
    */

    'custom' => [
        'attribute-name' => [
            'rule-name' => 'custom-message',
        ],
    ],

    /*
    |--------------------------------------------------------------------------
    | Custom Validation Attributes
    |--------------------------------------------------------------------------
    |
    | The following language lines are used to swap attribute place-holders
    | with something more reader friendly such as E-Mail Address instead
    | of "email". This simply helps us make messages a little cleaner.
    |
    */

    'attributes' => [],


];

やっと終わったー

Laravel Socialite

In addition to typical, form based authentication, Laravel also provides a simple, convenient way to authenticate with OAuth providers using Laravel Socialite. Socialite currently supports authentication with Facebook, Twitter, LinkedIn, Google, GitHub and Bitbucket.

Tip!! Adapters for other platforms are listed at the community driven Socialite Providers website.

Installation
To get started with Socialite, use Composer to add the package to your project’s dependencies:

composer require laravel/socialite

Configuration
Before using Socialite, you will also need to add credentials for the OAuth services your application utilizes. These credentials should be placed in your config/services.php configuration file, and should use the key facebook, twitter, linkedin, google, github or bitbucket, depending on the providers your application requires. For example:

‘github’ => [
‘client_id’ => env(‘GITHUB_CLIENT_ID’), // Your GitHub Client ID
‘client_secret’ => env(‘GITHUB_CLIENT_SECRET’), // Your GitHub Client Secret
‘redirect’ => ‘http://your-callback-url’,
],

Routing
Next, you are ready to authenticate users! You will need two routes: one for redirecting the user to the OAuth provider, and another for receiving the callback from the provider after authentication. We will access Socialite using the Socialite facade:

redirect();
}

/**
* Obtain the user information from GitHub.
*
* @return \Illuminate\Http\Response
*/
public function handleProviderCallback()
{
$user = Socialite::driver(‘github’)->user();

// $user->token;
}
}
The redirect method takes care of sending the user to the OAuth provider, while the user method will read the incoming request and retrieve the user’s information from the provider.

Of course, you will need to define routes to your controller methods:

Route::get(‘login/github’, ‘Auth\LoginController@redirectToProvider’);
Route::get(‘login/github/callback’, ‘Auth\LoginController@handleProviderCallback’);

Optional Parameters
A number of OAuth providers support optional parameters in the redirect request. To include any optional parameters in the request, call the with method with an associative array:

return Socialite::driver(‘google’)
->with([‘hd’ => ‘example.com’])
->redirect();
Note: When using the with method, be careful not to pass any reserved keywords such as state or response_type.

Access Scopes
Before redirecting the user, you may also add additional “scopes” on the request using the scopes method. This method will merge all existing scopes with the ones you supply:

return Socialite::driver(‘github’)
->scopes([‘read:user’, ‘public_repo’])
->redirect();
You can overwrite all existing scopes using the setScopes method:

return Socialite::driver(‘github’)
->setScopes([‘read:user’, ‘public_repo’])
->redirect();
Stateless Authentication
The stateless method may be used to disable session state verification. This is useful when adding social authentication to an API:

return Socialite::driver(‘google’)->stateless()->user();
Retrieving User Details
Once you have a user instance, you can grab a few more details about the user:

$user = Socialite::driver(‘github’)->user();

// OAuth Two Providers
$token = $user->token;
$refreshToken = $user->refreshToken; // not always provided
$expiresIn = $user->expiresIn;

// OAuth One Providers
$token = $user->token;
$tokenSecret = $user->tokenSecret;

// All Providers
$user->getId();
$user->getNickname();
$user->getName();
$user->getEmail();
$user->getAvatar();
Retrieving User Details From A Token (OAuth2)
If you already have a valid access token for a user, you can retrieve their details using the userFromToken method:

$user = Socialite::driver(‘github’)->userFromToken($token);
Retrieving User Details From A Token And Secret (OAuth1)
If you already have a valid pair of token / secret for a user, you can retrieve their details using the userFromTokenAndSecret method:

$user = Socialite::driver(‘twitter’)->userFromTokenAndSecret($token, $secret);

Laravel Scout

Introduction
Laravel Scout provides a simple, driver based solution for adding full-text search to your Eloquent models. Using model observers, Scout will automatically keep your search indexes in sync with your Eloquent records.

Currently, Scout ships with an Algolia driver; however, writing custom drivers is simple and you are free to extend Scout with your own search implementations.

Installation
First, install Scout via the Composer package manager:

composer require laravel/scout
After installing Scout, you should publish the Scout configuration using the vendor:publish Artisan command. This command will publish the scout.php configuration file to your config directory:

php artisan vendor:publish –provider=”Laravel\Scout\ScoutServiceProvider”

Finally, add the Laravel\Scout\Searchable trait to the model you would like to make searchable. This trait will register a model observer to keep the model in sync with your search driver:

namespace App;

use Laravel\Scout\Searchable;
use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
use Searchable;
}

Queueing
While not strictly required to use Scout, you should strongly consider configuring a queue driver before using the library. Running a queue worker will allow Scout to queue all operations that sync your model information to your search indexes, providing much better response times for your application’s web interface.

Once you have configured a queue driver, set the value of the queue option in your config/scout.php configuration file to true:

Driver Prerequisites
Algolia
When using the Algolia driver, you should configure your Algolia id and secret credentials in your config/scout.php configuration file. Once your credentials have been configured, you will also need to install the Algolia PHP SDK via the Composer package manager:

composer require algolia/algoliasearch-client-php

Configuring Model Indexes
Each Eloquent model is synced with a given search “index”, which contains all of the searchable records for that model. In other words, you can think of each index like a MySQL table. By default, each model will be persisted to an index matching the model’s typical “table” name. Typically, this is the plural form of the model name; however, you are free to customize the model’s index by overriding the searchableAs method on the model:

namespace App;

use Laravel\Scout\Searchable;
use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    use Searchable;

    /**
     * Get the index name for the model.
     *
     * @return string
     */
    public function searchableAs()
    {
        return 'posts_index';
    }
}

Indexing
Batch Import
If you are installing Scout into an existing project, you may already have database records you need to import into your search driver. Scout provides an import Artisan command that you may use to import all of your existing records into your search indexes:

php artisan scout:import “App\Post”
The flush command may be used to remove all of a model’s records from your search indexes:

php artisan scout:flush “App\Post”
Adding Records
Once you have added the Laravel\Scout\Searchable trait to a model, all you need to do is save a model instance and it will automatically be added to your search index. If you have configured Scout to use queues this operation will be performed in the background by your queue worker:

$order = new App\Order;

// …

$order->save();
Adding Via Query
If you would like to add a collection of models to your search index via an Eloquent query, you may chain the searchable method onto an Eloquent query. The searchable method will chunk the results of the query and add the records to your search index. Again, if you have configured Scout to use queues, all of the chunks will be added in the background by your queue workers:

// Adding via Eloquent query…
App\Order::where(‘price’, ‘>’, 100)->searchable();

// You may also add records via relationships…
$user->orders()->searchable();

// You may also add records via collections…
$orders->searchable();
The searchable method can be considered an “upsert” operation. In other words, if the model record is already in your index, it will be updated. If it does not exist in the search index, it will be added to the index.

Updating Records
To update a searchable model, you only need to update the model instance’s properties and save the model to your database. Scout will automatically persist the changes to your search index:

$order = App\Order::find(1);

// Update the order…

$order->save();
You may also use the searchable method on an Eloquent query to update a collection of models. If the models do not exist in your search index, they will be created:

// Updating via Eloquent query…
App\Order::where(‘price’, ‘>’, 100)->searchable();

// You may also update via relationships…
$user->orders()->searchable();

// You may also update via collections…
$orders->searchable();
Removing Records
To remove a record from your index, delete the model from the database. This form of removal is even compatible with soft deleted models:

$order = App\Order::find(1);

$order->delete();
If you do not want to retrieve the model before deleting the record, you may use the unsearchable method on an Eloquent query instance or collection:

// Removing via Eloquent query…
App\Order::where(‘price’, ‘>’, 100)->unsearchable();

// You may also remove via relationships…
$user->orders()->unsearchable();

// You may also remove via collections…
$orders->unsearchable();
Pausing Indexing
Sometimes you may need to perform a batch of Eloquent operations on a model without syncing the model data to your search index. You may do this using the withoutSyncingToSearch method. This method accepts a single callback which will be immediately executed. Any model operations that occur within the callback will not be synced to the model’s index:

App\Order::withoutSyncingToSearch(function () {
// Perform model actions…
});
Conditionally Searchable Model Instances
Sometimes you may need to only make a model searchable under certain conditions. For example, imagine you have App\Post model that may be in one of two states: “draft” and “published”. You may only want to allow “published” posts to be searchable. To accomplish this, you may define a shouldBeSearchable method on your model:

public function shouldBeSearchable()
{
return $this->isPublished();
}
Searching
You may begin searching a model using the search method. The search method accepts a single string that will be used to search your models. You should then chain the get method onto the search query to retrieve the Eloquent models that match the given search query:

$orders = App\Order::search(‘Star Trek’)->get();
Since Scout searches return a collection of Eloquent models, you may even return the results directly from a route or controller and they will automatically be converted to JSON:

use Illuminate\Http\Request;

Route::get(‘/search’, function (Request $request) {
return App\Order::search($request->search)->get();
});
If you would like to get the raw results before they are converted to Eloquent models, you should use the raw method:

$orders = App\Order::search(‘Star Trek’)->raw();
Search queries will typically be performed on the index specified by the model’s searchableAs method. However, you may use the within method to specify a custom index that should be searched instead:

$orders = App\Order::search(‘Star Trek’)
->within(‘tv_shows_popularity_desc’)
->get();
Where Clauses
Scout allows you to add simple “where” clauses to your search queries. Currently, these clauses only support basic numeric equality checks, and are primarily useful for scoping search queries by a tenant ID. Since a search index is not a relational database, more advanced “where” clauses are not currently supported:

$orders = App\Order::search(‘Star Trek’)->where(‘user_id’, 1)->get();
Pagination
In addition to retrieving a collection of models, you may paginate your search results using the paginate method. This method will return a Paginator instance just as if you had paginated a traditional Eloquent query:

$orders = App\Order::search(‘Star Trek’)->paginate();
You may specify how many models to retrieve per page by passing the amount as the first argument to the paginate method:

$orders = App\Order::search(‘Star Trek’)->paginate(15);
Once you have retrieved the results, you may display the results and render the page links using Blade just as if you had paginated a traditional Eloquent query:

@foreach ($orders as $order)
{{ $order->price }}
@endforeach

{{ $orders->links() }}
Soft Deleting
If your indexed models are soft deleting and you need to search your soft deleted models, set the soft_delete option of the config/scout.php configuration file to true:

‘soft_delete’ => true,
When this configuration option is true, Scout will not remove soft deleted models from the search index. Instead, it will set a hidden __soft_deleted attribute on the indexed record. Then, you may use the withTrashed or onlyTrashed methods to retrieve the soft deleted records when searching:

// Include trashed records when retrieving results…
$orders = App\Order::withTrashed()->search(‘Star Trek’)->get();

// Only include trashed records when retrieving results…
$orders = App\Order::onlyTrashed()->search(‘Star Trek’)->get();
Tip!! When a soft deleted model is permanently deleted using forceDelete, Scout will remove it from the search index automatically.

Customizing Engine Searches
If you need to customize the search behavior of an engine you may pass a callback as the second argument to the search method. For example, you could use this callback to add geo-location data to your search options before the search query is passed to Algolia:

use AlgoliaSearch\Index;

App\Order::search(‘Star Trek’, function (Index $algolia, string $query, array $options) {
$options[‘body’][‘query’][‘bool’][‘filter’][‘geo_distance’] = [
‘distance’ => ‘1000km’,
‘location’ => [‘lat’ => 36, ‘lon’ => 111],
];

return $algolia->search($query, $options);
})->get();
Custom Engines
Writing The Engine
If one of the built-in Scout search engines doesn’t fit your needs, you may write your own custom engine and register it with Scout. Your engine should extend the Laravel\Scout\Engines\Engine abstract class. This abstract class contains seven methods your custom engine must implement:

use Laravel\Scout\Builder;

abstract public function update($models);
abstract public function delete($models);
abstract public function search(Builder $builder);
abstract public function paginate(Builder $builder, $perPage, $page);
abstract public function mapIds($results);
abstract public function map($results, $model);
abstract public function getTotalCount($results);
You may find it helpful to review the implementations of these methods on the Laravel\Scout\Engines\AlgoliaEngine class. This class will provide you with a good starting point for learning how to implement each of these methods in your own engine.

Registering The Engine
Once you have written your custom engine, you may register it with Scout using the extend method of the Scout engine manager. You should call the extend method from the boot method of your AppServiceProvider or any other service provider used by your application. For example, if you have written a MySqlSearchEngine, you may register it like so:

use Laravel\Scout\EngineManager;

/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
resolve(EngineManager::class)->extend(‘mysql’, function () {
return new MySqlSearchEngine;
});
}
Once your engine has been registered, you may specify it as your default Scout driver in your config/scout.php configuration file:

‘driver’ => ‘mysql’,
Builder Macros
If you would like to define a custom builder method, you may use the macro method on the Laravel\Scout\Builder class. Typically, “macros” should be defined within a service provider’s boot method:

engine->getTotalCount(
$this->engine()->search($this)
);
});
}
}
The macro function accepts a name as its first argument, and a Closure as its second. The macro’s Closure will be executed when calling the macro name from a Laravel\Scout\Builder implementation:

App\Order::search(‘Star Trek’)->count();

API Authentication (Passport)

Introduction
Laravel already makes it easy to perform authentication via traditional login forms, but what about APIs? APIs typically use tokens to authenticate users and do not maintain session state between requests. Laravel makes API authentication a breeze using Laravel Passport, which provides a full OAuth2 server implementation for your Laravel application in a matter of minutes. Passport is built on top of the League OAuth2 server that is maintained by Andy Millington and Simon Hamp.

Installation
To get started, install Passport via the Composer package manager:

The Passport service provider registers its own database migration directory with the framework, so you should migrate your database after installing the package. The Passport migrations will create the tables your application needs to store clients and access tokens:

php artisan migrate

Next, you should run the passport:install command. This command will create the encryption keys needed to generate secure access tokens. In addition, the command will create “personal access” and “password grant” clients which will be used to generate access tokens:

php artisan passport:install
After running this command, add the Laravel\Passport\HasApiTokens trait to your App\User model. This trait will provide a few helper methods to your model which allow you to inspect the authenticated user’s token and scopes:

namespace App;

use Laravel\Passport\HasApiTokens;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable
{
    use HasApiTokens, Notifiable;
}

Next, you should call the Passport::routes method within the boot method of your AuthServiceProvider. This method will register the routes necessary to issue access tokens and revoke access tokens, clients, and personal access tokens:

namespace App\Providers;

use Laravel\Passport\Passport;
use Illuminate\Support\Facades\Gate;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;

class AuthServiceProvider extends ServiceProvider
{
    /**
     * The policy mappings for the application.
     *
     * @var array
     */
    protected $policies = [
        'App\Model' => 'App\Policies\ModelPolicy',
    ];

    /**
     * Register any authentication / authorization services.
     *
     * @return void
     */
    public function boot()
    {
        $this->registerPolicies();

        Passport::routes();
    }
}
'guards' => [
    'web' => [
        'driver' => 'session',
        'provider' => 'users',
    ],

    'api' => [
        'driver' => 'passport',
        'provider' => 'users',
    ],
],

Passport ships with a JSON API that you may use to allow your users to create clients and personal access tokens. However, it can be time consuming to code a frontend to interact with these APIs. So, Passport also includes pre-built Vue components you may use as an example implementation or starting point for your own implementation.

To publish the Passport Vue components, use the vendor:publish Artisan command:

php artisan vendor:publish –tag=passport-components

The published components will be placed in your resources/js/components directory. Once the components have been published, you should register them in your resources/js/app.js file:

Vue.component(
    'passport-clients',
    require('./components/passport/Clients.vue')
);

Vue.component(
    'passport-authorized-clients',
    require('./components/passport/AuthorizedClients.vue')
);

Vue.component(
    'passport-personal-access-tokens',
    require('./components/passport/PersonalAccessTokens.vue')
);
After registering the com

After registering the components, make sure to run npm run dev to recompile your assets. Once you have recompiled your assets, you may drop the components into one of your application’s templates to get started creating clients and personal access tokens:

Configuration
Token Lifetimes
By default, Passport issues long-lived access tokens that expire after one year. If you would like to configure a longer / shorter token lifetime, you may use the tokensExpireIn and refreshTokensExpireIn methods. These methods should be called from the boot method of your AuthServiceProvider:
public function boot()
{
$this->registerPolicies();

Passport::routes();

Passport::tokensExpireIn(now()->addDays(15));

Passport::refreshTokensExpireIn(now()->addDays(30));
}

Overriding Default Models
You are free to extend the models used internally by Passport. Then, you may instruct Passport to use your custom models via the Passport class:

use App\Models\Passport\Client;
use App\Models\Passport\AuthCode;
use App\Models\Passport\TokenModel;
use App\Models\Passport\PersonalAccessClient;

/**
* Register any authentication / authorization services.
*
* @return void
*/
public function boot()
{
$this->registerPolicies();

Passport::routes();

Passport::useClientModel(Client::class);
Passport::useTokenModel(TokenModel::class);
Passport::useAuthCodeModel(AuthCode::class);
Passport::usePersonalAccessClientModel(PersonalAccessClient::class);
}

Issuing Access Tokens
Using OAuth2 with authorization codes is how most developers are familiar with OAuth2. When using authorization codes, a client application will redirect a user to your server where they will either approve or deny the request to issue an access token to the client.

Managing Clients
First, developers building applications that need to interact with your application’s API will need to register their application with yours by creating a “client”. Typically, this consists of providing the name of their application and a URL that your application can redirect to after users approve their request for authorization.

The passport:client Command
The simplest way to create a client is using the passport:client Artisan command. This command may be used to create your own clients for testing your OAuth2 functionality. When you run the client command, Passport will prompt you for more information about your client and will provide you with a client ID and secret:

php artisan passport:client
Redirect URLs

If you would like to whitelist multiple redirect URLs for your client, you may specify them using a comma-delimited list when prompted for the URL by the passport:client command:

JSON API
Since your users will not be able to utilize the client command, Passport provides a JSON API that you may use to create clients. This saves you the trouble of having to manually code controllers for creating, updating, and deleting clients.

However, you will need to pair Passport’s JSON API with your own frontend to provide a dashboard for your users to manage their clients. Below, we’ll review all of the API endpoints for managing clients. For convenience, we’ll use Axios to demonstrate making HTTP requests to the endpoints.

The JSON API is guarded by the web and auth middlewares; therefore, it may only be called from your own application. It is not able to be called from an external source.