tag:blogger.com,1999:blog-3313860425007637192024-02-20T19:55:37.447+01:00The thoughts of a rambling web fanaticAnonymoushttp://www.blogger.com/profile/09283463794711646819noreply@blogger.comBlogger4125tag:blogger.com,1999:blog-331386042500763719.post-22693006503453157832013-12-22T13:50:00.003+01:002013-12-22T13:52:00.473+01:00Unit testing a InputFilter in Zend framework 2Today i was working on a new resource in my api and i wanted to test my input filter so i didn't have to worry about it causing problems later when i need to do the front end.<br />
<br />
So what is a input filter and why is it annoying to test ? Well a input filter is actually pretty much just a configuration of different elements, and testing an array structure is rather pointless. So the two things that we need to test are the element names and it's configuration.<br />
<br />
<b>This is my input filter that i am testing... </b><br />
<pre class="php" name="code">/**
* Class EstimateRequestInputFilter
*/
class EstimateRequestInputFilter extends InputFilter
{
/**
* {@Inheritdoc}
*/
public function init()
{
$this->add(
[
'name' => 'name',
'label' => 'Name',
'validators' => [
[
'name' => 'NotEmpty'
],
],
'filters' => [
[
'name' => 'StringTrim'
]
]
]
);
$this->add(
[
'name' => 'email',
'label' => 'E-mail',
'validators' => [
[
'name' => 'NotEmpty',
'break_chain_on_failure' => true
],
[
'name' => 'EmailAddress'
]
],
'filters' => [
[
'name' => 'StringTrim'
]
]
]
);
$this->add(
[
'name' => 'mobile',
'label' => 'Mobile',
'validators' => [
[
'name' => 'NotEmpty'
]
],
'filters' => [
[
'name' => 'StringTrim'
]
]
]
);
$this->add(
[
'name' => 'telephone',
'label' => 'Telephone',
'allow_empty' => true,
'filters' => [
[
'name' => 'StringTrim'
]
]
]
);
$this->add(
[
'name' => 'budget',
'label' => 'Budget',
'allow_empty' => true,
'filters' => [
[
'name' => 'StringTrim'
]
]
]
);
$this->add(
[
'name' => 'targetDate',
'label' => 'Target date',
'allow_empty' => true,
'filters' => [
[
'name' => 'StringTrim'
]
]
]
);
$this->add(
[
'name' => 'projectDescription',
'label' => 'Project description',
'validators' => [
[
'name' => 'NotEmpty',
'break_chain_on_failure' => true
],
[
'name' => 'StringLength',
'options' => [
'min' => 200
]
]
],
'filters' => [
[
'name' => 'StringTrim'
]
]
]
);
}
}</pre>
<br />
If you have a keen eye you will notice that i didn't use a constructor to define the the input filter and that is because i store all my input filters in the InputFilterPluginManager. <b>PLEASE DO THIS!!!</b><br />
<br />
For multiple reasons..<br />
<ol>
<li>It keeps the service locator clean</li>
<li>It will inject the ValidatorManager and FilterManager so that you can access your custom validators by specifying the name you stored them as. </li>
</ol>
<div>
<br /></div>
<div>
<b>And this is my testcase</b></div>
<pre class="php" name="code">class EstimateRequestInputFilterTest extends \PHPUnit_Framework_TestCase
{
/**
* @var \PHPUnit_Framework_MockObject_MockObject
*/
private $validator;
/**
* @var \Company\InputFilter\Company\EstimateRequestInputFilter
*/
private $inputFilter;
protected function setUp()
{
$this->inputFilter = new EstimateRequestInputFilter();
$this->inputFilter->init();
}
public function propertyValidationData()
{
return [
['name', '', [Validator\NotEmpty::IS_EMPTY]], // Empty
['name', ' ', [Validator\NotEmpty::IS_EMPTY]], // Empty, asserting StringTrim
['name', 'Antoine', null, 'Antoine'], // Valid
['email', '', [Validator\NotEmpty::IS_EMPTY]], // Empty
['email', ' ', [Validator\NotEmpty::IS_EMPTY]], // Empty, asserting StringTrim
['email', 'foo', [Validator\EmailAddress::INVALID_FORMAT]], // Invalid email address format
['email', 'foo@bar.com', null, 'foo@bar.com'], // Valid
// todo: add validation for phone numbers from i18n?
['mobile', '', [Validator\NotEmpty::IS_EMPTY]],
['mobile', ' ', [Validator\NotEmpty::IS_EMPTY]],
['telephone', '', null, ''], // Valid
['telephone', 'test ', null, 'test'], // Valid, asserting StringTrim
['budget', '', null, ''], // Valid
['budget', 'test ', null, 'test'], // Valid, asserting StringTrim
['targetDate', '', null, ''], // Valid
['targetDate', 'test ', null, 'test'], // Valid, asserting StringTrim
['projectDescription', '', [Validator\NotEmpty::IS_EMPTY]], // Empty
['projectDescription', ' ', [Validator\NotEmpty::IS_EMPTY]], // Empty, asserting StringTrim
['projectDescription', 'h', [Validator\StringLength::TOO_SHORT]],
['projectDescription', str_repeat('h', 200), null, str_repeat('h', 200)]
];
}
/**
* @dataProvider propertyValidationData
*
* @param string $property
* @param string $value
* @param array|null $errors
* @param string|null $expected
*
* @return void
*/
public function testValidationOfEachProperty($property, $value, array $errors = null, $expected = null)
{
// We only validate against the given property
$this->inputFilter->setValidationGroup([$property]);
$this->inputFilter->setData([$property => $value]);
// we expect errors
if (! empty($errors)) {
$this->assertFalse($this->inputFilter->isValid());
$this->assertEquals($errors, array_keys($this->inputFilter->getMessages()[$property]));
} else {
$this->assertTrue($this->inputFilter->isValid());
$this->assertSame($expected, $this->inputFilter->getValue($property));
}
}
}
</pre>
<br />
So if you look closely you will see that i'm validating a number of things<br />
<ol>
<li>Validating that the element with the given name has a certain configuration</li>
<li>Checking that the returned value matches any expected filters (In my case StringTrim)</li>
<li>Checking that a given value with fail with a certain validator message key (Always use keys since the messages can be translated to a different language) </li>
</ol>
<div>
<b>P.S. This is how i do it, It is no way more correct then other methods. I just thought it would be nice to share!</b></div>
Anonymoushttp://www.blogger.com/profile/09283463794711646819noreply@blogger.com0tag:blogger.com,1999:blog-331386042500763719.post-51343407201802930862013-12-12T12:16:00.001+01:002013-12-22T13:51:25.023+01:00Total number of results using PhlyRestfully & collectionsAnybody using <a href="http://www.blogger.com/www.github.com/phly/phlyrestfully" target="_blank">PhlyRestfully</a> has most likely used a paginated result at one time, and sometimes they need to display the total number of results. It's actually rather easy but a bit different then injecting it into the result body....<br />
<br />
What you need to do is create a listener that is attached to the SharedEventManager and inserts a header with the total count. In my case i have selected to use the header "X-total-count".<br />
<br />
<pre class="php" name="code">class InjectPaginationCount implements SharedListenerAggregateInterface
{
/**
* @var \Zend\Stdlib\CallbackHandler
*/
protected $listener;
/**
* Attach one or more listeners
*
* Implementors may add an optional $priority argument; the SharedEventManager
* implementation will pass this to the aggregate.
*
* @param SharedEventManagerInterface $events
*/
public function attachShared(SharedEventManagerInterface $events)
{
$this->listener = $events->attach('PhlyRestfully\ResourceController', 'getList.post', function(Event $event) {
/**
* @var $response \Zend\Http\Response
* @var $paginator \Zend\Paginator\Paginator
*/
$response = $event->getTarget()->getResponse();
$paginator = $event->getParam('collection')->collection;
if ($paginator instanceof Paginator) {
$response->getHeaders()->addHeaderLine('X-total-count', $paginator->getTotalItemCount());
}
});
}
/**
* Detach all previously attached listeners
*
* @param SharedEventManagerInterface $events
*/
public function detachShared(SharedEventManagerInterface $events)
{
$events->detach('PhlyRestfully\ResourceController', $this->listener);
}
}
</pre>
<br />
<br />Anonymoushttp://www.blogger.com/profile/09283463794711646819noreply@blogger.com0tag:blogger.com,1999:blog-331386042500763719.post-30171898726362329772013-10-24T14:01:00.002+02:002013-10-24T14:09:43.416+02:00Dynamic vhosts using a central DNS serverI was inspired by Evans & Robs blogpost about dynamic vhosts using nginx/apache and we used this a fair amount at our office but it's not really useful if you want to quickly share your work with colleagues.<br />
<br />
Links to their blogposts<br />
<a href="http://blog.evan.pro/how-to-set-up-dynamic-virtual-hosts-for-web-development">http://blog.evan.pro/how-to-set-up-dynamic-virtual-hosts-for-web-development</a> (Nginx)<br />
<a href="http://akrabat.com/computing/automatic-apache-vhosts/">http://akrabat.com/computing/automatic-apache-vhosts/</a> (Apache)<br />
<br />
I set about setting up a centralised DNS server that i could use fake TLD's to point to each persons computer. If i would have used dnsmasq instead it would have been a lot easier.... But unluckily i had a fat configuration of bind that i didn't want to migrate to dnsmasq.<br />
<br />
<b>Doing this with bind9 step 1</b><br />
<br />
Edit /etc/bind/named.conf.local and add a section zone for each colleague<br />
<pre class="php" name="code">zone "antoine" {
type master;
file "/etc/bind/db.antoine";
};
zone "jonas" {
type master;
file "/etc/bind/db.jonas";
};
</pre>
<br />
<br />
Save and create a new file for each zone that you have created
<br />
<pre class="php" name="code">; BIND db file for antoine
$TTL 86400
@ IN SOA |NAMESERVER DOMAIN|. |EMAIL DOT DOMAIN|. (
2013102401 ; serial number YYMMDDNN
28800 ; Refresh
7200 ; Retry
864000 ; Expire
86400 ; Min TTL
)
NS |NAMESERVER DOMAIN|.
$ORIGIN antoine.
* 3600 A 192.168.0.7
</pre>
<br />
<br />
So for us that would be
<br />
<pre class="php" name="code">; BIND db file for antoine
$TTL 86400
@ IN SOA router.pmg.se. spam.pmg.se. (
2013102401 ; serial number YYMMDDNN
28800 ; Refresh
7200 ; Retry
864000 ; Expire
86400 ; Min TTL
)
NS router.pmg.se.
$ORIGIN antoine.
* 3600 A 192.168.0.7
</pre>
<br />
I will be frank when i say i have no idea why i have to specify an email in the zone SOA declaration or why it's in that format.
I might even have done something terrible wrong.... but it works and it allows me to visit my collegues projects without having to edit my /etc/hostsAnonymoushttp://www.blogger.com/profile/09283463794711646819noreply@blogger.com0tag:blogger.com,1999:blog-331386042500763719.post-34039132553007293662013-10-01T00:38:00.001+02:002013-10-01T09:56:36.246+02:00Why i wish to remove getServiceLocator from AbstractControllerHeya good people!<br />
<br />
This is the first post on this blog so bare with me! So a few days ago i started a discussion after a PR was made against the ZF2. <a href="https://github.com/zendframework/zf2/issues/5168" rel="nofollow" target="_blank">Here</a><br />
<br />
I especially like the remarks from from a few people<br />
<a href="https://github.com/zendframework/zf2/issues/5168#issuecomment-25174848">https://github.com/zendframework/zf2/issues/5168#issuecomment-25174848</a><br />
<a href="https://github.com/zendframework/zf2/issues/5168#issuecomment-25232532">https://github.com/zendframework/zf2/issues/5168#issuecomment-25232532</a><br />
<a href="https://github.com/zendframework/zf2/issues/5168#issuecomment-25205969">https://github.com/zendframework/zf2/issues/5168#issuecomment-25205969</a><br />
<br />
But none of these explicitly tell us why having the ServiceLocatorAwareInterface is an anti-pattern.<br />
So here are my five cents to the discussion.<br />
<br />
1, Using the service locator directly within the controller it's really easy to request new services. Which means it's very easy to lose track of the single responsibility principle (<a href="http://en.wikipedia.org/wiki/Single_responsibility_principle" rel="nofollow" target="_blank">SRP</a>) your controller <b>should</b> have.<br />
<br />
2, Testing becomes more complicated because you will need to mock the service locator making your tests more fragile. Below you will find the difference between injecting dependencies and use the service locator<br />
<br />
<b>First example is using "proper" injection</b><br />
<pre class="php" name="code">class ExampleController extends AbstractActionController
{
public function __construct(FooServiceInterface $fooService, BarServiceInterface $barService)
{
$this->fooService = $fooService;
$this->barService = $barService;
}
public function testAction()
{
return $this->fooService->foo();
}
public function test2Action()
{
return $this->barService->bar();
}
}
</pre>
And here comes the test
<br />
<pre class="php" name="code">class ExampleControllerTest
{
protected function setUp()
{
$this->fooService = $this->getMock('FooServiceInterface');
$this->barService = $this->getMock('BarServiceInterface');
$this->controller = new ExampleController($this->fooService, $this->barService);
}
}
</pre>
<b>Second example is using the service locator anti-pattern</b>
<br />
<pre class="php" name="code">class ExampleController extends AbstractActionController
{
public function testAction()
{
return $this->getServiceLocator()->get('fooService')->foo();
}
public function test2Action()
{
return $this->getServiceLocator()->get('barService')->bar();
}
}
</pre>
And it's test case
<br />
<pre class="php" name="code">class ExampleControllerTest
{
protected function setUp()
{
$this->fooService = $this->getMock('FooServiceInterface');
$this->barService = $this->getMock('BarServiceInterface');
$sm = new ServiceManager();
$sm->setService('fooService', $this->fooService);
$sm->setService('barService', $this->barService);
$this->controller = new ExampleController();
$this->controller->setServiceLocator($sm);
}
}
</pre>
<br />
<b>Note</b><br />
Both of the setup for our controllers are really quick and dirty and are far from perfect examples of how to properly test a controller.<br />
<br />
<b>Conclusion</b><br />
As you noticed in the second example we also need to setup the ServiceManager and it's not a perfect setup. One could argue that i should modify the ServiceManager that is created by running the bootstrap on the Module. But that means we are doing more then we should be doing in the setUp method.<br />
<br />
3, If your lazy like me you love the autocomplete of your favorite IDE but the docblock return param is <b>mixed</b> so your IDE won't be playing nice with you!<br />
<br />
Well...... I could just add an annotation<br />
<br />
<pre class="php" name="code">/** @var FooServiceInterface $service */
$service = $this->getServiceLocator()->get('FooService');
return $service->foo();
</pre>
<br />
<br />
<b>So my final conclusion</b><br />
We use the service locator anti-pattern for it's convenience but in the end we still end up writing the same amount of code that is harder to test, less readable and more confusing for new developers that join the project.Anonymoushttp://www.blogger.com/profile/09283463794711646819noreply@blogger.com0