<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>PHP &amp; Web on PHP Boy Scout</title><link>https://blog-570662.gitlab.io/categories/php-web/</link><description>Recent content in PHP &amp; Web on PHP Boy Scout</description><generator>Hugo -- gohugo.io</generator><language>en-gb</language><copyright>Matt Cockayne</copyright><lastBuildDate>Thu, 08 Oct 2015 00:00:00 +0000</lastBuildDate><atom:link href="https://blog-570662.gitlab.io/categories/php-web/index.xml" rel="self" type="application/rss+xml"/><item><title>A metaphor about PSR-7 and Middleware for non-developers</title><link>https://blog-570662.gitlab.io/metaphor-psr7-middleware/</link><pubDate>Thu, 08 Oct 2015 00:00:00 +0000</pubDate><guid>https://blog-570662.gitlab.io/metaphor-psr7-middleware/</guid><description>&lt;img src="https://blog-570662.gitlab.io/metaphor-psr7-middleware/fire-bucket-brigade.jpg" alt="Featured image of post A metaphor about PSR-7 and Middleware for non-developers" /&gt;&lt;p&gt;Never one to shy away from coming up with a metaphor for explaining something technical I found myself having to come up with one on the spot for PSR-7 and Middleware while at the recent PHPNW15 Conference.&lt;/p&gt;
&lt;p&gt;Normally my brain will come up with something completely inappropriate but this time round I found I quite liked the imagery that came to mind.&lt;/p&gt;
&lt;p&gt;If you would like to find out more of the specifics about PSR-7 you can take a look at &lt;a class="link" href="http://www.php-fig.org/psr/psr-7/" target="_blank" rel="noopener"
 &gt;http://www.php-fig.org/psr/psr-7/&lt;/a&gt; which will make a better job of explaining it than I could ever do.&lt;/p&gt;
