MySQL: timezone

MySQL has system timezone, global timezone and session timezone (also call as per request timezone).

System timezone is current machine's timezone.
Global timezone and session timezone default value is system timezone.

When user insert a value to timestamp column (we call "date1"), MySQL suppose date1 as session timezone and convert to global timezone then save to DB.

When user select timestamp column, MySQL will convert from global timezone to session timezone than return value.

Docker behind proxy

Environment:

  • Window 10 Home
  • Docker toolbox
  • Proxy set in internet options

Problem:

  1. Docker can not pull images.
  2. Container can not connect to internet.

Solution:

To fix problem 1

Step1: remove your default machine
docker-machine rm default
Step2: recreate your default machine with proxy
docker-machine create -d virtualbox --engine-env HTTP_PROXY=http://your_proxy_url:your_proxy_port default
if that not working, you may try this option instead.
docker-machine create -d virtualbox \
    --engine-env HTTP_PROXY=http://example.com:8080 \
    --engine-env HTTPS_PROXY=https://example.com:8080 \
    --engine-env NO_PROXY=example2.com \
    default

To fix problem 2

Create or edit the file ~/.docker/config.json in the home directory of the user which starts containers.
{
 "proxies":
 {
   "default":
   {
     "httpProxy": "http://your_proxy_url:your_proxy_port"
   }
 }
}
Then restart ... computer and rebuild any thing.

Acceptance test with Codeception, Laravel ORM, Faker in Window

Let's say we have a website located at http://localhost:8080/

1. Install composer

Download and install composer for window https://getcomposer.org/download/.

2. Install php

If you already have php installed, go to next step.
To check if you already have php installed, open cmd and type php -v. If you have php installed, php version will show up.
Download php zip file from http://windows.php.net/download.
Unzip and put it somewhere you want, then add that folder path to system PATH like this:



Now you can check php version by type php -v in cmd.

3. Install laravel

Open cmd and go to folder that you want to put your test code to.
Tips: open folder by Window Explorer then type "cmd" in address bar, cmd will open and point to current folder.
Create project and install laravel by type:
composer create-project --prefer-dist laravel/laravel your-project-test
And cd to your-project-test folder in cmd.

4. Config database

If you using MySQL, make sure to enable pdo_mysql by uncomment extension=pdo_mysql line in php.ini file inside your php folder.

Open .env file and config your sql infomation, example:
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=database_name
DB_USERNAME=root
DB_PASSWORD=123456

5. Generate models from your existing database

Install reliese/laravel via composer:
composer require reliese/laravel --dev
Publish config file and clear cache:
php artisan vendor:publish --tag=reliese-models
php artisan config:clear
This will avoid "mkdir(): Invalid path" error
Open app/Providers/AppServiceProvider.php and register provider:
public function register()
{
    if ($this->app->environment() == 'local') {
        $this->app->register(\Reliese\Coders\CodersServiceProvider::class);
    }
}
Run this command to generate models:
php artisan code:models
Models will be generated in app/Models folder.
If you still got "mkdir(): Invalid path" error, try runing these command again and check if config/models.php file exists:
php artisan vendor:publish --tag=reliese-models  # this command will create config/models.php file
php artisan config:clear

6. Install Codeception

Download codecept.phar file from http://codeception.com/quickstart and put into your-project-test folder.

Init Codeception:
php codecept.phar bootstrap
All Codeception files generated in your-project-test/tests/ folder.
By default laravel already has a tests folder, if you do not use laravel default test file, delete tests folder before init codeception.

7. Config Codeception

Codeception use PHPBrowser by default, it very fast but does not have wait function to wait for javascript actions. So it better to use real browser.

To run codeception with real browser, for example with chrome we need to download selenium and chrome driver.

Download selenium from http://docs.seleniumhq.org/download/ (jar file) and put inside your-project-test.

Download chrome driver from https://sites.google.com/a/chromium.org/chromedriver/downloads (exe file) and put it to anywhere then set system PATH like to do with PHP.

Open test/acceptance.suite.yml file and add config:
actor: AcceptanceTester
modules:
    enabled:
        - WebDriver:
            url: http://localhost:8080/    # your website url
            browser: chrome
        - \Helper\Acceptance
        - Laravel5:    # this will load all laravel feature like: helper function (ex. dd()), Eloquent, factories ...
            part: ORM
            cleanup: false # can't wrap into transaction
Need to rebuild codeception after change config file:
php codecept.phar build

8. Define factories

For example with class app/Models/User.php:
Create factory file:
php artisan make:factory UserFactory
UserFactory.php file will be created in database/factories/ folder.
Define factory:
<?php

use Faker\Generator as Faker;

/*
|--------------------------------------------------------------------------
| Model Factories
|--------------------------------------------------------------------------
|
| This directory should contain each of the model factory definitions for
| your application. Factories provide a convenient way to generate new
| model instances for testing / seeding your application's database.
|
*/

