Build a Basic CRUD App with Laravel and React

Build a Basic CRUD App with Laravel and React

Today I’ll show you how you can build a Laravel API and connect it to a React frontend. We’ll use Okta for user authentication and authorization which will allow us to implement a top-notch security system in (almost) no time at all.

Today I’ll show you how you can build a Laravel API and connect it to a React frontend. We’ll use Okta for user authentication and authorization which will allow us to implement a top-notch security system in (almost) no time at all.

Build a Basic CRUD App with Laravel and React. Add Okta for Authentication. Start Your Laravel + React CRUD Application. Set Up Your Okta Dev Account. Set Up Laravel. Create a Laravel API. Install React and Set Up the React Frontend. Add Authentication and Basic Routing to React. Display Your Players List Using React.

Laravel is an amazing web application framework which regularly tops the lists of best PHP frameworks available today. This is partly because its based on PHP which runs 80% of the web today and the learning curve is relatively small (despite it being packed with advanced features, you can understand the basic concepts easily). However, the real reason for its popularity is its robust ecosystem and abundance of high-quality learning resources available for free (like this blog post!).

Laravel is configured with Vue and build tools (based on webpack) out of the box so you can set up a development environment for building dynamic, single-page applications with little hassle. You are not limited to Vue though - you can also use Laravel as a backend that powers a frontend built in your preferred framework. Today I’ll show you how you can build a Laravel API and connect it to a React frontend. We’ll use Okta for user authentication and authorization which will allow us to implement a top-notch security system in (almost) no time at all.

Before you start, you’ll need to set up a development environment with PHP 7 and Node.js 8+/npm. You will also need an Okta developer account.

Add Okta for Authentication

Well, we might be biased, but we think Okta makes identity management easier, more secure, and more scalable than what you’re used to. Okta is an API service that allows you to create, edit, and securely store user accounts and user account data, and connect them with one or more applications.

To complete this tutorial, you’ll need to register for a forever-free developer account. When you’re done, come back to learn more about building a secure CRUD app with Laravel and React.

Start Your Laravel + React CRUD Application

The application we are going to build is a simple game interface for trivia quizzes. It allows you to register the players, generate new questions from a free API and mark the answers of the players as either right or wrong.

Here’s what the finished app will look like:

Here’s how to play:

  • One of the players assumes the role of host and doesn’t participate in the rankings
  • The host reads the question to the players
  • The players ‘race’ to answer the question
  • If the answer is correct, the player gets +1 point. If the answer is wrong, the player gets -1 point
  • When the question is answered correctly, the host can hit ‘Refresh Question’ to load the next question
Set Up Your Okta Dev Account

Let’s set up your Okta account so it’s ready when you need it.

Before you proceed, you need to log into your Okta account (or create a new one for free) and set up a new OIDC app. You’ll mostly use the default settings. Make sure to take note of your Okta domain and the Client ID generated for the app.

Here are the step-by-step instructions:

Go to the Applications menu item and click the ‘Add Application’ button:

Select ‘Single Page Application’ and click ‘Next’.

Set a descriptive application name, add http://localhost:3000/ as the Base URI, and http://localhost:3000/implicit/callback as the Login redirect URI, and click Done. You can leave the rest of the settings as they are.

Set Up Laravel

Install the laravel command globally on your system through composer. Then create a new Laravel project, navigate to it and start the development PHP server:

composer global require laravel/installer
laravel new trivia-web-service
cd trivia-web-service
php artisan serve


Now create a MySQL database and user for your app (of course, if you prefer a different database engine like PostgreSQL, you can use it instead):

mysql -uroot -p
CREATE DATABASE trivia CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'trivia'@'localhost' identified by 'trivia';
GRANT ALL on trivia.* to 'trivia'@'localhost';
quit


The configuration variables are stored in the .env file in the main project directory. Let’s put your database credentials there:

.env

DB_DATABASE=trivia
DB_USERNAME=trivia
DB_PASSWORD=trivia


Note: You’ll need to restart the php artisan serve command after you’ve made changes to the .env file.

Create a Laravel API

Our project will have a single entity (Player). Let’s create a model and a migration for it:

php artisan make:model Player -m
Model created successfully.
Created Migration: 2018_11_28_094351_create_players_table


(the -m option is short for --migration)

Edit the migration and put the code that creates our database table in the up() method:

database/migrations/2018_11_28_094351_create_players_table.php

public function up()
{
    Schema::create('players', function (Blueprint $table) {
        $table->increments('id');
        $table->string('name');
        $table->integer('answers')->default(0);
        $table->integer('points')->default(0);
        $table->timestamps();
    });
}


Run the migration to apply the changes to our database:

php artisan migrate


We need to define the $fillable attribute of our model so we can tell Laravel which fields can be mass-assigned in create() and update() operations on the model:

app/Player.php

class Player extends Model
{
    protected $fillable = ['name', 'answers', 'points'];
}


We also need to create two API resources (this is a relatively new feature in Laravel, introduced in 5.6, which allows us to deal with the JSON representation of our objects more efficiently). The resources we need are: Player (dealing with an individual player) and PlayerCollection (dealing with a collection of players).

php artisan make:resource Player
php artisan make:resource PlayerCollection


Modify the toArray() functions of the resources:

app/Http/Resources/Player.php

public function toArray($request)
{
    return [
        'id'         => $this->id,
        'name'       => $this->name,
        'answers'    => (int) $this->answers,
        'points'     => (int) $this->points,
        'created_at' => $this->created_at,
        'updated_at' => $this->updated_at,
    ];
}


app/Http/Resources/PlayerCollection.php

public function toArray($request)
{
    return [
        'data' => $this->collection
    ];
}


We can now create the routes and controller for our REST API.

php artisan make:controller PlayerController


routes/api.php

Route::get('/players', '[email protected]');
Route::get('/players/{id}', '[email protected]');
Route::post('/players', '[email protected]');
Route::post('/players/{id}/answers', '[email protected]');
Route::delete('/players/{id}', '[email protected]');
Route::delete('/players/{id}/answers', '[email protected]');


app/Http/Controllers/PlayerController.php

...
use App\Player;
use App\Http\Resources\Player as PlayerResource;
use App\Http\Resources\PlayerCollection;
...

class PlayerController extends Controller
{
    public function index()
    {
        return new PlayerCollection(Player::all());
    }

    public function show($id)
    {
        return new PlayerResource(Player::findOrFail($id));
    }

    public function store(Request $request)
    {
        $request->validate([
            'name' => 'required|max:255',
        ]);

        $player = Player::create($request->all());

        return (new PlayerResource($player))
                ->response()
                ->setStatusCode(201);
    }

    public function answer($id, Request $request)
    {
        $request->merge(['correct' => (bool) json_decode($request->get('correct'))]);
        $request->validate([
            'correct' => 'required|boolean'
        ]);

        $player = Player::findOrFail($id);
        $player->answers++;
        $player->points = ($request->get('correct')
                           ? $player->points + 1
                           : $player->points - 1);
        $player->save();

        return new PlayerResource($player);
    }

    public function delete($id)
    {
        $player = Player::findOrFail($id);
        $player->delete();

        return response()->json(null, 204);
    }

    public function resetAnswers($id)
    {
        $player = Player::findOrFail($id);
        $player->answers = 0;
        $player->points = 0;

        return new PlayerResource($player);
    }
}


The API supports methods for retrieving all players or a specific player, adding/deleting players, marking answers as right/wrong and resetting the player’s score. There’s validation of the requests and the code generates JSON responses with the appropriate status codes in a rather modest amount of code.

We also need to enable CORS so we can access our API from the frontend application:

composer require barryvdh/laravel-cors


app/Http/Kernel.php

protected $middlewareGroups = [
    'web' => [
        ...
        \Barryvdh\Cors\HandleCors::class,
    ],

    'api' => [
        ...
        \Barryvdh\Cors\HandleCors::class,
    ],
];


You can add some dummy data to the database or use the Faker library to automate the process of generating test data. Once you have some data, you can access these URLs:

  • One of the players assumes the role of host and doesn’t participate in the rankings
  • The host reads the question to the players
  • The players ‘race’ to answer the question
  • If the answer is correct, the player gets +1 point. If the answer is wrong, the player gets -1 point
  • When the question is answered correctly, the host can hit ‘Refresh Question’ to load the next question

