Git Product home page Git Product logo

cool's Introduction

====================================== Cool - a tiny autowiring PHP framework

Features

  • Autowiring
  • Singletons
  • Services
  •  Signals, Receivers, Hooks
  •  Modularization
  • Autoloading

Installation

git clone [email protected]:t3elmar/Cool.git

Autowiring - Dependency injection for dummies

class People { ... }
class Beer   { ... }
class Music  { ... } 

class Party {
	function __construct(People $people, Beer $beer, Music $music) {
		...
	}
}

$container = new \Cool\Container();
$party = $container->getInstance('Party');

// And the party is up and running ...

Autowiring, the details

Autowiring is triggert by a call to getInstance($classname) of the container. It is based on the signature of the constructor.

For each parameter in the construtor definition a classname has to be specified. Else it doesn't works and an error is thrown. It tries to to create an instance for each parameter by a recursive call to getInstance.

If getInstance() doesn't do what you want, you can still fall back to the static call to new or implement your own factory.

Out-look

The recursive auto-instantiation of objects is a nice feature, but not the definition and strength of dependency injection. The strenght is flexibility. Future versions will provide mechanism, to replace classes (or interfaces in general) by subclasses through configuration.

Singletons

By implementing the interface \Cool\Singleton an object is managed as Singleton by the container, as long as it called by the conatainer methods getInstance or getService.

class SantaClaus implements \Cool\Singleton { ... }

The interface itself is empty. It serves as a flag.

Services

A service is a class, that implements a service interface.

class PizzaCourier implements PizzaService { ... }

This interface defines the type of the service. It must extend \Cool\Service.

interface PizzaService extends \Cool\Service { ... }

Interface \Cool\Service has one class method canServe($mixedCriteria).

When it's method getService($serviceType , $mixedCriteria) is called, the container asks all classes of the given service type, if they could serve the request. The first service that answers with TRUE is the winner. It is instantiated and returned ready to do the job.

Out-look

This is the most simple algorythm to find the winnig service, but it's simplicity by intention. Inject your own finders in future versions.

// ... Concierge get me a pizza service! 
// ... We have a surprising monday party and the fridge is empty.

$pizzaService = $container->getService(
				'MyModule\PizzaService', array('dayOfWeek' => 'monday'));

//  Concierge wiring some pizza services, 
//  all closed on monday, until suddenly ...

class PizzaCourier implements PizzaService {  
	// ...
	static public function canServe($mixedCriteria) { 
		return ($mixedCriteria['dayOfWeek'] != 'tuesday');
	}
	// ...
}

Hint

It depends on the service type, what canServe uses as $mixedCriteria and how it evaluates its answer. If you don't set a stricter type for $mixedCriteria in the interface definition, you should at least document it in that place.

Hint

canServe is a static method, a class method.

To get inheritance work with static methods and variables, late static bindings are your friends: http://www.php.net/manual/en/language.oop5.late-static-bindings.php

Services are autoregistered. They must stay in a module directory named Services/ to work, while the interface definition belongs into Interfaces/.

MyModule/Interfaces/PizzaService.php
MyModule/Services/PizzaCourier.php

Hint

Instantiation is delegated to getInstance. That means that a service must provide a construtor that satisfies the criteria of getInstance.

Signals, Receivers, Hooks

Signals are messesages, that are send at certain events in the code, to inform others about them. They are typically targeted to be used by other modules. Hence, they are designed to support the other developers as far as possible.

1.) Visibility

Signals are declared as classes in the module directory Signals to give them visibiltiy.

2.) Documentation

The very same place is targeted to document them.

3.) Augmentation

Signals may be augmented by special getters to make them more easy and intuitive to use by the receivers.

Signals

They create and broadcast themself, by extending the class AbstractSignal, that itself implementes the interface \Cool\Signal.

class MySignal extends \Cool\AbstractSignal { ... }

Signals are called by the static message send.

There is nothing like signal injection, because signals are strongly related to the class they are send by.

MySignal::send($this, $optionallyMixedData);

The first parameter of send is the sending object. The second parameter is optionally any data that is expected by the signal.

class MySpecialSignal extends \Cool\AbstractSignal { 

	/**
	* @param object the sender
	* @param \SpecialClass the special data
	*/
	static function send($sender, $specialObject) {
		assert($specialObject instanceOf \SpecialClass);
		parent::send($sender, $specialObject);
	}

	/**
	* @return \SpecialClass the special data
	*/
	function getSpecialObject() {
		return $this->getData();
	}
}

The method send can be specialized and special getters can by added.

The sender can by accessed by the method getSender().

Receivers

Receivers implement the interface \Cool\Receivers. They stay in the module directory Receivers. The static method listensTo returns the implementation of \Cool\Signal to listen to. That is all to be done to register a receiver.

It's up to the receiver what to do with the signal.

class MyReceiver implements \Cool\Receiver { 

	static functions listensTo() { return 'MySignal'; }

	/**
	* @param MySignal the expected signal
	*/
	function receive(\Cool\Signal $signal) { 
		assert($signal instanceOf self::listensTo());
		...  
	}

}

Using signals as hooks

