PK W+ED9G% % + upcloo-web-framework-develop/searchindex.jsSearch.setIndex({envversion:42,terms:{all:1,code:6,execut:[2,3],whatev:1,when:[3,4,6],particular:2,popo:[3,1],obtain:6,phpenviron:3,through:[3,4,1,6],servicelocatorinterfac:6,bergmann:1,follow:3,webtestcas:1,web:1,onli:[3,6],locat:3,thank:3,img:1,amethod:1,getstatuscod:1,except:2,param:[3,1],should:1,add:1,other:3,folder:1,bye:3,app:[2,4,1,6],overwritten:6,applic:[2,3,1],them:5,good:3,vendor:1,string:3,get:[],handl:[2,6],autoload:1,framework:[],dispatch:1,world:[3,1],requir:[1,5],name:3,pre:2,like:[2,3,1,6],anyth:3,simpl:1,fetch:2,getcont:1,list:2,method:[3,1],assertequ:1,provid:2,css:1,contain:3,output:1,controllertest:3,sebastian:1,redirector:3,right:[2,6],just:[3,1],walterdalmut:3,continu:1,appendconfig:[1,6],see:[3,1,6],phpunit:1,anhook:3,pass:[3,6],home:[3,1,6],event:[],testworkingact:3,oracledata:1,extend:[3,1],correctli:1,section:[3,1,6],definit:1,cruel:3,content:[0,1],zf2:[2,1,5,6],matchedroutenam:3,inject:3,"new":[3,1,5,6],size:3,"public":[3,4,1,5],can:[2,3,1,5,6],signatur:1,who:2,run:[2,1],insid:3,situat:2,privat:[3,1],isol:[3,1],satisfi:1,reason:[3,1],entir:3,address:1,put:1,depend:[2,1],post:1,standard:[1,6],inclus:1,valu:1,addit:6,thrown:2,src:1,protect:3,last:1,plai:3,argument:3,could:[3,6],current:6,introduct:[],hydrat:3,page:0,thing:[3,1,6],length:3,mvc:3,place:1,arrrai:4,action:[],mani:[3,6],chang:2,com:3,upcloo:[],first:[3,1],load:[1,6],myhook:3,simpli:[3,1],render:[],servicemang:5,arrai:[3,4,1,5,6],possibil:1,automat:3,loader:1,hook:[3,6],"boolean":3,least:1,testmyact:1,miss:2,select:2,merg:6,fire:[3,4],differ:6,from:[3,1,6],wai:[3,6],memori:1,widli:2,compos:1,empti:3,custom:3,compon:2,few:3,json:[2,1],trigger:3,call:3,includ:[1,6],interest:1,basic:6,stdclass:5,type:[1,6],start:[],getrespons:3,fals:3,"function":[3,4,1,5,6],setup:[3,1],option:[3,1,6],namespac:[3,4,1,5],trait:[3,5],search:0,specifi:6,ani:6,assert:[3,1],subsequ:1,link:4,togeth:6,jsonp:[2,3,6],line:1,"true":[1,6],those:6,must:6,examplecontrol:[3,6],liter:[1,6],ident:6,word:3,target:3,"default":[2,3,1,6],aservic:3,second:[3,1,6],structur:[3,1],project:1,defin:2,invok:[4,1,6],itself:3,obvious:1,stoppropag:3,error:[2,4,6],testsimpleindexmethod:1,modul:[0,1],more:1,similar:1,thehookcontain:3,control:[],factori:[6,5],hello:[3,1,5],file:1,creat:1,"int":3,dure:1,zend:[3,6],direct:1,sourc:1,have:[2,3,4,1,5],need:[3,1,6],upclootestwebtestcas:1,serial:1,treeroutestack:[2,3],attach:[2,3],declar:[3,1],cours:4,engin:1,goal:1,want:1,phpunit_framework_testcas:[3,1],suggest:1,rout:[2,1,6],arrayprocessor:[1,6],boot:[1,6],same:[3,6],orient:1,conf:[1,6],how:6,controllertestutil:3,valid:[2,6],env:6,you:[],config:[4,1,6],prepar:3,singl:[1,6],"25mb":1,map:3,begin:2,finish:[2,3],http:3,index:[0,1],may_termin:[1,6],after:1,reach:2,"return":[3,1,5,6],servicemanag:[],driven:2,befor:[3,1,5],mycontrollertest:1,routematch:3,two:2,router:[2,3,1,6],php:[3,4,1,5,6],"class":[3,4,1,5],"__dir__":[1,6],myaction:6,indextest:1,practic:6,mention:5,url:1,whole:1,clear:3,bootstrap:[2,1],flow:2,seteventmanag:3,inherit:1,order:[2,1,6],alias:6,geteventfromparam:3,exampl:[2,3,6,5],environ:6,thi:[2,3,1,5,6],time:[3,1],callabl:6,getrequest:3,someth:[3,1,6]},objtypes:{},objnames:{},filenames:["index","getting-started","introduction","controllers","listeners","service-manager","configuration"],titles:["Welcome to UpCloo Framework’s documentation!","Getting Started with UpCloo Framework","Introduction","Controllers and Actions","Listeners","The ServiceManager","Configuration"],objects:{},titleterms:{control:3,render:2,point:1,tabl:0,indic:0,respons:3,event:[2,3],redirect:3,welcom:0,interact:3,configur:[2,1,6],overload:6,your:[3,1,6],start:1,busi:1,test:[3,1],you:1,document:0,listen:[4,6],get:1,object:3,servicemanag:[3,5],framework:[0,1],base:1,now:1,data:3,introduct:2,actioncontrol:1,entri:1,eventmanag:3,request:3,integr:1,logic:1,action:3,servic:[2,6],upcloo:[0,1]}})PK W+EDAK' ' ( upcloo-web-framework-develop/search.html
Basically only the router section is a must.
<?php
return array(
"router" => array(
"routes" => array(
"home" => array(
"type" => "literal",
"options" => array(
"route" => "/"
"defaults" => array(
"controller" => "Your\\NS\\Controller",
"action" => "myAction"
)
),
"may_terminate" => true
)
)
)
);
The configuration is practically identical to ZF2 standard router configuration
In addition you can configure services:
"services" => array(
"invokables" => array(
"My\\Controller\\Example" => "My\\Controller\\Example",
"UpCloo\\Renderer\\Jsonp" => "UpCloo\\Renderer\\Jsonp",
),
"factories" => array(
"example" => function(\Zend\ServiceManager\ServiceLocatorInterface $sl) {
return "that-service";
}
),
"aliases" => array(
"exampleController" => "My\\Controller\\Example",
"renderer" = "UpCloo\\Renderer\\Jsonp"
)
),
The configuration is the same for ZF2 services
When you need to hook your code on events you can specify through the listeners section:
"listeners" => array(
"404" => array(
array("My\\Controller\\Error", "error")
)
)
Any callable hook is valid
"listeners" => array(
"404" => array(
function() {
// handle 404
}
)
)
You can pass to your Boot different configurations. The framework merge those together in order to obtain a single configuration.
This thing could be useful in order to obtain the right configuration for the current environment.
For example see something like this:
$config = new \UpCloo\App\Config\ArrayProcessor();
$config->appendConfig(include __DIR__ . "/../configs/app.php");
$config->appendConfig(include __DIR__ . "/../configs/app.{$env}.php");
$boot = new \UpCloo\App\Boot($config);
...
In this way the conf loaded from app.php is overwritten by the second configuration and so on. You can load how many conf you need.
The base folder structure is: whatever you want...
We suggest something like this:
- configs
- src
- Your
- Project
- Namespace
- tests
- Your
- Project
- Namespace
- web
- js
- css
- img
That is similar to a standard ZF2 module.
Into web direction you have to place your single entry point for your application the index.php file.
<?php
// web/index.php
$loader = require __DIR__ . "/../../vendor/autoload.php";
$loader->add("My", __DIR__ . '/../src');
$conf = include __DIR__ . "/../configs/app.php";
$config = new UpCloo\App\Config\ArrayProcessor();
$config->appendConfig($conf);
$boot = new UpCloo\App\Boot($config);
$engine = new UpCloo\App\Engine();
$app = new UpCloo\App($engine, $boot);
$app->run();
As you can see the first to line uses the composer autoloader in order to satisfy all your dependencies.
The configuration is loaded through the inclusion. Subsequently we create the application and after that we run it.
We want to create a json response at the / address. So, we need the router and at least one controller.
<?php
// configs/app.php
return array(
"router" => array(
"routes" => array(
"home" => array(
"type" => "Literal",
"options" => array(
"route" => "/"
'defaults' => array(
'controller' => 'My\\NM\\Index',
'action' => 'aMethod'
)
),
'may_terminate' => true,
)
)
),
"services" => array(
"invokables" => array(
"My\\NM\\Index" => "My\\NM\\Index",
)
)
)
The controller class is simply a POPO definition with just the action declared.
<?php
// src/My/NM/Index.php
namespace My\\NM;
class Index
{
public function aMethod()
{
return array(
"hello" => "world"
);
}
}
As you can see the method should return the value that the renderer will serialize into the response.
The goal of this structure is oriented to testing. For that reason the test section is not optional!
// tests/My/NM/IndexTest.php
namespace My\\NM;
class IndexTest extends \PHPUnit_Framework_TestCase
{
private $object;
public function setUp()
{
$this->object = new Index();
}
public function testSimpleIndexMethod()
{
$oracleData = array(
"hello" => "world"
);
$this->assertEquals($oracleData, $this->object->aMethod());
}
}
Obviously this is just a simple action! Before run tests correctly we need to load classes and framework, for that use a bootstrap file.
<?php
// tests/bootstrap.php
$loader = require __DIR__ . '/../vendor/autoload.php'; //composer load the framework
$loader->add("My", __DIR__ . '/../src'); //Your source
$loader->add("My", __DIR__); // tests folder
Now run your tests:
phpunit --bootstrap tests/bootstrap.php tests/
The output should be something similar to this:
PHPUnit 3.7.22 by Sebastian Bergmann.
.
Time: 1 seconds, Memory: 1.25Mb
OK (1 tests, 1 assertions)
Now you can continue with more interesting things!
You can test your controller in isolation (see Controllers and Actions) or you can run the whole application. If you are interested in this last thing, you have to inherits from UpClooTestWebTestCase during testing.
<?php
namespace Your\NM;
use UpCloo\Test\WebTestCase;
class MyControllerTest extends WebTestCase
{
public function setUp()
{
$this->appendConfig([
"router" => [
... // Routes
],
"services" => [
... // A conf
],
...
]);
}
public function testMyAction()
{
$response = $this->dispatch("/my-action"); //get method
$this->assertEquals(200, $response->getStatusCode());
//... more assert
$content = $response->getContent();
//...
}
}
The dispatch method signature is:
public function dispatch($url, $method = "GET", array $params = array())
Possibile methods are:
- GET
- POST
- PUT
Listeners are object that are used when an event is fired!
<?php
namespace My\NM;
class Error
{
public function error()
{
}
}
Of course we have to link listeners through the configuration:
// configs/app.php
"services" => arrray(
"invokables" => array(
"My\\NM\\Error" => "My\\NM\\Error",
)
),
"listeners" => array(
"404" => array(
array("My\\NM\\Error", "error")
)
)
Controllers are simply POPO object, like this:
class Me
{
public function hello()
{
return "hello!";
}
}
Controllers and actions are mapped thanks to the TreeRouteStack as you can see in the Getting Started with UpCloo Framework section.
When your action is called, the event is passed as method argument and you can interact with the RouteMatch in this way:
class Me
{
public function hello($event)
{
//Play with $event
}
}
The $event object is a Zend\EventManager\Event object, in few words something like this:
object(Zend\EventManager\Event)[31]
protected 'name' => string 'execute' (length=7)
protected 'target' =>
object(Zend\Mvc\Router\Http\RouteMatch)[35]
protected 'length' => int 7
protected 'params' =>
array (size=3)
'renderer' => string 'UpCloo\Renderer\Jsonp' (length=21)
'controller' => string 'exampleController' (length=17)
'action' => string 'method' (length=6)
protected 'matchedRouteName' => string 'home' (length=4)
protected 'params' =>
array (size=0)
empty
protected 'stopPropagation' => boolean false
The “param” contains the “RouteMatch” structure.
Many times you need to interact with Request (Zend\Http\PhpEnvironment\Request) object. When you need to use the http request you can use “UpCloo\Controller\Request” trait.
<?php
namespace Your\NM;
use UpCloo\Controller\Request;
class Me
{
use Request;
public function hello($event)
{
$request = $this->getRequest();
}
}
The framework hydrate your controller with the Request object only if you declare that you need it using the trait!
The Response object (Zend\Http\PhpEnvironment\Response) follow the same of Request.
<?php
namespace Your\NM;
use UpCloo\Controller\Response;
class Me
{
use Response;
public function hello($event)
{
$response = $this->getResponse();
}
}
As before you have to use traits, the UpCloo\Controller\Action\Redirector to be clear
<?php
namespace Your\NM;
use UpCloo\Controller\Action\Redirector;
class Me
{
use Redirector;
public function hello($event)
{
$this->redirect("http://walterdalmut.com", 302);
}
}
The second argument of “redirect” method is optional (302 by default) and the first argument is the redirect location.
The Redirector traits uses the “Response trait” by itself, for that reason when you use the redirector the Response traits is automatically added to your controller.
You can request anything from the service locator through just using the ServiceManager trait.
<?php
namespace Your\NM;
use UpCloo\Controller\ServiceManager;
class TheHookContainer
{
use ServiceManager;
public function anHook()
{
$aService = $this->services()->get("a-service");
...
}
}
Inside an event you can attach and fire other events adding the EventManager trait:
<?php
namespace Your\NM;
use UpCloo\Controller\EventManager;
class TheHookContainer
{
use EventManager;
public function anHook()
{
// Attach something to an event
$this->events()->attach("finish", function() {
//Good bye cruel world!
});
// Trigger a custom event...
$this->events()->trigger("my.hook.event", $this, ["name" => "a name"]);
}
}
You can test your controller in isolation from the entire application, you have just to prepare things that you need and inject into your controller.
See an example:
<?php
namespace Your\NM;
use UpCloo\Controller\EventManager;
class Controller
{
use EventManager;
public function myHook($event)
{
$this->events()->trigger("my.hook.start", $this);
... // do something...
$this->events()->trigger("my.hook.finish", $this, $data);
return $data;
}
}
Your tests could be something like this:
<?php
namespace UpCloo\NM;
use Zend\EventManager\EventManager;
use UpCloo\Test\ControllerTestUtils;
class ControllerTest extends \PHPUnit_Framework_TestCase
{
use ControllerTestUtils;
private $object;
public function setUp()
{
// Prepare the controller
$this->object = new Controller();
$this->object->setEventManager(new EventManager());
}
public function testWorkingAction()
{
$event = $this->getEventFromParams([
"param" => "hello"
]);
$data = $this->object->myHook($event);
// asserts on data
}
}
As mentioned before, the ZF2 ServiceManger is used. You can configure your services and require for them in your controller.
In your configuration:
<?php
return array(
"services" => array(
"factories" => array(
"example" => function($sl) {
return new stdClass();
}
)
)
)
In your controller you have to require the ServiceManager trait
<?php
namespace My\NM;
use UpCloo\Controller\ServiceManager;
class My
{
use ServiceManager;
public function hello($event)
{
$service = $this->get("example");
return $service;
}
}
UpCloo framework is based on ZF2 components and in particular:
- TreeRouteStack (Router)
- EventManager
- ServiceManager
You have to define “renderers” (who render your data). The framework provides two default renderers that are:
- UpCloo\Renderer\Json
- UpCloo\Renderer\Jsonp
The framework flow is event driven and the execution depends in your actions. In a valid request you reach this events list
- begin
- route
- pre.fetch
- execute
- renderer
- finish
The default flow can change on errors, redirections and exceptions, for example if a route is missing the “404” event is thrown and the flow is like this:
- begin
- route
- 404
- finish
You have to attach a listener on the “404” event in order to handle this error situation.
The ServiceManager is responsible to provide objects to your application and is widly used into the App framework in order to select the right controller and renderer.
The framework uses your configuration in order to bootstrap and run.
Contents: