Wednesday, 9 November 2016

PHP Interfaces

When building multiple PHP classes that are interchangeable - for instance two user classes where one reads from a MySql database and one from a JSON file - it is crucial that these classes do not diverge in functionality; If you add a 'getUserInfo' method to the one, you have to add it to the other, chances are you are using a factory to instantiate your objects and would thus expect to be able to use them in exactly the same manner. An interface solves this problem.
An interface provides a set of rules that determine the shape of the class that implements this interface. In the above example the interface will enforce the existence of a 'getUserInfo' method in both the UserMySql and UserJSON classes.

Building an interface

Let's build an interface for the example above. A user class that fetches it's data from a MySql database, and a user class reads from a JSON file. These must both contain public 'create', 'read', 'update' and 'delete' methods.
interface.account.php
<?php
interface Account {
  public function create(string $name, string $email);
  public function delete();
  public function read(int $id);
  public function update(string $name, string $email);
}
?>
class.user.json.php
<?php
class UserJSON implements Account {
  public $id;
  public $name;
  public $email;
  public function create(string $name, string $email) {
    // insert into JSON file
  }
  public function delete() {
    // delete user with {$this->id}
  }
  public function read(int $id) {
    // read user from {$id}.json
  }
  public function update(string $name, string $email) {
    // update user with {$this->id}
  }
  public function doesSomethingElse () {
    // do something else
  }
  private function doesSomethingDifferent () {
    // do something different (and private)
  }
}
?>
class.user.mysql.php
<?php
class UserJSON implements Account {
  public $id;
  public $name;
  public $email;
  public function create(string $name, string $email) {
    // insert into JSON file
  }
  public function delete() {
    // delete user with {$this->id}
  }
  public function read(int $id) {
    // read user from {$id}.json
  }
  public function update(string $name, string $email) {
    // update user with {$this->id}
  }
}
?>
The interface and two classes above will work together well and the interface will keep the classes aligned properly. If either of these classes do no conform to the shape provided in the interface PHP will throw an error thus indicating that the class does not conform.

Sunday, 6 November 2016

Nesting unit tests in karma/jasmine with a higher order function

Unit tests are incredibly important, but sometimes test suites become difficult to read because the tests are not properly nested and now you are seeing 600 tests in a single line; Nesting them can also be quite tedious; Even though karma and jasmine nests test cases together with the same name, redefining a list of 'groups' in each test can be a bit difficult to maintain. We can solve this problem with a higher-order-function that accepts the entire grouping as an array.

The higher order function

The code for the higher order function (which we will call 'hofDescribe' from now on) is nothing too large or difficult, let's take a look:
/app/test/index.js
const hofDescribe = (groups, test) => {
  groups.reverse().reduce((previousTest, group) => (
    () => describe(`.${group}`, previousTest)
  ), test)();
};

export default hofDescribe;
hofDescribe take in an array of groups and the test (a function that returns a 'describe' block). It then nests the describes from the bottom up (from the deepest nested node/describe to the top root node/describe). It starts by reversing the array to have the bottom node first and passes the test given to hofDescribe as the test for the bottom node, and then returns a new describe to each parent until it reaches the top.

Putting it to use

Using hofDescribe is simple, lets 'test' three files and create a small test hiearchy. We will be testing one React component and two redux reducers.
/app/test/reducers/layout/size.js
import hofDescribe from 'test';

hofDescribe(['REDUCERS', 'Layout', 'Size'], () => describe('{ app.layout.size }', () => {
  it('Does something', () => {});
  it('Does something else even better', () => {});
}));
/app/test/reducers/layout/color.js
import hofDescribe from 'test';

hofDescribe(['REDUCERS', 'Layout', 'Color'], () => describe('{ app.layout.color }', () => {
  it('Does something', () => {});
  it('Does something else even better', () => {});
}));
/app/test/components/layout/shared/link.jsx
import hofDescribe from 'test';

hofDescribe(['COMPONENTS', 'Account'], () => describe('<Avatar />', () => {
  it('Does something', () => {});
  it('Does something else even better', () => {});
}));
The output from a test suite like this would give you a proper structured tree that makes much more sense:
.COMPONENTS
  .Account
    <Avatar />
      ✓ Does something
      ✓ Does something else even better

.REDUCERS
  .Layout
    .Color
      { app.layout.color }
        ✓ Does something
        ✓ Does something else even better
    .Size
      { app.layout.size }
        ✓ Does something
        ✓ Does something else even better

Using react-flexbox-grid in your react application

react-flexbox-grid is a great grid component layout library built for React, based on flexbox-grid.

Installation and setup

To install react-flexbox-grid, simply install it via npm:
$ npm install --save-dev react-flexbox-grid
To set it up with your webpack config you can add the following code to your webpack configuration file:
webpack.config.js
module.exports = {
  ...
  module: {
    loaders: [
      {
        test: /\.s?css$/,
        loaders: [
          'style-loader',
          'css-loader?modules&importLoaders=1&localIdentName=[name]-[local]___[hash:base64:5]',
          'sass-loader',
        ],
        include: /node_modules\/(react-toolbox|flexboxgrid)/,
      }
    ],
  },
  ...
};
The setup above is used for react-flexbox-grid and for react-toolbox, if you are not using react-toolbox you can just remove that piece from the configuration above.

Usage

To use react-flexbox-grid in your project you need to import the components you want to use (Grid, Row or Column), and use them just like you would any other React component.
/app/my-new-component.jsx
import { Grid, Row, Col } from 'react-flexbox-grid/lib/index';

const MyNewComponent = () => (
  <Grid className="my-new-component">
    <Row>
      <Col xs={12} sm={6} md={4} lg={3}>Column content here</Col>
      <Col xs={12} sm={6} md={4} lg={3}>Column content here</Col>
      <Col xs={12} sm={6} md={4} lg={3}>Column content here</Col>
    </Row>
  </Grid>
);

export default MyNewComponent;
For the full list of settings and features, have a look at the react-flexbox-grid website and Github page:
react-flexbox-grid website: http://roylee0704.github.io/react-flexbox-grid/
react-flexbox-grid GitHub: https://github.com/roylee0704/react-flexbox-grid

Friday, 4 November 2016

Splitting React Redux reducers into multiple files

Using redux for state management of your application is a really great and light way of having a single source of truth for your application; The problem is that sometimes reducers just become too big to maintain. Luckily we have the ability to split these up into smaller, more dedicated reducers with ES6 import/export and Redux's combineReducers method. Let's have a look.

Building the store

Install redux and react-redux packages.
$ npm i -D redux react-redux
We need to create the store and create the method to configure the store. Let's have a look at the store configuration method first:
/app/store/configureStore/index.js
import { compose, createStore } from 'redux';

import reducer from 'reducer';

const configureStore = (params = {}) => {
  const { initialState } = params;
  const store = createStore(
    reducer,
    initialState,
    compose(
      window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__(),
    ),
  );
};

export default configureStore;
/app/store/index.js
import configureStore from './configureStore';

export const store = configureStore();
Now you can add your store to the store provider provided by react-redux.
/app/root/index.jsx
import React from 'react';
import { Provider } from 'react-redux';

const App = () => (
  <Provider store="{store}">
    <h1>App content here</h1>
  </provider>
);

export default App;

State and file structure

For this example we will be working towards creating a state that looks something like the following:
{
  app: {
    account: {
      name: '',
      email: '',
    },
    products: {
      data: [
        { id: 1, name: '', favourite: false },
        { id: 2, name: '', favourite: false },
      ],
      settings: {
        layout: 'grid',
      }
    },
  },
}
The file structure will very closely resemble out state tree:
app
--account
----actions.js
----index.js
--products
----data
------index.js
------product
--------actions.js
--------index.js
----settings
------actions.js
------index.js

Creating the reducers

We will be creating a reducer for each 'node' in our state (each key in our state object). Let's start by creating the top level 'app' node in the main reducer file, which is being passed to the 'configureStore' method described above.
/app/reducers/index.js
import { combineReducers } from 'redux';

import app from './app';

const reducer = combineReducers({
  app,
});

export default reducer;
Now we will build the 'app' reducer which will add the 'account' and 'products' nodes. Because the 'app' node contains more sub-nodes ('account' and 'products') the app reducer should only be concerned with combining the reducers for each sub-node, this will look like follows:
/app/reducers/app.js
import { combineReducers } from 'redux';

import account from './account';
import products from './products';

const app = combineReducers({
  account,
  products,
});

export default app;
The next reducer - the one for the 'account' node - will contain some logic to perform actions. We will split it up into two files, the reducer, and the actions. Let's build the actions file first:
/app/reducers/account/actions.js
export const ACCOUNT_CHANGE_NAME = 'ACCOUNT_CHANGE_NAME';