&lt;p&gt;Now on to the metaphor&lt;/p&gt;
&lt;p&gt;Imagine a house on fire, a bizarre way to start I know but bear with me. The nearest well with water that can put out the fire is 500 meters away! We then have a human chain stretching between the well and the house with a bucket going back and forth between trying to put the fire out. So lets break this down, the house represents the internet, or more specifically you and your browser. The fact you are on fire means that you are desperately needing water to quench the flames. At this point you send an empty bucket which represents your &amp;ldquo;request&amp;rdquo;, along the human chain, which in itself represents the application, to the well.&lt;/p&gt;
&lt;p&gt;At the start of the chain the bucket is pretty normal, it&amp;rsquo;s a bucket of course, its round, made of wood with a rope handle, lets say it has a small leak in it.&lt;/p&gt;
&lt;p&gt;As it travels down the chain it&amp;rsquo;s passed from person to person, everyone in it has the opportunity to do something with the bucket, or not as the case may be and could just pass it to the next person in the chain. Others may attempt to fix the leak in the bucket, someone may choose to replace it with a metal bucket, change the handle or make it bigger. Regardless of what may be done to the bucket in essence it remains a bucket.&lt;/p&gt;
&lt;p&gt;&lt;img alt="colonial_bucket3" class="gallery-image" data-flex-basis="240px" data-flex-grow="100" height="500" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://blog-570662.gitlab.io/metaphor-psr7-middleware/colonial_bucket3.jpg" width="500"&gt;&lt;/p&gt;
&lt;p&gt;Inexorably the bucket will continue to move down the chain to the well. When it reaches the well it changes state because now it has been filled with water. All of the interaction with the bucket thus far, mean that what happens at the well could vary depending on the changes have been made . If its been made bigger, for example, it could be filled with significantly more water, if swapped for a metal one it could imply that the bucket descends the well to get the water quicker because its heavier. Either way it is filled with water and begins its journey back towards the house.&lt;/p&gt;
&lt;p&gt;Again it passes through the hands of each person in the chain, but now that its state has changed it now has the opportunity to be modified again. Someone may empty some water out as there is too much in the bucket, others may say that there is not enough and send it back down the line towards the well to be refilled. Either way the bucket continues to change hands over and over until it reaches the house and the contents are thrown on the fire to complete the request for water.&lt;/p&gt;
&lt;p&gt;During this whole time the human chain could have been in flux. Some people may have swapped places, left the chain, added to the chain, some extraordinary people may have played leapfrog in the chain and appeared to handle the bucket more than once. Regardless of these changes the chain remains and continues to pass the bucket from one person to the another as long as the requests for water keep coming.&lt;/p&gt;
&lt;p&gt;This, in the simplest possible form, explains PSR-7 and the concept of Middleware.&lt;/p&gt;
&lt;p&gt;The bucket remains a bucket because PSR-7 says that is what is needed to complete the request for water, it also defines how you should interact with it regardless of what modifications have been made. If the bucket cant be used according to how PSR-7 describes a bucket to be, then the middleware can&amp;rsquo;t complete the request.&lt;/p&gt;
&lt;p&gt;Every person in the human chain can be classed as a piece of middleware all the way from the house to the well and back again. If at any point someone enters the chain that doesn&amp;rsquo;t agree that the bucket is a bucket or doesn&amp;rsquo;t know how to handle it, then the it is dropped on the ground and the request fails.&lt;/p&gt;</description></item><item><title>Flexbox cross browser</title><link>https://blog-570662.gitlab.io/flexbox-cross-browser/</link><pubDate>Fri, 16 Aug 2013 00:00:00 +0000</pubDate><guid>https://blog-570662.gitlab.io/flexbox-cross-browser/</guid><description>&lt;p&gt;Despite having been around for a while and having been through a couple of revisions, its support across browsers can vary greatly. From &amp;ldquo;Candidate Recommendation&amp;rdquo; on Chrome/Opera, &amp;ldquo;legacy flexbox&amp;rdquo; on Firefox and no support at all on IE9 and earlier.&lt;/p&gt;
&lt;p&gt;Making flexbox work consistently across browsers was a challenge for us on a recent project, but I have found a solution that seems to work quite well.&lt;/p&gt;
&lt;p&gt;Below is an SCSS @mixin that will attempt to handle compatibility between CR and legacy cross browsers flexbox.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;@mixin flex($content: flex-start, $items: stretch, $direction: row, $wrap: wrap) {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; $packLegacy: $content;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; @if $packLegacy == flex-start {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; $packLegacy: start;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; } @else if $packLegacy == flex-end {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; $packLegacy: end;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; $alignLegacy: $items;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; @if $alignLegacy ==flex-start {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; $alignLegacy: start;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; } @else if $alignLegacy == flex-end {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; $alignLegacy: end;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; $oritentLegacy: $direction;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; $directionLegacy: normal;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; @if $oritentLegacy == row {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; $oritentLegacy: horizontal;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; } @else if $oritentLegacy == column {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; $oritentLegacy: vertical;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;/** SAFARI **/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; display: -webkit-box;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -webkit-box-orient: $oritentLegacy;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -webkit-box-pack: $packLegacy;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -webkit-box-align: $alignLegacy;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;/** FIREFOX LEGACY **/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; display: -moz-box;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -moz-box-orient: $oritentLegacy;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -moz-box-direction: $directionLegacy;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -moz-box-pack: $packLegacy;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -moz-box-align: $alignLegacy;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;/** LEGACY **/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; display: box;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; box-orient: $oritentLegacy;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; box-direction: $directionLegacy;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; box-pack: $packLegacy;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; box-align: $alignLegacy;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;/** IE 10+ **/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; display: -ms-flexbox;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -ms-flex-wrap: $wrap;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -ms-flex-direction: $direction;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -ms-justify-content: $content;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -ms-align-items: $items;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;/** CHROME **/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; display: -webkit-flex;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -webkit-flex-wrap: $wrap;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -webkit-flex-direction: $direction;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -webkit-justify-content: $content;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -webkit-align-items: $items;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;/** NATIVE **/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; display: flex;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; flex-wrap: $wrap;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; flex-direction: $direction;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; justify-content: $content;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; align-items: $items;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;} //@mixin flex
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;@mixin flexItem($width) {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -webkit-box-flex: $width;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -moz-box-flex: $width;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; box-flex: $width;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -ms-flex: $width;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -webkit-flex: $width;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; flex: $width;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; min-height: 0;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Firefox however only half supports flexbox (all revisions) and to get around this I would recommend using &lt;a class="link" href="http://modernizr.com/" title="Modernizr"
 target="_blank" rel="noopener"
 &gt;Modernizr&lt;/a&gt; as this will add the class &amp;ldquo;no-flexbox&amp;rdquo; to the &lt;html&gt; tag. This provides us with a simple work around that allows non flexbox supporting browsers render correctly by using specifically crafted and targeted CSS for non-flexbox browsers&lt;/p&gt;
&lt;p&gt;I found that IE9 support could be implemented using the &lt;a class="link" href="http://flexiejs.com/" title="FlexieJS"
 target="_blank" rel="noopener"
 &gt;flexie&lt;/a&gt; javascript plugin. In IE8 M&lt;a class="link" href="http://modernizr.com/" title="Modernizr"
 target="_blank" rel="noopener"
 &gt;odernizr&lt;/a&gt; will add the class &amp;ldquo;no-flexboxlegacy&amp;rdquo; which can again allow you to create targeted CSS that wont affect your Flexbox layout.&lt;/p&gt;
&lt;p&gt;For a great overview of the &amp;ldquo;CR&amp;rdquo; of flexbox, CSS Tricks has an amazingly comprehensive coverage of the functionality here &lt;a class="link" href="http://css-tricks.com/snippets/css/a-guide-to-flexbox/" target="_blank" rel="noopener"
 &gt;http://css-tricks.com/snippets/css/a-guide-to-flexbox/&lt;/a&gt;&lt;/p&gt;</description></item><item><title>Creating Custom Routes in Silverstripe 3.1</title><link>https://blog-570662.gitlab.io/creating-custom-routes-silverstripe/</link><pubDate>Wed, 31 Jul 2013 00:00:00 +0000</pubDate><guid>https://blog-570662.gitlab.io/creating-custom-routes-silverstripe/</guid><description>&lt;p&gt;We wanted to create a Route to our custom Products Controller in our products module for SilverStripe 3.1, such as: &amp;ldquo;&lt;a class="link" href="http://www.examplesite.com/products/" target="_blank" rel="noopener"
 &gt;http://www.examplesite.com/products/&lt;/a&gt;&lt;product-slug&gt;&amp;rdquo;&lt;/p&gt;
&lt;p&gt;However looking at the &lt;a class="link" href="http://doc.silverstripe.org/framework/en/3.1/topics/controller" title="Controller Documentation"
 target="_blank" rel="noopener"
 &gt;Controller Documentation&lt;/a&gt; it was not clear how to create a route without an Action being supplied. In our example above the action is not specified, as we just want to use &amp;lsquo;view&amp;rsquo;.&lt;/p&gt;
&lt;p&gt;Solution:&lt;/p&gt;
&lt;p&gt;Create a &lt;module-name&gt;/_config/routes.yml file containing the following:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;---
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Name: productsroutes
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;After: &amp;#39;framework/routes#coreroutes&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;---
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Director:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; rules:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#39;product&amp;#39;: &amp;#39;Product_Controller&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;---
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The above will redirect any Url that starts with &amp;ldquo;/product&amp;rdquo; to our Product_Controller. Note that everything after the rule, so after &amp;ldquo;/product&amp;rdquo;, is used in the next bit for matching.&lt;/p&gt;
&lt;p&gt;Now we need to add &lt;code&gt;private static $url_handers&lt;/code&gt; to Product_Controller to match our path, so in this example we need to match &amp;ldquo;$Slug!&amp;rdquo; which will match &amp;ldquo;&lt;product-slug&gt;&amp;rdquo;. Note the ! means the slug is required. Of course we want to direct this to a specific action, in this case &amp;ldquo;view&amp;rdquo;, this gives us:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;private static $url_handlers = array(
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#39;$Slug!&amp;#39; =&amp;gt; &amp;#39;view&amp;#39;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now just add &amp;ldquo;view&amp;rdquo; to the $allow_actions and add the &amp;ldquo;view&amp;rdquo; function. This gives the final Product_Controller as follows:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-gdscript3" data-lang="gdscript3"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="n"&gt;Product_Controller&lt;/span&gt; &lt;span class="k"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;Page_Controller&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="n"&gt;url_handlers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;$Slug!&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;view&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="n"&gt;allowed_actions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;view&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;public&lt;/span&gt; &lt;span class="n"&gt;function&lt;/span&gt; &lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SS_HTTPRequest&lt;/span&gt; &lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="n"&gt;Your&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt; &lt;span class="n"&gt;code&lt;/span&gt; &lt;span class="n"&gt;goes&lt;/span&gt; &lt;span class="n"&gt;here&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;render&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Handy note:&lt;/p&gt;
&lt;p&gt;You can put ?&lt;code&gt;debug_request=1 on the end of your URL to see how it determines which Controller to use.&lt;/code&gt;&lt;/p&gt;</description></item><item><title>Disabling Cache in Silverstripe 3.1</title><link>https://blog-570662.gitlab.io/disabling-cache-silverstripe/</link><pubDate>Wed, 31 Jul 2013 00:00:00 +0000</pubDate><guid>https://blog-570662.gitlab.io/disabling-cache-silverstripe/</guid><description>&lt;p&gt;While working with Silverstripe we found ourselves having to run &amp;ldquo;?flush=1&amp;rdquo; a lot to clear the Cache. To switch it off, while you work, add the following to your mysite/_config.php:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;SS_Cache::set_cache_lifetime(&amp;#39;default&amp;#39;, -1, 100);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description></item><item><title>Set up SilverStripe 3.1 using only Git (No Composer)</title><link>https://blog-570662.gitlab.io/set-up-silverstripe-3-1-using-only-git/</link><pubDate>Mon, 29 Jul 2013 00:00:00 +0000</pubDate><guid>https://blog-570662.gitlab.io/set-up-silverstripe-3-1-using-only-git/</guid><description>&lt;p&gt;We recently tried to use composer to set up SilverStripe 3.1, but ended up with a dependency nightmare. In order to work around this we decided to make use of Git submodules.&lt;/p&gt;
&lt;p&gt;First set up your Git repository and run:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git init
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Next set up a site directory for the code inside your Git repository. Then navigate to &lt;a class="link" href="https://github.com/silverstripe/silverstripe-installer" target="_blank" rel="noopener"
 &gt;SilverStripe Installer&lt;/a&gt; in your browser and Download a copy. Extract files, and copy contents to site folder. Now we need to add the CMS and Framework. Navigate in a browser to the Git Hub repositories for &lt;a class="link" href="https://github.com/silverstripe/silverstripe-cms" target="_blank" rel="noopener"
 &gt;CMS&lt;/a&gt; and &lt;a class="link" href="https://github.com/silverstripe/silverstripe-framework" target="_blank" rel="noopener"
 &gt;Framework.&lt;/a&gt; Now copy the HTTPS clone URL for each project and run the following, to add these as Git sub modules.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git submodule add https://github.com/silverstripe/silverstripe-framework.git site/framework
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git submodule add https://github.com/silverstripe/silverstripe-cms.git &amp;lt;path-to-site&amp;gt;site/cms
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now delete mysite/_config.php and load the site. Follow the normal install instructions displayed and you will have a running version of &lt;a class="link" href="http://www.silverstripe.org/" title="SilverStripe"
 target="_blank" rel="noopener"
 &gt;SilverStripe 3.1&lt;/a&gt;&lt;/p&gt;</description></item><item><title>Enabling MYSQL_CLIENT_INTERACTIVE with Doctrine 2 on Rackspace Cloud Database</title><link>https://blog-570662.gitlab.io/mysql-client-interactive-with-doctrine-on-rackspace/</link><pubDate>Fri, 26 Jul 2013 00:00:00 +0000</pubDate><guid>https://blog-570662.gitlab.io/mysql-client-interactive-with-doctrine-on-rackspace/</guid><description>&lt;p&gt;We recently ran into problem using Doctrine 2 connecting to a Rackspace Cloud Database using the MySqli Driver.&lt;/p&gt;
&lt;p&gt;Problem:&lt;/p&gt;
&lt;p&gt;We have a long running PHP script that can sometimes run for hours at a time whilst processing information. This script requires a connection to a database, but has long periods of inactivity where there is no actual interaction with MySQL. By default MySQL uses the &amp;ldquo;wait_timeout&amp;rdquo; setting which states, how long an inactive connection can exist before it is killed. This is normally fine with web pages requests, as it is usually a short lived request. Unfortunately you do not have the ability to alter this setting when using Rackspaces Cloud Database.&lt;/p&gt;
&lt;p&gt;Solution:&lt;/p&gt;
&lt;p&gt;When using the MySQLi extension you can create a connection in &amp;ldquo;interactive mode&amp;rdquo; by passing the &amp;ldquo;MYSQLI_CLIENT_INTERACTIVE&amp;rdquo; flag, which will then use the &amp;ldquo;interactive_timeout&amp;rdquo; setting. On Rackspace this is set to 8 hours!&lt;/p&gt;
&lt;p&gt;Annoyingly Doctrine does not allow you to pass any flags to the MySQLi Connection. So we overrode Doctrine\DBAL\Driver\Connection with our own &lt;a class="link" href="https://github.com/zucchi/ZucchiDoctrine/blob/master/src/ZucchiDoctrine/Driver/Mysqli/MysqliConnection.php" title="ZucchiDoctrine/Driver/Mysqli/MysqliConnection.php"
 target="_blank" rel="noopener"
 &gt;Driver&lt;/a&gt; which then allows us to pass a &amp;ldquo;flags&amp;rdquo; parameter through.&lt;/p&gt;
&lt;p&gt;Feel free to look at some of the other helpful features in we have added to Doctrine 2 here: &lt;a class="link" href="https://github.com/zucchi/ZucchiDoctrine" title="ZucchiDoctrine"
 target="_blank" rel="noopener"
 &gt;ZucchiDoctrine&lt;/a&gt;&lt;/p&gt;</description></item><item><title>Installing PECL extensions for Zend Server 6</title><link>https://blog-570662.gitlab.io/installing-pecl-extensions-zend-server-6/</link><pubDate>Mon, 13 May 2013 00:00:00 +0000</pubDate><guid>https://blog-570662.gitlab.io/installing-pecl-extensions-zend-server-6/</guid><description>&lt;p&gt;Recently we have revisited using Zend Server for some of our projects and decided to give the new version 6 a chance to prove itself.&lt;/p&gt;
&lt;p&gt;Overall its a big improvement over version 5. There are still some things that are extremely annoying but we have decided that we can overlook them.&lt;/p&gt;
&lt;p&gt;However there is one thing that we couldn&amp;rsquo;t do without. By default you will find that a number of PECL extensions will not install out of the box (at least this is what we experience using the Debian based install).&lt;/p&gt;
&lt;p&gt;To fix this you will need to make sure you install the additional packages in ubuntu&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;php-5.4-source-zend-server&lt;/strong&gt; or &lt;strong&gt;php-5.3-source-zend-server&lt;/strong&gt; depending on the php version you are using&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;autoconf&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;build-essential&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Once this is done you should now be able to install extensions from PECL without too much hassle.&lt;/p&gt;</description></item><item><title>Introducing ZuQ - A Simple ZeroMQ Queuing Daemon</title><link>https://blog-570662.gitlab.io/introducing-zuq/</link><pubDate>Tue, 19 Mar 2013 00:00:00 +0000</pubDate><guid>https://blog-570662.gitlab.io/introducing-zuq/</guid><description>&lt;p&gt;We recently had the need to create a queuing system to replace an implementation of RabbitMQ that was being used on a previous project. The reasoning behind this is that the requirements of the project required a very custom implementation of a queuing system that would drastically alter in architecture as the project grew and RabbitMQ just wasn&amp;rsquo;t going to fit the bill. However to start with we required something super simple and efficient that could be expanded and developed as required. After a little investigation and a lot of recommendation from others we decided to use ZeroMQ as our transport layer for that very reason, as we could build something which could span across multiple servers and was fast.&lt;/p&gt;
&lt;p&gt;&lt;a class="link" href="http://phpboyscout.uk/wp-content/uploads/2013/03/clientQueue.png" target="_blank" rel="noopener"
 &gt;&lt;img alt="This is a simple Queue and Client Diagram" class="gallery-image" data-flex-basis="1082px" data-flex-grow="450" height="165" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://blog-570662.gitlab.io/introducing-zuq/clientQueue.png" width="744"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The diagram above helps describe our basic queuing system. We have a queue daemon that is continuously listening for connections and two clients, one that populates the queue and the other that retrieves from the queue.&lt;/p&gt;
&lt;h2 id="the-clients"&gt;The Clients
&lt;/h2&gt;&lt;p&gt;Each client is written in PHP and uses a 0mq socket to communicate with a service, in this case our queue service. We used a SOCKET_REQ type of socket in order to have a request/response communication with our queue service.&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;function client_socket(\ZMQContext $context)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; // SOCKET_REQ used to create a client that sends requests to and receive from a service
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; $client = new \ZMQSocket($context,\ZMQ::SOCKET_REQ);
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; $client-&amp;gt;connect(&amp;#34;tcp://localhost:5555&amp;#34;);
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; // SOCKOPT_LINGER = 0 Configure socket to not wait at close time
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; $client-&amp;gt;setSockOpt(\ZMQ::SOCKOPT_LINGER, 0);
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; return $client;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;public function injectIntoQueue()
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; $context = new \ZMQContext();
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;  $client = $this-&amp;gt;client_socket($context);
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;  $msg = &amp;#34;This is a message&amp;#34;;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;  $retries_left = 3;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;  $read = $write = array();
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;  while ($retries_left) {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;    // We send a request, then we wait to get a reply
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;        $client-&amp;gt;send($msg);
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;        $expect_reply = true;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;        while ($expect_reply) {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;        // Poll socket for a reply, with timeout
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;            $poll = new \ZMQPoll();
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;            $poll-&amp;gt;add($client, \ZMQ::POLL_IN);
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;            $events = $poll-&amp;gt;poll($read, $write, 2500);
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;            // If we got a reply, process it
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;            if ($events &amp;gt; 0) {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;            // We got a reply from the server, must match sequence
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;                $reply = $client-&amp;gt;recv();
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;                if (intval($reply) == $msg) {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;                $retries_left = 0;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;                    $expect_reply = false;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;                }
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;             } elseif (--$retries_left == 0) {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;            break;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;             } else {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;               // Old socket will be confused; close it and open a new one
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;                $client = $this-&amp;gt;client_socket($context);
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;                // Send request again, on new socket
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;                $client-&amp;gt;send($msg);
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
 &lt;/blockquote&gt;
&lt;p&gt;You can see from the code above, have a 3 strike rule. The reasoning behind this is that if the client fails to connect to the queue service more than 3 times, we can stop trying to inject into the queue and move on to the next item. As we ultimately intend to adapt the &lt;a class="link" href="http://zguide.zeromq.org/page:all#Client-side-Reliability-Lazy-Pirate-Pattern" title="lazy pirate pattern"
 target="_blank" rel="noopener"
 &gt;lazy pirate pattern&lt;/a&gt; we have made it so that if the socket times out, we can then create a new socket and retry. Without this, as the architecture becomes more complicated we may then end up in a situation where we might have errors, thus the recommend solution is to create a new socket. Once the client has sent its message to the queue, we poll for a response (i.e. which is the message we sent returned back). Once we have a response that is valid, meaning that the queue has been populated, we can stop polling until the next message.&lt;/p&gt;
&lt;p&gt;The Frontend Client&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;protected function getFromQueue()
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; $context = new \ZMQContext();
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; $worker = new \ZMQSocket($context, \ZMQ::SOCKET_REQ);
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; $read = $write = array();
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; // Set random identity to make tracing easier
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; $worker-&amp;gt;connect(&amp;#34;tcp://localhost:5556&amp;#34;);
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; // Tell queue we&amp;#39;re ready for work
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; $worker-&amp;gt;send(&amp;#34;ready&amp;#34;);
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; $reply = $worker-&amp;gt;recv();
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; return $reply;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
 &lt;/blockquote&gt;
&lt;p&gt;Our Frontend Client is much simpler as it is part of a process that is being continually updated, therefore it doesn&amp;rsquo;t need the same connection retries are the Backend Client. We simply send &amp;ldquo;ready&amp;rdquo; to the queue system and if the queue is populated it will return us the first item.&lt;/p&gt;
&lt;h2 id="the-queuing-service"&gt;The Queuing Service
&lt;/h2&gt;&lt;p&gt;This is a continuously running executable created using c++.&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;zmq::context_t context(1);
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;zmq::socket_t frontend (context, ZMQ_ROUTER);
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;zmq::socket_t backend (context, ZMQ_ROUTER);
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;backend.bind(&amp;#34;tcp://*:5555&amp;#34;);
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;frontend.bind(&amp;#34;tcp://*:5556&amp;#34;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
 &lt;/blockquote&gt;
&lt;p&gt;We create two sockets of type ZMQ_ROUTER which is an advanced pattern used for extending request/reply sockets. This means when we improve our queuing system we will be able to route packets to specific recipients using an address in the message.&lt;/p&gt;
&lt;p&gt;After creating our sockets, we initialise them&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;// Initialize poll set
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;zmq::pollitem_t items [] = {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; { frontend, 0, ZMQ_POLLIN, 0 },
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; { backend, 0, ZMQ_POLLIN, 0 }
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;//poll the sockets - this seems to poll both sockets at the same time
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;zmq::poll (items, 2, -1);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
 &lt;/blockquote&gt;
&lt;h2 id="backend-handler"&gt;Backend Handler
&lt;/h2&gt;&lt;p&gt;If we get a message from the backend, we check the contents to see if it contains purge at which point we empty the queue, otherwise we push the msg contents onto the queue. Finally we send the message back to the backend to show that the message has been received.&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;//receive msg from client
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;if (items [1].revents &amp;amp; ZMQ_POLLIN) {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; //get message from client
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; zmq::message_t message(0);
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; string client_addr = s_recv (backend);
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; string empty = s_recv (backend);
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; assert (empty.size() == 0);
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; string msg = s_recv (backend);
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; //allow the backend to purge the queue
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; if(msg == &amp;#34;purge&amp;#34;) {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; while (!queue.empty()) queue.pop();
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; } else {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; queue.push(msg);
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; //send response back to the backend
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; s_sendmore (backend, client_addr);
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; s_sendmore (backend, &amp;#34;&amp;#34;);
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; s_send (backend, msg);
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt; &lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h2 id="frontend-handler"&gt;Frontend Handler
&lt;/h2&gt;&lt;p&gt;If we get the &amp;ldquo;ready&amp;rdquo; message from the frontend client, we pop a message off the queue and return it to the frontend client. If the queue is empty we send an &amp;ldquo;empty&amp;rdquo; message back instead.&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;// Handle activity on frontend
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;if (items [0].revents &amp;amp; ZMQ_POLLIN) {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; //get message from worker
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; zmq::message_t message(0);
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; string worker_addr = s_recv (frontend);
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; string empty = s_recv (frontend);
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; assert (empty.size() == 0);}
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; string msg = s_recv (frontend); string queueMsg;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; if(msg == &amp;#34;ready&amp;#34;) {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; if(queue.size() &amp;gt; 0) {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; queueMsg = queue.front();
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; queue.pop();
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; } else {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; queueMsg = &amp;#34;empty&amp;#34;;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; //send reply to worker with contents of queue
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; s_sendmore (frontend, worker_addr);
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; s_sendmore (frontend, &amp;#34;&amp;#34;);
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; s_send (frontend, queueMsg);
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
 &lt;/blockquote&gt;
&lt;p&gt;That is our complete queuing system using ZeroMQ with PHP and C++.&lt;/p&gt;
&lt;h2 id="summary"&gt;Summary
&lt;/h2&gt;&lt;p&gt;Using the above has allowed us to create a very simple in memory queue daemon that we can use to quickly pass data from one system to a another. On the whole it works well and we are looking to expand on it in the near future to increase both its functionality and scalability.&lt;/p&gt;
&lt;p&gt;You can find the queueing daemon (christened as &amp;ldquo;ZuQ&amp;rdquo;) on github @ &lt;a class="link" href="https://github.com/zucchi/ZuQ" target="_blank" rel="noopener"
 &gt;https://github.com/zucchi/ZuQ&lt;/a&gt;&lt;/p&gt;</description></item><item><title>Docblock, Oh Docblock, wherefore art thou Docblock (hint: Zend Optimizer Plus lost them)</title><link>https://blog-570662.gitlab.io/docblock-docblock-wherefore-art/</link><pubDate>Fri, 01 Mar 2013 00:00:00 +0000</pubDate><guid>https://blog-570662.gitlab.io/docblock-docblock-wherefore-art/</guid><description>&lt;p&gt;tl;dr&amp;gt; I make a terrible assumption about Zend Optimizer+ and am corrected by Dominic in the comments;&lt;/p&gt;
&lt;p&gt;Terrible post title I know but its the best I could come up with.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve just come up for air after spending the majority of the day debugging some issues on our current development sandbox.&lt;/p&gt;
&lt;p&gt;Now our sandbox tends to be quite bleeding edge in some circumstances and as such we run a fair few bits of unstable code. On the sandbox in question we have been running PHP 5.4.11 and unfortunately we have struggled to get APC working with it just the way we need it to. The lack of APC tends to make this sandbox quite slow.&lt;/p&gt;
&lt;p&gt;We recently saw that Zend have open-sourced their OptimizerPlus extension (&lt;a class="link" href="https://github.com/zend-dev/ZendOptimizerPlus" title="https://github.com/zend-dev/ZendOptimizerPlus"
 target="_blank" rel="noopener"
 &gt;https://github.com/zend-dev/ZendOptimizerPlus&lt;/a&gt;) and that it was compatible with 5.4&amp;hellip;. Fantastic, or so we thought.&lt;/p&gt;
&lt;p&gt;So I added the new OptimiserPlus to the sandbox and everything was going swimmingly. That was until we had to run one of the utility scripts that we use to rebuild some of our data structures. These scripts make use of different parts of both Zend Framework and Doctrine which tend to rely on some heavy DocBlock annotations.&lt;/p&gt;
&lt;p&gt;Now having used both APC and Zend Server knowing that they done affect this kind of functionality I had expected that OptimizerPlus would be fine&amp;hellip;. Wrongo. It took me a good few hours of head scratching trying to figure out what had happened.&lt;/p&gt;
&lt;p&gt;It turns out that OptimizerPlus suffers from the same flaws that eAccellerator does and strips Docblocks when caching the bytecode. This results in Reflection returning false when you call methods such as `getDocComment()`.&lt;/p&gt;
&lt;p&gt;All in all its not the end of the world I just disable OptimizerPlus and have to wait till I can get APC working. Not my ideal scenario but I can live with it.&lt;/p&gt;
&lt;p&gt;Something that does concern me is that there is currently an RFC that has gone to vote (&lt;a class="link" href="https://wiki.php.net/rfc/optimizerplus" title="https://wiki.php.net/rfc/optimizerplus"
 target="_blank" rel="noopener"
 &gt;https://wiki.php.net/rfc/optimizerplus&lt;/a&gt;) about integrating OptimizerPlus into the PHP 5.5 distribution. While this is great I do worry how many other things may break and will they be picked up and fixed for the 5.5 release.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; Since writing this post the RFC has finished being voted upon and has been approved. You can expect to see Optimizer Plus appearing bundled with PHP soon.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update (15th Mar 13):&lt;/strong&gt; Thanks to Dominics&amp;rsquo; comment I now know that you can tell Optimizer+ to retain your Docblocks by setting your config using&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-gdscript3" data-lang="gdscript3"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;zend_optimizerplus&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;save_comments&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;default&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;1&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;	&lt;span class="n"&gt;If&lt;/span&gt; &lt;span class="n"&gt;disabled&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;all&lt;/span&gt; &lt;span class="n"&gt;PHPDoc&lt;/span&gt; &lt;span class="n"&gt;comments&lt;/span&gt; &lt;span class="n"&gt;are&lt;/span&gt; &lt;span class="n"&gt;dropped&lt;/span&gt; &lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;code&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;reduce&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;	&lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;optimized&lt;/span&gt; &lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="n"&gt;Disabling&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Doc Comments&amp;#34;&lt;/span&gt; &lt;span class="n"&gt;may&lt;/span&gt; &lt;span class="k"&gt;break&lt;/span&gt; &lt;span class="n"&gt;some&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;	&lt;span class="n"&gt;existing&lt;/span&gt; &lt;span class="n"&gt;applications&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;frameworks&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="n"&gt;Doctrine&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ZF2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;PHPUnit&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;zend_optimizerplus&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;load_comments&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;default&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;1&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;	&lt;span class="n"&gt;If&lt;/span&gt; &lt;span class="n"&gt;disabled&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;PHPDoc&lt;/span&gt; &lt;span class="n"&gt;comments&lt;/span&gt; &lt;span class="n"&gt;are&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;loaded&lt;/span&gt; &lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;SHM&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;so&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Doc Comments&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;	&lt;span class="n"&gt;may&lt;/span&gt; &lt;span class="n"&gt;be&lt;/span&gt; &lt;span class="n"&gt;always&lt;/span&gt; &lt;span class="n"&gt;stored&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;save_comments&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;but&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;loaded&lt;/span&gt; &lt;span class="n"&gt;by&lt;/span&gt; &lt;span class="n"&gt;applications&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;	&lt;span class="n"&gt;that&lt;/span&gt; &lt;span class="n"&gt;don&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;t need them anyway.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That&amp;rsquo;ll teach me to write a blog post without investigating more first.&lt;/p&gt;</description></item><item><title>Debug PHP CLI on Remote Server with Xdebug and PHPStorm</title><link>https://blog-570662.gitlab.io/debug-cli-remote-server/</link><pubDate>Wed, 06 Feb 2013 00:00:00 +0000</pubDate><guid>https://blog-570662.gitlab.io/debug-cli-remote-server/</guid><description>&lt;p&gt;This was a head scratcher when I ran into this yesterday and I thought I would share my solution to the following scenario:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;I need to debug PHP Command Line script, located on Remote LAMP Virtual WebServer running in Virtual Box with a Shared Folder, using local PHPStorm 5.0.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The solution:&lt;/p&gt;
&lt;p&gt;You first must set PHPStorm to use remote file paths. To set these go to the following:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;PHPStorm -&amp;gt; Peferences -&amp;gt; PHP -&amp;gt; Servers&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This gives the following display:&lt;/p&gt;
&lt;p&gt;&lt;a class="link" href="http://phpboyscout.uk/wp-content/uploads/2013/02/PHPStorm-Peferences.png" target="_blank" rel="noopener"
 &gt;&lt;img alt="PHPStorm Peferences" class="gallery-image" data-flex-basis="656px" data-flex-grow="273" height="312" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://blog-570662.gitlab.io/debug-cli-remote-server/PHPStorm-Peferences.png" srcset="https://blog-570662.gitlab.io/debug-cli-remote-server/PHPStorm-Peferences_hu_a6aad5ce5c233f20.png 800w, https://blog-570662.gitlab.io/debug-cli-remote-server/PHPStorm-Peferences.png 854w" width="854"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Replace the Name, Host and Absolute path on the server, to match your own settings. Note keep the Name and Host the same for ease.&lt;/p&gt;
&lt;p&gt;Next add some breakpoints in PHPStorm and set it to listen for any debug connections using the listener icon:&lt;/p&gt;
&lt;p&gt;&lt;a class="link" href="http://phpboyscout.uk/wp-content/uploads/2013/02/Listen-to-debug-connections.png" target="_blank" rel="noopener"
 &gt;&lt;img alt="Listen to debug connections" class="gallery-image" data-flex-basis="546px" data-flex-grow="227" height="90" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://blog-570662.gitlab.io/debug-cli-remote-server/Listen-to-debug-connections.png" width="205"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Now login to your Remote Server via SSH etc.&lt;/p&gt;
&lt;p&gt;You now need to change settings for Xdebug in either xdebug.ini or php.ini depending on how you installed it. You also need to know the IP of the local machine. This can permanently set in the Network Setting of your VM in Virtual Box, so you will never have to change it. In my example the local machine running PHPStorm is:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;192.168.56.1&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Now edit the ini file that contains your Xdebug settings and set the following:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;xdebug.remote_host = 192.168.56.1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;xdebug.remote_connect_back = 0
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;xdebug.remote_port = 9000
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;xdebug.remote_handler = dbgp
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;xdebug.remote_mode = req
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;xdebug.remote_enable = 1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;xdebug.idekey = phpstorm1
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Be aware you might have to change the &lt;strong&gt;remote_host&lt;/strong&gt; and the &lt;strong&gt;idekey&lt;/strong&gt; based on your own environment. To better understand what each option does, see &lt;a class="link" href="http://xdebug.org/docs/all_settings" title="Xdebug Settings"
 target="_blank" rel="noopener"
 &gt;Xdebug Settings&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Finally, when running the script you must set the following variables:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;PHP_IDE_CONFIG=&amp;#34;serverName=dev.example.com&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;PHP_IDE_CONFIG will tell PHPStorm how to map the Remote File Paths to what it sees Locally. Again replace the URL with the Name/Host you set in PHPStorm. &lt;strong&gt;Note:&lt;/strong&gt; You can export this, if your system is only running one site; mine is not.&lt;/p&gt;
&lt;p&gt;You can run this inline with your script:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;PHP_IDE_CONFIG=&amp;#34;serverName=dev.example.com&amp;#34; ./testscript.sh
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This should send you to PHPStorm where you earlier placed breakpoints.&lt;/p&gt;
&lt;p&gt;Happy Debugging!&lt;/p&gt;</description></item><item><title>Registering custom view helpers in ZF2</title><link>https://blog-570662.gitlab.io/registering-custom-view-helpers-zf2/</link><pubDate>Wed, 18 Jul 2012 00:00:00 +0000</pubDate><guid>https://blog-570662.gitlab.io/registering-custom-view-helpers-zf2/</guid><description>&lt;p&gt;If you want to register custom view helpers with a module you can do so by using the service location built into the Skeleton Application and creating a module config that looks something like.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;return array(
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#39;view_helpers&amp;#39; =&amp;gt; array(
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#39;invokables&amp;#39; =&amp;gt; array(
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; // generic view helpers
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#39;truncate&amp;#39; =&amp;gt; &amp;#39;Zucchi\View\Helper\Truncate&amp;#39;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; // form based view helpers
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#39;bootstrapForm&amp;#39; =&amp;gt; &amp;#39;Zucchi\Form\View\Helper\BootstrapForm&amp;#39;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#39;bootstrapRow&amp;#39; =&amp;gt; &amp;#39;Zucchi\Form\View\Helper\BootstrapRow&amp;#39;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#39;bootstrapCollection&amp;#39; =&amp;gt; &amp;#39;Zucchi\Form\View\Helper\BootstrapCollection&amp;#39;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ),
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ),
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description></item><item><title>Bootstrapping ZF2 Forms</title><link>https://blog-570662.gitlab.io/bootstrapping-zf2-forms/</link><pubDate>Tue, 17 Jul 2012 00:00:00 +0000</pubDate><guid>https://blog-570662.gitlab.io/bootstrapping-zf2-forms/</guid><description>&lt;p&gt;So&amp;hellip;&lt;/p&gt;
&lt;p&gt;With the release of beta 5 for Zend Framework 2 I thought it time for me to tidy up and fix a few modules I created back at beta 3.&lt;/p&gt;
&lt;p&gt;Now I&amp;rsquo;m a big fan of Twitter Bootstrap CSS framework as I&amp;rsquo;m sure a lot of other people are as well. Seeing that the Zend Skeleton Application comes with bootstrap already included it was easy enough to set up my forms using the old ZF Forms found in ZF1.&lt;/p&gt;
&lt;p&gt;However a brand spanking new Forms component has been rolled out with ZF2. The long and the short of this new component meant that I had the opportunity to hand roll a new way of making my forms work with Twitter Bootstrap.&lt;/p&gt;
&lt;p&gt;So, a little tinkering, a quick &lt;a class="link" href="https://github.com/zendframework/zf2/pull/1893" target="_blank" rel="noopener"
 &gt;pull request&lt;/a&gt; to ZF2 to allow the definition of arbitrary options and I came up with some useful View Helpers that can be dropped into a project and used.&lt;/p&gt;
&lt;p&gt;You can find them at &lt;a class="link" href="https://github.com/zucchi/Zucchi/tree/master/src/Zucchi/Form/View/Helper" title="https://github.com/zucchi/Zucchi"
 target="_blank" rel="noopener"
 &gt;https://github.com/zucchi/Zucchi&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;So how to use them. Lets start by creating a new form (we&amp;rsquo;ll keep it simple for now)&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-gdscript3" data-lang="gdscript3"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="n"&gt;MyForm&lt;/span&gt; &lt;span class="k"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;Form&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;public&lt;/span&gt; &lt;span class="n"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;myform&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;name&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;price&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;attributes&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;type&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;text&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;required&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;required&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;placeholder&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;0.99&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;options&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;label&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;bootstrap&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;help&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;style&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;block&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;content&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;The price you wish to use&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;prepend&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;$&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;append&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;¢&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="n"&gt;actions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;actions&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="n"&gt;actions&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;setAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;class&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;form-actions&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="n"&gt;actions&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;name&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;submit&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;attributes&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;type&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;submit&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;value&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Save&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;class&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;btn btn-primary&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;options&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;bootstrap&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;style&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;inline&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="n"&gt;actions&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;name&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;reset&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;attributes&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;type&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;reset&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;value&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;reset&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;class&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;btn&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;options&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;bootstrap&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;style&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;inline&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="n"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You&amp;rsquo;ll notice that I have highlighted some lines. Thanks to the ability to set arbitrary options we can define a &amp;ldquo;bootstrap&amp;rdquo; option which we can then use to allow us to pass data into our new bootstrap view helpers. You can also see that I have added a save and reset button to a collection. I&amp;rsquo;ll explain that later.&lt;/p&gt;
&lt;p&gt;So what next&amp;hellip; Rather than go into the mechanics of how to work with forms I&amp;rsquo;ll refer you to &lt;a class="link" href="http://zend-framework-2-doc.readthedocs.org/en/latest/modules/zend.form.intro.html" title="the ZF documentation"
 target="_blank" rel="noopener"
 &gt;the ZF documentation&lt;/a&gt; and this excellent &lt;a class="link" href="http://www.michaelgallego.fr/blog/?p=190" title="New Zend\Form features explained"
 target="_blank" rel="noopener"
 &gt;blog post&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;We then pick up by looking at your view, and the helpers I have created.&lt;/p&gt;
&lt;h2 id="bootstrapformform-formstyle"&gt;BootstrapForm($form, $formStyle)
&lt;/h2&gt;&lt;p&gt;One of the few things I miss from the ZF1 implementation of Forms is the self rendering aspect! So what did I decide to do? That&amp;rsquo;s right I created a view helper to render everything in one command.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;$this-&amp;gt;bootstrapForm()&lt;/code&gt; takes two parameters. The first is quite obviously the form. The second is the style of form. This is directly related to the form types that can be found &lt;a class="link" href="http://twitter.github.com/bootstrap/base-css.html#forms" title="here"
 target="_blank" rel="noopener"
 &gt;http://twitter.github.com/bootstrap/base-css.html#forms&lt;/a&gt;. You can use any of &amp;lsquo;vertical&amp;rsquo;, &amp;lsquo;inline&amp;rsquo;, &amp;lsquo;search&amp;rsquo; &amp;amp; &amp;lsquo;horizontal&amp;rsquo;. If you dont specify a formStyle then it will default to &amp;lsquo;vertical&amp;rsquo;&lt;/p&gt;
&lt;p&gt;Caveat: This helper will then iterate through all of the associated elements and render them first. Only after the direct elements have been generated will it then move onto Collections or Fieldsets (as soon as I work out how I&amp;rsquo;ll fix this).&lt;/p&gt;
&lt;h2 id="bootstraprowelement-formstyle"&gt;BootstrapRow($element, $formStyle)
&lt;/h2&gt;&lt;p&gt;This is a straightforward modification of the &lt;code&gt;FormRow&lt;/code&gt; helper that come bundled with the new component.&lt;/p&gt;
&lt;p&gt;We have a few differences now though. We have a second parameter as with the &lt;code&gt;BootstrapForm&lt;/code&gt; view helper and the output is generated using sprintf and a set of templates that mimic the structures of the different form styles from bootstrap.&lt;/p&gt;
&lt;p&gt;This helper can be used by itself to generate an element row and is used by the &lt;code&gt;BootstrapForm&lt;/code&gt; helper&lt;/p&gt;
&lt;p&gt;We can also now take advantage of the &amp;ldquo;bootstrap&amp;rdquo; options we set earlier.&lt;/p&gt;
&lt;h3 id="bootstrap-options"&gt;Bootstrap Options
&lt;/h3&gt;&lt;p&gt;style&lt;/p&gt;
&lt;p&gt;The style of form element to use regardless of what style may be passed into the view helper (you can see an example of this in the buttons from the MyForm example above)&lt;/p&gt;
&lt;p&gt;help&lt;/p&gt;
&lt;p&gt;This works in the same way as &amp;ldquo;description&amp;rdquo; did from ZF1 but allows you to define it either as a string or an array with the keys &amp;ldquo;style&amp;rdquo; for either &amp;lsquo;inline&amp;rsquo; or &amp;lsquo;block&amp;rsquo; and &amp;ldquo;Content&amp;rdquo; which should be self explainatory&lt;/p&gt;
&lt;p&gt;prepend&lt;/p&gt;
&lt;p&gt;Takes advantage of Bootstraps ability to prepend blocks to an input field. This can be defined as a single string, or an array of strings to allow you to add multiple blocks should you want to&lt;/p&gt;
&lt;p&gt;prepend&lt;/p&gt;
&lt;p&gt;Takes advantage of Bootstraps ability to append blocks to an input field. This can be defined as a single string, or an array of strings to allow you to add multiple blocks should you want to&lt;/p&gt;
&lt;p&gt;These options get evaluated and spat out from the new &lt;code&gt;renderBootstrapOptions()&lt;/code&gt; method as part of the &amp;ldquo;render&amp;rdquo;.&lt;/p&gt;
&lt;h2 id="bootstrapcollectionelement-style-wrap"&gt;BootstrapCollection($element, $style, $wrap)
&lt;/h2&gt;&lt;p&gt;Again this is a direct rip off of the &lt;code&gt;FormCollection&lt;/code&gt; helper found in the ZF2 Form component witha few modifications. The main difference is that is makes use of the &lt;code&gt;BootstrapRow&lt;/code&gt; helper and has methods and properties to allow the setting of the form style to use.&lt;/p&gt;
&lt;p&gt;You can see from the &lt;code&gt;MyForm&lt;/code&gt; example above that we set a &lt;code&gt;Collection&lt;/code&gt; called &amp;lsquo;actions&amp;rsquo;. This is a pretty standard way of grouping elements together. You can also see that we set a class for the &lt;code&gt;Collection&lt;/code&gt; which may look familiar to those that have used Twitter Bootstrap for a while.&lt;/p&gt;
&lt;p&gt;What our helper will then do is wrap the buttons in a div with the appropriate class attached. If you were to define a &lt;code&gt;label&lt;/code&gt; for the Collection/Fieldset You would then also find that the fieldset and legend tags are also spat out with our &lt;code&gt;&amp;lt;div class=&amp;quot;form-actions&amp;quot;&amp;gt;&lt;/code&gt; sandwiched between them and the elements.&lt;/p&gt;
&lt;h3 id="result"&gt;Result
&lt;/h3&gt;&lt;p&gt;So what we now get when we use &lt;code&gt;MyForm&lt;/code&gt; with out helpers.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$this-&amp;gt;bootstrapForm($form, &amp;#39;horizontal&amp;#39;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Should now look something like this&lt;/p&gt;
&lt;p&gt;&lt;a class="link" href="http://phpboyscout.uk/wp-content/uploads/2012/07/bootstrap-result1.png" target="_blank" rel="noopener"
 &gt;&lt;img alt="results of bootstrap helper" class="gallery-image" data-flex-basis="760px" data-flex-grow="316" data-title-escaped="bootstrap-result" height="159" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://blog-570662.gitlab.io/bootstrapping-zf2-forms/bootstrap-result1.png" title="bootstrap-result" width="504"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="how-you-can-use-it"&gt;How you can use it
&lt;/h3&gt;&lt;p&gt;As of right now you can get the library from its repo on github @ &lt;a class="link" href="https://github.com/zucchi/Zucchi" target="_blank" rel="noopener"
 &gt;https://github.com/zucchi/Zucchi&lt;/a&gt; and can be found on &lt;a class="link" href="http://packagist.org/packages/zucchi/zucchi" title="zucchi/zucchi"
 target="_blank" rel="noopener"
 &gt;packagist&lt;/a&gt; for use with composer&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Edit:&lt;/strong&gt; The bootstrap stuff has moved to a new location as a separate ZF2 module. you can find it @ &lt;a class="link" href="https://github.com/zucchi/ZucchiBootstrap" target="_blank" rel="noopener"
 &gt;https://github.com/zucchi/ZucchiBootstrap&lt;/a&gt; or @ &lt;a class="link" href="http://packagist.org/packages/zucchi/bootstrap" title="zucchi/bootstrap"
 target="_blank" rel="noopener"
 &gt;packagist&lt;/a&gt; for use with composer&lt;/p&gt;</description></item></channel></rss>