If you also want to test the POST/PUT/DELETE requests (for example with Postman), make sure to set the following header on each request, so the validation errors will be returned in JSON format.

Accept: "application/json"


Install React and Set Up the React Frontend

We’ll use react-create-app (installed globally) to create our application. We will also install all the dependencies we will need in advance (React Router, Semantic UI React, Okta React) and run the development server:

npm install --global create-react-app
npx create-react-app trivia-web-client-react
cd trivia-web-client-react
yarn add react-router-dom semantic-ui-react
yarn add @okta/okta-react --save
yarn start


The default React application should now load on http://localhost:3000.

Add Authentication and Basic Routing to React

We will start with the most basic React application possible. Let’s delete everything except the index.js and App.js files from the /src folder, and change their contents like this:

src/index.js

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';

ReactDOM.render(<App />, document.getElementById('root'));


src/App.js

import React, { Component } from 'react';

class App extends Component {
  render() {
    return (
      <div>
        App
      </div>
    );
  }
}

export default App;


We’ll create a Semantic UI navbar and a Router with two basic routes: Home (not secure) and Trivia Game (secure). Then we’ll integrate the Okta authentication and implement the Login/Logout buttons. We’ll follow the Okta Authentication Quick Start Guide for React.

public/index.html

Add:

<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.3.3/semantic.min.css"></link>


src/Home.js

import React, { Component } from 'react';

class Home extends Component {
    render() {
        return <div>Home page</div>
    }
}

export default Home


src/Trivia.js

import React, { Component } from 'react';

class Trivia extends Component {
  render() {
    return <div>Trivia Game page</div>
  }
}

export default Trivia


src/Navbar.js

import React, { Component } from 'react';
import { withAuth } from '@okta/okta-react';

import { Container, Menu } from 'semantic-ui-react';

export default withAuth(class Navbar extends Component {
  constructor(props) {
    super(props);
    this.state = { authenticated: null };
    this.checkAuthentication = this.checkAuthentication.bind(this);
    this.login = this.login.bind(this);
    this.logout = this.logout.bind(this);
  }

  async componentDidMount() {
    this.checkAuthentication();
  }

  async componentDidUpdate() {
    this.checkAuthentication();
  }

  async login() {
    this.props.auth.login('/');
  }

  async logout() {
    this.props.auth.logout('/');
  }

  async checkAuthentication() {
    const authenticated = await this.props.auth.isAuthenticated();
    if (authenticated !== this.state.authenticated) {
      this.setState({ authenticated });
    }
  }

  render() {
    return (
      <div>
        <Menu fixed="top" inverted>
          <Container>
            <Menu.Item as="a" header href="/">
              Home
            </Menu.Item>
            {this.state.authenticated === true && <Menu.Item id="trivia-button" as="a" href="/trivia">Trivia Game</Menu.Item>}
            {this.state.authenticated === true && <Menu.Item id="logout-button" as="a" onClick={this.logout}>Logout</Menu.Item>}
            {this.state.authenticated === false && <Menu.Item as="a" onClick={this.login}>Login</Menu.Item>}
          </Container>
        </Menu>
      </div>
    );
  }
});


src/App.js

import React, { Component } from 'react';
import { BrowserRouter as Router, Route } from 'react-router-dom';
import { Container } from 'semantic-ui-react';

import { Security, SecureRoute, ImplicitCallback } from '@okta/okta-react';

import Navbar from './Navbar';
import Home from './Home'
import Trivia from './Trivia'

const config = {
  issuer: 'https://{yourOktaDomain}/oauth2/default',
  redirect_uri: window.location.origin + '/implicit/callback',
  client_id: '{yourClientId}'
}

class App extends Component {
  render() {
    return (
        <Router>
            <Security issuer={config.issuer}
                   client_id={config.client_id}
                redirect_uri={config.redirect_uri}
            >
            <Navbar />
            <Container text style={{ marginTop: '7em' }}>
                <Route path="/" exact component={Home} />
                <Route path="/implicit/callback" component={ImplicitCallback} />
                <SecureRoute path="/trivia" component={Trivia} />
            </Container>
        </Security>
      </Router>
    );
  }
}

export default App


Don’t forget to replace the config values for issuer and client_id with your own!

The app now contains a navbar with placeholder pages for Home, Trivia (only available when logged in), Login or Logout button (depending on the login state) and the login/logout actions work through Okta. We are ready to add the business logic of the application and connect it to the backend API.

Display Your Players List Using React

We will display the list of players in a table on the Trivia page. We’ll get the list from the API and add a ‘Loading…’ message until the API request completes.

We’ll create a new config.js file and define our base API URL there:

src/config.js

export const API_BASE_URL = 'http://localhost:8000/api';


We can now modify our Trivia.js component so that it looks like the below:

import React, { Component } from 'react';
import { Header, Message, Table } from 'semantic-ui-react';
import { withAuth } from '@okta/okta-react';

import { API_BASE_URL } from './config'

export default withAuth(class Trivia extends Component {

    constructor(props) {
        super(props);
        this.state = {
            players: null,
            isLoading: null
        };
    }

    componentDidMount() {
        this.getPlayers();
    }

    async getPlayers() {
        if (! this.state.players) {
            try {
                this.setState({ isLoading: true });
                const accessToken = await this.props.auth.getAccessToken();
                const response = await fetch(API_BASE_URL + '/players', {
                    headers: {
                        Authorization: `Bearer ${accessToken}`,
                    },
                });
                const playersList = await response.json();
                this.setState({ players: playersList.data, isLoading: false});
            } catch (err) {
                this.setState({ isLoading: false });
                console.error(err);
            }
        }
    }

    render() {
        return (
            <div>
                <Header as="h1">Players</Header>
                {this.state.isLoading && <Message info header="Loading players..." />}
                {this.state.players &&
                    <div>
                        <Table>
                            <thead>
                                <tr>
                                    <th>ID</th>
                                    <th>Name</th>
                                    <th>Answers</th>
                                    <th>Points</th>
                                    <th>Actions</th>
                                </tr>
                            </thead>
                            <tbody>
                            {this.state.players.map(
                                    player =>
                                        <tr id={player.id} key={player.id}>
                                            <td>{player.id}</td>
                                            <td>{player.name}</td>
                                            <td>{player.answers}</td>
                                            <td>{player.points}</td>
                                            <td>
                                                Action buttons placeholder
                                            </td>
                                        </tr>
                            )}
                            </tbody>
                        </Table>
                    </div>
                }
            </div>
        );
    }

});


Add Authentication to Your Laravel API

We need to secure our backend API so it uses the Okta token to allow only authorized requests. We need to install the JWT Verifier package and add a custom middleware for API authentication:

composer require okta/jwt-verifier spomky-labs/jose guzzlehttp/psr7
php artisan make:middleware AuthenticateWithOkta


app/Http/Middleware/AuthenticateWithOkta.php

<?php
namespace App\Http\Middleware;

use Closure;

class AuthenticateWithOkta
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        if ($this->isAuthorized($request)) {
            return $next($request);
        } else {
            return response('Unauthorized.', 401);
        }
    }

    public function isAuthorized($request)
    {
        if (! $request->header('Authorization')) {
            return false;
        }

        $authType = null;
        $authData = null;

        // Extract the auth type and the data from the Authorization header.
        @list($authType, $authData) = explode(" ", $request->header('Authorization'), 2);

        // If the Authorization Header is not a bearer type, return a 401.
        if ($authType != 'Bearer') {
            return false;
        }

        // Attempt authorization with the provided token
        try {

            // Setup the JWT Verifier
            $jwtVerifier = (new \Okta\JwtVerifier\JwtVerifierBuilder())
                            ->setAdaptor(new \Okta\JwtVerifier\Adaptors\SpomkyLabsJose())
                            ->setAudience('api://default')
                            ->setClientId('{YOUR_CLIENT_ID}')
                            ->setIssuer('{YOUR_ISSUER_URL}')
                            ->build();

            // Verify the JWT from the Authorization Header.
            $jwt = $jwtVerifier->verify($authData);
        } catch (\Exception $e) {

            // We encountered an error, return a 401.
            return false;
        }

        return true;
    }

}


app/Http/Kernel.php

    protected $middlewareGroups = [
        'web' => [
            ...
        ],

        'api' => [
            ...
            \App\Http\Middleware\AuthenticateWithOkta::class,
        ],
    ];


Don’t forget to replace the client ID and issuer URL with your own! I also recommend to extract these variables into the .env file (they are not secrets and they are visible in the frontend application so it’s not a security concern to keep them in the repo, but it’s not convenient if you have multiple environments).

If you did everything correctly, http://localhost:8000/api/players should now show you an ‘Unauthorized.’ message but loading the list of players in the React frontend should work fine (when you are logged in).

Create a New Player Component in React

We need a new React component for the Add Player form that we will add below the table on the Trivia page. First, we will modify Trivia.js to include the form and we will add a new method to updates the list of players when a new player is added:

src/Trivia.js

import PlayerForm from './PlayerForm';

(replace the constructor method)
    constructor(props) {
        super(props);
        this.state = {
            players: null,
            isLoading: null
        };
        this.onAddition = this.onAddition.bind(this);
    }

(add a new method)
    onAddition(player) {
        this.setState({
            players: [...this.state.players, player]
        })
    }

(below the closing </Table> tag in the render() method):
                        <PlayerForm onAddition={this.onAddition} />


We also need to create a new PlayerForm component:

src/PlayerForm.js

import React, { Component } from 'react';
import { Button, Form, Message } from 'semantic-ui-react'
import { withAuth } from '@okta/okta-react';

import { API_BASE_URL } from './config'

export default withAuth(class PlayerForm extends Component {

    constructor (props) {
        super(props);
        this.state = {
            name: '',
            errorMessage: '',
            error: false,
            isLoading: false
        }
        this.handleChange = this.handleChange.bind(this);
        this.onSubmit = this.onSubmit.bind(this);
    }

    handleChange(e) {
        this.setState({
            name: e.target.value
        })
    }

    async onSubmit(e) {
        e.preventDefault();
        this.setState({
            isLoading: true,
            error: false,
            errorMessage: ''
        });

        const accessToken = await this.props.auth.getAccessToken();
        const response = await fetch(API_BASE_URL + '/players', {
            method: 'POST',
            headers: {
                'Content-Type':'application/json',
                Authorization: `Bearer ${accessToken}`,
                Accept: 'application/json'
            },
            body: JSON.stringify({
                "name": this.state.name
            })
        });
        const player = await response.json();

        if (player.errors) {
            this.setState({
                isLoading: false,
                error: true,
                errorMessage: player.errors
            });
        } else {
            this.setState({
                name: '',
                isLoading: false,
                error: false,
                errorMessage: ''
            });
            this.props.onAddition(player.data);
        }
    }

    render() {
        return (
            <Form error={this.state.error} onSubmit={this.onSubmit}>
                <Form.Field error={this.state.error}>
                    <label>Player Name:</label>
                    <input placeholder='enter player name' value={this.state.name} onChange={this.handleChange}/>
                { this.state.error &&
                <Message
                    error
                    header='Error creating player'
                    content={this.state.errorMessage}
                />
                }
                </Form.Field>
                <Button type='submit' loading={this.state.isLoading}>Add Player</Button>
            </Form>
        )
    }
});


We can add more players to our game now using the form we just created.

Add a Delete Player Button to React

The next step is to implement the “Delete Player” button. We’ll create a new component for the button and pass the player ID as a property.

src/Trivia.js

import DeletePlayerButton from './DeletePlayerButton';

    constructor(props) {
        super(props);
        this.state = {
            players: null,
            isLoading: null
        };
        this.onAddition = this.onAddition.bind(this);
        this.onDelete = this.onDelete.bind(this);
    }

   onDelete(id) {
        let players = this.state.players;
        let index = players.findIndex(player => player.id === id)
        players.splice(index, 1)       
        this.setState({
            players: players
        })
    }


Replacing the action buttons placeholder text in the table inside the render() method:

<DeletePlayerButton onDelete={this.onDelete} playerId={player.id} />


src/DeletePlayerButton.js

import React, { Component } from 'react';
import { Form, Button } from 'semantic-ui-react'
import { withAuth } from '@okta/okta-react';

import { API_BASE_URL } from './config'

export default withAuth(class DeletePlayerButton extends Component {

    constructor (props) {
        super(props);
        this.state = {
            id: props.playerId,
            isUpdating: false
        }
        this.onSubmit = this.onSubmit.bind(this);
    }

    async onSubmit(e) {
        e.preventDefault();
        this.setState({
            isUpdating: true
        });

        const accessToken = await this.props.auth.getAccessToken();
        const response = await fetch(API_BASE_URL + '/players/' + this.state.id, {
            method: 'DELETE',
            headers: {
                'Content-Type':'application/json',
                Authorization: `Bearer ${accessToken}`,
                Accept: 'application/json'
            }
        });

        await response;
        await this.setState({
            isUpdating: false
        });
        this.props.onDelete(this.state.id);
    }

    render() {
        return (
            <Form onSubmit={this.onSubmit}>
                <Button type='submit' loading={this.state.isUpdating}>Delete Player</Button>
            </Form>
        )
    }
});


Add the Trivia Service to React

We’ll use a public API for trivia questions. This is a free service that provides random quiz questions from various topics. We’ll define the URL in the config.js file and get an initial question when the Trivia page is loaded. We will also modify the render() method of the Trivia component so the html includes a card with the question and answer, and buttons to indicate correct and wrong answer for each player:

src/config.js

export const TRIVIA_ENDPOINT = 'http://jservice.io/api/random?count=1';


src/Trivia.js

Changes:

    import { Header, Message, Table, Card, Button } from 'semantic-ui-react';
    import { API_BASE_URL, TRIVIA_ENDPOINT } from './config'

    constructor(props) {
        super(props);
        this.state = {
           players: null,
            isLoading: null,
            question: null,
            isQuestionLoading: null
        };
        this.onAddition = this.onAddition.bind(this);
        this.onDelete = this.onDelete.bind(this);
        this.getQuestion = this.getQuestion.bind(this);
    }

    componentDidMount() {
        this.getPlayers()
        this.getQuestion()
    }

    async getQuestion() {
        try {
            this.setState({ isQuestionLoading: true });
            const response = await fetch(TRIVIA_ENDPOINT);
            const questions = await response.json();
            this.setState({ question: questions[0], isQuestionLoading: false });
        } catch (err) {
            this.setState({ isQuestionLoading: false });
            console.error(err);
        }
    }

    render() {
        return (
            <div>
                <Header as="h1">Players</Header>
                {this.state.isLoading && <Message info header="Loading players..." />}
                {this.state.players &&
                    <div>
                        <Table>
                            <thead>
                                <tr>
                                    <th>ID</th>
                                    <th>Name</th>
                                    <th>Answers</th>
                                    <th>Points</th>
                                    <th>Actions</th>
                                </tr>
                            </thead>
                            <tbody>
                            {this.state.players.map(
                                    player =>
                                        <tr id={player.id} key={player.id}>
                                            <td>{player.id}</td>
                                            <td>{player.name}</td>
                                            <td>{player.answers}</td>
                                            <td>{player.points}</td>
                                            <td>
                                                <DeletePlayerButton onDelete={this.onDelete} playerId={player.id} />
                                            </td>
                                        </tr>
                            )}
                            </tbody>
                        </Table>
                        <PlayerForm onAddition={this.onAddition} />
                    </div>
                }
                <Header as="h2">Current Question</Header>
                {this.state.isQuestionLoading && <Message info header="Loading question..." />}
                {this.state.question &&
                    <div>
                        <Card>
                            <Card.Content>
                              <Card.Header>{this.state.question.question}</Card.Header>
                              <Card.Description> Correct answer: {this.state.question.answer}</Card.Description>
                            </Card.Content>
                        </Card>
                        <Button type='button' onClick={this.getQuestion}>Refresh Question</Button>
                    </div>
                }
            </div>
        );
    }


When you load the Trivia page, a question will automatically show now. Click ‘Refresh Question’ to display a new question.

Add Buttons to Indicate Right and Wrong Answers

We’ll add buttons to indicate right and wrong answers by the players similarly to the “Delete Player” button we already added.

src/Trivia.js

import RightAnswerButton from './RightAnswerButton';
import WrongAnswerButton from './WrongAnswerButton';

   constructor(props) {
        super(props);
        this.state = {
            players: null,
            isLoading: null,
            question: null,
            isQuestionLoading: null
        };
        this.onAddition = this.onAddition.bind(this);
        this.onDelete = this.onDelete.bind(this);
        this.getQuestion = this.getQuestion.bind(this);
        this.onAnswer = this.onAnswer.bind(this);
    }

    onAnswer(id, data) {
        let players = this.state.players
        let player = players.findIndex(player => player.id === id)
        players[player] = data
        this.setState({
            players: players
        })
    }

(add the following before `DeletePlayerButton` inside the `render()` method):

<RightAnswerButton onRightAnswer={this.onAnswer} playerId={player.id} />
<WrongAnswerButton onWrongAnswer={this.onAnswer} playerId={player.id} />


src/RightAnswerButton.js

import React, { Component } from 'react';
import { Form, Button } from 'semantic-ui-react'
import { withAuth } from '@okta/okta-react';

import { API_BASE_URL } from './config'

export default withAuth(class RightAnswerButton extends Component {

    constructor (props) {
        super(props);
        this.state = {
            id: props.playerId,
            isUpdating: false
        }
        this.onSubmit = this.onSubmit.bind(this);
    }

    async onSubmit(e) {
        e.preventDefault();
        this.setState({
            isUpdating: true
        });

        const accessToken = await this.props.auth.getAccessToken();
        const response = await fetch(API_BASE_URL + '/players/' + this.state.id + '/answers', {
            method: 'POST',
            headers: {
                'Content-Type':'application/json',
                Authorization: `Bearer ${accessToken}`,
                Accept: 'application/json'
            },
            body: JSON.stringify({
                "correct": true
            })
        });

        const player = await response.json();
        await this.setState({
            isUpdating: false
        });
        this.props.onRightAnswer(this.state.id, player.data);
    }

    render() {
        return (
            <Form onSubmit={this.onSubmit}>
                <Button type='submit' loading={this.state.isUpdating}>(+1) Right</Button>
            </Form>
        )
    }
});


src/WrongAnswerButton.js

import React, { Component } from 'react';
import { Form, Button } from 'semantic-ui-react'
import { withAuth } from '@okta/okta-react';

import { API_BASE_URL } from './config'

export default withAuth(class WrongAnswerButton extends Component {

    constructor (props) {
        super(props);
        this.state = {
            id: props.playerId,
            isUpdating: false
        }
        this.onSubmit = this.onSubmit.bind(this);
    }

    async onSubmit(e) {
        e.preventDefault();
        this.setState({
            isUpdating: true
        });

        const accessToken = await this.props.auth.getAccessToken();
        const response = await fetch(API_BASE_URL + '/players/' + this.state.id + '/answers', {
            method: 'POST',
            headers: {
                'Content-Type':'application/json',
                Authorization: `Bearer ${accessToken}`,
                Accept: 'application/json'
            },
            body: JSON.stringify({
                "correct": false
            })
        });

        const player = await response.json();
        await this.setState({
            isUpdating: false
        });
        this.props.onWrongAnswer(this.state.id, player.data);
    }

    render() {
        return (
            <Form onSubmit={this.onSubmit}>
                <Button type='submit' loading={this.state.isUpdating}>(-1) Wrong</Button>
            </Form>
        )
    }
});


You can refactor RightAnswerButton and WrongAnswerButton to remove the code duplication as an exercise. The application is complete at this point! You can register players, ask them questions and record their answers as right or wrong.

Learn More

Modern React with Redux

Become a JavaScript developer - Learn (React, Node,Angular)

The Complete React Web Developer Course (2nd Edition)

Node with React: Fullstack Web Development

Beginner Full Stack Web Development: HTML, CSS, React & Node

React JS and Redux - Mastering Web Apps

React 16 - The Complete Guide (incl. React Router 4 & Redux)

MERN Stack Front To Back: Full Stack React, Redux & Node.js

PHP with Laravel for beginners - Become a Master in Laravel

Laravel 5 Starter Course

Laravel for RESTful: Build Your RESTful API with Laravel

Ultimate Laravel Course 2018

Clear Cache in Laravel 6.8 App using Artisan Command Interface (CLI)

Clear Cache in Laravel 6.8 App using Artisan Command Interface (CLI)