The static method send of the signal returns an iterator \Cool\Receivers with all the listening receivers. By iterating the receivers and calling methods on them the signalling mechanism can be used like a hook.

For this to work the listening receivers must provide the method that is called by the sender, to hook them in.

class MyClass { 

	function myFunction() { 
		$receivers = MySignal::send($this);
		foreach($receivers as $receiver) {
			$receiver->doSomthing();
		}
	}

}

It is a good idea to provide a hook interface defining the methods the receiver must implement to be usable by this hook.

	function myFunction() { 
		$receivers = MySignal::send($this);
		foreach($receivers as $receiver) {
			if(!$receiver isInstanceOf MyHookInterface) throw new Exception('invalid hook');
			$receiver->doSomthing();
		}
	}

Modularization

A module is created by putting a directory into Modules.

Cool/Modules/MyModule/

The Module hierarchy is flat. If you want to introduce hierarchy, you have to do this in Form of the name.

Cool/Modules/MyCompanyMySuperModule/

The subdirectories Interfaces, Classes, Services, Signals and Receivers are the places where the autoloader is looking for. If your pathes differ from this, you have to provide your own loading mechanism.

MyModule/Interfaces/
MyModule/Classes/
MyModule/Services/
MyModule/Signals/
MyModule/Receivers/

Services and Receivers must stay in their matching directory to be autoregistered.

MyModule/Services/
MyModule/Receivers/

Other recommended Directories

MyModule/Configuration/
MyModule/Executables/
MyModule/Documentation/
MyModule/Tests/

Coding guidelines

The coding guidelines are recommendations. They don't differ from the up-to-date mainstream:

  • Use CamelCase as far as possible.
  • Classnames start uppercase, functions and variables lowercase.
  • Constants are all uppercase: TRUE, FALSE
  • Respect the security requirements of PHP programming
  • Wrap all PHP code into classes, even configurations.
  • Use namespaces.
  • Write configurations as PHP array for now.
  • Put a license into your module.
  • When you call code from other modules, adhere their licences. They may not be as liberal as the Cool framework itself.

Goals of the design

  • Small footprint.
  • Feature minimized. Features can be added by modules.
  • Easy to get started.
  • Human readable namings.
  • Flat organization of module directories.
  • Proofed by unit testing
  • MIT license, to let modules choose their own way

Hello World

Hello world as a service.

Setting up directories

cd Cool/Modules/
mkdir HelloWorld/
cd HelloWorld/
mkdir Executables Configuration Interfaces Classes Services

GreeterService interface

Path Interfaces/GreeterService.php:

<?php namepace HelloWorld;
interface GreeterService extends \Cool\Service {
	// expects morning | evening| other string
	public static CanServe($timeOfDay);
	public greet($name);
}
?>

Greeter services

Path Services/MorningGreeter.php:

<?php namepace HelloWorld;
class MorningGreeter implements GreeterService {
	static public CanServe($timeOfDay) { return $timeOfDay == 'morning'; }
	public greet($name) { print 'Good morning, '.$name.'!'; }
}
?>

Path Services/EveningGreeter.php:

<?php namepace HelloWorld;
class EveningGreeter implements GreeterService {
	static public CanServe($timeOfDay) { return $timeOfDay == 'evening'; }
	public greet($name) { print 'Good evening, '.$name.'!'; }
}
?>

Path Services/DefaultGreeter.php:

<?php namepace HelloWorld;
class DefaultGreeter implements GreeterService {
	static public canServe($timeOfDay) { 
		return $timeOfDay != 'evening' && $timeOfDay != 'morning'; }
	public greet($name) { print 'Hello '.$name.'!'; }
}
?>

The program

Path Classes/HelloWorld.php:

<?php namepace HelloWorld;
class Program {
	private $container;

	// The container (a singleton) will inject itself. 
	public function __construct(\Cool\Container $container) {
		$this->container = $container;
	}

	public function go($name) {
		$timeOfDay = $this->getTimeOfDay();
		$container->getService('HelloWorld\GreeterService', $timeOfDay)->greet($name);
	}

	// returns a string: morning | evening | other
	public function getTimeOfDay() { ... }

}
?>

Configuration

Path Configuration/Main.php:

<?php namepace HelloWorld;
class Main {
	static public main($argv) { 
		$moduleBase = __DIR__.'/../..';
		require_once($moduleBase.'/Cool/Classes/AutoLoader.php');
		$loader = new \Cool\AutoLoader();
		$loader->addModuleBase($moduleBase);
		$loader->go();
		$loader = new \Cool\DedicatedDirectoriesLoader();
		$loader->addModuleBase($moduleBase);
		$loader->go();
		$container = new \Cool\Container();
		$program = $container->getInstance('HelloWorld\Program');
		// the user provides his name as argument
		$program->go($argv[1]);
	}
}
?>

Executable

Path Executables/sayHello.sh:

#! /usr/bin/env php
<?php
require_once(__DIR__."/../Configuration/Main.php");
\HelloWorld\Main::main($argv);
?>

make it executable:

chmod +x Executables/sayHello.sh

TODO

  • Signals and Receivers
  • Add customized finders
  • Improve documentation
  • Improve documentation of the code
  • More unit testing

cool's People

Contributors

dmitryd avatar

Stargazers

 avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.