Saturday, October 24, 2015

Yii2: RESTful api: tutorial

1. Install Yii2

Download, install and verify the installation of Yii2 (I'm using the advanced application template) .
Instructions: https://github.com/yiisoft/yii2-app-advanced/blob/master/docs/guide/start-installation.md

2. Folder structure

  • \
    • api
      • config
      • modules
        • v1
          • controllers
          • models
      • runtime
        • cache
        • debug
        • logs
      • web
    • backend
    • common
    • ...

3. Files

3.1 Add files

I copied the files from the backend directory and edited them afterwards. (Some files have been created manually)
  • \
    • api
      • config
        • main.php
        • main-local.php
        • params.php
        • params-local.php
      • modules
        • v1
          • controllers
            • ArtistController.php
          • models
            • Artist.php
        • Module.php
      • runtime
        • cache
        • debug
        • logs
      • web
        • .htaaccess
        • index.php
    • backend
    • common
    • ...

3.2 Edit files

\common\config\main-local.php

Configure the database correctly

\api\config\main.php
  • Change the id from 'app-backend' to 'app-api'
  • Remove the controllerNamespace
  • Change the modules to:
    'modules' => [
            'v1' => [
                'basePath' => '@app/modules/v1',
                'class' => 'api\modules\v1\Module'
            ]
        ],
  • Add the the components:
    'request' => [
     'parsers' => [
      'application/json' => 'yii\web\JsonParser',
     ]
    ],
    'urlManager' => [
     'enablePrettyUrl' => true,
     'enableStrictParsing' => true,
     'showScriptName' => false,
     'rules' => [
      [
       'class' => 'yii\rest\UrlRule', 
       'controller' => 'v1/artist',
       'tokens' => [
        '{id}' => '<id:\\w+>'
       ],
       'extraPatterns' => [
        // 'GET alive' => 'alive',
       ],
      ]
     ],        
    ]
\api\config\main-local.php
  • Change $config to $config = [];
\api\modules\v1\controllers\ArtistController.php

Change the file to:
<?php

namespace api\modules\v1\controllers;

use yii\rest\ActiveController;

/**
 * Artist Controller API
 *
 * @author Unknown
 */

class ArtistController extends ActiveController
{
    public $modelClass = 'api\modules\v1\models\Artist';

 // Default actions
 // GET /artists: list all artists
 // HEAD /artists: show the overview information of artist listing
 // POST /artists: create a new artist
 // GET /artists/AU: return the details of the artist AU
 // HEAD /artists/AU: show the overview information of artist AU
 // PATCH /artists/AU: update the artist AU
 // PUT /artists/AU: update the artist AU
 // DELETE /artists/AU: delete the artist AU
 // OPTIONS /artists: show the supported verbs regarding endpoint /artists
 // OPTIONS /artists/AU: show the supported verbs regarding endpoint /artists/AU.

 public function actions()
 {
        $actions = parent::actions();
 // Possibility to unset default actions
        // unset($actions['index']);
        return $actions;
 }

 // Define custom actions
 // public function actionAlive()
 // {
 //     return new ActiveDataProvider([
 //         'query' => Proxy::find()->where(['Alive' => 1]),
 //         'pagination' => false,
 //     ]);
 // }
}
\api\modules\v1\models\Artist.php

Use GII to generate your model.

Make sure that the use and the namespace is correct:

namespace api\modules\v1\models;

use \yii\db\ActiveRecord;

\api\modules\v1\Module.php

Change the file to:

<?php

namespace api\modules\v1;

class Module extends \yii\base\Module
{
    public $controllerNamespace = 'api\modules\v1\controllers';

    public function init()
    {
        parent::init();
    }
}

\api\web\.htaccess

Change the file to:

RewriteEngine On

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d

RewriteRule . index.php

\api\web\index.php

Change the file to:
<?php
defined('YII_DEBUG') or define('YII_DEBUG', true);
defined('YII_ENV') or define('YII_ENV', 'dev');

require(__DIR__ . '/../../vendor/autoload.php');
require(__DIR__ . '/../../vendor/yiisoft/yii2/Yii.php');
require(__DIR__ . '/../../common/config/bootstrap.php');

$config = yii\helpers\ArrayHelper::merge(
    require(__DIR__ . '/../../common/config/main.php'),
    require(__DIR__ . '/../../common/config/main-local.php'),
    require(__DIR__ . '/../config/main.php'),
    require(__DIR__ . '/../config/main-local.php')
);

$application = new yii\web\Application($config);
$application->run();
\common\bootstrap.php

Add to the file:

Yii::setAlias('api', dirname(dirname(__DIR__)) . '/api');

4. Test

Navigate to: http://localhost:8080/Music%20api/advanced/api/web/v1/artists

Expected result:
<response>
   <item>
      <Id>31</Id>
      <Name>Mampi Swift</Name>
   </item>
   <item>
      <Id>32</Id>
      <Name>Psion</Name>
   </item>
   <item>
      <Id>33</Id>
      <Name>Perfect Combination</Name>
   </item>
</response>

5. References

Saturday, December 20, 2014

Smashing Magazine wallpaper calendars

Today I created a tool to automatically receive the latest wallpaper calendars from Smashing Magazine.
The tool can be downloaded from here.
When you download the tool and extract the zip file there are 3 files available.

  1. HtmlAgilityPack.dll
  2. WallpaperCalendars.exe
  3. WallpaperCalendars.exe.config
In the configuration file there are a some interesting properties to set.
  • WallpaperFolder -> Folder where all the wallpapers will be placed.
  • Resolution1 >The first resolution that will be downloaded.
  • Resolution2 >If the first resolution isn't available, the second resolution will be downloaded.
  • Resolution3 >If the second resolution isn't available, the third resolution will be downloaded.
  • WithCalendar > Should the calendar be displayed on the wallpaper?
  • OnlyLatestWallpapers > Download only the latest wallpapers.
  • AskToClose > When everything is finished the application will stay open

Possible resolutions

  • 2560x1440
  • 1920x1440
  • 1920x1200
  • 1920x1080
  • 1680x1200
  • 1680x1050
  • 1600x1200
  • 1440x900
  • 1400x1050
  • 1280x1024
  • 1280x960
  • 1280x800
  • 1280x720
  • 1152x864
  • 1024x1024
  • 1024x768
  • 800x600
  • 800x480
  • 640x480
  • 320x480

Once you've configured the application to your needs you can test the application.When you run the application, the application will place the wallpapers from the latest month in the provided folder (WallpaperFolder).


I've created a scheduled task to automate the wallpaper updates. (How to create a scheduled task in windows 8)

Saturday, November 29, 2014

Table Naming Dilemma: Singular vs. Plural Names

Today I created a new database, but didn't know which table names I should use singular or plural ...
On my work we use plural names, when I studied it were singular names.

I was curious what I should use and after a little search I came across this post on Stack Overflow "Table Naming Dilemma: Singular vs. Plural Names [closed]".

The following reasons convinced me to use singular names (source):
  • Reason 1 (Concept). You can think of bag containing apples like "AppleBag", it doesn't matter if contains 0, 1 or a million apples, it is always the same bag. Tables are just that, containers, the table name must describe what it contains, no how much data it contains.

  • Reason 2. (Convenience). it is easier come out with singular names, than with plural ones. Objects can have irregular plurals or not plural at all, but will always have a singular one (with few exceptions like News).
    • Customer
    • Order
    • User
    • Status
    • News

  • Reason 3. (Aesthetic and Order). Specially in master-detail scenarios, this reads better, aligns better by name, and have more logical order (Master first, Detail second):
    1. Order
    2. OrderDetail
Compared to:
    1. OrderDetails
    2. Orders

  • Reason 4 (Simplicity). Put all together, Table Names, Primary Keys, Relationships, Entity Classes... is better to be aware of only one name (singular) instead of two (singular class, plural table, singular field, singular-plural master-detail...)
Customer
Customer.CustomerID
CustomerAddress
public Class Customer {...}
SELECT FROM Customer WHERE CustomerID = 100
Once you know you dealing with "Customer", you can be sure you will use the same word for all your database interaction needs.

  • Reason 5. (Globalization). The world is getting smaller, you may have a team of different nationalities, not everybody has English as native language. Would be easier for a non-native English language programmer to think of "Repository" than of "Repositories", or avoid them type "Statuses" instead of "Status". Having singular names can lead to less errors caused by typos, save time by avoid spending extra seconds to think "is it Child or Children?", hence improving productivity.

  • Reason 6. (Why not?). It can even save you writing time, save you disk space, and even make your computer keyboard lasts more!
SELECT Customer.CustomerName FROM Customer WHERE Customer.CustomerID = 100
SELECT Customers.CustomerName FROM Customers WHERE Customers.CustomerID = 100
You have saved 3 letters, 3 bytes, 3 extra keyboard hits :)

  • And finally, you can name those ones messing up with reserved names like:
