diff --git a/.gitignore b/.gitignore index 57f6f89c9..c6fa3e1f8 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,6 @@ /vendor/ _build/ *.mo +.vagrant/ +phpunit.xml +composer.phar diff --git a/.travis.yml b/.travis.yml index 9f379f8b0..e2111642b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,18 +3,7 @@ language: php sudo: false php: - - 5.3 - - 5.4 - - 5.5 - - 5.6 - 7.0 - - hhvm - -matrix: - allow_failures: - - php: hhvm - - php: 7.0 - fast_finish: true cache: directories: diff --git a/Creational/FactoryMethod/Bicycle.php b/Creational/FactoryMethod/Bicycle.php index 01fa8a0a3..6bb4ace8d 100644 --- a/Creational/FactoryMethod/Bicycle.php +++ b/Creational/FactoryMethod/Bicycle.php @@ -1,9 +1,11 @@ color = $rgb; } diff --git a/Creational/FactoryMethod/FactoryMethod.php b/Creational/FactoryMethod/FactoryMethod.php index dd24b1565..cf161b886 100644 --- a/Creational/FactoryMethod/FactoryMethod.php +++ b/Creational/FactoryMethod/FactoryMethod.php @@ -1,26 +1,25 @@ 'Cheap', + 2 => 'Fast', + ]; /** * Creates a new vehicle @@ -29,11 +28,22 @@ abstract protected function createVehicle($type); * * @return VehicleInterface a new vehicle */ - public function create($type) + public function create(int $type) : VehicleInterface { $obj = $this->createVehicle($type); $obj->setColor("#f00"); return $obj; } + + /** + * The children of the class must implement this method + * + * Sometimes this method can be public to get "raw" object + * + * @param int $type a generic type + * + * @return VehicleInterface a new vehicle + */ + abstract protected function createVehicle(int $type) : VehicleInterface; } diff --git a/Creational/FactoryMethod/Ferrari.php b/Creational/FactoryMethod/Ferrari.php index c905f918e..5786224c2 100644 --- a/Creational/FactoryMethod/Ferrari.php +++ b/Creational/FactoryMethod/Ferrari.php @@ -1,9 +1,11 @@ color = $rgb; } diff --git a/Creational/FactoryMethod/GermanFactory.php b/Creational/FactoryMethod/GermanFactory.php index 67306e9aa..006cb1093 100644 --- a/Creational/FactoryMethod/GermanFactory.php +++ b/Creational/FactoryMethod/GermanFactory.php @@ -1,16 +1,18 @@ color = $rgb; } diff --git a/Creational/FactoryMethod/Tests/FactoryMethodTest.php b/Creational/FactoryMethod/Tests/FactoryMethodTest.php index acbe0c648..5313239fd 100644 --- a/Creational/FactoryMethod/Tests/FactoryMethodTest.php +++ b/Creational/FactoryMethod/Tests/FactoryMethodTest.php @@ -1,4 +1,5 @@ type as $oneType) { - $vehicle = $shop->create($oneType); - $this->assertInstanceOf('DesignPatterns\Creational\FactoryMethod\VehicleInterface', $vehicle); + foreach ($this->type as $type) { + $this->assertInstanceOf( + 'DesignPatterns\Creational\FactoryMethod\VehicleInterface', + $shop->create($type) + ); } } /** - * @dataProvider getShop + * @dataProvider getShop * @expectedException \InvalidArgumentException - * @expectedExceptionMessage spaceship is not a valid vehicle + * @expectedExceptionMessage Not a valid vehicle, vehicles allowed: Cheap, Fast */ public function testUnknownType(FactoryMethod $shop) { - $shop->create('spaceship'); + $shop->create(self::UNKNOWN); } } diff --git a/Creational/FactoryMethod/VehicleInterface.php b/Creational/FactoryMethod/VehicleInterface.php index a734b612f..59e2382d5 100644 --- a/Creational/FactoryMethod/VehicleInterface.php +++ b/Creational/FactoryMethod/VehicleInterface.php @@ -1,9 +1,11 @@ title; } diff --git a/Creational/Prototype/FooBookPrototype.php b/Creational/Prototype/FooBookPrototype.php index 9707bfd42..358c0d282 100644 --- a/Creational/Prototype/FooBookPrototype.php +++ b/Creational/Prototype/FooBookPrototype.php @@ -1,16 +1,20 @@ fooBookPrototype = new FooBookPrototype(); + $this->barBookPrototype = new BarBookPrototype(); + } + + public function testCloneOfFooBookPrototype() + { + for ($i = 0; $i < 100; $i++) { + $book = clone $this->fooBookPrototype; + + $this->assertInstanceOf('DesignPatterns\Creational\Prototype\FooBookPrototype', $book); + $this->assertNotSame($this->fooBookPrototype, $book); + } + } + + public function testCloneOfBarBookPrototype() + { + for ($i = 0; $i < 100; $i++) { + $book = clone $this->barBookPrototype; + + $this->assertInstanceOf('DesignPatterns\Creational\Prototype\BarBookPrototype', $book); + $this->assertNotSame($this->barBookPrototype, $book); + } + } +} diff --git a/Creational/Prototype/index.php b/Creational/Prototype/index.php deleted file mode 100644 index f268e5c60..000000000 --- a/Creational/Prototype/index.php +++ /dev/null @@ -1,17 +0,0 @@ -setTitle('Foo Book No ' . $i); -} - -for ($i = 0; $i < 5000; $i++) { - $book = clone $barPrototype; - $book->setTitle('Bar Book No ' . $i); -} diff --git a/Creational/SimpleFactory/Bicycle.php b/Creational/SimpleFactory/Bicycle.php index 67215f185..f4e20512f 100644 --- a/Creational/SimpleFactory/Bicycle.php +++ b/Creational/SimpleFactory/Bicycle.php @@ -1,18 +1,20 @@ typeList = array( + $this->typeList = [ 'bicycle' => __NAMESPACE__ . '\Bicycle', - 'other' => __NAMESPACE__ . '\Scooter' - ); + 'other' => __NAMESPACE__ . '\Scooter', + ]; } /** @@ -32,13 +34,12 @@ public function __construct() * @return VehicleInterface a new instance of VehicleInterface * @throws \InvalidArgumentException */ - public function createVehicle($type) + public function createVehicle(string $type) : VehicleInterface { if (!array_key_exists($type, $this->typeList)) { - throw new \InvalidArgumentException("$type is not valid vehicle"); + throw new \InvalidArgumentException($type . ' is not valid vehicle'); } - $className = $this->typeList[$type]; - return new $className(); + return new $this->typeList[ $type ](); } } diff --git a/Creational/SimpleFactory/DestinationInterface.php b/Creational/SimpleFactory/DestinationInterface.php new file mode 100644 index 000000000..90d7a00b0 --- /dev/null +++ b/Creational/SimpleFactory/DestinationInterface.php @@ -0,0 +1,12 @@ +factory = new ConcreteFactory(); + return [ + ['bicycle'], + ['other'], + ]; } - public function getType() + protected function setUp() { - return array( - array('bicycle'), - array('other') - ); + $this->factory = new ConcreteFactory(); } /** diff --git a/Creational/SimpleFactory/VehicleInterface.php b/Creational/SimpleFactory/VehicleInterface.php index eb13a6689..42df9b1a9 100644 --- a/Creational/SimpleFactory/VehicleInterface.php +++ b/Creational/SimpleFactory/VehicleInterface.php @@ -1,16 +1,18 @@ global => evil * Note2: Cannot be subclassed or mock-upped or have multiple different instances + * + * @package DesignPatterns\Creational\StaticFactory */ class StaticFactory { @@ -18,7 +23,7 @@ class StaticFactory * @throws \InvalidArgumentException * @return FormatterInterface */ - public static function factory($type) + public static function factory(string $type) : FormatterInterface { $className = __NAMESPACE__ . '\Format' . ucfirst($type); diff --git a/Creational/StaticFactory/Tests/StaticFactoryTest.php b/Creational/StaticFactory/Tests/StaticFactoryTest.php index f0304ca93..4032368a6 100644 --- a/Creational/StaticFactory/Tests/StaticFactoryTest.php +++ b/Creational/StaticFactory/Tests/StaticFactoryTest.php @@ -1,22 +1,26 @@ assertTrue(is_subclass_of($className, $interfaceName)); } - /** - * Second key-point of this pattern : the decorator is type-hinted - * - * @expectedException \PHPUnit_Framework_Error - */ - public function testDecoratorTypeHinted() - { - $this->getMockForAbstractClass('DesignPatterns\Structural\Decorator\Decorator', array(new \stdClass())); - } - /** * The decorator implements and wraps the same interface */ diff --git a/Vagrantfile b/Vagrantfile new file mode 100755 index 000000000..30f924c46 --- /dev/null +++ b/Vagrantfile @@ -0,0 +1,59 @@ +################################################## +# Generated by phansible.com +################################################## + +#If your Vagrant version is lower than 1.5, you can still use this provisioning +#by commenting or removing the line below and providing the config.vm.box_url parameter, +#if it's not already defined in this Vagrantfile. Keep in mind that you won't be able +#to use the Vagrant Cloud and other newer Vagrant features. +Vagrant.require_version ">= 1.5" + +# Check to determine whether we're on a windows or linux/os-x host, +# later on we use this to launch ansible in the supported way +# source: https://stackoverflow.com/questions/2108727/which-in-ruby-checking-if-program-exists-in-path-from-ruby +def which(cmd) + exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : [''] + ENV['PATH'].split(File::PATH_SEPARATOR).each do |path| + exts.each { |ext| + exe = File.join(path, "#{cmd}#{ext}") + return exe if File.executable? exe + } + end + return nil +end +Vagrant.configure("2") do |config| + + config.vm.provider :virtualbox do |v| + v.name = "design-patterns" + v.customize [ + "modifyvm", :id, + "--name", "design-patterns", + "--memory", 512, + "--natdnshostresolver1", "on", + "--cpus", 1, + ] + end + + config.vm.box = "ubuntu/trusty64" + + config.vm.network :private_network, ip: "192.168.11.2" + config.ssh.forward_agent = true + + ############################################################# + # Ansible provisioning (you need to have ansible installed) + ############################################################# + + + if which('ansible-playbook') + config.vm.provision "ansible" do |ansible| + ansible.playbook = "ansible/playbook.yml" + ansible.inventory_path = "ansible/inventories/dev" + ansible.limit = 'all' + end + else + config.vm.provision :shell, path: "ansible/windows.sh", args: ["default"] + end + + + config.vm.synced_folder "./", "/vagrant", type: "nfs" +end diff --git a/ansible/inventories/dev b/ansible/inventories/dev new file mode 100755 index 000000000..86d8f3b76 --- /dev/null +++ b/ansible/inventories/dev @@ -0,0 +1,2 @@ +[phansible-web] +192.168.11.2 diff --git a/ansible/playbook.yml b/ansible/playbook.yml new file mode 100755 index 000000000..33e3fda98 --- /dev/null +++ b/ansible/playbook.yml @@ -0,0 +1,11 @@ +--- +- hosts: all + sudo: true + vars_files: + - vars/all.yml + roles: + - server + - vagrant_local + - php + - xdebug + - app diff --git a/ansible/roles/app/tasks/main.yml b/ansible/roles/app/tasks/main.yml new file mode 100755 index 000000000..c330e4818 --- /dev/null +++ b/ansible/roles/app/tasks/main.yml @@ -0,0 +1,5 @@ +--- +# application tasks to be customized and to run after the main provision +- name: update file db + sudo: yes + shell: updatedb diff --git a/ansible/roles/php/tasks/configure.yml b/ansible/roles/php/tasks/configure.yml new file mode 100755 index 000000000..1b093e734 --- /dev/null +++ b/ansible/roles/php/tasks/configure.yml @@ -0,0 +1,6 @@ +--- +- stat: path=/etc/php5/cli/php.ini + register: phpcli + +- include: php-cli.yml + when: phpcli.stat.exists diff --git a/ansible/roles/php/tasks/main.yml b/ansible/roles/php/tasks/main.yml new file mode 100755 index 000000000..7603d868f --- /dev/null +++ b/ansible/roles/php/tasks/main.yml @@ -0,0 +1,20 @@ +--- +- name: Add ppa Repository + sudo: yes + apt_repository: repo=ppa:ondrej/{{ php.ppa }} + +- name: Update apt + sudo: yes + apt: update_cache=yes + +- name: Install php + sudo: yes + apt: pkg=php state=latest + +- name: Install PHP Packages + sudo: yes + apt: pkg={{ item }} state=latest + with_items: php.packages + when: php.packages is defined + +- include: configure.yml diff --git a/ansible/roles/php/tasks/php-cli.yml b/ansible/roles/php/tasks/php-cli.yml new file mode 100755 index 000000000..e1cfffa13 --- /dev/null +++ b/ansible/roles/php/tasks/php-cli.yml @@ -0,0 +1,10 @@ +--- +- name: ensure timezone is set in cli php.ini + lineinfile: dest=/etc/php5/cli/php.ini + regexp='date.timezone =' + line='date.timezone = {{ server.timezone }}' + +- name: enabling opcache cli + lineinfile: dest=/etc/php5/cli/php.ini + regexp=';opcache.enable_cli=0' + line='opcache.enable_cli=1' diff --git a/ansible/roles/server/tasks/main.yml b/ansible/roles/server/tasks/main.yml new file mode 100755 index 000000000..f1ffc0866 --- /dev/null +++ b/ansible/roles/server/tasks/main.yml @@ -0,0 +1,31 @@ +--- +- name: Update apt + sudo: yes + apt: update_cache=yes + +- name: Install System Packages + sudo: yes + apt: pkg={{ item }} state=latest + with_items: + - curl + - wget + - python-software-properties + +- name: Install Extra Packages + sudo: yes + apt: pkg={{ item }} state=latest + with_items: server.packages + when: server.packages is defined + +- name: Configure the timezone + sudo: yes + template: src=timezone.tpl dest=/etc/timezone + +- name: More Configure the timezone + sudo: yes + file: src=/usr/share/zoneinfo/{{server.timezone}} dest=/etc/localtime state=link force=yes backup=yes + +- name: Set default system language pack + shell: locale-gen {{server.locale}} + sudo: yes + diff --git a/ansible/roles/server/templates/timezone.tpl b/ansible/roles/server/templates/timezone.tpl new file mode 100755 index 000000000..cca236521 --- /dev/null +++ b/ansible/roles/server/templates/timezone.tpl @@ -0,0 +1 @@ +{{server.timezone}} diff --git a/ansible/roles/vagrant_local/tasks/main.yml b/ansible/roles/vagrant_local/tasks/main.yml new file mode 100755 index 000000000..cd53609cf --- /dev/null +++ b/ansible/roles/vagrant_local/tasks/main.yml @@ -0,0 +1,11 @@ +--- +- name: Set the hostname in /etc/hostname + shell: echo {{ vagrant_local.vm.hostname }} > /etc/hostname + when: vagrant_local.vm.hostname is defined + +- name: Set the hostname + shell: hostname {{ vagrant_local.vm.hostname }} + when: vagrant_local.vm.hostname is defined + +- name: Update /etc/hosts + lineinfile: dest=/etc/hosts regexp='^127\.0\.0\.1' line='127.0.0.1 localhost {{ vagrant_local.vm.hostname }}' owner=root group=root mode=0644 diff --git a/ansible/roles/xdebug/defaults/main.yml b/ansible/roles/xdebug/defaults/main.yml new file mode 100755 index 000000000..f2d917eb8 --- /dev/null +++ b/ansible/roles/xdebug/defaults/main.yml @@ -0,0 +1,7 @@ +--- +xdebug: + settings: + - xdebug.remote_enable=1 + - xdebug.idekey=PHPSTORM + - xdebug.remote_connect_back=1 + - xdebug.remote_port=9000 diff --git a/ansible/roles/xdebug/tasks/main.yml b/ansible/roles/xdebug/tasks/main.yml new file mode 100755 index 000000000..e38815d00 --- /dev/null +++ b/ansible/roles/xdebug/tasks/main.yml @@ -0,0 +1,4 @@ +--- +- name: Install xDebug + sudo: yes + apt: pkg=php5-xdebug state=latest diff --git a/ansible/vars/all.yml b/ansible/vars/all.yml new file mode 100755 index 000000000..81b1eea43 --- /dev/null +++ b/ansible/vars/all.yml @@ -0,0 +1,15 @@ +--- +server: + install: '1' + packages: [vim, htop, iotop, bwm-ng] + timezone: UTC + locale: en_US.UTF-8 +vagrant_local: + install: '1' + vm: { base_box: trusty64, hostname: design-patterns, ip: 192.168.11.2, sharedfolder: ./, enableWindows: '1', useVagrantCloud: '1', syncType: nfs } +php: + install: '1' + ppa: php-7.0 + packages: [] +xdebug: + install: '1' diff --git a/ansible/windows.sh b/ansible/windows.sh new file mode 100755 index 000000000..eab5d9a5b --- /dev/null +++ b/ansible/windows.sh @@ -0,0 +1,31 @@ +#!/usr/bin/env bash + +# Update Repositories +sudo apt-get update + +# Determine Ubuntu Version +. /etc/lsb-release + +# Decide on package to install for `add-apt-repository` command +# +# USE_COMMON=1 when using a distribution over 12.04 +# USE_COMMON=0 when using a distribution at 12.04 or older +USE_COMMON=$(echo "$DISTRIB_RELEASE > 12.04" | bc) + +if [ "$USE_COMMON" -eq "1" ]; +then + sudo apt-get install -y software-properties-common +else + sudo apt-get install -y python-software-properties +fi + +# Add Ansible Repository & Install Ansible +sudo add-apt-repository -y ppa:ansible/ansible +sudo apt-get update +sudo apt-get install -y ansible + +# Setup Ansible for Local Use and Run +cp /vagrant/ansible/inventories/dev /etc/ansible/hosts -f +chmod 666 /etc/ansible/hosts +cat /vagrant/ansible/files/authorized_keys >> /home/vagrant/.ssh/authorized_keys +sudo ansible-playbook /vagrant/ansible/playbook.yml -e hostname=$1 --connection=local \ No newline at end of file