Monday, 30 January 2017

PHP Traits to ease dependency injection

In proramming larger applications, the DIP (Dependency inversion Pattern) is an important tool in keeping maintenance to a minimum; Munir Hassan for Codeproject has a great article that covers the topic Dependency Inversion Principle and the Dependency Injection Pattern. When we couple modules too tightly without abstraction layers or interfaces, maintenance costs go up greatly. The Codeproject article above has saved me a lot of time, and when I read about PHP Traits a while back I realised that it can be used to make this even easier.

What is a PHP Trait?

A trait is a class-like structure in PHP that many call "language assisted copy and paste". It basically means that when you import a Trait into a Class all the properties and methods defined in the Trait get copy/pasted into your Class at runtime by the PHP interpreter. Take the following example:

Without traits

<?php
  class User {

    private $connection;

    public function __construct(ConnectionInterface $connection) {
      $this->setConnection($connection);
    }

    private function setConnection(ConnectionInterface $connection) {
      $this->connection = $connection;
    }

    public function getConnection(): ConnectionInterface {
      return $this->connection;
    }

  };
?>
The above seems fine (except for the possibility of getConnection() failing if it's not set, we'll worry about that at another time), it uses a form of constructor injection to make sure the User class knows as little as possible about the Connection class. This does however create the issue where, let's say, another class (Product) now also needs a connection, now we'll have the following code too:
<?php
  class Product {

    private $connection;

    public function __construct(ConnectionInterface $connection) {
      $this->setConnection($connection);
    }

    private function setConnection(ConnectionInterface $connection) {
      $this->connection = $connection;
    }

    public function getConnection(): ConnectionInterface {
      return $this->connection;
    }

  };
?>

With traits

These two classes also have other methods and properties, but the imprtant thing to note here is that both of these now use the exact same code to set and get it's connection implementations. We can simplify this process by using a connection trait. Below is the trait we are going to use in both classes:
<?php
  trait connectionTrait {

    private $connection;

    private function setConnection(ConnectionInterface $connection) {
      $this->connection = $connection;
    }

    public function getConnection(): ConnectionInterface {
      return $this->connection;
    }

  };
?>
Now we can use our new trait in both our classes instead of re-defining the code in both classes, let's have a look at the new User class with the Trait imported/applied:
<?php
  use Connection\ConnectionInterface;
  class User {

    use \Connection\ConnectionTrait;

    public function __construct(ConnectionInterface $connection) {
      $this->setConnection($connection);
    }

  };
?>

Conclusion

In the last example our User class now imports the Trait which adds the private $connection property to our class. It also adds the setconnection() and getConnection() methods to our User class at runtime. This way we both save lines of code and we ensure that if the connection trait ever needs to change we can easily apply this change through all classes that use it.

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
/>

Saturday, 15 October 2016

Creating a VirtualHost in Apache 2.4

What is a VirualHost?

In apache a VirtualHost is a way to host multiple websites on a single apache instance. If you're a developer that works on more than one website this is the best way to test all those websites on one machine.
Creating a VirtualHost
Creating a VirtualHost is simple, we can achieve this in four easy steps. In the following example we will be creating a VirtualHost named "website.demo":

  1. Create the VirtualHost file
    sudo nano /etc/apache2/sites-available/website.demo.conf
    <VirtualHost *:80>
      DocumentRoot /home/username/Software/website
      ServerName website.demo
    </virtualhost>
  2. Create the hosts file entry
    $ sudo nano /etc/hosts
    127.0.0.1    website.demo
  3. Enable the new VirtualHost
    $ a2ensite website.demo
  4. Restart Apache
    $ sudo service apache2 restart
Now you can go to http://website.demo and you website (which is located at /home/username/Software/website) will be there.

The VirtualHost file

The VirtualHost file (/etc/apache2/sites-available/website.demo.conf) is loaded by apache on startup and serves website.demo on port 80 which means you can visit it via your web browser.
The DocumentRoot entry tells apache where the files for this VirtualHost are located. The ServerName entry tells apache what name to serve the website as.

a2ensite and a2dissite

a2ensite enables a VirtualHost inside your sites-available folder by creating a symbolic link to it from the sites-enabled folder (which apache loads during startup). a2dissite disables a VirtualHost by removing the symbolic link created by a2ensite.

And that's it, you should now be able to create your own VirtualHosts easily.