Skip to content

Tutorial

Richard DeSilvey edited this page Nov 27, 2018 · 6 revisions

Design Tutorial

Intro

Laravel in my opinion is a fantastic PHP framework for the backend of your software. I love Laravel and will always love it. Laravel follows the MVC (Model, view, controller) design pattern, however, I don't really enjoy the Blade template engine. It's a great engine but I prefer single-paged web applications. They feel more like actual software than a traditional web page (Must reload the browser for another resource or view).

I chose ReactJS as it's a fantastic framework for creating a template of HTML that adds state and properties to your components and allows you to remove code duplication in your application. I don't like code duplication and anything I find that is duplicated I remove it.

Of course implementing ReactJS to Laravel is trivial but can be tedious when you want a full working application without having to always set things up from the getgo. This template starts you out at square one with everything you need on the backend and the frontend. You just need Node Package Manager, Composer, and PHP installed on your development environment.

I recommend using XAMMP as a development server for this template. You'll notice that in your webpack.min.js file at the top you have two variables that are defined.

let AppName = 'PhatChat';
let AppRoot = 'htdocs';

These are used in a post-script after you build your frontend using npm run dev or npm run watch. htdocs is the naming scheme that XAMPP uses. Though if you use any other server you need not worry because you want to build your app.js file in the public directory when you deploy your application. (More on that later for the noobs). The post-script only runs when you run npm run dev this will copy everything in your public directory to htdocs. You can adjust this script to your liking though if you're more advanced. (webpack.min.js is in the root directory of this template, ~line 51 is where the copy happens).

The backend

I'm not going to go into full details with this but I setup Auth to match what is on the frontend. You can change how these forms look but the backend shouldn't need too much tweaking. Everything else though would be the same as you would expect for Laravel. Follow the design patterns Laravel uses and everything will workout great.

The frontend

This is where everything is, once you setup your backend you want to create a perfect frontend for your users. The frontend as mentioned above uses ReactJS and the Flux design pattern. You can remove everything and rebuild it for Redux but I like Flux as it is similar to MVC. Your Models are your Stores, your Views are your Components, and your Controllers are your Actions. Sorta. The location of the front end is resources/assets/js/

There are a couple classes I put in that I'll go over first.

  1. The Router
  2. The AppDispatcher
  3. The RenderManager

The Router

I setup the Router as a "Store" for your Routes. These routes are defined in the routes.js file. The names of your routes should follow the names of your Actions. I.e. why I said your Controllers are your like your Actions. For instance LOG_OUT is an action but it is also a route /logout. So your URL should match your Action since an Action is something the application needs to do, a Uniform Resource Locator is a way to do something, or find something.

First register your constants. For instance const GET_ADDRESS = 'get-address' You can use this to Identify your Action and Route. Register your route in routes.js at the root of the frontend. Next go into the directory actions and you'll find a file called ActionRepo.js. Include your actions here. If you don't the action won't be registered.

There are examples for Routes, Actions, Stores, and even Components for you to look at.

This project uses Axios as an HTTP service rather than Fetch (before it was used as a PoC) When you send a request you want to use the Router via request function. This function will prepare everything Axios needs to send an HTTP request. The function signature is Router.request(type, routeName, requestData, headers)

type is of course post get put etc. your routeName is what you used to register your route in routes.js. The requestData is slightly more tricky, you need to specify args and/or data here. Headers can remain empty unless you want your own headers. But be sure to always include the X-CSRF-TOKEN to your headers with Laravel. You can get the csrf token using the function getCSRF from the Router import. import { getCSRF } from './router.js'

When you register a route you have the following

Router.registerRoute(Constants.GET_EXAMPLE_MESSAGE, args => {
  return `/getExampleMessage/${args.id}`;
});

args injects into your URL the thing you need. Maybe an ID or whatever.

data is used in the body of your request. It's not part of the URI.

You can see here

return {
 method: type,
 url: this.partialRoute(routeName, requestData.args),
 headers: HEADERS,
 data: requestData.data
}

Axios allows you to defined the data that is being sent. Axios will "Stringify" this data and send it to the backend.

So the most complex Router.request you'll see is like the following...

Axios(Router.request('GET', GET_EXAMPLE_MESSAGE, {
  args: {id: payload.id}
  data: {
   message: 'hello'
  }
}))
.then(checkStatus)
.then(response => {
  ExampleStore.setExampleMessage(response.data.message);
  Actions.finish(payload);
}).catch(handleError);

The AppDispatcher

There really should only be one dispatcher for a single app. However if your app gets larger (Please wait as I want to be able to scale this Template to have multiple modules).

When you dispatch an action to the dispatcher you want to have the following

AppDispatcher.dispatch({
 action: <The constant that defines your Action i.e. GET_SOMETHING>
 something: data
 id: whatever
 emitOn: [{
  store: AStore,
  componentIds: [id1, id2, ... ]
 }, {
  store: BStore,
  componentIds: [id1, id2, ... ]
 }]
});

I made it so that you can emit on multiple stores and components. Normally you really only need to emit a change on one store and one component, maybe two components. Keep it simple and clean. But this allows you to do so. In many cases you shouldn't need to.

In order for emitOn to work you need to finish your action using Actions.finish(payload) in your action. Here is an example to remind you of that...

Actions.register(GET_EXAMPLE_MESSAGE, payload => {
  Axios(Router.request('GET', GET_EXAMPLE_MESSAGE, {
    args: {id: payload.id}
  }))
  .then(checkStatus)
  .then(response => {
    ExampleStore.setExampleMessage(response.data.message);
    Actions.finish(payload); // <--- FINISH YOUR ACTION, unless you don't want to emit a change on a Store(s)
  }).catch(handleError);
});

The RenderManager

This is a simple section. To remove the Blade template stuff I cleaned out each template-out-of-the-box to only return a simple div with an id that defines what it was. You can see these in each view. The RenderManager will only render what div Laravel serves up to the front end.

Most of the time you probably won't need to worry about this but it is in place to expand the Template to have multiple modules in the future.

To register a main component to be rendered you must supply the id of the div and the component that will be rendered in it. For example.

RenderManager.registerElement('app', <App />);

If the 'app' id is present in the DOM the component App will be rendered in it. This registering can be done in render.js.

You'll notice in the views directory the home view is same as the code below

@extends('layouts.app')

@section('content')
<div id='app'></div>
@endsection

This view is sent to the client, everything in the app layout will be used for each content section. here the 'app' div is present and the render manager will be able to find this div in the DOM.

Clone this wiki locally