User > LoginUser, AppUser, SystemUser, CMSUser,...
Or use the infamous squared brackets [User]

Wednesday, November 26, 2014

Headphone jack color code

Last week I fixed my headphone jack.
It wasn't easy to find which color from the cable needs to be connected to which part of the headphone jack.

Until I discovered a post about "Headphone wire color coding" on StackExchange.

What I learned from the post:

Red is for Right. Blue (or green) is for Left. Copper is for ground (I remember this with the mnemonic Red Right bLue Left Copper Common). All 3 are coated in a lacquer you need to burn or scrape off before you solder. With standard headphone plugs, with the plug facing away from you, the right pin is right, the center pin is ground, and the left pin is left.
  1. Common (or "ground")
  2. Right
  3. Left
  4. Insulating ring

Sunday, July 20, 2014

Invite all your friends to a Facebook event

The fastest way to select all your friends for a Facebook event is:
  1. Open a Facebook event
  2. Pretend to invite your friends, scroll to the bottom of your friendlist
  3. Press F12 (on your keyboard) in Chrome
  4. Go to the console tab in the new window
  5. Paste the following line:
    javascript:elms=document.getElementsByName("checkableitems[]");for (i=0;i<elms.length;i++){if (elms[i].type="checkbox" )elms[i].click()}; 
  6. All your friends are now selected
  7. Confirm the selection
  8. Done, all your friends are now invited.

Thursday, July 10, 2014

Implementing Singleton in C#

Today was the day I wanted to create a Singleton class.
I've did it many times before but couldn't remember which "template" I used before.

I started looking around and found which "template" I usually use.

I always used template 4 from the article Implementing the Singleton Pattern in C#.

Screenshot of template 4 with some information:

Sunday, May 4, 2014

How to download source code from code.google.com

Navigate to http://downloadsvn.codeplex.com/ and click the download button.
After clicking the download button, you will download a zip file, the zip file contains an executable.
Extract the zip file and execute the executable.

You will get a window like this:

What should we enter in the source URL?
For this example I'm going to use  the recaptcha project (https://code.google.com/p/recaptcha/).
By navigate to the source page (https://code.google.com/p/recaptcha/source/checkout), it will be clear which URL we have to use.
The URL we have to use is this one http://recaptcha.googlecode.com/svn/trunk/.

After filling in the source URL, we can define a folder where all the source files will be downloaded to.
When you chose a target folder we have to define the download type, to download from google code we have to set the type to "SVN"

Example with all the settings:

Once everything is filled in we can press the start button.
After completing the download you receive a notification on your screen:

When you navigate to the target folder you will see that all the downloaded files are available.

Have fun with the source code.