export const accountChangeName = name => ({
  type: ACCOUNT_CHANGE_NAME,
  name
});
Now the reducer:
/app/reducers/account/index.js
import { ACCOUNT_CHANGE_NAME } from './actions';
export const defaultState = {
  name: '',
  email: '',
};

const account = (state = defaultState, action = {}) => {
  switch (action.type) {
    case ACCOUNT_CHANGE_NAME:
      return {
        ...state,
        name: action.name,
      };
    default:
      return state;
  };
};

export default account;
The next node - 'products' - is another reducer that combines to sub-reducers for it's two sub-nodes, 'data' and 'settings', so it looks almost identical to the 'app' node's reducer. The 'settings' node's reducer will look almost identical to the 'account' node's reducer. The 'data' node returns an array of 'product' nodes. Let's build a reducer for the 'data' node and for each 'product' sub-node:
/app/reducers/products/data/index.js
import productReducer from './product';

const defaultState = [];

const data = (state = defaultState, action = {}) => {
  return [ ...state.map(product => productReducer(product, action)) ];
};

export default data;
The product reducer would then need actions and a reducer, let's build the actions first:
/app/reducers/products/data/product/actions.js
export const PRODUCT_ADD_TO_FAVOURITES = 'PRODUCT_ADD_TO_FAVOURITES';

export const productAddToFavourites = id => ({
  type: PRODUCT_ADD_TO_FAVOURITES,
  id,
});
/app/reducers/products/data/product/index.js
import { PRODUCT_ADD_TO_FAVOURITES } from './actions';

export const defaultState = {
  id: 0,
  name: '',
  favourite: false,
};

const productReducer = (state = defaultState, action = {}) => {
  switch (action.type) {
    case PRODUCT_ADD_TO_FAVOURITES:
      return {
        ...state,
        favourite: state.id === action.id ? !state.favourite : state.favourite,
      };
  };
};

export default productReducer;
Now we have split our reducer into many smaller, more maintainable - and testable - chunks.

Thursday, 3 November 2016

Adding react-toolbox to your React project

Installing react-toolbox

install the react-toolbox package via npm:
$ npm install react-toolbox --save-dev

Setting up the (s)css loader In webpack

you will need to add loaders for the react-toolbox stylesheets. This took me quite a while to figure out, hopefully someone finds it useful :).
webpack.config.js
module.exports = {
  ...
  module: {
    loaders: [
      ...
      {
        test: /\.s?css$/,
        loaders: ['style-loader', 'css-loader', 'sass-loader'],
        exclude: /node_modules/,
      },
      {
        test: /\.s?css$/,
        loaders: [
          'style-loader',
          'css-loader?modules&importLoaders=1&localIdentName=[name]-[local]___[hash:base64:5]',
          'sass-loader',
        ],
        include: /node_modules\/(react-toolbox|flexboxgrid)/,
      },
      ...
    ],
  },
  ...
};

Customizing the style variables

The default colors/layout/typography might not be right for you but luckily they are customizable, to change any of the variables you can create your own variables file and place some custom ones for your site:
/app/variables.scss
$my-app-color-white: rgb(255, 255, 255);
$my-app-color-black: rgb(0, 0, 0);
$my-app-color-dull: rgb(120, 120, 120);
$color-background: $my-app-color-white !default;
$color-text: $my-app-color-black !default;
$color-text-secondary: $my-app-color-dull !default;
This file can now be loaded via your webpack config
webpack.config.js
module.exports = {
  ...
  sassLoader: {
    data: `@import "${path.resolve(__dirname, 'app/variables.scss')}";`,
  },
  ...
}
You can find a full list of colors and globals at the following urls:
Colors: https://github.com/react-toolbox/react-toolbox/blob/dev/lib/_colors.scss
Globals: https://github.com/react-toolbox/react-toolbox/blob/dev/lib/_globals.scss
You can also set variables for each component, have a look in the lib folder on the react-toolbox GitHub repository:
lib folder: https://github.com/react-toolbox/react-toolbox/tree/dev/lib
GitHub: https://github.com/react-toolbox/react-toolbox

Using the components

Now the components can be imported into your react project and used alongside your own custom components
/app/custom-component.jsx
...
import { Button } from 'react-toolbox/lib/button';
...
<Button
  type="submit"
  icon="person"
  label="Login"
  raised
  primary
/>