In Laravel 6 tutorial, we learn how to use PHP artisan command interface (CLI) to clear the cache from Laravel 6.8 application. How To Clear Cache in Laravel 6.8 Application using Artisan Command Line Interface (CLI)? How to clear route cache using php artisan command? How to easily clear cache in Laravel application? How to clear config cache in PHP Laravel via artisan command? How to clear Laravel view cache? How to Reoptimized class in Laravel via artisan CLI?

Today in this tutorial, we are going to learn how to clear route cache, laravel application cache, config cache, view cache and reoptimized class in a Laravel 6.8 application using artisan command-line interface.

I’m pretty sure many of you may have found yourself gotten into the situation where you do not see changes in the view after making the changes in the app.

Laravel application serves the cached data so caching problem occurs due to the robust cache mechanism of Laravel.

But, if you are still facing this issue, then you do not have to worry further. Let me do the honour of introducing you some of the best artisan commands to remove the cache from your Laravel app via PHP artisan command line interface.

Artisan is the command-line interface included with Laravel. It provides a number of helpful commands that can assist you while you build your application.

Table of Contents

  • Clear Route Cache in Laravel
  • Clear Laravel Application Cache
  • Clear Config Cache via PHP Artisan
  • Clear Laravel View Cache
  • Reoptimized Class
Clear Route Cache in Laravel

Laravel caching system also takes routes in consideration, to remove route cache in Laravel use the given below command:

php artisan route:cache
Clear Application Cache in Laravel

Run the following command to clear application cache:

php artisan cache:clear
Clear Config Cache in Laravel

Run the following command to clear config cache:

php artisan config:cache
Clear View Cache in Laravel

Run the following command to clean your view cache:

php artisan view:clear
Reoptimize Class

Run the below command to reoptimize the class loader:

php artisan optimize

Conclusion

We have completed this Laravel 6 tutorial, In this tutorial we learned how to use php artisan command to clear the cache from your Laravel application. We have answered the following questions in this article.

  • How to clear route cache using php artisan command?
  • How to easily clear cache in Laravel application?
  • How to clear config cache in PHP Laravel via artisan command?
  • How to clear Laravel view cache?
  • How to Reoptimized class in Laravel via artisan CLI?

Now, it’s your time to let me know what do you think about this laravel 6 article. Go forth and try these super awesome artisan commands and let me know how these commands are helping you.

Get Weather Data with Laravel Weather

Get Weather Data with Laravel Weather

Get Weather Data with Laravel Weather. Laravel Weather is a good package which we can use to get weather data. It's a wrapper around Open Weather Map API (Current weather). A wrapper around Open Weather Map API (Current weather)

🌤️ A wrapper around Open Weather Map API (Current weather)

Installation

You can install the package via composer:

source-shell
composer require gnahotelsolutions/laravel-weather
Usage
text-html-php
$weather = new Weather();

// Checking weather by city name
$currentWeatherInGirona = $weather->get('girona,es');

// You can use the city id, this will get you unambiguous results
$currentWeatherInGirona = $weather->find('3121456');

Units

By default the package uses metric for Celsius temperature results, this can be modified using the configuration file or on the fly:

text-html-php
$weather = new Weather();

$currentWeatherInGirona = $weather->inUnits('imperial')->get('girona,es');

Language

By default the package uses es for the description translation, this can be modified using the configuration file or on the fly:

text-html-php
$weather = new Weather();

$currentWeatherInGirona = $weather->inLanguage('en')->get('girona');

Guzzle Client Instance

If you need to use another instance of Guzzle, to modify headers for example:

text-html-php
$weather = new Weather();

$guzzle = $this->getSpecialGuzzleClient();

$currentWeatherInGirona = $weather->using($guzzle)->get('girona');

Testing

source-shell
composer test

Laravel Sweet Alert | How to use the SweetAlert package in Laravel PHP

Laravel Sweet Alert | How to use the SweetAlert package in Laravel PHP

Sweet Alert is a laravel wrapper around #sweetalert javascript library for showing alert or notification message. This is a great package created by rashid, and this laravel package is very famous because it has tonnes of features you can choose from.

Sweet Alert is a laravel wrapper around #sweetalert javascript library for showing alert or notification message.

This is a great package created by rashid, and this laravel package is very famous because it has tonnes of features you can choose from.