The HTTP abstraction library implementing the PSR-7 standard is out. In addition to implementing the standard it provides wrappers for Requests and Responses and also abstractions for Cookies and Session. Since these wrappers work with any PSR-7 implementation it now will be possible to run PHPixie in some interesting environments, like inside ReactPHP etc. You can also use these abstractions to create your own PSR-7 compatible microframework.
Here is a quick demo:
1
2
3
//Initialization is prety straightforward
$slice = new \PHPixie\Slice();
$http = new \PHPixie\HTTP($slice);
Requests
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
//Build a Request from globals ($_GET etc)
$request = $http->request();
//Or you can pass a PSR-7 ServerRequestInterface to wrap
$request = $http->request($serverRequest);
//$_GET
$query = $request->query();
//$_POST
$query = $request->data();
//Additional attributes,
//e.g. parameters from routing
$query = $request->attributes();
//$_GET['pixie']
$query->get('pixie');
//With default value
$query->get('pixie', 'Trixie');
//Throw an exception if field is not set
$query->getRequired('pixie');
//$_GET['user']['name'];
$query->get('user.name');
//Or like this
$userData = $query->slice('user');
$userData->get('name');
//In this case $userData
//is an instance of \PHPixie\Slice\Data
//totally unrelated to HTTP library
//so you can pass it around the system
//without coupling to HTTP
//Accessing $_SERVER
$request->server()->get('http_host');
//Get a header line
//If multiple values are present
//for the same header, they will be
//concatenated with ','
$request->headers()->get('host');
$request->headers()->getRequired('host');
//Get header values as array
$request->headers()->getLines('accept');
//Handling uploads
$uploadedFile = $request->uploads()->get('file');
$uploadedFile->move('/images/fairy.png');
//HTTP method
$uri = $request->method();
//Accessing Uri
$uri = $request->uri();
$path = $uri->getPath();
//Underlying ServerRequest
$serverRequest = $request->serverRequest();
Response
Apart from provideing a Response wrapper, PHPixie HTTP also can simplify building some frequently used responses, like JSON responses with proper headers and file downloads.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
$responses = $http->responses();
//The simplest response
$response = $responses->string('hello world');
//JSON with headers that forbid caching
$responses->json(array('name' => 'Pixie'));
//Redirect
$responses->redirect('http://phpixie.com/');
//File streaming
$responses->streamFile('pixie.png');
//Download contetnts as a file
//useful for CSV, TXT types
$responses->download('name.txt', 'text/plain', 'Trixie');
//File download
$responses->downloadFile('pixie.png', 'image.png', 'images/fairy.png');
//Modifying the status code
$response->setStatus('404', 'Not Found');
//OR you can omit the phrase to use
//the default one for the provided code
$response->setStatus('404');
//Modifying headers
$response->headers->set('Content-Type', 'text/csv');
//Transforming into PSR-7 Response
$response->asResponseMessage();
//Outputting a response
$http->output($response);
Context
Another important part is managing users Cookies and Session. Frequently you would access them outside of the request processing, for example in you authroization library. Also for non0standard environments, like in ReactPHP you would need special handlers for modifying the session. That’s why PHPixie separates these into a Context instance. You can store it separately, allowing users to modify cookies independently and then merge them with the Response. It’s rather easy:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//Generate context for a particular request
$context = $http->context($request);
//And then it's pretty straightforward
$cookies = $context->cookies();
$session = $context->session();
$cookies->set('lang', 'en');
$session->getRequired('user_id');
//Remember to pass the context
//when outputting the Response
//or generation a PSR-7 response
$http->output($response, $context);
$response->asResponseMessage($context);
Also you can just use the PSR-7 implementations without PHPixie wrappers:
1
2
3
//Get the PSR-7 factory
$psr7 = $http->messages();
$serverRequest = $psr7->sapiServerRequest();
As all the other PHPixie libraries it is 100% unit tested and has a high codeclimate score (actually perfect score in this case)
You can find the project here: https://github.com/phpixie/http
Composer snipper:
1
2
3
4
5
"require": {
"phpixie/http": "3.*@dev",
"phpixie/slice": "3.*@dev",
"psr/http-message": "1.0.*@dev"
},
One more thing
I haven’t decided on a shortcut method for getting data from the request, so I’d love to hear your opinions. Here are the two ideas I came up with:
1
2
3
4
5
6
7
8
9
10
11
12
13
//The original way
$request->query()->get('pixie', 'Trixie');
//Idea #1
$request->query('pixie', 'Trixie');
//If parameters are present in query() and data()
//forward the call to the ->get method()
//Idea #2
$request->query()->pixie;
//Rely on __get
//But this doesn't allow for
//default values to be specified
Which one do you prefer?
Here is the recording of my presentation of the new PHPixie ORM library:
Slides: http://rawgit.com/PHPixie/Presentations/master/orm.html
If you would like to help translating these slides into a different language you can find it here :https://github.com/phpixie/presentations
The new Templating library is out now, introducing a lot of new features. If you just want to try it out and get your hands dirty just do this:
1
2
3
4
5
6
7
8
git clone https://github.com/phpixie/template
cd template/examples
#install composer if you don't have it yet
curl -sS https://getcomposer.org/installer | php
php composer.phar install
php quickstart.php
PHPixie Template still uses PHP as templating language, but now it can also handle template inheritance and custom formats. It’s super easy to use it to parse HAML, Markdown or whatever else you like. All you need to do is provide a compiler that will translate your format into a plain PHP template, the library will take care of caching the result, updating it when the files are modiefied etc. by itself.
So let’s try integrating it with Markdown, we’ll use mthaml/mthaml for that:
1
2
3
4
5
6
7
8
//composer.json
{
"require": {
"phpixie/template": "3.*@dev",
"phpixie/slice": "3.*@dev",
"mthaml/mthaml": "1.7.0"
}
}
And here is our compiler:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class HamlFormat implements \PHPixie\Template\Formats\Format
{
protected $mtHaml;
public function __construct()
{
$this->mtHaml = new \MtHaml\Environment('php');
}
public function handledExtensions()
{
return array('haml'); // register which file extension we handle
}
public function compile($file)
{
$contents = file_get_contents($file);
return $this->mtHaml->compileString($contents, $file);
}
}
And now let’s inject it into Template:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$slice = new \PHPixie\Slice();
$config = $slice->arrayData(array(
'resolver' => array(
'locator' => array(
//template directory
'directory' => __DIR__.'/templates/',
'defaultExtension' => 'haml',
)
),
'compiler' => array(
'cacheDirectory' => > __DIR__.'/cache/',
)
));
$template = new \PHPixie\Template($slice, $config, array(), array(
new HamlCompiler()
));
That’s it, we can now use HAML for our templates while retaining all the original features like Extensions and inheritance.
Inheritance
It’s pretty inuitive to understand template inheritance, especially if you used Twig or even Smarty. Here is a quick example:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!--layout.php-->
<html>
<title>
<?php $this->block('title'); ?>
</title>
<body>
<?php $this->childContent(); ?>
</body>
</html>
``````php?start_inline=1
<!--fairy.php-->
<?php $this->layout('layout'); ?>
<?php $this->startBlock('title'); ?>
Fairy page
<?php $this->endBlock(); ?>
<h2>Hello <?php $_($name); ?></h2>
This will result in:
1
2
3
4
5
6
<?php $this->layout('layout'); ?>
<?php $this->startBlock('title'); ?>
Fairy page
<?php $this->endBlock(); ?>
<h2>Hello <?php $_($name); ?></h2>
Of course it’s always possible to continue using include like in the previous version of PHPixie:
1
include $this->resolve('fairy');
Template name resolution
Usually templating libraries have some way of providing fallback tempates, that are used if the template you wan’t to use does not exist. And usually they handle it via some naming convention. PHPixie alows you to fine tune name resolutiion using 3 locator types:
This sounds more complex then it actually is, so let’s look at an example, assume the following config:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
$config = $slice->arrayData([
'resolver' => [
'locator' => [
'type' => 'prefix',
'locators' => [
'Site' => [
'directory' => __DIR__.'/site/',
],
'Theme' => [
'type' => 'group',
'locators' => [
[
'directory' => __DIR__.'/templates/',
],
[
'directory' => __DIR__.'/fallback/',
],
]
]
]
]
]
]);
It means that Site::layout template will be searched for in the site/ folder, while the Theme::home one will be searched for in templates/ and fallback/.
Extensions
Extensions provide additional methods that you may use inside your views, they are helpful for things like formatting and escaping. As an example let’s look at the HTML extension:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
class HTML implements \PHPixie\Template\Extensions\Extension
{
public function name()
{
return 'html';
}
//Methods we would like to expose
public function methods()
{
return array('escape', 'output');
}
//Also we can assign aliases to some methods, meaning that they will also
//be assigned to a specified local variable
//In this case it allows us to use $_($name) instead of $this->output($name)
public function aliases()
{
return array(
'_' => 'output'
);
}
public function escape($string)
{
return htmlspecialchars($string, ENT_QUOTES, 'UTF-8');
}
public function output($string)
{
echo $this->escape($string);
}
}
Your Extensions then have to be injected in the library constructor just like Formats.
I don’t know any other templating library that allows you so much flexibility in regards to formats and name resolution, so I hope you like what you see here =)
The unit tests for the next version of ORM are at 98.72% now. It’s just a formality though ,since it’s already fully working an all functional tests pass. As promised on the forum I have created a small tutorial to get you started right away.
Unfortunately because of some namespace conflicts ( namely \PHPixie\ORM and \PHPixie\Config) you won’t be able to use it with PHPixie v2 yet, although a bridge packets will be released that will allow you to use new components with the older version of the framework.
I created quickstart example with some explanation on how things work. Running it is super simple:
1
2
3
4
5
6
7
8
9
git clone https://github.com/phpixie/orm
cd orm/examples
#if you don't have composer yet
curl -sS https://getcomposer.org/installer | php
php composer.phar install
php quickstart.php
More examples to come soon, next time we’ll take a look at embedded relationships with Mongo =)
So tell me what do you guys think about this one:
Somewhat different this time
She\s definitely something new this time around =)
So Phil Sturgeon tweeted that he was looking for a Mock HTTP server with some simple functionality. This sounded like a fun and useful project and it seemed that there was nothing like it on Packagist. So I implemented it =)
Github repo: https://github.com/phpixie/illusion
Packagist: https://packagist.org/packages/phpixie/illusion
Usage is as simple as can be:
1
2
3
4
5
6
7
8
9
10
11
12
13
//Set up client
$illusion = \PHPixie\Illusion::start($port = 4747);
//Set up a route and response and get a URL
$url = $illusion->route('/pixie/fairy', 'Trixie');
//And now:
echo file_get_contents($url); // 'Trixie'
//Also with HTTP method and headers support
$headers = array('Content-Type: text/plain');
$url = $illusion->route('/pixie', 'PHPixie', 'GET', $headers);
It’s simple like that, and it also helped me brush up my socketing skills ^__^
P.S. use this composer.json to try it out:
1
2
3
4
5
{
"require":{
"phpixie/illusion": "dev-master"
}
}
Recently Phil Sturgeon blogged on the tendency in the PHP world to create redundant packages and reinvent the wheel. Matthias Noback retorted with some arguments in favor of such tendencies. But neither of them tried to find the reasons for this happening.
Just yesterday I have watched a talk by the man behind the Sphinx search engine, and he made a very interesting point as to why so many people are interested in developing search engines.
Search engine development is very appealing. It as well as game development presents the programmer with a lot of new and interesting problems to solve. Unlike web development, which is basically taking up shovel and throwing data from the database into HTML.
– Andrej Aksenov ( very loosely translated )
Now let’s delve into some psychology, let me present to you Maslow’s hierarchy of needs:
Maslow’s hierarchy of needs
The part we are interested in is the very top of the diagram, creativity and self-actualization. It’s pretty self-explanatory, each person tries to be creative and to do something, e.g. I am writing this post right now =) Sometimes I even feel that it’s not me writing PHPixie, but that it is an entity on it’s own demanding to be brought into this world.
Obviously for some people their day-to-day job may be interesting and challenging enough to fulfill this need, but sadly in PHP world the majority of developers are doing redundant things like shoveling the data from database to HTML or implementing yet another user registration form. sometimes they read blog posts of these new cool tools, continuous integration, on building opensource communities, contributing and want to be part of it. And their creative fairy pushes from inside and begs to be let out, and she won’t stop until they sit down and code something.
Now comes the second problem of the PHP world. When you want to create a library you want people to use it, a lot, you want to make it popular. But since a lot of web development is based around redundant tasks usually all the useful niches are already taken. And then you have to choose, either make something for a rather small userbase or try to create yet another router. This is how we get both yet-another-routers and strange things like Anthony’s PHP interpreter in PHP. Well there is also the third category of people that write new libraries because they really hate all existing implementations =)
The only advice I can give is to try learning other languages. Perhaps there is more place for your creativity in desktop, mobile or gaming apps.
P.S. there were a lot of artists who produced fake painting of well-known painters like Monet and then donated them to galleries for free. When caught they said that one of the reasons was to prove to the world that they were as good as those they copied.
I think this one is truly awesome!
Some more artwork for PHPixie 3
What do you guys think?
I am frequently relying interfaces in PHPixie components and have faced the problem of how should I be naming them. Specifically whether the “Interface” suffix should be added to the name.
Most frameworks in PHP have decided to adopt the suffix approach, there are some notable exceptions though, like for example Zend 2. Usually when facing an OOP-related question I try to see how it’s done in Java and C++, and the consensus there seems to be quite different. Let me try to explain why:
In the OOP world both classes and interfaces are considered types. When using strict typing declaring a variable of both types is the same. So from the perspective of the developer that is using your library there is no difference between whether the type he is relying on is a class or an interface. This is one of the cool things that actually made interfaces that useful.
Skipping the suffix also allows you to easily refactor your existing concrete dependencies to interfaces.
1
2
3
4
5
6
7
8
9
abstract class Spell
{
/**/
}
class Fairy
{
public function cast(Spell $spell);
}
The Fairy class is relying on a concrete Spell implementation right now, but it’s much better to depend on an abstraction so let’s change it to an interface:
1
2
3
4
5
6
7
8
9
10
interface Spell
{
/**/
}
//The classes relying on the Spell type don't have to change
class Fairy
{
public function cast(Spell $spell);
}
Changing the Spell type into an interface could be done in one place. You don’t need to change the classes depending on it. This saves you and people that are already using your library time, since it doesn’t cause backwards compatibility breaks. If you change the name too you now get:
1
2
3
4
5
6
7
8
9
10
interface SpellInterface
{
/**/
}
//People using your library now have to change their code
class Fairy
{
public function cast(SpellInterface $spell);
}
If you follow the suffix approach the only way to assure that your code will be backwards compatible is to have interfaces for everything from the start, which is of course the best approach.
if you follow best practices and all you dependencies are already interfaces there is no point in adding the suffix to them, since you already know that you never depend on concretions
Also, prefixes and suffixes in type names don’t carry any domain significance. A Spell type represents a spell domain entity. The words “Interface” and “Abstract” don’t really belong in the domain field, they are part of the type definition, but not the type itself.
the bottomline is: if you want shorter names, easier refactoring and semantic meaning you should name your types what they represent and not what they are.
I’m planning on redesigning the website for the 3.0 release. I was thinking about going for a more paper-ish style this time. For example here is a candidate for a frontpage logo:
Do you like it ?