$factory->define(App\User::class, function (Faker $faker) {
    return [
        'name' => $faker->name,
        'email' => $faker->unique()->safeEmail,
        'password' => '$2y$10$TKh8H1.PfQx37YgCzwiKb.KjNyWgaHb9cbcoQgdIVFlYg7B77UdFm', // secret
        'remember_token' => str_random(10),
    ];
});
Laravel auto created UserFactory by default.

9. Create acceptance test

php codecept.phar generate:cest acceptance Login
test/acceptance/LoginCest.php file will be created.

Write test:
<?php

use App\User;

class LoginCest
{
    public function _before(AcceptanceTester $I)
    {
    }

    public function _after(AcceptanceTester $I)
    {
    }

    // tests
    public function tryToTest(AcceptanceTester $I)
    {
        // use Eloquent example
        $user = User::first();

        // use factories example
        $user = factory(User::class)->make(); // make user object
        $user = factory(User::class)->create(); // make user object and insert to database

        // acceptance test example
        $I->amOnPage('/login');
        $I->fillField('username', 'davert');
        $I->fillField('password', 'qwerty');
        $I->click('LOGIN');
        $I->see('Welcome, Davert!');
    }
}

10. Run

Open cmd (point to your-project-test folder).
Start selenium server:
java -jar selenium-server-standalone-3.8.1.jar
Open other cmd and run:
php codecept.phar run

11. References

Internet Explorer: Your sites broken with compatibility view mode

Why compatibility view mode ?

Some old sites are created to work with old versions of IE. For example, your site only work with IE7, so if I open your site in IE11, I will get some issues (such as misaligned text, images, or text boxes, issues with scripts, and some crash situations)

To fix, I need to set your site in compatibility view list in my IE (Tools -> Compatibility View settings), IE will show your site using older IE versions (IE will detect which version suitable for your site), and make it work.

In other hands, if your site is created to work with latest IE version (IE11 for now), and for some reason, i was set your site in compatibility view list, it may get some issues also.

In this case, I need to remove your site from compatibility view list, IE will show your site using latest IE version by default.

How to fix automatically ?

As above, in both cases, you should set your default IE version for your site to work, by adding this meta tag to your pages. This tag must be placed before any other meta tags for it to work.
<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7"> <!-- to force it work with IE7 -->
or
<meta http-equiv="X-UA-Compatible" content="IE=edge" /> <!-- to force it work with latest IE version -->
If this tag was set, IE will show your site with point out IE version, and do not care if i set your site in compatibility view list or not.

If you would like to make this change throughout your site and do not want to edit every page edit your .htaccess file and add the below lines into that file.
# Emulate IE7 to prevent compatibility view
BrowserMatch "^.*MSIE 8.*$" emulate_ie7
Header set X-UA-Compatible "IE=EmulateIE7" env=emulate_ie7
or
# Emulate edgeto prevent compatibility view
BrowserMatch "^.*MSIE 8.*$" edge
Header set X-UA-Compatible "IE=edge" env=edge

npm: Understanding dependencies

1. dependencies

Suppose, you create a javascript package name your-package and release a your-package.js file.

And Bob (someone) want to use your-package.js in his project name bob-project. Then Bob install your-package via npm:
npm install your-package

But your-package.js required lodash 1.0.0 to work with.
'use strict';

var _ = require('lodash');

// call some lodash functions

so if Bob want to use your-package.js then he must have lodash 1.0.0 somewhere in bob-project.
And because of Bob only care about your-package.js, it painfull for Bob to install lodash 1.0.0 manually.

In this case, you should define lodash 1.0.0 as your-package dependency, inside package.json file:
"dependencies": {
  "lodash": "1.0.0"
}

# Note 1
You may need lodash 1.0.0 as well to run test. So you should install lodash via npm:
npm install lodash@1.0.0
npm will automaticlly add dependency lodash 1.0.0 to package.json file.

Now if Bob install your-package, npm automaticlly install lodash 1.0.0 along with it.
bob-project folder structure is like:
bob-project/
├──node_modules/
│  ├──your-package/
│  └──lodash/              # version 1.0.0
├──package-lock.json
└──package.json

# Note 2
If already have other version of lodash (ex 2.0.0) installed before Bob installing bob-project, folder struct will become:
bob-project/
├──node_modules/
│  ├──your-package/
│  │  └──node_modules/
│  │     └──lodash/        # version 1.0.0
│  └──lodash/              # version 2.0.0
├──package-lock.json
└──package.json
when execute require, nodejs will search modules from current folder first, if package can not be found nodejs will find package in parent folder an so on, so your-package.js will get lodash 1.0.0, separate with lodash 2.0.0. Everything still work!

2. devDependencies

To create your-package you may need some task-runner like gulp, for example to concat all js file into one. So you install gulp via npm:
npm install gulp

By this way (# Note 1 above), npm will add gulp to dependencies, and Bob will get automaticlly install gulp that he does not need to run your-package.js.

In this case, you should define gulp as "devDependencies" by install gulp with --save-dev:
npm install gulp --save-dev
your package.json will be like:
"dependencies": {
  "lodash": "1.0.0"
},
"devDependencies": {
  "gulp": "^3.9.1"
},

Now when Bob install your-package, npm does not care about "devDependencies" and Bob only get lodash be installed.

3. peerDependencies

If your-package actually is a grunt plugin for example, your-package.js file will be like:
'use strict';

var _ = require('lodash');

module.exports = (grunt) => {

  // call some lodash functions

  // use grunt instance to do some small stuff to support main grunt function
}
Without require('grunt'), it's using host grunt package instance (the package installed in bob-project). That mean your-package still need grunt for running, and like "1. dependencies" above it may need to automaticlly install grunt as dependencies.

But, because of your-package is a grunt plugin so maybe Bob has already installed other version of grunt in bob-project, therefore a version of grunt will be automaticlly installed inside your-package folder structure (# Note 2) and would never be used, that is not good.

So your-package should not automaticlly install grunt. By this way you need to tell Bob (when he's installing your-package) that he need grunt for your-package, moreover which version of grunt that your-package can run with. To do this, you need peerDependencies!

You define grunt as peerDependencies like this:
"dependencies": {
  "lodash": "1.0.0"
},
"devDependencies": {
  "gulp": "^3.9.1"
},
"peerDependencies": {
  "grunt": "0.4.2"        # suppose that your-package only work with 0.4.2
},
Now when Bob install your-package, he will get a warning that he need to manually install grunt 0.4.2.

Yes, peerDependencies is just for giving warnings, nothing else!

Event if your-package using direct dependency like lodash 1.0.0 (1.0.0 is lasted version of lodash when you create your-package). But now lodash release 2.0.0 with many great features, using your-package with lodash 2.0.0 would great, and you too lazy to test and update your-package. In this case, you would consider to define lodash in peerDependencies like this:
"dependencies": {
},
"devDependencies": {
  "gulp": "^3.9.1"
},
"peerDependencies": {
  "grunt": "0.4.2"        # suppose that your-package only work with 0.4.2
  "lodash": ">=1.0.0"     # 1.0.0 or newer
},
Now when Bob install your-package, he just manually install lodash 2.0.0 to work with.

Why not define direct dependency to automaticlly install lodash 2.0.0 like this ?:
"dependencies": {
  "lodash": ">=1.0.0"     # 1.0.0 or newer
},
"devDependencies": {
  "gulp": "^3.9.1"
},
"peerDependencies": {
  "grunt": "0.4.2"        # suppose that your-package only work with 0.4.2
},
Because in case of your-package can not work with lodash 2.0.0 due to removed APIs (you can not test in time when lodash 2.0.0 release), your-package in bob-project will brocken.
If you using peerDependencies, after manually installed lodash 2.0.0 and realize that issues, Bob can rollback to lodash 1.0.0 to make your-package work. Fine!

# Preferences

# Peer Dependencies
# Understanding the npm dependency model
# Why use peer dependencies in npm for plugins?
# Semantic Versioning
# Specifics of npm's package.json handling
# Requiring modules in Node.js: Everything you need to know

Linux: Download and install compressed package

1. Download package

Open terminal and run follow command:
wget url_of_compressed_file

2. Extract file

If it's tar.gz use
tar xvzf file_name.tar.gz

If it's a tar.bz2 use
tar xvjf file_name.tar.bz2

3. Go to extracted folder and run follow command

./configure
make
sudo make install

Setup lumen using homestead on OSX

1. Downloading and installing VirtualBox manually

https://www.virtualbox.org/wiki/Downloads

2. Downloading and installing Vagrant manually

https://www.vagrantup.com/downloads.html

3. Installing The Homestead Vagrant Box

$vagrant box add laravel/homestead
This is a virtual machine image that runs the operating system.

4. Installing Homebrew (global)

https://brew.sh/

5. Installing Composer via Homebrew (global)

$brew install composer
open ~/.zshrc (if using zsh, or whatever bash profile file we using) and add this to end of file:
export PATH="$PATH:$HOME/.composer/vendor/bin"
we need to reopen terminal.

6. Installing Lumen installer (global)

$composer global require "laravel/lumen-installer"

7. Create new Lumen project

$lumen new NEW_PROJECT

8. Installing Homestead (local)

Go to NEW_PROJECT folder and run this command:
$composer require "laravel/homestead"
This is configurations repo which are used when running homestead virtual machine image.

init Homestead
$php vendor/bin/homestead make
Homestead.yaml will be created like below:
ip: 192.168.10.10
memory: 2048
cpus: 1
provider: virtualbox
authorize: ~/.ssh/id_rsa.pub
keys:
    - ~/.ssh/id_rsa
folders:
    -
        map: #your new project dir
        to: /home/vagrant/code
sites:
    -
        map: homestead.test
        to: /home/vagrant/code/public
databases:
    - homestead
name: NEW_PROJECT
hostname: NEW_PROJECT

9. Config

Add this line to host file /etc/hosts
192.168.10.10 homestead.test

10. Run

Start virtual machine
$vagrant up
and access via browser
http://homestead.test/