
<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Development &#8211; Conetix</title>
	<atom:link href="https://testing.conetix.com.au/blog/category/development/feed/" rel="self" type="application/rss+xml" />
	<link>https://testing.conetix.com.au</link>
	<description>Premier Web Hosting Provider</description>
	<lastBuildDate>Thu, 17 Oct 2024 00:17:28 +0000</lastBuildDate>
	<language>en-AU</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	

<image>
	<url>https://testing.conetix.com.au/wp-content/uploads/favicon.png</url>
	<title>Development &#8211; Conetix</title>
	<link>https://testing.conetix.com.au</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Anchoring Bias: The IT Technician&#8217;s Arch Nemesis for fault finding</title>
		<link>https://testing.conetix.com.au/blog/anchoring-bias-the-it-technicians-arch-nemesis-for-fault-finding/</link>
					<comments>https://testing.conetix.com.au/blog/anchoring-bias-the-it-technicians-arch-nemesis-for-fault-finding/#comments</comments>
		
		<dc:creator><![CDATA[Tim Butler]]></dc:creator>
		<pubDate>Tue, 25 Aug 2020 04:17:06 +0000</pubDate>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[General]]></category>
		<category><![CDATA[anchor bias]]></category>
		<category><![CDATA[bias]]></category>
		<category><![CDATA[expert beginner]]></category>
		<category><![CDATA[fault finding]]></category>
		<category><![CDATA[learning]]></category>
		<guid isPermaLink="false">https://conetix.com.au/?p=11454</guid>

					<description><![CDATA[Regardless of if we realise it or not, we apply our own biases to our cognitive thinking all the time. In the Information Technology (IT) world of diagnostics, one of the most influential is Anchoring Bias. Let’s start with the definition: Anchoring or focalism is a cognitive bias where an individual depends too heavily on...  <a class="excerpt-read-more" href="https://testing.conetix.com.au/blog/anchoring-bias-the-it-technicians-arch-nemesis-for-fault-finding/" title="Read Anchoring Bias: The IT Technician&#8217;s Arch Nemesis for fault finding">Read more &#187;</a>]]></description>
										<content:encoded><![CDATA[
<p>Regardless of if we realise it or not, we apply our own biases to our cognitive thinking all the time. In the Information Technology (IT) world of diagnostics, one of the most influential is <strong>Anchoring Bias.</strong> Let’s start with the definition:</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p><em>Anchoring or focalism is a cognitive bias where an individual depends too heavily on an initial piece of information offered to make subsequent judgments during decision making. Once the value of this anchor is set, all future negotiations, arguments, estimates, etc. are discussed in relation to the anchor.</em></p><cite>Source: <a href="https://en.wikipedia.org/wiki/Anchoring_(cognitive_bias)">https://en.wikipedia.org/wiki/Anchoring_(cognitive_bias)</a></cite></blockquote>



<p>The important part to remember here is that <strong>subconsciously your brain can and will fixate on the first piece of information it finds</strong>. When it comes to fault finding, this can be the first error we see or the first reported information provided. This information (and therefore bias) can then cloud our judgement when it comes to further diagnostics of a fault, as we gravitate back to that singular piece of information instead of considering the bigger picture.</p>



<p>An IT person’s job is normally 90% fault finding, 10% doing. As the saying goes: “<em>I’m not a geek, I’m just better at Googling than you</em>”. What’s more, the saying is right. Nobody wants to spend 3 hours diagnosing the cause of a fault if they can simply jump straight to the fix.</p>



<p>Programmers are no different here too, the moment there’s a fault or error message it’s straight to Google to try and find someone else who’s had the same issue so that they can copy and paste the code to fix.</p>



<div class="wp-block-image"><figure class="aligncenter size-large"><img fetchpriority="high" decoding="async" width="735" height="613" src="https://testing.conetix.com.au/wp-content/uploads/2020/07/doctors-googling-stuff-online-does-not-make-you-a-doctor-programmers-confused.jpg" alt="" class="wp-image-11457" srcset="https://testing.conetix.com.au/wp-content/uploads/2020/07/doctors-googling-stuff-online-does-not-make-you-a-doctor-programmers-confused.jpg 735w, https://testing.conetix.com.au/wp-content/uploads/2020/07/doctors-googling-stuff-online-does-not-make-you-a-doctor-programmers-confused-300x250.jpg 300w, https://testing.conetix.com.au/wp-content/uploads/2020/07/doctors-googling-stuff-online-does-not-make-you-a-doctor-programmers-confused-50x42.jpg 50w, https://testing.conetix.com.au/wp-content/uploads/2020/07/doctors-googling-stuff-online-does-not-make-you-a-doctor-programmers-confused-32x27.jpg 32w, https://testing.conetix.com.au/wp-content/uploads/2020/07/doctors-googling-stuff-online-does-not-make-you-a-doctor-programmers-confused-64x53.jpg 64w, https://testing.conetix.com.au/wp-content/uploads/2020/07/doctors-googling-stuff-online-does-not-make-you-a-doctor-programmers-confused-128x107.jpg 128w" sizes="(max-width: 735px) 100vw, 735px" /><figcaption>Source: <a href="https://starecat.com/doctors-googling-stuff-online-does-not-make-you-a-doctor-programmers-confused/">starecat.com</a></figcaption></figure></div>



<p>While finding the right result in Google can and does lead to a quick fix in many cases, it can also lead to a fallacy in your decision making process. In many cases, the focus is then on finding the right result for the error message, not <strong>why </strong>the error message existed in the first place.</p>



<h2 class="wp-block-heading">A real world example</h2>



<p>This is where Anchoring bias will rear its ugly head. If we see an error message about backups failing because it couldn’t run a certain command, we’re straight onto Google to find someone else who’s experienced that error message. IT faults can usually be broken down into three parts:</p>



<div class="wp-block-image"><figure class="aligncenter size-large"><img decoding="async" width="240" height="300" src="https://testing.conetix.com.au/wp-content/uploads/2020/07/conetix-fault-parts.png" alt="" class="wp-image-11458" srcset="https://testing.conetix.com.au/wp-content/uploads/2020/07/conetix-fault-parts.png 240w, https://testing.conetix.com.au/wp-content/uploads/2020/07/conetix-fault-parts-40x50.png 40w, https://testing.conetix.com.au/wp-content/uploads/2020/07/conetix-fault-parts-26x32.png 26w, https://testing.conetix.com.au/wp-content/uploads/2020/07/conetix-fault-parts-51x64.png 51w, https://testing.conetix.com.au/wp-content/uploads/2020/07/conetix-fault-parts-102x128.png 102w" sizes="(max-width: 240px) 100vw, 240px" /></figure></div>



<p>To start with, we normally only have the result and the output. For example:</p>



<figure class="wp-block-table"><table><tbody><tr><td><strong>Result</strong></td><td>Backups Failed</td></tr><tr><td><strong>Output</strong></td><td>Error message in the logs that the system didn’t have the correct permissions to create the backup file.</td></tr></tbody></table></figure>



<p>In this scenario (which was a real world one), it’s very easy to race to the conclusion that the filesystem has the wrong permissions and start to google for “Vendor X error file permissions” or to even start instantly running commands to widen permissions.</p>



<p>Scenarios like this are what have led to so many S3 bucket leaks, where the wrong fix is applied to a backup failure fault and while it may fix the problem it’s created a far worse one behind the scenes.</p>



<p>Because the focus was all on <strong>what</strong> the error said, we lost sight of the actual fault itself. In this real world scenario, here was the resultant fault:</p>



<figure class="wp-block-table"><table><tbody><tr><td><strong>Fault</strong></td><td>Storage was full.</td></tr></tbody></table></figure>



<p>The true fault ended up being that the backup system had run out of disk space. The particular vendor (seemingly) had no check in place to determine if it should try to create a new backup file and therefore failed during that particular area of the code.</p>



<p>But why the wrong error message? It’s normally because we see error messages where a try / catch or other similar error handling is too broad. For example, here’s some pseudo code for the above example:</p>



<pre class="wp-block-code"><code>try {
   create_backup_file();
   set_backup_permissions();
   start_backup();
}
catch (err) {
   panic("Failed to start the backup. Tried to set the backup permissions but couldn't do so");
}</code></pre>



<p>Because there’s multiple potential points of failure handled by a singular error message, it means the error itself may not be enough to effectively fault find.</p>



<p>Those who remember Windows 95 and had filled their hard drive may have been greeted with this error:</p>



<div class="wp-block-image"><figure class="aligncenter size-large"><img decoding="async" width="800" height="267" src="https://testing.conetix.com.au/wp-content/uploads/2020/07/cannot-delete-samples.jpg" alt="" class="wp-image-11459" srcset="https://testing.conetix.com.au/wp-content/uploads/2020/07/cannot-delete-samples.jpg 800w, https://testing.conetix.com.au/wp-content/uploads/2020/07/cannot-delete-samples-300x100.jpg 300w, https://testing.conetix.com.au/wp-content/uploads/2020/07/cannot-delete-samples-768x256.jpg 768w, https://testing.conetix.com.au/wp-content/uploads/2020/07/cannot-delete-samples-50x17.jpg 50w, https://testing.conetix.com.au/wp-content/uploads/2020/07/cannot-delete-samples-32x11.jpg 32w, https://testing.conetix.com.au/wp-content/uploads/2020/07/cannot-delete-samples-64x21.jpg 64w, https://testing.conetix.com.au/wp-content/uploads/2020/07/cannot-delete-samples-128x43.jpg 128w" sizes="(max-width: 800px) 100vw, 800px" /><figcaption>Source: <a href="https://www.techrepublic.com/pictures/27-old-school-computer-error-screens-that-will-fill-you-with-anxiety/12/">techrepublic.com</a></figcaption></figure></div>



<p>This one is obvious of course, but a simple example of how the wrong conclusion to a fault has led to a scenario which doesn’t make sense.</p>



<h2 class="wp-block-heading">It gets worse</h2>



<p>Even worse, when there’s no corresponding error message or log output for the fault at all, we can sometimes attribute the fault to one of the other (unrelated) error messages. This scenario still involves Anchoring bias as we’ve fixated on the first message seen and means we drift even further off track trying to find the fault. Time is now spent chasing errors which aren’t even related to the original fault, leading to the possibility of applying fixes which will make things worse instead of better. These “fixes” can then induce further faults, leading to a huge mess or catastrophic failure instead of a minor one.</p>



<p>Biases can also be combined subconsciously with other cognitive faults as well. As it was distinctly put by Erik Dietrich, you can also have <strong><a href="https://daedtech.com/how-developers-stop-learning-rise-of-the-expert-beginner/">Expert Beginners</a></strong>:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="413" height="777" src="https://testing.conetix.com.au/wp-content/uploads/2020/07/ExpertBeginner.jpg" alt="" class="wp-image-11462" srcset="https://testing.conetix.com.au/wp-content/uploads/2020/07/ExpertBeginner.jpg 413w, https://testing.conetix.com.au/wp-content/uploads/2020/07/ExpertBeginner-159x300.jpg 159w, https://testing.conetix.com.au/wp-content/uploads/2020/07/ExpertBeginner-27x50.jpg 27w, https://testing.conetix.com.au/wp-content/uploads/2020/07/ExpertBeginner-17x32.jpg 17w, https://testing.conetix.com.au/wp-content/uploads/2020/07/ExpertBeginner-34x64.jpg 34w, https://testing.conetix.com.au/wp-content/uploads/2020/07/ExpertBeginner-68x128.jpg 68w" sizes="auto, (max-width: 413px) 100vw, 413px" /><figcaption>Source: <a href="https://daedtech.com/how-developers-stop-learning-rise-of-the-expert-beginner/" target="_blank" aria-label="undefined (opens in a new tab)" rel="noreferrer noopener">daedtech.com</a></figcaption></figure>



<p>The difficulty is that as you learn, you can fall into the false trap that you understand a system well enough that your learning plateaus. This is normally due to only having a narrow view or understanding of a system, whereby you’ve only dealt with a small component of a large system and therefore reach the logical fallacy that you’ve learnt everything there is to know.</p>



<p>This narrowed view combined with anchoring bias leads will often strip you of the ability to consider wider views of the systems and the complexities involved.</p>



<h2 class="wp-block-heading">How do we get around it?</h2>



<p>There’s a few quick steps we can take:</p>



<p><strong>Acknowledge the existence of bias:</strong> Like any bias, the first step is to acknowledge the existence. Once you know to be wary of this bias, it means you can compensate for it. There’s more than a dozen <a href="https://en.wikipedia.org/wiki/List_of_cognitive_biases" target="_blank" rel="noreferrer noopener">different biases</a> which can affect your fault finding and decision making processes too, so it&#8217;s worth understanding how and where they may affect your thinking.</p>



<p><strong>Write the fault out on paper:</strong> In the same way that <a href="https://en.wikipedia.org/wiki/Rubber_duck_debugging" target="_blank" rel="noreferrer noopener">Rubber duck debugging</a> can help you because it forces you to put all the pieces together, writing it out on paper can also achieve the same thing. I also find drawing a timeline or flow diagram also helps, again because your brain will skip parts unless you force it to explicitly detail each stage.</p>



<p><strong>Treat error messages with scepticism.</strong> Unless you can see the code itself to confirm, expect that they may not cover every fault scenario fully and may be generic messages. Think about the error message in context, does it fit the fault scenario? Did it occur timing wise when you&#8217;d expect it to trigger? Could it be triggered by a different scenario?</p>



<p><strong>Look for the cause, not the symptom:</strong> This is the most effective method. Many of these examples can be traced back to the fault if you look for the <strong>cause</strong>. This isn’t to say we ignore the symptoms as such, but in a broad sense we use them as guidance not as gospel.&nbsp;</p>



<p>In our storage scenario, we can use the fact that it can’t set file permissions as a guide that the fault is to do with the filesystem and not as narrow as just file permissions themselves.</p>



<p>Running through rudimentary system checks in these scenarios (ie, looking at space, system load, network errors etc) can potentially serve as a quick sanity check and identify root causes early. At the very least, they will give you some confirmation that there’s not a high level or systemic fault.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://testing.conetix.com.au/blog/anchoring-bias-the-it-technicians-arch-nemesis-for-fault-finding/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>What is a nulled plugin?</title>
		<link>https://testing.conetix.com.au/blog/what-is-a-nulled-plugin/</link>
		
		<dc:creator><![CDATA[Tim Butler]]></dc:creator>
		<pubDate>Thu, 02 Apr 2020 00:24:00 +0000</pubDate>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Security]]></category>
		<category><![CDATA[WordPress]]></category>
		<category><![CDATA[compromise]]></category>
		<category><![CDATA[download]]></category>
		<category><![CDATA[free]]></category>
		<category><![CDATA[nulled]]></category>
		<category><![CDATA[paid]]></category>
		<category><![CDATA[plugin]]></category>
		<category><![CDATA[pro]]></category>
		<category><![CDATA[wp-vcd]]></category>
		<category><![CDATA[wpvcd]]></category>
		<guid isPermaLink="false">https://conetix.com.au/?p=10403</guid>

					<description><![CDATA[Everyone loves things for free, which is one of the contributing factors which has led to the popularity of WordPress as a Content Management System (CMS). Now commanding over 60% of the CMS market, third party plugins and themes are therefore a booming market as well. While within WordPress you can automatically search and find...  <a class="excerpt-read-more" href="https://testing.conetix.com.au/blog/what-is-a-nulled-plugin/" title="Read What is a nulled plugin?">Read more &#187;</a>]]></description>
										<content:encoded><![CDATA[
<p>Everyone loves things for free, which is one of the contributing factors which has led to the popularity of WordPress as a Content Management System (CMS). Now commanding over 60% of the CMS market, third party plugins and themes are therefore a booming market as well.</p>



<p>While within WordPress you can automatically search and find many thousands of free plugins and themes, developers often have a “pro” or premium version where they provide additional functionality and features for their paid version. The free versions are often a great way to try the basics of a product and in many instances they offer enough functionality that you may not even require a more comprehensive version.</p>



<p>However, when you do there’s a temptation for some to go and find a “nulled” version of the plugin for free so that you don’t have to pay for it.</p>



<h2 class="wp-block-heading"><strong>What is a “nulled” plugin?</strong></h2>



<p>The original term “nulled” used to refer to paid applications where any copyright protection (such as remote license checks) are disabled or bypassed. While it used to be mostly focussed around desktop software, it also applies to the web as well.</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p><strong>This software is illegal.</strong></p>
</blockquote>



<p>However, rather than just being altruistic notions to release software for free so that everyone can use it, nearly all nulled WordPress plugins and themes contain <strong>malware.</strong> This malware will vary in payload, but in nearly all instances will infect your site beyond just the plugin and add hooks into the core and/or other components so that third party entities can upload other malicious code to use your website for illegal means.</p>



<p>This illegal usage could vary from sending spam, conducting phishing campaigns and even be as severe as to delete your data and hold it to ransom through cryptoware.&nbsp;</p>



<h2 class="wp-block-heading"><strong>Why do I have to pay for some plugins and themes?&nbsp;</strong></h2>



<p>The simple answer is, <strong>software is written by humans and humans need to eat</strong>. Yes, while many developers may seem advanced and futuristic boffins at times, they still succumb to the rat race of work-eat-sleep.&nbsp;</p>



<p>In fact, if you get value from the plugin or theme then paying for it is a good way to ensure that the developer can afford to continue to work on it. Given that some CMS platforms in the enterprise world charge upwards of $60,000 per year, paying $99 (for example) is still outstanding value and still one of the cheapest parts of running a business or website.</p>



<h2 class="wp-block-heading"><strong>Should I use a nulled plugin or theme?</strong></h2>



<p class="has-large-font-size"><strong><span class="has-inline-color has-vivid-red-color">NO. </span></strong></p>



<p>The only reason I have this here so bluntly is so that there is no ambiguity whatsoever.&nbsp;</p>



<p>While the previous section should clearly articulate why, many don’t heed the warning signs and continue down the path of nulled plugins or nulled themes.</p>



<p>If you require the services of a paid plugin and can’t afford to purchase it, you have three options:</p>



<ol class="wp-block-list">
<li>Find an alternative.</li>



<li>Go without it.</li>



<li>Find a way to pay for it.</li>
</ol>



<p>The great thing about WordPress is the amount of choice you have, so if you find that a plugin is too expensive then there may be alternative out there already. </p>



<h2 class="wp-block-heading"><strong>What sites offer nulled plugins?</strong></h2>



<p>If you’re not downloading it directly from the plugin author’s site after paying for it, chances are it’s a nulled plugin. There is only one site to trust for downloads, and that’s <a href="https://wordpress.org">wordpress.org</a>.&nbsp;</p>



<p>Any other site should be displaying a high degree of caution and you will need to verify the site. There are a few ways to check this:</p>



<ol class="wp-block-list">
<li>Is the site linked from a free version within wordpress.org or within the plugin / theme itself?</li>



<li>Does the URL of the site match the website contained within the official social media sites?</li>



<li>Are there any deals on the site which seem “too good to be true” ?</li>



<li>Have you arrived at the site from a trusted link?</li>
</ol>



<p>If there’s any ambiguity in the above four steps, <strong>STOP</strong>. Verify the site with your web developer or trusted technical advisor before downloading and before paying any money.</p>



<h2 class="wp-block-heading"><strong>What should I do if I discover I have a nulled plugin?</strong></h2>



<p>We recommend you <strong>immediately </strong>contact your web developer <strong>and </strong>check what backups you have for your site. Once a nulled plugin or theme has been installed, it may have completely compromised your website and this may require a restoration from backup.</p>



<p>We’d also recommend <a href="https://testing.conetix.com.au/support/installing-and-configuring-wordfence/">installing WordFence</a> and running a full scan of your website. This can identify and correct security issues in many instances. While we’ve found that WordFence is the best security tool out there, you shouldn’t ever be 100% reliant on a singular tool to correct any security issues.</p>



<p>You should also contact your hosting provider, as they may have additional tools to scan your website and may be able additional information about the level of compromise to your website.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="666" height="369" src="https://testing.conetix.com.au/wp-content/uploads/2017/01/10/website-malware.png" alt="Website with malware" class="wp-image-1528" srcset="https://testing.conetix.com.au/wp-content/uploads/2017/01/10/website-malware.png 666w, https://testing.conetix.com.au/wp-content/uploads/2017/01/10/website-malware-300x166.png 300w" sizes="auto, (max-width: 666px) 100vw, 666px" /></figure>



<p>Lastly, you should check your <a href="https://search.google.com/search-console/about">Google Search Console</a> for any warnings or notifications. If Google has detected that your site has a security compromise amd/or is being used for phishing then it will either display a warning message or completely block access <strong>and </strong>have a potential SEO impact.</p>



<h2 class="wp-block-heading"><strong>Conclusion</strong></h2>



<p>As the saying goes, prevention is better than the cure. The only way to 100% ensure any infection or compromise is removed is to restore the site from a backup prior to the nulled plugin or theme being installed.</p>



<p>We highly recommend that you show your support for your favourite plugins and themes by playing for them. By ensuring that the developers have a sustainable income from the plugins and themes they provide, you’re also ensuring that development continues and it’s highly likely that new features will continue to be released.</p>



<p class="has-small-font-size"><em>Cover photo by&nbsp;<a href="https://unsplash.com/@markusspiske?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Markus Spiske</a>&nbsp;on&nbsp;<a href="https://unsplash.com/s/photos/hacker?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></em>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Laravel 5 Implementing Scheduled Themes</title>
		<link>https://testing.conetix.com.au/blog/laravel-5-implementing-scheduled-themes-3/</link>
		
		<dc:creator><![CDATA[Sid Young]]></dc:creator>
		<pubDate>Mon, 04 Sep 2017 05:58:00 +0000</pubDate>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[framework]]></category>
		<category><![CDATA[laravel]]></category>
		<category><![CDATA[php]]></category>
		<guid isPermaLink="false">https://conetix.com.au/laravel-5-implementing-scheduled-themes-3/</guid>

					<description><![CDATA[Introduction Here at Conetix we have&#160;been&#160;using the Laravel PHP Framework for many internal&#160;business automation projects for the last 2 years, we have also noticed a growing range of software coming on the market using the Laravel Framework. We host a lot of WordPress sites (also Joomla, Drupal, Magento) and as these are all PHP based...  <a class="excerpt-read-more" href="https://testing.conetix.com.au/blog/laravel-5-implementing-scheduled-themes-3/" title="Read Laravel 5 Implementing Scheduled Themes">Read more &#187;</a>]]></description>
										<content:encoded><![CDATA[<h2>Introduction</h2>
<p>Here at Conetix we have&nbsp;been&nbsp;using the Laravel PHP Framework for many internal&nbsp;business automation projects for the last 2 years, we have also noticed a growing range of software coming on the market using the Laravel Framework. We host a lot of WordPress sites (also Joomla, Drupal, Magento) and as these are all PHP based like&nbsp;Laravel, it seams natural for us to be able to support it and use it. As our skill set has risen so has the need to implement features not found natively in the framework.</p>
<p>Recently I wrote a number of articles on Laravel, some have been geared towards refactoring&nbsp;such as this article &quot;<a href="https://www.conetix.com.au/blog/developing-applications-laravel-5-part-2">Developing applications with Laravel 5 &#8211; Part 2</a>&quot;. In fact I find each release of Laravel requires me to do some degree of refactoring and as I learn more and more about the framework I go back and refactor a lot of code removing big chunks of code that is already provided in the framework. In this article, I&#39;m going to outline a simple date based mechanism for rendering themes in any Laravel Application.&nbsp;For this tutorial I have used&nbsp;Laravel v5.3 and the code does not require any additional packages other than what comes standard.</p>
<p>To implement Themes, the design concept is simple, use a directory in&nbsp;the resources/views directory called &quot;Themes&quot; and under that a &quot;default&quot; directory to hold our basic fully functional application code prior to any theme specific code. To add another theme, you simply create a sub-directory under &quot;Themes&quot; and provide the required directories for the various components the software requires. If you only provide a sub-set of the directories then the &quot;default&quot; theme components are used instead.</p>
<p>For this tutorial, the default theme directories (located under resources/views/Themes/default) are:</p>
<ul>
<li>Home</li>
<li>Header</li>
<li>Footer</li>
<li>Errors</li>
<li>Includes</li>
<li>Support</li>
</ul>
<p>Additional directories can be added by you over time as your application evolves, so you have the flexibility to craft your own directory structures.</p>
<p>In this tutorial, Themes are activated based on the date, but there is no reason why you cannot use a field in your &quot;users&quot; table to add a theme name and specify a &quot;per user theme&quot;. I will outline it in the provider code below. But I&#39;ve used the date based mechanism so you can use the code in an eCommerce application, that way&nbsp;you can stage well in advance the look and feel of the site for various festival times of the year like Christmas, Halloween, New Years Eve etc. This is controlled from a database table called &quot;themes&quot;. When no theme applies the &quot;default&quot; is automatically used.</p>
<h2>Database Migration</h2>
<p>For this tutorial we first need to have a&nbsp;database table to hold the theme name (case sensitive), a starting date and ending date the theme is active for. Keep in mind, when a theme is not found, the default is active.</p>
<p>Using the &quot;artisan&quot; tool, we can create our Model and Migration template as such:</p>
<pre class="prettyprint lang-sh " data-pbcklang="sh" data-pbcktabsize="4">
#php artisan make:model Theme --migration</pre>
<p>After defining the fields, the migration file looks like this:</p>
<pre class="prettyprint lang-php " data-pbcklang="php" data-pbcktabsize="4">
&lt;?php

use IlluminateSupportFacadesSchema;
use IlluminateDatabaseSchemaBlueprint;
use IlluminateDatabaseMigrationsMigration;

class CreateThemesTable extends Migration
{
    /**
    * Run the migrations.
    *
    * @return void
    */
    public function up()
    {
        Schema::create(&#39;themes&#39;, function (Blueprint $table) {
        $table-&gt;increments(&#39;id&#39;);
            $table-&gt;string(&#39;theme_name&#39;);
            $table-&gt;date(&#39;theme_date_from&#39;);
            $table-&gt;date(&#39;theme_date_to&#39;);
            $table-&gt;timestamps();
        });
    }

    /**
    * Reverse the migrations.
    *
    * @return void
    */
    public function down()
    {
        Schema::dropIfExists(&#39;themes&#39;);
    }
}</pre>
<p>After you have created the migration file, you can run it using the following command:</p>
<pre class="prettyprint lang-sh " data-pbcklang="sh" data-pbcktabsize="4">
#php artisan migrate</pre>
<p>The database table should be created and look like this:</p>
<pre class="prettyprint lang-sh " data-pbcklang="sh" data-pbcktabsize="">
MariaDB [teststore]&gt; desc themes;
+-----------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------------+------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| theme_name | varchar(255) | NO | | NULL | |
| theme_date_from | date | NO | | NULL | |
| theme_date_to | date | NO | | NULL | |
| created_at | timestamp | YES | | NULL | |
| updated_at | timestamp | YES | | NULL | |
+-----------------+------------------+------+-----+---------+----------------+
7 rows in set (0.01 sec)</pre>
<h2>Model Code</h2>
<p>The Model code created by the Laravel &quot;Artisan&quot; tool&nbsp;is pretty basic, I added one line of code, the $table variable. And changed the namespace to AppModels as I keep all my Model code in app/Models. See my previous article on <a href="https://www.conetix.com.au/blog/namespaces-laravel-applications">Namespaces&nbsp;In Laravel Applications</a></p>
<pre class="prettyprint lang-php " data-pbcklang="php" data-pbcktabsize="4">
&lt;?php

namespace AppModels;

use IlluminateDatabaseEloquentModel;

class Theme extends Model
{
    protected $table = &quot;themes&quot;;
}</pre>
<h2>Service Provider</h2>
<p>As hinted to earlier, the correct theme to apply is determined in the <a href="https://laravel.com/docs/5.4/providers">service provider</a>. &nbsp;Laravel service providers live in the app/Providers directory, and for our tutorial I have called ours &quot;ThemeServiceProvider.php&quot;.</p>
<p>The provider&nbsp;has to read our theme table using a single Eloquent call, to get all themes then, using today&#39;s date, work out the theme name to apply and finally determine the correct Theme paths and create the global variables for the Views and Controllers that need to know about where the blade templates are located.</p>
<p>If you were to build a per user based theme, then you could get the user ID, read the users table and set the $theme_name variable to the desired theme and not process any date specific code,&nbsp;the rest of the path determining code remains the same.</p>
<p>The working Provider code is as follows:</p>
<pre class="prettyprint lang-php " data-pbcklang="php" data-pbcktabsize="4">
&lt;?php
/**
* @author Sid Young
* @date 2017-09-04
* class ThemeServiceProvider
*
*
* [CC]
*/
namespace AppProviders;

use IlluminateSupportFacadesView;
use IlluminateSupportServiceProvider;
use AppModelsTheme;

/**
* brief Provides a series of global variables that can be used to access the required Theme Directory structure.
* See notes above for user based themes rather than date based themes.
*/
class ThemeServiceProvider extends ServiceProvider
{

/**
* Assign our theme paths, point to default theme path if named theme does not have the required path.
* That way you can implement but some components as needed (like a different header at certain times of the year).
*
* @return void
*/
public function boot()
{
$theme_name = &quot;default&quot;;
$today = strtotime(date(&quot;Y-m-d&quot;));
#
# 1. Get theme names from DB table, 
#    For &quot;user&quot; based themes, read the user table for the logged in user.
#
$theme_data = Theme::all();
foreach($theme_data as $t)
{
  #
  # 2. Test for the required date range.
  #    For &quot;user&quot; based themes, comment this out and just set the $theme_name variable.
  if(($today &gt;= strtotime($t-&gt;theme_date_from)) &amp;&amp; ($today &lt;=strtotime($t-&gt;theme_date_to)))
  {
    $theme_name = $t-&gt;theme_name;
    break;
  }
}
View::share(&quot;THEME_NAME&quot;, $theme_name);
#
# 3. Build Paths, test and set path, if dir does not exist then set the default path.
#
$theme_directories = array(&quot;Home&quot;,&quot;Header&quot;,&quot;Footer&quot;,&quot;Support&quot;,&quot;Includes&quot;,&quot;Errors&quot;);
foreach($theme_directories as $theme_dir)
{
   $theme_u_dir = &quot;THEME_&quot;.strtoupper($theme_dir);
   $blade_path = &quot;Themes.&quot;.$theme_name.&quot;.&quot;.$theme_dir.&quot;.&quot;;
   $default_blade_path = &quot;Themes.default.&quot;.$theme_dir.&quot;.&quot;;

    $path = resource_path(&quot;views/Themes/&quot;.$theme_name.&quot;/&quot;.$theme_dir);
    #echo &quot;PATH: &quot;.$path.&quot;&lt;br&gt;&quot;;
    if(file_exists($path) &amp;&amp; is_dir($path))
    {
      View::share($theme_u_dir, $blade_path);
      Config::set($theme_u_dir , $blade_path);
    }
    else
    {
       View::share($theme_u_dir, $default_blade_path);
       Config::set($theme_u_dir, $default_blade_path);
    }
  }
}

  /**
   * Register any application services.
   *
   * @return void
   */
   public function register()
   {
   }
}</pre>
<p>To make the &quot;THEME_XXXXX&quot;&nbsp;variables available to the application we use the View:share() method, this enables every directory we need to be defined, if the theme directory does not exist, we assign it to the equivalent &quot;default&quot; structure.</p>
<p>An example of the theme paths are:</p>
<ul>
<li>Themes/default</li>
<li>Themes/&lt;your_theme_name&gt;</li>
<li>Themes/&lt;next_theme_name&gt;</li>
</ul>
<p>To make the theme variables available in our Controller we use the <a href="https://laravel.com/docs/5.4/configuration">Config::set()</a>&nbsp;in the Provider and Config::get() method in the Controller(s). The Theme Home variable becomes THEME_HOME and points to Themes/&lt;your_theme_name&gt;/Home but returns a string formatted for accessing a Blade, &quot;Themes.&lt;your_theme_name&gt;.Home.&quot;, note the trailing &quot;.&quot;, its for convenience when constructing Blade paths.</p>
<p>So if we created a theme called &quot;modern&quot;, THEME_HOME would be:</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <strong>Themes.modern.Home.</strong></p>
<p>We only need to add onto the end the view located in the /Themes/modern/Home/ directory to get the Blade to render.</p>
<p>The last step for the Service Provider is to enable it in our app.php config file, using &quot;vi&quot; or your favourite editor, open the config/app.php file and add this line to the end of the &quot;providers&quot; array:</p>
<pre class="prettyprint lang-php " data-pbcklang="php" data-pbcktabsize="4">
...
AppProvidersThemeServiceProvider::class,
];
</pre>
<p>Save the file and test your development site, it should continue to render without error.</p>
<h2>Controller Code</h2>
<p>The <a href="https://laravel.com/docs/5.4/controllers">Controller</a> code needs to know the theme variable in order to call the appropriate view. Where we would normally invoke a view with something like:</p>
<p>return view(&#39;Users.testpage&#39;,[&#39;mydata&#39;=&gt;$mydata]);</p>
<p>We now use a Config:get(&#39;THEME_HOME&#39;) call like so:</p>
<pre class="prettyprint lang-php " data-pbcklang="php" data-pbcktabsize="4">
$route = Config:get(&#39;THEME_HOME&#39;).&#39;Users.testpage&#39;;
return view($route,[&#39;mydata&#39;=&gt;$mydata]);</pre>
<p>Every time we need to call a view inside a Controller, we just use the theme configuration variables that are automatically set for us. No hard coding of theme paths and we still have the flexibility to implement a full theme or any subset by letting the Service Provider do the hard work for us.</p>
<h2>View Implementation</h2>
<p>The real simplicity of this approach becomes apparent in the view files. Using Laravel&#39;s Blade templates we can easily return the THEME variables inside any <a href="https://laravel.com/docs/5.4/blade">Blade</a> and use them in Blade directives.</p>
<p>To test the correct processing of the theme variables, I created a simple blade in the resources/views directory, it looks like this:</p>
<pre class="prettyprint lang-html " data-pbcklang="html" data-pbcktabsize="4">
views]# cat themeinfo.blade.php

&lt;table cellpadding=5 cellspacing=5&gt;
&lt;tr&gt;&lt;td&gt;Theme Name&lt;/td&gt;&lt;td&gt;{{ $THEME_NAME }}&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Home&lt;/td&gt;&lt;td&gt;{{ $THEME_HOME }}&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Header&lt;/td&gt;&lt;td&gt;{{ $THEME_HEADER }}&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Footer&lt;/td&gt;&lt;td&gt;{{ $THEME_FOOTER }}&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
views]#</pre>
<p>To invoke the test blade, I added a single GET route to my routes file:</p>
<pre class="prettyprint lang-php " data-pbcklang="php" data-pbcktabsize="4">
...
Route::get(&#39;/themeinfo&#39;, function() { return View::make(&#39;themeinfo&#39;); });
...</pre>
<p>As you can see the Blade uses the same {{ }} variables for any passed variables thanks to the use of the View::share() method in the Provider code. The output from the URL call gives us:</p>
<table cellpadding="5" cellspacing="5">
<tbody>
<tr>
<td>Theme Name</td>
<td>test</td>
</tr>
<tr>
<td>Home</td>
<td>Themes.default.Home.</td>
</tr>
<tr>
<td>Header</td>
<td>Themes.default.Header.</td>
</tr>
<tr>
<td>Footer</td>
<td>Themes.default.Footer.</td>
</tr>
</tbody>
</table>
<p>Now lets add a theme, for this tutorial I will just do an insert in mysql:</p>
<pre class="prettyprint lang-sql " data-pbcklang="sql" data-pbcktabsize="4">
MariaDB [teststore]&gt; insert into themes values (0,&#39;test&#39;,&#39;2017-08-29&#39;,&#39;2017-10-30&#39;,0,0,0);
Query OK, 1 row affected (0.01 sec)</pre>
<p>Now I will create the theme directory but only the Footer directory for testing and create a footer file with a couple of test lines:</p>
<pre class="prettyprint lang-sh " data-pbcklang="sh" data-pbcktabsize="4">
resources/views#mkdir -p Themes/test/Footer
resources/views#vi Themes/test/Footer/footer.blade.php
&lt;br/&gt;
&lt;br/&gt;
&lt;b&gt;I&#39;m the Test footer&lt;/b&gt; used in {{ THEME_NAME }}
resources/views#</pre>
<p>Re-running our <strong>themeinfo</strong> blade test we now get:</p>
<table cellpadding="5" cellspacing="5">
<tbody>
<tr>
<td>Theme Name</td>
<td>test</td>
</tr>
<tr>
<td>Home</td>
<td>Themes.default.Home.</td>
</tr>
<tr>
<td>Header</td>
<td>Themes.default.Header.</td>
</tr>
<tr>
<td>Footer</td>
<td>Themes.<strong>test</strong>.Footer.</td>
</tr>
</tbody>
</table>
<p>Note: To get the same results, adjust the dates in the insert SQL so today falls in the required date range.</p>
<p>My application calls the Theme/default/Home/frontend.blade.php file when the &quot;/&quot; page is called. Using our new &quot;test&quot; theme, lets add a new test homepage in Themes/test/Home/frontend.blade.php</p>
<pre class="prettyprint lang-html " data-pbcklang="html" data-pbcktabsize="4">
resources/views#vi Themes/test/Home/frontend.blade.php
&lt;p&gt;I&#39;m the test Frontend&lt;/p&gt;
.
.
resources/views#</pre>
<p>Calling the web site with no URL parameters now returns our message, so lets include the new Footer and use the THEME_FOOTER variable in a Blade directive.</p>
<pre class="prettyprint lang-html " data-pbcklang="html" data-pbcktabsize="4">
resources/views#vi Themes/test/Home/frontend.blade.php
&lt;p&gt;I&#39;m the test Frontend&lt;/p&gt;
.
@include( $THEME_FOOTER.&#39;footer&#39;)
resources/views#</pre>
<p>Calling our home page gives us:</p>
<p>I&#39;m the test Frontend</p>
<p><strong>I&#39;m the test footer</strong> used in test</p>
<p>That&#39;s it! You can use the $THEME_XXXXX variables in any directive and the string assigned will be returned!</p>
<p>The List of THEME_XXX variables created is defined in the Service Provider, the current list is:</p>
<ul>
<li>THEME_NAME</li>
<li>THEME_HOME</li>
<li>THEME_FOOTER</li>
<li>THEME_HEADER</li>
<li>THEME_ERRORS</li>
</ul>
<p>You can extend this as you need by adding more directory names in the Service Provider code.</p>
<p>Enjoy!</p>
<p><strong>-oOo-</strong></p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>A simple guide to using Traits in Laravel 5</title>
		<link>https://testing.conetix.com.au/blog/simple-guide-using-traits-laravel-5/</link>
		
		<dc:creator><![CDATA[Sid Young]]></dc:creator>
		<pubDate>Thu, 17 Nov 2016 02:02:00 +0000</pubDate>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[laravel]]></category>
		<category><![CDATA[ph]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[traits]]></category>
		<guid isPermaLink="false">https://conetix.com.au/simple-guide-using-traits-laravel-5/</guid>

					<description><![CDATA[Overview If you have exposure to Object Oriented programming, then you will have been introduced to the concept of abstract classes and interfaces.&#160;A &#8220;Trait&#8221; is similar to an abstract class, in that it cannot be instantiated on its own but contains methods that can be used in a concrete class.&#160;Traits were introduced in PHP in...  <a class="excerpt-read-more" href="https://testing.conetix.com.au/blog/simple-guide-using-traits-laravel-5/" title="Read A simple guide to using Traits in Laravel 5">Read more &#187;</a>]]></description>
										<content:encoded><![CDATA[
<h2 class="wp-block-heading">Overview</h2>



<p>If you have exposure to Object Oriented programming, then you will have been introduced to the concept of abstract classes and interfaces.&nbsp;A &#8220;Trait&#8221; is similar to an abstract class, in that it cannot be instantiated on its own but contains methods that can be used in a concrete class.&nbsp;Traits were introduced in PHP in version 5.4 and are used extensively in the Laravel Framework. They are ideal in reducing&nbsp;the limiting effect of single inheritance, thus enabling the exposing of methods as if they were defined in the calling class. The exact definition from the PHP site defines Traits as such:</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>“Traits are a mechanism for code reuse in single inheritance languages such as PHP. A Trait is intended to reduce some limitations of single inheritance by enabling a developer to reuse sets of methods freely in several independent classes living in different class hierarchies. The semantics of the combination of Traits and classes is defined in a way which reduces complexity, and avoids the typical problems associated with multiple inheritance and Mixins.</p>



<p>A Trait is similar to a class, but only intended to group functionality in a fine-grained and consistent way. It is not possible to instantiate a Trait on its own. It is an addition to traditional inheritance and enables horizontal composition of behavior; that is, the application of class members without requiring inheritance.”</p>
</blockquote>



<h2 class="wp-block-heading">Example File</h2>



<p>Creating a Trait is just like defining a class, the following simple example (excluding comments) shows a single file with one trait which has 2 methods:</p>



<pre class="wp-block-preformatted prettyprint lang-php">&lt;?php namespace AppTraits;

trait ExampleCode
{
    public function printThis()
    {
        echo "Trait executed";
        dd($this);
    }

    public function anotherMethod()
    {
        echo "Trait – anotherMethod() executed";
    }
}</pre>



<p>Our example looks just like a class definition, except we use the keyword &#8220;trait&#8221;, there is no constructor as it cannot be instantiated&nbsp;(just like an abstract class). It uses a <a href="https://www.conetix.com.au/blog/namespaces-laravel-applications" target="_blank" rel="noopener noreferrer">name space</a> of <strong>AppTraits</strong> to give it a clear grouping (you can use anything you like here). If you need to access code in other name spaces then just include the &#8220;use&#8221; statement (see example below) and create and call the method(s) as needed.</p>



<p>Within the file, function names must be unique and if they do conflict with existing methods then the following precedence takes effect:</p>



<ol class="wp-block-list">
<li>An inherited member from a base class is overridden by a member inserted by a Trait.</li>



<li>Members from the current class override Trait methods.</li>
</ol>



<h2 class="wp-block-heading">Storing Traits</h2>



<p>For convenience I created a directory under “app” called “Traits”, and placed my custom PHP files there. Each file uses the name of the Trait for logical correlation. By using a <a href="https://www.conetix.com.au/blog/namespaces-laravel-applications" target="_blank" rel="noopener noreferrer">name space</a> of <strong>“AppTraits” </strong>in each file the Framework was able to locate my files when I “use” them in another file.</p>



<p>Sample Usage Code:</p>



<pre class="wp-block-preformatted prettyprint lang-php">&lt;?php
/**
 * class AdminLoginJob
 * @date 2016-11-03
 */
namespace AppJobs;

use AppJobsJob;
use IlluminateContractsBusSelfHandling;

use AppTraitsExampleCode;

/**
 *  brief Example code using a Trait in a Laravel "Job"
 */
class AdminLoginJob extends Job implements SelfHandling
{
    use ExampleCode;
    
&nbsp;   /**
&nbsp;    * Call trait to print something. Note the use of "$this".
     * 
&nbsp;    * @return void
&nbsp;    */
    public function __construct()
    {
        $this-&gt;printThis();
    }

</pre>



<pre class="wp-block-preformatted prettyprint lang-php">   /**
&nbsp;    * Do more stuff here.
     * 
&nbsp;    * @return void
&nbsp;    */
     public function handle()
    {
        // never gets called in this example.
    }
}</pre>



<p>The printThis() method is in our trait and accessed using $this-&gt; notation just as if it was in the Class file. Multiple traits can be used in this manor, just select names carefully.</p>



<h2 class="wp-block-heading">Laravel 5.8 Working Example</h2>



<p>Since the release of the original article, Laravel has evolved and some of the syntax has changed. Below is a fully working example, with code.</p>



<p>To kick it off, add a route to your routes file for a GET call to the controller, mine looks like this:</p>



<p class="has-text-align-center"><em>Route::get( &#8216;/example&#8217;,&#8217;Example@Example&#8217;);</em></p>



<h4 class="wp-block-heading">app/Traits/ExampleCode.php</h4>



<p>This is the actual Trait we will use in the example. It has two methods, for this example we will just use the first one &#8220;printThis()&#8221;.</p>



<pre class="wp-block-preformatted">&lt;?php 
 namespace App\Traits;
 trait ExampleCode
 {
     public function printThis()     
     {               
         echo "Trait executed";    
         dd($this);           
     }
     public function anotherMethod()
     {
         echo "Trait - anotherMethod() executed";
     }
 }   </pre>



<h4 class="wp-block-heading">app/Jobs/ExampleJob.php</h4>



<p>In our example, we have attached the Trait to a Job, you could use it anywhere but in this example we will dispatch a job and call the Trait code. </p>



<pre class="wp-block-preformatted">&lt;?php
 /**
 \class ExampleJob
 @date 2019-07-31
 */
 namespace App\Jobs; 
 use App\Jobs\Job;
 use App\Traits\ExampleCode;
 /**
 \brief Example code using a Trait in a Laravel "Job"
 */
 class ExampleJob extends Job
 {
 use ExampleCode; 
 /**
 Call trait to print something. Note the use of "$this".
 *
 @return void
 */
 public function __construct()
 {
     $this-&gt;printThis();
 }
 public function handle()
 {
     // never gets called in this example.
 }
 } </pre>



<h4 class="wp-block-heading">app/Http/Controllers/Example.php</h4>



<p>Our controller is the entry point for the route and its sole purpose is to dispatch the Job.</p>



<pre class="wp-block-preformatted">&lt;?php
 namespace App\Http\Controllers;
 use App\Http\Controllers\Controller;
 use App\Jobs\ExampleJob;
 class Example extends Controller
 {
     public function __construct()
     {
     }
     public function Example()
     {
         dispatch(new ExampleJob());
     }
 }</pre>



<h4 class="wp-block-heading">Browser Output</h4>



<p>Web Browser output:</p>



<p>Trait executed<br>
ExampleJob {#458 ▼<br>
  +connection: null<br>
  +queue: null<br>
  +chainConnection: null<br>
  +chainQueue: null<br>
  +delay: null<br>
  +chained: []<br>
}</p>



<p>Yep! &#8211; that&#8217;s it a working example with the Trait attached to a Job being dispatched from a Controller in this example.</p>



<h2 class="wp-block-heading">Documenting Traits with Doxygen</h2>



<p>I think code documentation is critical, so it pays to make an effort to insert formatted comments that can be collected by a suitable tool and generated onto a web site for easy access. I tend to CRON my document generation, so as code is edited and saved&nbsp;new comments and code appear in the reports. Another handy feature is leaving TODO notes so code can be revisited to introduce new functionality. To achieve this I use Doxygen as my main tool but also run phpDocumentor2 and phpDox over the code, this given me lots of useful info in different formats.</p>



<p>By default Doxygen does not support PHP Traits in its documentation output, however several StackExchange posts cover a workaround:</p>



<ul class="wp-block-list">
<li><a href="https://stackoverflow.com/questions/26585100/doxygen-php-traits">https://stackoverflow.com/questions/26585100/doxygen-php-traits</a></li>
</ul>



<p>Related posts:</p>



<ul class="wp-block-list">
<li><a href="https://stackoverflow.com/questions/26168273/doxygen-not-documenting-php-code-inside-if-tags/26206860">https://stackoverflow.com/questions/26168273/doxygen-not-documenting-php-code-inside-if-tags/26206860</a></li>



<li><a href="https://stackoverflow.com/questions/24485609/double-include-prevention-code-in-php-prevents-doxygen-from-generating-documenta/25655189">https://stackoverflow.com/questions/24485609/double-include-prevention-code-in-php-prevents-doxygen-from-generating-documenta/25655189</a></li>
</ul>



<p>Manual Page on input Filters:</p>



<ul class="wp-block-list">
<li><a href="https://www.doxygen.nl/">https://www.doxygen.nl/</a></li>
</ul>



<p>Enjoy!</p>



<p>-oOo-<br>&nbsp;</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Namespaces in Laravel Applications</title>
		<link>https://testing.conetix.com.au/blog/namespaces-laravel-applications/</link>
					<comments>https://testing.conetix.com.au/blog/namespaces-laravel-applications/#comments</comments>
		
		<dc:creator><![CDATA[Sid Young]]></dc:creator>
		<pubDate>Thu, 03 Nov 2016 05:00:00 +0000</pubDate>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[larave]]></category>
		<category><![CDATA[laravel]]></category>
		<category><![CDATA[php]]></category>
		<guid isPermaLink="false">https://conetix.com.au/namespaces-laravel-applications/</guid>

					<description><![CDATA[Like many languages, PHP does not allow you to have two classes with the same name at a global level.  While on the surface this may sound like a good idea, it becomes a problem when you import libraries and a name collision occurs (completing libraries have one or more classes with the same name)....  <a class="excerpt-read-more" href="https://testing.conetix.com.au/blog/namespaces-laravel-applications/" title="Read Namespaces in Laravel Applications">Read more &#187;</a>]]></description>
										<content:encoded><![CDATA[<p>Like many languages, PHP does not allow you to have two classes with the same name at a global level.  While on the surface this may sound like a good idea, it becomes a problem when you import libraries and a name collision occurs (completing libraries have one or more classes with the same name). To solve this issue the concept of “name spaces” was added in PHP 5.3.</p>
<p>A name space allows you to partition code into logical groups by defining them into their own “namespace”. A text string after the “namespace” keyword identifies the name space and all code below it then lives within that name space. Name spaces also provide a way to group interfaces functions and constants.</p>
<p>As you application grows name spaces become essential to logically group code and to keep code separate from other code. Another great benefit to name spaces is when generating documentation. Name spaced code gets grouped accordingly by the most common PHP Documentors like <a href="https://www.doxygen.nl/" target="_blank" rel="noopener noreferrer">Doxygen</a>, <a href="https://www.phpdoc.org">phpDocumentor</a> and <a href="https://phpdox.de/">phpDox</a>.</p>
<p>Lets look at some simple examples so the idea is easy to follow and implement.</p>
<p>Without using a name space a simple class looks like:</p>
<pre class="prettyprint lang-php " data-pbcklang="php" data-pbcktabsize="4">&lt;?php
/**
* brief Handle all User Option preferences
*/
class UserOptions
{
    public function getOptions()
    {
    …...
    }
}</pre>
<p>To define a name space, use the &#8220;namespace&#8221; keyword followed by a path identifier. Here I have used <strong>AppUtilities</strong> to wrap the UserOptions class:</p>
<pre class="prettyprint lang-php " data-pbcklang="php" data-pbcktabsize="4">&lt;?php
namespace AppUtilities;
/**
* brief Handle all User Option preferences for a normall user of the application
*/
class UserOptions
{
    /**
     * Given a user object retrieve all associated options for the user and return them in
     * an array and key-value pairs.
     */
    public function getOptions(User $user)
    {
    …...
    }
}</pre>
<p>The &#8220;namespace&#8221; keyword must have no other keywords before it but comments are OK and needed for most documentation generators.</p>
<p>Now that we have the class defined inside a Utilities name space we can access it in two ways, and here it is assumed we are not trying to access it from another name space:</p>
<pre class="prettyprint lang-php " data-pbcklang="php" data-pbcktabsize="4">$userOption = new AppUtilitiesUserOptions();
$options = $userOption-&gt;getOptions();</pre>
<p>or</p>
<pre class="prettyprint lang-php " data-pbcklang="php" data-pbcktabsize="4">use AppUtilities;

$userOption = new UserOptions();
$options = $userOption-&gt;getOptions();</pre>
<p>If we are trying to use the class from within another name space then the “use” keyword will need to be changed to include the class name like so:</p>
<pre class="prettyprint lang-php " data-pbcklang="php" data-pbcktabsize="4">use AppUtilitiesUserOptions;</pre>
<p>This allows the compiler to import the correct class name from the correct name space. Let see another example of this, first we define a class:</p>
<pre class="prettyprint lang-php " data-pbcklang="php" data-pbcktabsize="4">&lt;?php

namespace AppThirdPartyInvoicing;

/**
* brief Invoice module options for all users from ThirdParty software sales.
*/
Class UserOptions
{
    public function getOptions()
    {
    ….
    }
}</pre>
<p>In our example, we were given a new invoicing module and it also has a UserOptions class that has no relationship to our original UserOptions class and it even has a common method name. Let use both in a sample program.</p>
<p>Referencing the two classes in our code we get:</p>
<pre class="prettyprint lang-php " data-pbcklang="php" data-pbcktabsize="4">&lt;?php namespace App;

Class TestExample
{
    /**
     * Do a billing run
     * 
     * @return void
     */
    public function BillingRun()
    {
    ….
    $userOptions = new AppUtilitiesUserOptions();
    $billingOptions = new AppThirdPatyInvoicingUserOptions();
    ...
    }
}</pre>
<p>This looks messy and we can shorten it using an alias to the sub-name space as shown below:</p>
<pre class="prettyprint lang-php " data-pbcklang="php" data-pbcktabsize="4">&lt;?php namespace App;

use AppUtilities as Util;
use AppThirdPatyInvoicing as Billing;

Class TestExample
{
    
    /**
     * Do a billing run
     * 
     * @return void
     */
    public function BillingRun()
    {
        ….
        $userOptions = new UtilUserOptions();
        $billingOptions = new BillingUserOptions();
        ...
    }
}
</pre>
<h2>What if you don&#8217;t use namespaces?</h2>
<p>In a <a href="https://laravel.com" target="_blank" rel="noopener noreferrer">Laravel</a> application, you can&#8217;t take advantage of custom directories if you don’t use a name space., Instead, you need to add additional paths to your composer.json file to include the paths. This can be handy on a quick and dirty small application but at some point as the application grows you need to move to name spaces. Here is an example of the &#8220;autoload&#8221; class map entry from a Laravel composer.json file, it has a Models Directory and a ConfigHelprers directory defined:</p>
<pre class="prettyprint lang-javascript " data-pbcklang="javascript" data-pbcktabsize="4">"autoload": {
    "classmap": [
        "database",
        "app/Models",
        "app/ConfigHelpers"
    ],
    "psr-4": {
    "App\": "app/"
    }
},</pre>
<p>Getting in early and using well thought out name space keywords in your application will save time down the track when the functionality expands. In a complex Framework like Laravel, name spaces are used everywhere and each release new third party composer based packages are being made available only compounding the usage.</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
]]></content:encoded>
					
					<wfw:commentRss>https://testing.conetix.com.au/blog/namespaces-laravel-applications/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>Getting to Know Aura PHP &#8211; Part II</title>
		<link>https://testing.conetix.com.au/blog/getting-know-aura-php-part-ii/</link>
		
		<dc:creator><![CDATA[Matthew Setter]]></dc:creator>
		<pubDate>Wed, 14 Sep 2016 23:00:00 +0000</pubDate>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[ph]]></category>
		<category><![CDATA[php]]></category>
		<guid isPermaLink="false">https://conetix.com.au/getting-know-aura-php-part-ii/</guid>

					<description><![CDATA[Introduction Last week we took an introductory tour through&#160;AuraPHP&#160;and built a simple application using&#160;the Aura 2.x framework. This week, we&#39;re going to build on that foundation, by refactoring the code we wrote, so that it&#39;s more manageable and maintainable, as well as uses some of the other features on offer; such as logging, the response...  <a class="excerpt-read-more" href="https://testing.conetix.com.au/blog/getting-know-aura-php-part-ii/" title="Read Getting to Know Aura PHP &#8211; Part II">Read more &#187;</a>]]></description>
										<content:encoded><![CDATA[<h2>Introduction</h2>
<p>Last week we took an <a href="https://www.conetix.com.au/blog/getting-know-aura-php">introductory tour through&nbsp;</a><a href="https://auraphp.com">AuraPHP</a>&nbsp;and built a simple application using&nbsp;<a href="https://auraphp.com/framework/2.x/en/">the Aura 2.x framework</a>. This week, we&#39;re going to build on that foundation, by refactoring the code we wrote, so that it&#39;s more manageable and maintainable, as well as uses some of the other features on offer; such as logging, the response object, and the dependency injection container.</p>
<p>If you&#39;ve not read the introductory post, please do, as you&#39;ll need that one to following along with this one. Assuming you have, let&#39;s get on with the code. To keep it clear and straight-forward, here&#39;s what we&#39;re going to do:</p>
<ul>
<li>Retrieve and use the configured logger service</li>
<li>Redefine the Logger service configuration for the dev environment</li>
<li>Configure a custom service, the&nbsp;ExtendedPdo&nbsp;connection object</li>
<li>Refactor the data-view-sales dispatchable into an invokable class</li>
<li>Access some query variables from the request object</li>
</ul>
<p>That&#39;s quite a decent list of things to cover, but it helps give a more fleshed out understanding of the features on offer.</p>
<h2>Retrieve and Use the Configured Logger Service</h2>
<p>Projects, based on the AuraPHP 2.x framework come with a number of services configured, including&nbsp;logging,&nbsp;request,&nbsp;response,&nbsp;sessions,validation, and&nbsp;forms. These services are configured in&nbsp;<a href="https://auraphp.com/framework/2.x/en/configuration/">a series of config files</a>.</p>
<p>Let&#39;s refactor&nbsp;modifyWebRouter&nbsp;to retrieve and make use of the logger service, which uses&nbsp;<a href="https://github.com/Seldaek/monolog">the excellent Monolog library</a>. If you&#39;re not familiar with Monolog, it&#39;s written by Jordi Boggiano, creator and maintainer of Composer.</p>
<p>Monolog&#39;s&nbsp;<a href="https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md">a PSR-3 style</a>&nbsp;logging library, which can send logs to a range of locations and services, including&nbsp;files,&nbsp;sockets,&nbsp;inboxes,&nbsp;databases, as well as various web services, such as&nbsp;<a href="https://www.loggly.com">Loggly</a>&nbsp;and&nbsp;<a href="https://www.elastic.co/products/elasticsearch">ElasticSearch</a>.</p>
<p>I&#39;ve used it on numerous occasions and definitely recommend it.</p>
<pre class="prettyprint lang-php " data-pbcklang="php" data-pbcktabsize="4">
public function modifyWebRouter(Container $di)
{
    $router = $di-&gt;get(&#39;aura/web-kernel:router&#39;);

    /** @var MonologLogger $logger */
    $logger = $di-&gt;get(&#39;aura/project-kernel:logger&#39;);</pre>
<p>Firstly, we get access to the service, via its service name, from the DI container.</p>
<pre class="prettyprint lang-php " data-pbcklang="php" data-pbcktabsize="4">
$router-&gt;add(&#39;hello&#39;, &#39;/&#39;)
           -&gt;setValues(array(&#39;action&#39; =&gt; &#39;hello&#39;));

    $logger-&gt;addDebug(&#39;Added default route&#39;);

    // Add an about page
    $router-&gt;add(&#39;about&#39;, &#39;/about&#39;)
        -&gt;setValues(array(&#39;action&#39; =&gt; &#39;about&#39;));

    $logger-&gt;addDebug(&#39;Added about page route&#39;);

    // Add a sales data display page
    $router-&gt;add(&#39;data-view-sales&#39;, &#39;/data/view/sales&#39;)
        -&gt;setValues(array(&#39;action&#39; =&gt; &#39;data-view-sales&#39;));

    $logger-&gt;addDebug(&#39;Added sales data page route&#39;);
}</pre>
<p>Then, after each route is initialised, we add a call to the logger&#39;saddDebug()&nbsp;method, logging the route which was just added.</p>
<h3>Log Output</h3>
<p>By default, the logger writes to a file on the filesystem, located under/tmp/log, who&#39;s name is that of the currently executing environment, appended with&nbsp;.log. As the environment&#39;s currently set to &#39;dev&#39;, then the file will be called&nbsp;/tmp/log/dev.log. If it already exists, it will be appended to. If not, it will be created and written to.</p>
<p>Here&#39;s a sample of the logged messages:</p>
<pre class="prettyprint lang-sh " data-pbcklang="sh" data-pbcktabsize="" style="overflow-x: auto; color: rgb(77, 77, 76); padding: 0.5em; font-size: 14px; line-height: 22px; widows: 1;">
[2016-09-08 16:46:34] NULL.DEBUG: Added default route [] []
[2016-09-08 16:46:34] NULL.DEBUG: Added about page route [] []
[2016-09-08 16:46:34] NULL.DEBUG: Added sales data page route [] []
[2016-09-08 16:46:34] NULL.DEBUG: AuraWeb_KernelWebKernelRouter GET / [] []
[2016-09-08 16:46:34] NULL.DEBUG: AuraWeb_KernelWebKernelDispatcher::logControllerValue to hello [] []</pre>
<h2>Redefine the Logger Service Configuration for the Dev Environment</h2>
<p>Now it&#39;s great that we can use an existing configuration, but what about being able to change one if it doesn&#39;t suit our needs? After all, how often do pre-packaged solutions and configurations always work for us, just as we would like or need them to?</p>
<p>So let&#39;s see how to redefine the logging service configuration, just for the development environment. To do that, open&nbsp;config/Dev.php. By default, it will look like the code below.</p>
<pre class="prettyprint lang-php " data-pbcklang="php" data-pbcktabsize="" style="overflow-x: auto; color: rgb(77, 77, 76); padding: 0.5em; font-size: 14px; line-height: 22px; widows: 1;">
&lt;?php
namespace AuraFramework_Project_Config;

use AuraDiConfig;
use AuraDiContainer;
use MonologLogger;

class Dev extends Config
{
    public function define(Container $di)
    {
        ini_set(&#39;error_reporting&#39;, E_ALL);
        ini_set(&#39;display_errors&#39;, true);
    }

    public function modify(Container $di)
    {
    }
}</pre>
<p>Let&#39;s now redefine the service, similar to how it&#39;s defined in Common.php, but this time also making use of&nbsp;<a href="https://github.com/Seldaek/monolog/blob/master/doc/02-handlers-formatters-processors.md#logging-in-development">the ChromePHPHandler</a>, in the code below.</p>
<pre class="prettyprint lang-php " data-pbcklang="php" data-pbcktabsize="" style="overflow-x: auto; color: rgb(77, 77, 76); padding: 0.5em; font-size: 14px; line-height: 22px; widows: 1;">
protected function modifyLogger(Container $di)
{
    $project = $di-&gt;get(&#39;project&#39;);
    $mode = $project-&gt;getMode();
    $file = $project-&gt;getPath(&quot;tmp/log/{$mode}.log&quot;);

    /** @var MonologLogger $logger */
    $logger = $di-&gt;get(&#39;aura/project-kernel:logger&#39;);
    $logger-&gt;pushHandler($di-&gt;newInstance(
        &#39;MonologHandlerStreamHandler&#39;,
        array(
            &#39;stream&#39; =&gt; $file,
        )
    ));
    $logger-&gt;pushHandler($di-&gt;newInstance(
        &#39;MonologHandlerChromePHPHandler&#39;
    ), Logger::DEBUG);
}
</pre>
<p>As you can see, it&#39;s just about the same code, but with three extra lines at the bottom, which adds a lazy-loaded initialisation of the ChromePHPHandler, at the level of debug.</p>
<pre class="prettyprint lang-php " data-pbcklang="php" data-pbcktabsize="" style="overflow-x: auto; color: rgb(77, 77, 76); padding: 0.5em; font-size: 14px; line-height: 22px; widows: 1;">
public function modify(Container $di)
{
    $this-&gt;modifyLogger($di);
}
</pre>
<p>After that, we add a call to the&nbsp;modifyLogger()&nbsp;method, to themodify()&nbsp;function, which will override the setup when the code&#39;s running in the dev environment.</p>
<h2>Configure a Custom Service</h2>
<p>Now that&#39;s how to retrieve an existing service, but what about configuring and using a service which doesn&#39;t come with the project? To do that, we&#39;re going to refactor&nbsp;modifyWebDispatcher()&nbsp;so that theExtendedPdo&nbsp;object is no longer instantiated directly,&nbsp;<a href="https://github.com/auraphp/Aura.Di#setting-and-getting-services">but lazy-loaded instead</a>. To do that, we first refactor the code into the&nbsp;define()&nbsp;method as below.</p>
<pre class="prettyprint lang-php " data-pbcklang="php" data-pbcktabsize="" style="overflow-x: auto; color: rgb(77, 77, 76); padding: 0.5em; font-size: 14px; line-height: 22px; widows: 1;">
public function define(Container $di)
{
    $di-&gt;set(&#39;aura/project-kernel:logger&#39;, $di-&gt;lazyNew(&#39;MonologLogger&#39;));
    // add the database connection as a service
    $di-&gt;set(
        &#39;db-connection&#39;,
        $di-&gt;lazyNew(
            &#39;AuraSqlExtendedPdo&#39;, [
                &#39;dsn&#39; =&gt; &#39;sqlite:./../db/database.sqlite&#39;
            ]
        )
    );
}</pre>
<p>What this does is configure a new service called&nbsp;db-connection, using the same configuration as before. But this time, the service will only be instantiated the first time it&#39;s requested, instead of straight-away, making the application much more performant.</p>
<p>Next, in&nbsp;modifyWebDispatcher(), we then replace the instantiation of&nbsp;ExtendedPdo, with a reference to the service, like this:&nbsp;$this-&gt;di-&gt;get(&#39;db-connection&#39;);</p>
<h2>Refactor a Dispatchable into an Invokable Class</h2>
<p>Now I want to take the process a step further, as I don&#39;t like how everything&#39;s initialised directly in the&nbsp;modifyWebDispatcher()method. Instead, I want to make it more maintainable, by refactoring the code in to a callable.</p>
<blockquote>
<p>If you&#39;re not familiar with callables,&nbsp;<a href="https://www.lornajane.net/posts/2012/phps-magic-__invoke-method-and-the-callable-typehint">here&#39;s a great explanation from Lorna Jane</a>.</p>
</blockquote>
<p>The refactored code&#39;s a bit long, so I&#39;ve broken it down in to annotated chunks. Let&#39;s step through them and see how it all fits together.</p>
<pre class="prettyprint lang-php " data-pbcklang="php" data-pbcktabsize="" style="overflow-x: auto; color: rgb(77, 77, 76); padding: 0.5em; font-size: 14px; line-height: 22px; widows: 1;">
&lt;?php

namespace AuraSupplementalRouteDispatchablesSales;

use AuraDiContainer;

class DataView
{
    const TEMPLATE_DIR = &#39;./../src/templates/&#39;;

    /**
     * @var string The SQL statement to run
     */
    protected $statement = &#39;
        SELECT t.TrackId, sum(il.unitprice) as &quot;TotalSales&quot;, t.Name as &quot;TrackName&quot;, g.Name as Genre, a.Title as &quot;AlbumTitle&quot;, at.Name as &quot;ArtistName&quot;
        from InvoiceLine il
        inner join track t on (t.TrackId = il.TrackId)
        INNER JOIN genre g on (g.GenreId = t.GenreId)
        inner join album a on (a.AlbumId = t.AlbumId)
        INNER JOIN artist at on (at.ArtistId = a.ArtistId)
        WHERE g.Name like :genre
        group by t.TrackId
        HAVING at.Name = :artist_name
        order by sum(il.UnitPrice) desc, t.Name asc
    &#39;;</pre>
<p>There&#39;s no base class to extend, nor interface to implement, so we just create a standard PHP class. I&#39;ve then added a class constant, which provides the base path to the template directory, mainly for tidiness&#39; sake, and created a protected class member variable,&nbsp;$statement, to store the SQL statement.</p>
<pre class="prettyprint lang-php " data-pbcklang="php" data-pbcktabsize="" style="overflow-x: auto; color: rgb(77, 77, 76); padding: 0.5em; font-size: 14px; line-height: 22px; widows: 1;">
protected $view;
    protected $di;

    /**
     * @param AuraDiContainer $di
     */
    public function __construct(Container $di)
    {
        $this-&gt;di = $di;
        $this-&gt;buildView();
    }</pre>
<p>I&#39;ve then setup two further protected class member variables to store the view and DI container objects, and a class constructor. The constructor takes one argument,&nbsp;$di, an instance of the DI container, as the closure previously did.</p>
<p>So far the same functionality exists. Next,&nbsp;$di&nbsp;is initialised with the passed in&nbsp;$di&nbsp;object, and a call is made to the&nbsp;buildView()&nbsp;method, which we&#39;ll look at next.</p>
<pre class="prettyprint lang-php " data-pbcklang="php" data-pbcktabsize="" style="overflow-x: auto; color: rgb(77, 77, 76); padding: 0.5em; font-size: 14px; line-height: 22px; widows: 1;">
protected function buildView()
    {
        $view_factory = new AuraViewViewFactory;
        $this-&gt;view = $view_factory-&gt;newInstance();

        $layout_registry = $this-&gt;view-&gt;getLayoutRegistry();
        $layout_registry-&gt;set(&#39;default&#39;, self::TEMPLATE_DIR . &#39;sales.layout.php&#39;);

        $view_registry = $this-&gt;view-&gt;getViewRegistry();
        $view_registry-&gt;set(&#39;sales-data&#39;, self::TEMPLATE_DIR . &#39;data/sales/view.php&#39;);
        $this-&gt;view-&gt;setView(&#39;sales-data&#39;);
        $this-&gt;view-&gt;setLayout(&#39;default&#39;);

        // the &quot;sub&quot; template
        $view_registry-&gt;set(&#39;_result&#39;, self::TEMPLATE_DIR . &#39;data/sales/result.php&#39;);
    }
}
</pre>
<p>Now we refactor the view initialisation code into a distinct, utility method, so that it&#39;s kept separate from the rest of the code. The only real changes are that we use the&nbsp;TEMPLATE_DIR&nbsp;class constant instead of the base path, making the path that bit more flexible and adaptable, and initialise the protected member variable&nbsp;$view, with the result of calling$view_factory-&gt;newInstance();&nbsp;instead of initialising a standalone variable.</p>
<p>We now have a two-step view ready to go.</p>
<pre class="prettyprint lang-php " data-pbcklang="php" data-pbcktabsize="" style="overflow-x: auto; color: rgb(77, 77, 76); padding: 0.5em; font-size: 14px; line-height: 22px; widows: 1;">
/** Make the class an invokable/callable */
    public function __invoke($bindOptions = array())
    {
        $this-&gt;view-&gt;setData([
            &#39;results&#39; =&gt; $this-&gt;di-&gt;get(&#39;db-connection&#39;)
                -&gt;fetchObjects($this-&gt;statement, $bindOptions, &#39;AuraSupplementalDatabaseObjectsEntitySalesData&#39;)
        ]);

        $response = $this-&gt;di-&gt;get(&#39;aura/web-kernel:response&#39;);
        $response-&gt;content-&gt;set($this-&gt;view);

        return $response;
    }</pre>
<p>Finally, we define the magic&nbsp;__invoke()&nbsp;method, which will be called, when the object is invoked as though it were a function.</p>
<p>It receives one argument, an array, which contains the bind values which will be bound to the SQL statement, generating the SQL query, which will be passed to the database to retrieve the results, as before. I&#39;ve not added any special error or exception handling for when errors occur or no the array is empty.</p>
<p>Now we call the&nbsp;fetchObjects()&nbsp;method on our lazy-loaded database connection service, passing in the statement, bind options, and the class to hydrate per result and store the result of the call as a view template variable &#39;results&#39;.</p>
<p>Then, as before, we retrieve the response service, and pass the view member variable to the&nbsp;set()&nbsp;method on the response&#39;s content object, finishing up by returning the&nbsp;$response&nbsp;object. We need to do this as a callable doesn&#39;t automatically make this available, as a closure would.</p>
<p>That was a bit to go through, but except for a different structure, it&#39;s doing the same as before.</p>
<h2>The Modified modifyWebDispatcher Method</h2>
<p>With all of the code refactored, we now only need update thesetObject()&nbsp;method, where we define the dispatchable, as I have below. Firstly, the use statement was added to reference the class, then a new&nbsp;DataView&nbsp;object,&nbsp;$dataViewDispatchable, was instantiated, passing to the constructor the DI instance.</p>
<p>Following that, the request object service is retrieved, to make the code more concise.Finally, the&nbsp;setObject()&nbsp;method is updated, using the instantiated&nbsp;DataView&nbsp;object as a callable, passing in an associative array, where the two bind parameters are retrieved from the request query string.</p>
<pre class="prettyprint lang-php " data-pbcklang="php" data-pbcktabsize="" style="overflow-x: auto; color: rgb(77, 77, 76); padding: 0.5em; font-size: 14px; line-height: 22px; widows: 1;">
use AuraSupplementalRouteDispatchablesSalesDataView;

//...rest of the existing code

$dataViewDispatchable = new DataView($di);

$request = $di-&gt;get(&#39;aura/web-kernel:request&#39;);

$dispatcher-&gt;setObject(&#39;data-view-sales&#39;,
    $dataViewDispatchable([
        &#39;genre&#39; =&gt; $request-&gt;query-&gt;get(&#39;genre&#39;) . &#39;%&#39;,
        &#39;artist_name&#39; =&gt; $request-&gt;query-&gt;get(&#39;artist&#39;)
    ])
);</pre>
<p>With all this done, a range of different bind parameters can be supplied, through a more flexible route, such as<br />
https://localhost:8080/data/view/sales?genre=TV&amp;artist=Lost.</p>
<p>Please note that I&#39;ve done no sanitation or validation whatsoever on the query parameters, and in a real world application that&#39;s just insane. But for the purposes of a simple example, it&#39;s enough to demonstrate a series of features.</p>
<blockquote>
<p><strong>Suggestion:</strong>&nbsp;How about using&nbsp;<a href="https://auraphp.com/framework/2.x/en/validation/">the validation package</a>&nbsp;to implement validation and filtering to make the code more safe?</p>
</blockquote>
<h2>Wrapping Up</h2>
<p>And that&#39;s how to refactor the code so that it&#39;s more manageable and maintainable, as well as use some of the other features on offer, especially the dependency injection container.</p>
<p>If you have any issues, or just have questions to help flesh out your understanding, make sure to use&nbsp;<a href="https://groups.google.com/group/auraphp">the mailing list</a>&nbsp;or the IRC channel (#auraphp).</p>
<p>Finally, Aura&#39;s definitely one of the more well designed and written frameworks for PHP, as well as one of the more elegant. I strongly encourage you to check it out.</p>
<p>I hope you&#39;ve enjoyed this two-part introductory series to AuraPHP and the AuraPHP framework, as much as I&#39;ve enjoyed researching and writing it. I&#39;d love to know your thoughts in the comments.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Getting to Know Aura PHP &#8211; Part I</title>
		<link>https://testing.conetix.com.au/blog/getting-know-aura-php/</link>
		
		<dc:creator><![CDATA[Matthew Setter]]></dc:creator>
		<pubDate>Wed, 31 Aug 2016 23:00:00 +0000</pubDate>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[ph]]></category>
		<category><![CDATA[php]]></category>
		<guid isPermaLink="false">https://conetix.com.au/getting-know-aura-php/</guid>

					<description><![CDATA[In the world of PHP, you&#39;re not hard up for choice for packages and frameworks for just about everything, especially since the advent of Composer and Packagist. There&#39;s Zend Framework (1 &#38; 2), FuelPHP, Laravel (Here is a&#160;great article&#160;on Developing in Laravel 5), Symfony (1 &#38; 2), Phalcon and a whole lot more. They all...  <a class="excerpt-read-more" href="https://testing.conetix.com.au/blog/getting-know-aura-php/" title="Read Getting to Know Aura PHP &#8211; Part I">Read more &#187;</a>]]></description>
										<content:encoded><![CDATA[<p>In the world of PHP, you&#39;re not hard up for choice for packages and frameworks for just about everything, especially since the advent of Composer and Packagist.<br />
There&#39;s Zend Framework (1 &amp; 2), FuelPHP, Laravel (<a href="https://www.conetix.com.au/blog/developing-application-laravel-5">Here is a&nbsp;great article&nbsp;on Developing in Laravel 5</a>), Symfony (1 &amp; 2), Phalcon and a whole lot more.<br />
They all have a lot to offer, depending on your level of expertise with PHP.</p>
<p>However, recently, I was tasked, as part of my regular Education Station column for PHPArch Magazine, to write a 3-part series on&nbsp;<a href="https://www.phparch.com/magazine/2015-2/june/">Dependency Injection (DI)</a>, and the state of it in PHP. During the course of my research, I investigated four of the most notable Dependency Injection Containers (DiC) implementations in PHP, and one of them was&nbsp;<a href="https://github.com/auraphp/Aura.Di">Aura.Di</a>.</p>
<p>During the course of my research, I took time out to talk with Aura project founder, and lead contributor&nbsp;<a href="https://www.paul-m-jones.com">Paul M. Jones</a>, about the library. In the process, I discovered an excellent project, one where every component, whilst interoperable with the all the others, is not dependent upon them.</p>
<p>This stands in stark contrast with many of the existing frameworks and packages in PHP today, with some more recent, notable exceptions, such as Zend Framework 2.5. For so many packages, if you want just a component or two, often times you need a number of others, even if you don&#39;t use them.</p>
<p><strong>Aura doesn&#39;t work this way!</strong></p>
<p>Given that, it&#39;s unfortunate that it doesn&#39;t seem to get the same amount of coverage and exposure which other PHP frameworks do, such as the aforementioned Zend Framework and Laravel.</p>
<p>Perhaps because it&#39;s not as shiny as some of the others, or that it doesn&#39;t have a large, visible corporate presence to help it stand out from the crowd. But either way, if you&#39;re serious about professional coding practices, and software craftsmanship, this is the framework for you.</p>
<p>If you&#39;re yet to hear of it, and want to work with a very well designed set of packages, then today you&#39;re in for a treat. I&#39;m going to give you a rapid introduction, to the 2.x implementation, followed by a run-through of a sample application built using&nbsp;<a href="https://auraphp.com/framework/2.x/en">the 2.x framework</a>.</p>
<blockquote>
<p><strong>Note:</strong>&nbsp;The framework component&nbsp;<a href="https://auraphp.com/blog/2015/03/27/aura-3-plans/">is being phased out</a>&nbsp;in version 3 of the project. But it still provides an excellent way of introducing the project.</p>
</blockquote>
<p>In a follow up article, I&#39;ll be taking you through some of the changes both already implemented, and set to be implemented in version 3.x of the project. So keep an eye out for that.</p>
<h2>What is Aura PHP</h2>
<p>The simplest way is to&nbsp;<a href="https://auraphp.com/about">quote the website</a>:</p>
<blockquote>
<p>Aura 1.x began as a rewrite of Solar, re-imagined as a library collection with dependency injection instead of a monolithic framework with service location.</p>
<p>The project centers around a collection of high-quality, well-tested,&nbsp;<a href="https://semver.org/">semantically versioned</a>,&nbsp;<a href="https://auraphp.com/contributing#standards">standards-compliant</a>, independent library packages that can be used in any codebase.</p>
<p>Each library is self-contained and has only the things it needs for its core purpose. None of the library packages depends on any other package. They are decoupled, not only from any particular framework, but also from each other. This means developers can use as much or as little of the project as necessary.</p>
</blockquote>
<h2>Requirements</h2>
<p>Currently there isn&#39;t a long list of requirements. The key one is that your web server&#39;s running at least PHP 5.3. I&#39;d like to think that this was a minimum, at the very least.</p>
<p>However, if you&#39;re running later versions, and I hope you are, it&#39;s good to know that Aura&#39;s tested against 5.5, 5.6 and HHVM.&nbsp;<a href="https://www.conetix.com.au/blog/php-7-sneak-peek">PHP 7</a>&nbsp;has also been successfully test against, even though it&#39;s still in alpha.</p>
<h2>What&#39;s On Offer</h2>
<p>Aura comes with a range of packages which you would expect from a PHP web project, which include:</p>
<ul>
<li><strong>Autoloading:</strong>&nbsp;Compliant with PSR-4</li>
<li><strong>Dependency Injection:</strong>&nbsp;Complete with constructor and setter injection, lazy-loading and inheritable configuration</li>
<li><strong>Dispatching:</strong>&nbsp;Creates objects from a factory and invokes methods using named parameters; also provides a trait for invoking closures and object methods with named parameters</li>
<li><strong>Filtering:</strong>&nbsp;Provides filters to validate and sanitize objects and arrays</li>
<li><strong>Routing</strong></li>
<li><strong>Sessions:</strong>&nbsp;Provides session management functionality, including lazy session starting, session segments, next-request-only &quot;flash&quot; values, and CSRF tools</li>
<li><strong>SQL:</strong>&nbsp;Provides lazy connections, array quoting, identifier quoting, query profiling, value binding, and convenience methods for common fetch styles, along with object-oriented query builders for&nbsp;MySQL,&nbsp;PostgreSQL,&nbsp;SQLite, and&nbsp;SQLServer; can be used with any database connection library</li>
<li><strong>Views:</strong>&nbsp;Provides an implementation of the&nbsp;<a href="https://martinfowler.com/eaaCatalog/templateView.html">TemplateView</a>&nbsp;and&nbsp;<a href="https://martinfowler.com/eaaCatalog/twoStepView.html">TwoStepView</a>&nbsp;patterns, with support for helpers and for closures as templates, using PHP itself as the templating language</li>
<li><strong>Escaping:</strong>&nbsp;Provides HTML escapers and helpers, including form input helpers</li>
</ul>
<p>Have a look at the&nbsp;<a href="https://auraphp.com/">list of packages</a>&nbsp;to get an overview of what&#39;s on offer. If you&#39;re keen to know more about any one, follow the link to the respective GitHub repository, and browse the code or peruse the project&#39;s README.</p>
<h2>A Simple Application</h2>
<p>Now that I&#39;ve given you the big overview, let&#39;s get started creating a modest application using the 2.x framework. If you want to peruse the full application,&nbsp;<a href="https://github.com/settermjd/simple-auraframework-project">it&#39;s available on GitHub</a>. The application&#39;s not going to be too special, but take in a series of the components. It&#39;s going to have a routing table with three routes:</p>
<ol>
<li>The Home Page</li>
<li>An About Page</li>
<li>A Data View Page</li>
</ol>
<p>The home and about pages will be simple text output. The data view page will setup a&nbsp;PDOconnection to an SQLite3 database, which contains a copy of&nbsp;<a href="https://chinookdatabase.codeplex.com/">the Chinook example database</a>, and will submit a SQL query to collate and return the episode&#39;s of Lost with the highest grossing sales. When rendered, the page will look like the screenshot below.</p>
<p><img decoding="async" alt="Rendered View of Highest Grossing Sales" src="/wp-content/uploads/2016/09/01/rendered-view_1.png"" /></p>
<h3>The Project Structure</h3>
<p>Before we dive in to the code, let&#39;s first look at the directory structure. It contains 6 key directories, these are:</p>
<ul>
<li>cli</li>
<li>config</li>
<li>src</li>
<li>tests</li>
<li>tmp</li>
<li>web</li>
</ul>
<p>Most of these we don&#39;t need to be concerned about for the purposes of this example. The key ones, however, are config and web. In config, you&#39;ll see five files. Here&#39;s what they do:</p>
<ul>
<li>_env.php&nbsp;provides a default environment</li>
<li>Common.php&nbsp;provides the default setup which is used across all environments</li>
<li>Dev.php,&nbsp;Prod.php, and&nbsp;Test.php&nbsp;implement options specific to those environments</li>
</ul>
<p>The&nbsp;web&nbsp;directory is similar to the more commonly used&nbsp;/public&nbsp;directory. It contains the bootstrap, or front controller, file, where all requests are routed through.</p>
<p>Looking at&nbsp;Common.php, you&#39;ll see a number of existing functions; these being define, modify, modifyLogger, modifyCliDispatcher, modifyWebRouter, and modifyWebDispatcher. These do largely what the names imply.</p>
<p>define&nbsp;sets up the DiC configuration,&nbsp;modify&nbsp;is a utility function for calling any sub-modify functions.&nbsp;modifyLogger&nbsp;sets up logging,&nbsp;modifyCliDispatcher&nbsp;andmodifyWebDispatcher&nbsp;set up the dispatch configuration for cli and web environments respectively.</p>
<p>And&nbsp;modifyWebRouter&nbsp;sets up routing for the web environment. Of these, the only one I&#39;m going to modify is&nbsp;modifyWebRouter.<br />
It already has one route setup, which is defined as:</p>
<pre class="prettyprint lang-php " data-pbcklang="php" data-pbcktabsize="" style="overflow-x: auto; color: rgb(77, 77, 76); padding: 0.5em; font-size: 14px; line-height: 22px; widows: 1;">
$dispatcher-&gt;setObject(&#39;hello&#39;, function () use ($di) {
    $response = $di-&gt;get(&#39;aura/web-kernel:response&#39;);
    $response-&gt;content-&gt;set(&#39;Hello World!&#39;);
});</pre>
<p>What this does is to create a named route,&nbsp;hello, and provide a closure, which receives the DiC, as its handler. Via the DiC it accesses the response object and sets the content of it to be the string&nbsp;Hello World!.</p>
<h3>The About Page</h3>
<p>Following in that vein, I&#39;m going to add the about page, using the following configuration.</p>
<pre class="prettyprint lang-php " data-pbcklang="php" data-pbcktabsize="" style="overflow-x: auto; color: rgb(77, 77, 76); padding: 0.5em; font-size: 14px; line-height: 22px; widows: 1;">
$dispatcher-&gt;setObject(&#39;about&#39;, function () use ($di) {
    // Create a new View object
    $view_factory = new AuraViewViewFactory;
    $view = $view_factory-&gt;newInstance();

    // Setup a Two-Step View
    $layout_registry = $view-&gt;getLayoutRegistry();
    $layout_registry-&gt;set(&#39;default&#39;, &#39;./../src/templates/default.layout.php&#39;);

    // Configure the view
    $view_registry = $view-&gt;getViewRegistry();
    $view_registry-&gt;set(&#39;about&#39;, &#39;./../src/templates/about.php&#39;);
    $view-&gt;setView(&#39;about&#39;);
    $view-&gt;setLayout(&#39;default&#39;);

    // Set the view output to be the response body
    $response = $di-&gt;get(&#39;aura/web-kernel:response&#39;);
    $response-&gt;content-&gt;set($view());
});</pre>
<p>This will first setup a new named route, called&nbsp;about, also using a closure as it&#39;s handler. Inside the handler, I`ll create a new View object to handle the rendering of the view output, handled with templates. This is a lot simpler and more maintainable than creating the output in code.</p>
<p>You&#39;ll see above that there&#39;s a layout and view. The reason for this is that I love&nbsp;<a href="https://martinfowler.com/eaaCatalog/twoStepView.html">the two-step view pattern</a>, as it makes it simple to separate reusable elements, such as headers, footers, and sidebars, from action-specific output, such as the about page&#39;s content.</p>
<p>I do this by making a call to&nbsp;getLayoutRegistry(), which sets the layout template, linked to the key &#39;default&#39;. These are named as we may have multiple layout templates. Then I&#39;ll add a view template, linked to the key &#39;about.</p>
<p>With that done I&#39;ll tell the View which template to use for the content, and which to use for the layout, by calling&nbsp;setView()&nbsp;and&nbsp;setLayout()&nbsp;respectively.</p>
<p>With all this done, I&#39;ll set the response body to be the return result from calling&nbsp;$view&nbsp;<a href="https://www.lornajane.net/posts/2012/phps-magic-__invoke-method-and-the-callable-typehint">as a function</a>. In short, this will set the response body to be the rendered template result.</p>
<h3>The View Data Page</h3>
<p>The View Data Page is a bit more involved, so will take a bit more explaining. As such, I&#39;ve broken the code up in to chunks, talking about them a piece at a time.</p>
<pre class="prettyprint lang-php " data-pbcklang="php" data-pbcktabsize="4">
$dispatcher-&gt;setObject(&#39;data-view-sales&#39;, function () use ($di) {
    $view_factory = new AuraViewViewFactory;
    $view = $view_factory-&gt;newInstance();</pre>
<p>As before, we&#39;ve initialised a new view object.</p>
<pre class="prettyprint lang-php " data-pbcklang="php" data-pbcktabsize="4">
$pdo = new ExtendedPdo(
        &#39;sqlite:./../db/database.sqlite&#39;
    );

    $extended_pdo = new ExtendedPdo($pdo);</pre>
<p>Here we&#39;ve initialised a new ExtendedPdo object, pointing to our SQLite database, which is a PDO extension that provides lazy connections, array quoting, identifier quoting, query profiling etc.</p>
<pre class="prettyprint lang-php " data-pbcklang="php" data-pbcktabsize="4">
$stm = &#39;
        SELECT t.TrackId, sum(il.unitprice) as &quot;TotalSales&quot;, t.Name as &quot;TrackName&quot;, g.Name as Genre, a.Title as &quot;AlbumTitle&quot;, at.Name as &quot;ArtistName&quot;
        from InvoiceLine il
        inner join track t on (t.TrackId = il.TrackId)
        INNER JOIN genre g on (g.GenreId = t.GenreId)
        inner join album a on (a.AlbumId = t.AlbumId)
        INNER JOIN artist at on (at.ArtistId = a.ArtistId)
        WHERE g.Name like :genre
        group by t.TrackId
        HAVING at.Name = :artist_name
        order by sum(il.UnitPrice) desc, t.Name asc
    &#39;;

    $bind = [&#39;genre&#39; =&gt; &#39;TV%&#39;, &#39;artist_name&#39; =&gt; &#39;Lost&#39;];
    $sth = $pdo-&gt;prepare($stm);
    $sth-&gt;execute($bind);</pre>
<p>Next, we&#39;ve specified a semi-complex SQL statement, using named parameters to aid in avoiding SQL injection attacks. The named parameters are for genre and artist name. These we&#39;ve substituted for&nbsp;TV%&nbsp;and&nbsp;Lost. We&#39;ve then called&nbsp;execute()&nbsp;to run the query.</p>
<pre class="prettyprint lang-php " data-pbcklang="php" data-pbcktabsize="4">
$layout_registry = $view-&gt;getLayoutRegistry();
    $layout_registry-&gt;set(&#39;default&#39;, &#39;./../src/templates/sales.layout.php&#39;);

    $view_registry = $view-&gt;getViewRegistry();
    $view_registry-&gt;set(&#39;sales-data&#39;, &#39;./../src/templates/data/sales/view.php&#39;);
    $view-&gt;setView(&#39;sales-data&#39;);
    $view-&gt;setLayout(&#39;default&#39;);

    // the &quot;sub&quot; template
    $view_registry-&gt;set(&#39;_result&#39;, &#39;./../src/templates/data/sales/result.php&#39;);</pre>
<p>As before, we&#39;ve setup the layout and view templates for rendering the page.</p>
<pre class="prettyprint lang-php " data-pbcklang="php" data-pbcktabsize="4">
 $view-&gt;setData([
        &#39;results&#39; =&gt; $pdo-&gt;fetchObjects($stm, $bind, &#39;DatabaseObjectsEntitySalesData&#39;)
    ]);

    $response = $di-&gt;get(&#39;aura/web-kernel:response&#39;);
    $response-&gt;content-&gt;set($view());
});</pre>
<p>Finally, we&#39;ve set a view template variable called&nbsp;results&nbsp;which will hold the value of querying the database. Note the third parameter. This indicates that every result in the resultset, will be a hydrated&nbsp;DatabaseObjectsEntitySalesData&nbsp;object. Now I didn&#39;t have to do this, but I find it makes working with larger datasets a whole lot simpler, as well as object-oriented.</p>
<h3>Updating the Routing Table</h3>
<p>With the new endpoints created, we now need to update the routing table, so that we can reach them. To do so, in&nbsp;modifyWebRouter(), add the following code:</p>
<pre class="prettyprint lang-php " data-pbcklang="php" data-pbcktabsize="4">
// Add an about page
$router-&gt;add(&#39;about&#39;, &#39;/about&#39;)
       -&gt;setValues([&#39;action&#39; =&gt; &#39;about&#39;]);

// Add a sales data display page
$router-&gt;add(&#39;data-view-sales&#39;, &#39;/data/view/sales&#39;)
       -&gt;setValues([&#39;action&#39; =&gt; &#39;data-view-sales&#39;]);</pre>
<p>These create named routes,&nbsp;about&nbsp;and&nbsp;data-view-sales, pointing to&nbsp;/about&nbsp;and/data/view/sales&nbsp;respectively. The&nbsp;setValues()&nbsp;function is how we pass view template variable data, which admittedly I&#39;ve not used in the code so far.</p>
<h3>The View Templates</h3>
<p>Honestly, most of the templates are just plain HTML, which I&#39;ve borrowed from the Twitter Bootstrap examples. However two templates are worth looking over. These are&nbsp;view.phpand&nbsp;result.php&nbsp;in&nbsp;src/templates/data/sales/. In&nbsp;view.php&nbsp;you&#39;ll see the following code:</p>
<pre class="prettyprint lang-php " data-pbcklang="php" data-pbcktabsize="" style="overflow-x: auto; color: rgb(77, 77, 76); padding: 0.5em; font-size: 14px; line-height: 22px; widows: 1;">
&lt;?php
  foreach ($this-&gt;results as $result) {
      echo $this-&gt;render(&#39;_result&#39;, array(
              &#39;result&#39; =&gt; $result,
          )
      );
  }
?&gt;</pre>
<p>This iterates over each result, rendering the template named&nbsp;_result, which isresult.php, passing it the current result. Looking at&nbsp;result.php, we see the following code:</p>
<pre class="prettyprint lang-php " data-pbcklang="php" data-pbcktabsize="" style="overflow-x: auto; color: rgb(77, 77, 76); padding: 0.5em; font-size: 14px; line-height: 22px; widows: 1;">
&lt;tr&gt;
    &lt;td&gt;&lt;?php print $result-&gt;TrackId; ?&gt;&lt;/td&gt;
    &lt;td&gt;&lt;?php print $result-&gt;TotalSales; ?&gt;&lt;/td&gt;
    &lt;td&gt;&lt;?php print $result-&gt;TrackName; ?&gt;&lt;/td&gt;
    &lt;td&gt;&lt;?php print $result-&gt;Genre; ?&gt;&lt;/td&gt;
    &lt;td&gt;&lt;?php print $result-&gt;AlbumTitle; ?&gt;&lt;/td&gt;
    &lt;td&gt;&lt;?php print $result-&gt;ArtistName; ?&gt;&lt;/td&gt;
&lt;/tr&gt;
</pre>
<p>Nothing too special, but it outputs the value of the six object member variables. I didn&#39;t have to separate the templates out, but felt that it was worth showing how to do so, and how to make the code more reusable.</p>
<p>Other frameworks, such as Zend Framework, would use the term Partial here. There&#39;s not a strict implementation of partials, but an in-situ one.</p>
<h2>Running The Application</h2>
<p>Now that everything&#39;s setup, let&#39;s get it running. As it&#39;s not making use of external services or databases, then I&#39;m going to launch it using PHP&#39;s built-in web server. To do so, I&#39;ll run the following command: &nbsp;</p>
<pre class="prettyprint lang-sh " data-pbcklang="sh" data-pbcktabsize="4">
php -S localhost:8080 -t ./web</pre>
<h2>Wrapping Up</h2>
<p>And that&#39;s all it takes to create a basic, database-enabled Aura application. Sure, I&#39;ve only covered the basics. But in the follow-on article, I&#39;ll be adding a range of extra functionality, so that you get a better understanding, both of what&#39;s on offer, and how to better organise it, making better use of dependency injection.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Introduction to Travis.CI Part 2</title>
		<link>https://testing.conetix.com.au/blog/introduction-travisci-part-2/</link>
		
		<dc:creator><![CDATA[Matthew Setter]]></dc:creator>
		<pubDate>Wed, 24 Aug 2016 23:00:00 +0000</pubDate>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[travis.c]]></category>
		<guid isPermaLink="false">https://conetix.com.au/introduction-travisci-part-2/</guid>

					<description><![CDATA[As we started discussing in my last article Introduction to Travis.CI, modern application development is a pretty demanding task. Whether that&#8217;s because of the complexity of modern applications, or the sheer number of moving parts which have to be managed, there&#8217;s no denying that it&#8217;s a lot of work. But gladly, thanks to a range...  <a class="excerpt-read-more" href="https://testing.conetix.com.au/blog/introduction-travisci-part-2/" title="Read Introduction to Travis.CI Part 2">Read more &#187;</a>]]></description>
										<content:encoded><![CDATA[<p>As we started discussing in my last article <a href="https://www.conetix.com.au/blog/introduction-travisci">Introduction to Travis.CI</a>, modern application development is a pretty demanding task. Whether that&rsquo;s because of the complexity of modern applications, or the sheer number of moving parts which have to be managed, there&rsquo;s no denying that it&rsquo;s a lot of work.</p>
<p>But gladly, thanks to a range of modern tools such as continuous integration servers, the amount of work involved can be significantly reduced &#8211; if done properly. <a href="https://travis-ci.org/">Travis CI</a>, as we had a good introduction to in last week&rsquo;s post, is one of those tools. And what&rsquo;s more, depending on your needs &#8211; <strong>it&rsquo;s free</strong>.</p>
<p>In case you missed the previous instalment, we started by looking at what Travis is, and how it&rsquo;s configured. We then stepped through a series of builds, viewing the information provided, and how they work, and finished up configuring simple email notifications.</p>
<p>Now that&rsquo;s great, but it only just scratches the surface of what&rsquo;s possible. In this instalment, I&rsquo;m going to take you further, showing you a richer range of functionality. We&rsquo;re going to look at integrating notifications with third party applications and services, including <a href="https://www.irc.org/">IRC</a>, <a href="https://www.hipchat.com/">HipChat</a>, and <a href="https://www.codeclimate.com/">CodeClimate</a>.</p>
<p><strong>Notifications</strong></p>
<p>OK, let&rsquo;s get started adding further notification options. We&rsquo;ll start with IRC.</p>
<p><strong>&nbsp;IRC</strong></p>
<p>If you&rsquo;re not familiar with it, IRC is a simple, text-based, chat system, created in 1988 by Jarkko Oikarinen. It was one of the earlier chat systems, preceding most everything we know today; whether that&rsquo;s ICQ, Facebook Messenger, Slack, HipChat, and so on.</p>
<p>Whilst it&rsquo;s not nearly as popular as it once was, it&rsquo;s still a very well used medium, with some reports saying it has a user base of around half a million active users, at any one time.</p>
<p>Like most software and protocols this old, there are a range of clients from it, both in the console and for the GUI. Some of the more popular GUI clients are mIRC, for Windows, Colloquy for MAC OSX, and XChat for Linux.</p>
<p>Now let&rsquo;s get the IRC notification setup. For the purposes of this article, I&rsquo;ve setup a new IRC channel on freenode called #conetix-blog. To configure it to use it, in your .travis.yml, add the following configuration.</p>
<pre class="prettyprint lang-sh " data-pbcklang="sh" data-pbcktabsize="4">
irc:
    channels:
      - &quot;irc.freenode.net#conetix-blog&quot;
    use_notice: true
    on_success: always
    on_failure: always
    skip_join: true
</pre>
<p>Stepping through the options, the channel is set under channels, on_success and on_failure ensure that no matter the status of a build, a notification will be sent.</p>
<p>I&rsquo;ve then set use_notice so that a notice style message is sent, instead of a normal message. This makes it simpler to distinguish between normal conversation and notification messages.</p>
<p>Finally, I&rsquo;ve set skip_join to true, so that the bot doesn&rsquo;t have to join before it can send a message. You may or may not like taking this approach. As always, commit and push the changes to .travis.yml to the repository. When the next build is done, in your IRC channel, you should see a message appear.</p>
<p><strong>&nbsp;HipChat</strong></p>
<p>HipChat is one of the newer, cooler online chat services available today. Acquired by Atlassian in 2012, HipChat is a service providing both private and group chat, and instant messaging.</p>
<p>Available for Mac, Linux, and Windows, as well as Android and iOS, it&rsquo;s one of the biggest services around, handling 60 messages per/second and containing over half a terabyte of searchable data.</p>
<p>If you&rsquo;re team&rsquo;s not already using it, and are looking for a chat solution, I&rsquo;ve used it and thoroughly enjoy and recommend it. So that&rsquo;s why we&rsquo;re going to integrate with it today. To do so, add the following configuration to your .travis.yml configuration file.</p>
<pre class="prettyprint lang-sh " data-pbcklang="sh" data-pbcktabsize="4">
hipchat:
    rooms:
      - &lt;API_Token&gt;@&lt;Room_Name&gt;
    format: html
    on_success: always
    on_failure: always</pre>
<p>Stepping through the configuration, the rooms option requires an API token and the room name which the message will be sent to. To get the API token, you first need to login to your HipChat account, on the web, then under <strong>Rooms</strong> click the room name.</p>
<p>In the navigation on the left-hand side, click <strong>Tokens</strong>, where you&rsquo;ll need to generate a new token, specifying the token&rsquo;s scope. I&rsquo;ve chosen &ldquo;<strong>Send Notification</strong>&rdquo; only. After that, you&rsquo;ll see the token available in the <strong>Token</strong> list, as below. For the Room Name, you&rsquo;ll find that at the top of the same page.</p>
<p><img decoding="async" alt="Hip Chat Admin Overview" src="/wp-content/uploads/2016/08/25/hipchat-admin-overview.png"" style="height:552px; width:700px" /></p>
<p>Finally, I&rsquo;ve used format: html, which sets the format of the sent message to be HTML. Please be aware that it disables some features, such as @mentions. As with IRC, I&rsquo;ve stipulated on_success and on_failure to be set to always so that notifications are always sent to the chat room.</p>
<p><strong>Integrating with CodeClimate</strong></p>
<p>Now that we&rsquo;ve setup more powerful notifications, let&rsquo;s look at adding code quality analysis. There are a range of tools available to do this, some open-source, some closed. But one I want to look at today is a 3rd party service called <a href="https://www.codeclimate.com/">CodeClimate</a>.</p>
<p><strong>What is CodeClimate</strong></p>
<p>In essence, in the words of the CodeClimate team, the service:</p>
<blockquote>
<p>Consolidates the results from a suite of static analysis tools into a single, real-time report, giving your team the information it needs to identify hotspots, evaluate new approaches, and improve code quality.</p>
</blockquote>
<p>CodeClimate is a great service which helps developers improve the quality of their code by analysing a range of key metrics. These include:</p>
<ul>
<li>Duplicated Code</li>
<li>Excess Public Methods</li>
<li>High Total Complexity</li>
<li>Complex Methods</li>
<li>Debug functions are present</li>
<li>Short Variable Names</li>
<li>Use of the system command</li>
</ul>
<p>It integrates with a number of existing tools, such as PHPUnit for PHP, where it takes account of those tools in the overall calculation of the code&rsquo;s GPA. We&rsquo;ll see a bit of that soon when I add some <a href="https://phpunit.de/manual/current/en/code-coverage-analysis.html">code coverage</a> to the project.</p>
<p><strong>Logging In With GitHub</strong></p>
<p>Before we can get everything setup, you&rsquo;ll need to ensure you have an account. Gladly, you don&rsquo;t need to register. All you need to do is click &ldquo;<strong>Log in with GitHub</strong>&rdquo; at the bottom of the login page. If this is your first time logging in with GitHub, you&rsquo;ll be redirected to GitHub, where you&rsquo;ll be asked to authorise Codeclimate for access to your GitHub credentials. Click OK and you&rsquo;ll be redirected back to Codeclimate and logged in.</p>
<p><strong>Adding Your Project</strong></p>
<p>After that, you&rsquo;ll see any projects you may already have listed, none if this is your first time. Otherwise you&rsquo;ll see one, as I have in the screenshot below.</p>
<p>To add a new one, click &ldquo;<strong>Add Open Source Repo</strong>&rdquo; on the right hand side, where you can specify the account and repository name, under &ldquo;<strong>GitHub repo name</strong>&rdquo;, and click &ldquo;<strong>Import Repo from GitHub</strong>&rdquo; to start the import process.</p>
<p>Whilst that&rsquo;s happening, you&rsquo;ll see a page, similar to the one below. This page doesn&rsquo;t refresh automatically. So to check the status, which shouldn&rsquo;t take too long, reload the page after about 30 seconds &#8211; 1 minute. When everything is finished importing, you&rsquo;ll see an initial page as below.</p>
<p>I think it&rsquo;s pretty thoughtful how the ranking system is similar to a school report, where you get a GPA ranking for your code &#8211; so you know in a moment how it&rsquo;s faired. A GPA of 4.0&rsquo;s pretty good, don&rsquo;t you think?</p>
<p><strong>Updating Travis&rsquo; Configuration</strong></p>
<p>Now that was the easy part. Next comes the fun. For this, you need to make a number of changes. Specifically, we&rsquo;re going to need to:</p>
<ol>
<li>Add a new Composer package</li>
<li>Update the PHPUnit configuration</li>
<li>Add a CodeClimate Configuration in .travis.yml</li>
</ol>
<p>Let&rsquo;s start at the top. Firstly, run composer require codeclimate/php-test-reporter &#8211;dev in the root of the project directory, which will add the CodeClimate test reporter for PHP package to the dev requirements section, and update the vendor directory.</p>
<p>Next, you need to update phpunit.xml.dist, to enable logging, specifically using the Clover format. To do that, add the following line to the file.</p>
<pre class="prettyprint lang-sh " data-pbcklang="sh" data-pbcktabsize="4">
&lt;logging&gt;
      &lt;log type=&quot;coverage-clover&quot; target=&quot;./build/logs/clover.xml&quot;/&gt;
    &lt;/logging&gt;</pre>
<p>To ensure that the ./build/logs/ directory is always present, run the following command. This will ensure that it&rsquo;s present and under Git control:</p>
<pre class="prettyprint lang-sh " data-pbcklang="sh" data-pbcktabsize="4">
bash mkdir -p ./build/logs &amp;&amp; touch ./build/logs/.gitkeep</pre>
<p>Now we&rsquo;re down to the last step, configuring Travis to work with CodeClimate. To do that, in .travis.yml, add the following further configuration options:</p>
<pre class="prettyprint lang-sh " data-pbcklang="sh" data-pbcktabsize="4">
after_script:
  - vendor/bin/test-reporter
addons:
  code_climate:
    repo_token: &lt;YOUR_TOKEN&gt;</pre>
<p>To get the token, to replace &lt;YOUR_TOKEN&gt; with, when viewing your project in CodeClimate, click Settings -&gt; Test Coverage, and down under &ldquo;<strong>PHP Instructions</strong>&rdquo;, under Step 4, copy the token which it has listed there. This token is specific to this repo on Code Climate.</p>
<blockquote>
<p><strong>Note:</strong>&nbsp;This should be enough to get it working for you. However, if you see the lineUnexpected response: -60 server certificate verification failed. CAfile: /etc/ssl/certs/ca-certificates.crt CRLfile: none, in the job output, then, you need to add the configuration below, as this is a&nbsp;<a href="https://github.com/codeclimate/php-test-reporter#known-issue-ssl-certificate-error">known</a><a href="https://github.com/codeclimate/php-test-reporter#known-issue-ssl-certificate-error"> issue</a>.</p>
</blockquote>
<p><strong>Alternate Configuration</strong></p>
<pre class="prettyprint lang-sh " data-pbcklang="sh" data-pbcktabsize="4">
after_script:
  - CODECLIMATE_REPO_TOKEN=&quot;&lt;YOUR_TOKEN&gt;&quot; vendor/bin/test-reporter --stdout &gt; codeclimate.json
  - &quot;curl -X POST -d @codeclimate.json -H &#39;Content-Type: application/json&#39; -H &#39;User-Agent: Code Climate (PHP Test Reporter v0.1.1)&#39; https://codeclimate.com/test_reports&quot;</pre>
<p><strong>Adding Code Coverage</strong></p>
<p>Now if we don&rsquo;t change anything, the CodeClimate project Timeline&rsquo;s not going to change, as we&rsquo;ve not met <a href="https://docs.codeclimate.com/article/158-what-events-trigger-a-new-code-climate-analysis">the criteria</a> for it to do so.</p>
<p>Gladly, they&rsquo;re quite straight-forward, one of them being an increase in code coverage. So to do that, I&rsquo;ve added a simplistic constructor to the entity, and a test class for the SalesData entity, which you can see below.</p>
<pre class="prettyprint lang-php " data-pbcklang="php" data-pbcktabsize="4">
// new SalesData entity constructor
    public function __construct($data = array())
    {
        if (!empty($data)) {
            foreach(get_class_vars(__CLASS__) as $property =&gt; $value) {
                if (isset($data[$property])) {
                    $this-&gt;{$property} = $data[$property];
                }
            }
        }
    }</pre>
<pre class="prettyprint lang-php " data-pbcklang="php" data-pbcktabsize="4">
&lt;?php
// SalesData entity test
namespace AuraFramework_Project;

use DatabaseObjectsEntitySalesData;

/**
 * @coversDefaultClass DatabaseObjectsEntitySalesData
 */
class EntityTest extends PHPUnit_Framework_TestCase
{
    /**
     * @covers ::__construct
     */
    public function testObjectIsInitiallyEmpty()
    {
        $salesData = new SalesData(array());
        foreach(get_object_vars($salesData) as $property) {
            $this-&gt;assertTrue(is_null($property), &quot;Property {$property} should be null.&quot;);
        }
    }

    /**
     * @covers ::__construct
     */
    public function testObjectCanBeInitialised()
    {
        $data = [
            &#39;TrackId&#39; =&gt; 1, &#39;TotalSales&#39; =&gt; 100, &#39;TrackName&#39; =&gt; &#39;Hey Baby!&#39;,
            &#39;Genre&#39; =&gt; &#39;Bubblegum Pop&#39;, &#39;AlbumTitle&#39; =&gt; &#39;Tragic Love Songs&#39;,
            &#39;ArtistName&#39; =&gt; &#39;Unknown&#39;
        ];

        $salesData = new SalesData($data);

        foreach(get_object_vars($salesData) as $property =&gt; $value) {
            $this-&gt;assertEquals(
                $data[$property],
                $salesData-&gt;{$property},
                sprintf(&quot;Property %s should be set to %s&quot;, $property, $data[$property])
            );
        }
    }
}</pre>
<p>When that&rsquo;s done, commit all the changes and push them to the repository. When the next build&rsquo;s done, you should see the timeline for your project in CodeClimate change to look something like the following.</p>
<p><img decoding="async" alt="Travis.CI codeclimate timeline" src="/wp-content/uploads/2016/08/25/codeclimate-timeline-bordered.png"" style="height:365px; width:700px" /></p>
<blockquote>
<p><strong>Note:</strong>&nbsp;If you&#39;re keen to learn more about CodeClimate, either get started with them by adding an open source project of your own, or stay tuned for an upcoming article on them.</p>
</blockquote>
<p><strong>&nbsp;Wrapping Up</strong></p>
<p>And that&rsquo;s how to use some of the more advanced configuration options and features of <a href="https://travis-ci.org/">Travis CI</a>, including notifications to <a href="https://www.hipchat.com/">HipChat</a> and <a href="https://www.irc.org/">IRC</a>, and integrating it with <a href="https://codeclimate.com/">CodeClimate</a> to help reduce the stress and overhead of managing your software projects.</p>
<p>Are you already using Travis? Share your thoughts in the comments. If this is your first time seeing Travis, are you keen to add it to your workflow?</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Laravel Form Refactoring with Service layers</title>
		<link>https://testing.conetix.com.au/blog/laravel-form-refactoring-service-layers/</link>
		
		<dc:creator><![CDATA[Sid Young]]></dc:creator>
		<pubDate>Thu, 07 Jul 2016 01:14:00 +0000</pubDate>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[framework]]></category>
		<category><![CDATA[laravel]]></category>
		<category><![CDATA[php]]></category>
		<guid isPermaLink="false">https://conetix.com.au/laravel-form-refactoring-service-layers/</guid>

					<description><![CDATA[Update September 2017: This article does not implement any custom&#160;Namespace, in time it wil be updated to include more modern Laravel coding techniques. After writing my last&#160;article on Developing Applications with Laravel &#8211; Part 3&#160;I started on part 4 and I took a&#160;look back at early controller code I had written and realised there must...  <a class="excerpt-read-more" href="https://testing.conetix.com.au/blog/laravel-form-refactoring-service-layers/" title="Read Laravel Form Refactoring with Service layers">Read more &#187;</a>]]></description>
										<content:encoded><![CDATA[<p><strong>Update September 2017: This article does not implement any custom&nbsp;Namespace, in time it wil be updated to include more modern Laravel coding techniques.</strong></p>
<p>After writing my last&nbsp;article on <a href="https://www.conetix.com.au/blog/developing-applications-laravel-5-part-3" target="_blank" rel="noopener noreferrer">Developing Applications with Laravel &#8211; Part 3</a>&nbsp;I started on part 4 and I took a&nbsp;look back at early controller code I had written and realised there must be a better way to validate form data and then call the lower level model code that saves the data back to the database.</p>
<p>After some investigation I concluded that using both the Request classes and&nbsp;a Service Layer implementation would be a nice way to then use the Eloquent code we coded in the model classes in the previous article. So rather than just jump into part 4, I decided this shorter article would be a nice fit and provide a useful working implementation on the topic of&nbsp;Request and Service Layers.</p>
<p>As I delve more and more into Laravel I find myself constantly refactoring code into smaller more manageable and more reusable pieces. One area this has been beneficial has been in my business logic where I handle forms and save data back to the database.</p>
<p>In this article I am going to refactor some old code to use <a href="https://laravel.com/docs/master/validation" target="_blank" rel="noopener noreferrer">Request Validation</a> and add a Service layer. Request Validation files can be found in /app/Http/Requests, in a fresh application you will not have any files until you manually create them.</p>
<p>Using the artisan tool, I have created each Request Validation class, a sample command follows:</p>
<pre class="prettyprint lang-php " data-pbcklang="php" data-pbcktabsize="4">
php artisan make:request WorkFlowRequest</pre>
<p>This will create a templated Request class in the directory mentioned above. The class comes with two methods by default,<strong> authorize()</strong> and <strong>rules()</strong>.</p>
<p>For testing I edited the authorize() method to return &quot;true;&quot; rather than the default &quot;false;&quot;, &nbsp;this enables authentication when called. If you need custom authentication handling then this is where you put it and I will touch on that in another article. If authorize() returns false then a post of the form will display &ldquo;FORBIDDEN&rdquo; in the top corner of the web browser.</p>
<p>The rules() method is where we return an array of validation rules. The following are an example:</p>
<pre class="prettyprint lang-php " data-pbcklang="php" data-pbcktabsize="4">
public function rules()
{
return [
    &#39;workflow_name&#39;=&gt;&#39;required|min:5|max:128&#39;,
    &#39;workflow_description&#39;=&gt;&#39;required|min:5|max:1024&#39;,
    &#39;workflow_aid&#39;=&gt;&#39;required&#39;,
    &#39;workflow_create_date&#39;=&gt;&#39;required&#39;,
    &#39;workflow_status&#39;=&gt;&#39;required&#39;
    ];
}</pre>
<p>If the completed form meets the validation then the controller code is executed for the given route provided the class is defined in the method call as shown below:</p>
<p>Before changes to Controller method:</p>
<pre class="prettyprint lang-php " data-pbcklang="php" data-pbcktabsize="4">
public function SaveWorkflow($id)</pre>
<p>After addition of Request Validation:</p>
<pre class="prettyprint lang-php " data-pbcklang="php" data-pbcktabsize="4">
public function SaveWorkflow(WorkFlowRequest $request, $id)</pre>
<p>There is no change to the route logic to include the request class.</p>
<p>In addition to the changes to the standard templated class file outlined above, I also&nbsp;added&nbsp;a <strong>messages()</strong> function so I can return failure messages back to the form automatically. The messages() method is not defined by the artisan &ldquo;make&rdquo; command so you need to manually add it. The method is&nbsp;simple enough:</p>
<pre class="prettyprint lang-php " data-pbcklang="php" data-pbcktabsize="4">
public function messages()
{
    return [
        &#39;workflow_name.required&#39;=&gt;&#39;The workflow name is required&#39;,
        &#39;workflow_name.min&#39;=&gt;&#39;The workflow name must be at least 5 characters minimum&#39;,
        &#39;workflow_name.max&#39;=&gt;&#39;The workflow name must be between 5 and 128 characters&#39;,
        &#39;workflow_description.required&#39;=&gt;&#39;A description is required (&gt;5 and &lt; 1025 characters)&#39;,
        &#39;workflow_description.min&#39;=&gt;&#39;Description must be 5 or more characters&#39;,
        &#39;workflow_description.max&#39;=&gt;&#39;Description must be less than 1025 characters&#39;,
        &#39;workflow_status.required&#39;=&gt;&#39;Status field is required&#39;
        ];
}</pre>
<p>The complete Request file now looks like:</p>
<pre class="prettyprint lang-php " data-pbcklang="php" data-pbcktabsize="4">
&lt;?php namespace AppHttpRequests;

use AppHttpRequestsRequest;

class WorkFlowRequest extends Request
{
    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize()
    {
        return true;
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [
            &#39;workflow_name&#39;=&gt;&#39;required|min:5|max:128&#39;,
            &#39;workflow_description&#39;=&gt;&#39;required|min:5|max:1024&#39;,
            &#39;workflow_aid&#39;=&gt;&#39;required&#39;,
            &#39;workflow_create_date&#39;=&gt;&#39;required&#39;,
            &#39;workflow_status&#39;=&gt;&#39;required&#39;
        ];
    }


    public function messages()
    {
        return [
            &#39;workflow_name.required&#39;=&gt;&#39;The workflow name is required&#39;,
            &#39;workflow_name.min&#39;=&gt;&#39;The workflow name must be at least 5 characters minimum&#39;,
            &#39;workflow_name.max&#39;=&gt;&#39;The workflow name must be between 5 and 128 characters&#39;,
            &#39;workflow_description.required&#39;=&gt;&#39;A description is required (&gt;5 and &lt; 1025 characters)&#39;,
            &#39;workflow_description.min&#39;=&gt;&#39;Description must be 5 or more characters&#39;,
            &#39;workflow_description.max&#39;=&gt;&#39;Description must be less than 1025 characters&#39;,
            &#39;workflow_status.required&#39;=&gt;&#39;Status field is required&#39;
        ];
    }

</pre>
<h2>Controller Code</h2>
<p>Open the relevant controller file (for this example its called WorkflowController.php) and locate all the code that checks the validity of fields during insert and update operations, there may only be two places, an initial save method such as <strong>SaveWorkflow()</strong> and an <strong>UpdateWorkflow()</strong> method when you edit and save the form data.</p>
<p>Lets look at the <strong>original</strong> method before changes:</p>
<pre class="prettyprint lang-php " data-pbcklang="php" data-pbcktabsize="4">
public function SaveWorkflow($id)
{
    $WF = new AppWorkflows();
    $form = Input::all();
    $name = $form[&#39;workflow_name&#39;];
    $desc = $form[&#39;workflow_description&#39;];
    $aid = $form[&#39;workflow_aid&#39;];
    $status =$form[&#39;workflow_status&#39;];
    $crdate =$form[&#39;workflow_create_date&#39;];
    if(strlen($name)&gt;8)
    {
        if($id == $form[&#39;id&#39;])
        {
            $data = array(
                &#39;workflow_name&#39;=&gt;$name,
                &#39;workflow_description&#39;=&gt;$desc,
                &#39;workflow_aid&#39;=&gt;$aid,
                &#39;workflow_status&#39;=&gt;$status,
                &#39;workflow_create_date&#39;=&gt;$crdate);
            $rv = $WF-&gt;UpdateWorkflow($id,$data);
            if($rv==1)
                Session::flash(&#39;flash_message&#39;,&#39;Workflow updated successfully!&#39;);
            if($rv==0)
                Session::flash(&#39;flash_error&#39;,&#39;No Workflow update needed!&#39;);
        }
        else
            Session::flash(&#39;flash_error&#39;,&#39;ERROR - Invalid Workflow record.&#39;);
    }
    else
        Session::flash(&#39;flash_error&#39;,&#39;ERROR - Workflow name is too short (more than 8 characters please).&#39;);
    return $this-&gt;ShowWorkflowList();
}</pre>
<p>The original method does both the crude validation and saves the data back to the database via the Model code. It&#39;s acceptable but we can now refactor&nbsp;it to slim down our code.&nbsp;First, change the function signature to include the Request class, next remove all code that checks the fields and their lengths, that&#39;s now done for us in the Request validation rules() method.</p>
<p>The slimmed down code before we add a Service layer looks like this:</p>
<pre class="prettyprint lang-php " data-pbcklang="php" data-pbcktabsize="4">
public function UpdateWorkflow(WorkFlowRequest $request,$id)
{
    $WF = new AppWorkflows();
    $data = array(
        &#39;workflow_name&#39;=&gt;$request[&#39;workflow_name&#39;],
        &#39;workflow_description&#39;=&gt;$request[&#39;workflow_description&#39;],
        &#39;workflow_aid&#39;=&gt;$request[&#39;workflow_aid&#39;],
        &#39;workflow_status&#39;=&gt;$request[&#39;workflow_status&#39;],
        &#39;workflow_create_date&#39;=&gt;$request[&#39;workflow_create_date&#39;]);
    if($WF-&gt;UpdateWorkflow($id, $data) == 1)
    {
        Session::flash(&#39;flash_message&#39;,&#39;Workflow updated successfully!&#39;);
    }
    return $this-&gt;ShowWorkflowList();
}</pre>
<p>We can shorten it even furthur IF the form field names match the database column names exactly to:</p>
<pre class="prettyprint lang-php " data-pbcklang="php" data-pbcktabsize="4">
$data = $request-&gt;except([&#39;_token&#39;])</pre>
<p>Already we have reduced the code significantly&nbsp;and made the framework do a lot of the work for us, as a bonus, our validation is in one place (the Requests directory)&nbsp;so additional fields can be changed in the validation logic without impacting any methods that use it.</p>
<p>However, there are two issues with this code, in this example it&#39;s duplicated for two methods (SaveXXXX() and UpdateXXXX()&nbsp;) so we do have the potential of incorrectly saving some fields and not others if we do modifications.&nbsp;We also can&#39;t see our validation errors in the View when the validation fails, so we need to implement that facility as well. Our first&nbsp;step of the refactor is completed.</p>
<h2>Capturing Errors in the View</h2>
<p>Inside every form handling view, you can display the form validation errors using the following code. It first checks how many errors and returns a list. This code does not highlight the field that is at fault so you can add to it to do that later.</p>
<pre class="prettyprint lang-php " data-pbcklang="php" data-pbcktabsize="4">
@if(count($errors)&gt;0 )
    &lt;div class=&quot;alert alert-danger col-xs-4&quot;&gt;
        &lt;ul&gt;
        @foreach($errors-&gt;all() as $error)
            &lt;li&gt;{{ $error }}&lt;/li&gt;
        @endforeach
        &lt;/ul&gt;
    &lt;/div&gt;
@endif</pre>
<p>If there are no errors then this code does not render anything in the view, so an initial load of a &ldquo;Save New&rdquo; form will have no error list and only a blank form shown as expected. When we display the edit form, there will be no issues so the view renders accordingly. The Validation logic will fill the $errors array with the list of fields that failed validation in the Request class, so these will be listed in a unordered bullet list in a red div in our Bootstrap application framework.</p>
<h2>The Service Layer</h2>
<p>When you map out the directory structure of Laravel 5.2 you find there is no &ldquo;Services&rdquo; folder. Don&#39;t confuse this with <a href="https://laravel.com/docs/master/providers" target="_blank" rel="noopener noreferrer">ServiceProviders</a> which are a different topic. To solve this we will add a new directory, and in this example it will be under the &ldquo;app/Models&rdquo; directory. We also need to map it in our composer.json file IF we don&#39;t use a separate namespace, if you use the App namespace then you need to include these mappings:</p>
<pre class="prettyprint lang-javascript " data-pbcklang="javascript" data-pbcktabsize="4">
&quot;autoload&quot;: {
    &quot;classmap&quot;: [
        &quot;database&quot;,
        &quot;app/Models&quot;,
        &quot;app/Models/Services&quot;,
        &quot;app/Tasks&quot;
        ],
        &quot;psr-4&quot;: {
            &quot;App\&quot;: &quot;app/&quot;
            }
    },</pre>
<p>Now we go to our Models directory&nbsp;and create the Services directory.</p>
<pre class="prettyprint lang-sh " data-pbcklang="sh" data-pbcktabsize="4">
# cd app/Models
# mkdir Services 
# cd ../..
# composer dump-autoload</pre>
<p>By now doing a &quot;<strong>composer dump-autoload</strong>&quot;,&nbsp;we will configure our project with the new directory. We can now add a Service class to handle saving our data back.</p>
<p>There is no Artisan tool to make the Services class, so we can change into the directory and create the file manually.&nbsp;The <strong>WorkFlowService</strong>&nbsp;class&nbsp;will have two public methods,&nbsp;<strong>insert()</strong> and <strong>update()</strong>. This will take the&nbsp;data from our request validation and persist it to our database. It provides a single place where both operations are performed and called from anywhere in the framework. The class file looks like:</p>
<pre class="prettyprint lang-php " data-pbcklang="php" data-pbcktabsize="4">
&lt;?php namespace App;

use AppHttpRequestsWorkFlowRequest;



class WorkFlowService
{

    public static function insert(WorkFlowRequest $request)
    {
        $WF = new AppWorkflows();
        if($WF-&gt;InsertWorkflow( $request) &gt; 0)
        {
            Session::flash(&#39;flash_message&#39;,&#39;Workflow Saved!&#39;);
        }
    }




    public static function update(WorkFlowRequest $request)
    {
        $WF = new AppWorkflows();
        if($WF-&gt;UpdateWorkflow($request[&#39;id&#39;],$request) == 1)
        {
            Session::flash(&#39;flash_message&#39;,&#39;Workflow updated successfully!&#39;);
        }
    }
}

</pre>
<p>Inside our controller we now change the previously refactored method yet again, this time to use the service layer:</p>
<pre class="prettyprint lang-php " data-pbcklang="php" data-pbcktabsize="4">
public function SaveWorkflow(WorkFlowRequest $request,$id)
{
    AppWorkFlowService::update($request);
    return $this-&gt;ShowWorkflowList();
}</pre>
<p>At the top of our controller include a use statement for the Service class.</p>
<pre class="prettyprint lang-php " data-pbcklang="php" data-pbcktabsize="4" style="line-height: 20.8px;">
use AppHttpRequestsWorkFlowRequest;
use AppModelsServicesWorkFlowService;</pre>
<p>This exercise has considerably reduced our controller code, it has also placed our insert and update code into a single file where it can be maintained much easier with virtually no gremlins coming in as a result of column changes.</p>
<p>Now you can refactor all methods that handle form code and save considerable space.</p>
<p>-oOo-</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Developing applications with Laravel 5 &#8211; Part 3</title>
		<link>https://testing.conetix.com.au/blog/developing-applications-laravel-5-part-3/</link>
		
		<dc:creator><![CDATA[Sid Young]]></dc:creator>
		<pubDate>Thu, 19 May 2016 06:21:00 +0000</pubDate>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[larave]]></category>
		<category><![CDATA[laravel]]></category>
		<category><![CDATA[php]]></category>
		<guid isPermaLink="false">https://conetix.com.au/developing-applications-laravel-5-part-3/</guid>

					<description><![CDATA[Update August 2017: I am currently updating this article with more modern syntax and removal of a large number of now obsolete statements. Generally the code concepts are still valid however, please check back for updates in due course. &#160; This is Part 3 of Developing Applications in Laravel 5. To recap so far: In&#160;Part...  <a class="excerpt-read-more" href="https://testing.conetix.com.au/blog/developing-applications-laravel-5-part-3/" title="Read Developing applications with Laravel 5 &#8211; Part 3">Read more &#187;</a>]]></description>
										<content:encoded><![CDATA[<blockquote>
<p>Update August 2017: I am currently updating this article with more modern syntax and removal of a large number of now obsolete statements. Generally the code concepts are still valid however, please check back for updates in due course.</p>
</blockquote>
<p>&nbsp;</p>
<p>This is Part 3 of Developing Applications in Laravel 5. To recap so far:</p>
<ul>
<li>In&nbsp;<a href="https://www.conetix.com.au/blog/developing-application-laravel-5" target="_blank" rel="noopener noreferrer">Part 1</a>&nbsp;I covered developing a simple application that exercised the three&nbsp;essential&nbsp;components of the Laravel&nbsp;eco-system, that being Models, Views and Controllers.</li>
<li>In <a href="https://www.conetix.com.au/blog/developing-applications-laravel-5-part-2" target="_blank" rel="noopener noreferrer">Part 2</a> we looked at Views and we went through the steps of doing a&nbsp;refactor on an old&nbsp;blade template.</li>
</ul>
<p>In this&nbsp;article we will look at Models, in particular using&nbsp;<a href="https://laravel.com/docs/5.2/queries" target="_blank" rel="noopener noreferrer">Laravel&#39;s Fluent Query Builder</a>&nbsp;to build a Model to access the database and retrieve data using different queries.&nbsp;But first lets re-cap where a &quot;Model&quot; fits into the big picture.&nbsp;</p>
<p>When a Request reaches our application, the Laravel framework looks up&nbsp;a route table for a matching path. In routes.php we typically define a Path, Controller and Method which allows our code to be called as needed. So for any path, typically a Controller is instanced and a method inside it is called. From this Method, Models are usually invoked, data retrieved and business logic applied which then results in data that needs to be displayed. The Controller returns a&nbsp;View object, passing&nbsp;the data with it&nbsp;which is then rendered back to the user using the Blade Templating engine.</p>
<p>For this article, the key point is&nbsp;when the Controller is invoked, it gets data from one or Models as a result of User input or program Actions. Models usually get their data from a&nbsp;database, sometimes a flat file or other external data source.&nbsp;One of the big mistakes I see in code samples&nbsp;in many tutorials&nbsp;is direct access to a database being called from within a Controller or View rather than via a Model, even worse the data access methods used are typically low level SQL calls. In reviewing these code samples I&nbsp;consider them to fail dramatically as &quot;good&quot; examples; for the following reasons:</p>
<ol>
<li>In a large application, Database&nbsp;code cannot be&nbsp;maintained in the long term if its scattered with business logic.</li>
<li>Changes to the Database engine often introduce incompatibilities that are time consuming to refactor if code is not contained in a Model.</li>
<li>Poor coding skills and a lack of experience may lead to&nbsp;Database specific code being duplicated, introducing errors.</li>
<li>Limits enhancements to functionality.</li>
<li>Long term maintenance of production applications is hampered due to poor Database code design.</li>
</ol>
<p>In Laravel there are several ways to get access to a database, you can:</p>
<ul>
<li>Use the low level interface if you wish (see: <a href="https://laravel.com/docs/5.2/database" target="_blank" rel="noopener noreferrer">Database</a>), I highly suggest you re-think that path if that is what you are use to doing.</li>
<li>You could go the high level interface called <a href="https://laravel.com/docs/5.2/eloquent" target="_blank" rel="noopener noreferrer">Eloquent</a>, which has some powerful features on offer, or</li>
<li>You could go middle of the road and use the&nbsp;<a href="https://laravel.com/docs/5.2/queries" target="_blank" rel="noopener noreferrer">Fluent Query Builder</a>.</li>
</ul>
<p>When I initially&nbsp;started Laravel Development, the Eloquent path&nbsp;looked attractive, but I quickly found difficulties with my then limited knowledge to manipulate the data collections returned from simple queries. I investigated the&nbsp;<a href="https://laravel.com/docs/5.2/queries" target="_blank" rel="noopener noreferrer">Fluent Query Builder</a> and immediately had results, I also found solutions to all my needs so I began to use it for all my applications, even if you have 100&#39;s of tables, Fluent is still &nbsp;a viable solution.</p>
<h2>Creating a Model</h2>
<p>I find using the Artisan tool is a great way to create a model file, below is the syntax for it. When creating a Model it is often good to also create a <a href="https://laravel.com/docs/5.2/migrations" target="_blank" rel="noopener noreferrer">Migration</a> file with it, if you recall from&nbsp;the earlier articles in this series, the Migration file is where we define our database table and its columns.</p>
<pre class="prettyprint lang-sh " data-pbcklang="sh" data-pbcktabsize="4">
# php artisan help make:model          
Usage:
  make:model [options] [--] &lt;name&gt;

Arguments:
  name                  The name of the class

Options:
  -m, --migration       Create a new migration file for the model.
  -h, --help            Display this help message
  -q, --quiet           Do not output any message
  -V, --version         Display this application version
      --ansi            Force ANSI output
      --no-ansi         Disable ANSI output
  -n, --no-interaction  Do not ask any interactive question
      --env[=ENV]       The environment the command should run under.
  -v|vv|vvv, --verbose  Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug

Help:
 Create a new Eloquent model class</pre>
<p>So if we create a table called Registrations we can use the command line:</p>
<pre class="prettyprint lang-sh " data-pbcklang="sh" data-pbcktabsize="4">
#php artisan make:model Registrations --migration -vvv
Model created successfully.
Created Migration: 2016_03_24_111120_create_registrations_table
#</pre>
<p>The Model file generated is bare at best, but it doesn&#39;t hurt to have it done via the tool, you will find the Model file in the &quot;app&quot; dicrectory:</p>
<pre class="prettyprint lang-php " data-pbcklang="php" data-pbcktabsize="4">
&lt;?php namespace App;

use IlluminateDatabaseEloquentModel;

class Registrations extends Model
{
    //
}</pre>
<p>The migration file generated however does have extra support code in it.</p>
<pre class="prettyprint lang-php " data-pbcklang="php" data-pbcktabsize="4">
&lt;?php

use IlluminateDatabaseSchemaBlueprint;
use IlluminateDatabaseMigrationsMigration;

class CreateRegistrationsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create(&#39;registrations&#39;, function (Blueprint $table) {
            $table-&gt;increments(&#39;id&#39;);
            $table-&gt;timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::drop(&#39;registrations&#39;);
    }
}</pre>
<h2>Structuring a Model</h2>
<p>Below is a file for a table called &quot;account_plans&quot; from a real application (still in&nbsp;development). I selected it as it has a reasonable number of columns, it&#39;s still under development so I can make changes if needed and I can refactor the code with no production issues.</p>
<pre class="prettyprint lang-php " data-pbcklang="php" data-pbcktabsize="4">
&lt;?php namespace App;

use IlluminateDatabaseEloquentModel;

class AccountPlans extends Model
{
protected $id;
protected $plan_name;
protected $plan_description;
protected $plan_status;
protected $plan_base_cost;
protected $plan_cnt_clients;
protected $plan_cnt_debtors;
protected $plan_cnt_users;
protected $plan_cnt_storage;
protected $plan_additional_clients;
protected $plan_additional_debtors;
protected $plan_additional_users;
protected $plan_additional_storage;
protected $plan_date_created;

#
#
#
public $timestamps = false;
#
#
#
protected $fillable = array(&#39;plan_name&#39;,&#39;plan_description&#39;,&#39;plan_status&#39;,&#39;plan_base_cost&#39;,&#39;plan_cnt_clients&#39;,&#39;plan_cnt_debtors&#39;,&#39;plan_cnt_users&#39;,&#39;plan_cnt_storage&#39;,&#39;plan_additional_clients&#39;,&#39;plan_additional_debtors&#39;,&#39;plan_additional_users&#39;,&#39;plan_additional_storage&#39;,&#39;plan_date_created&#39;);



    public function InsertPlan($d)
    {
        $today = date(&quot;Y-m-d&quot;);
        return DB::table(&#39;account_plans&#39;)-&gt;insertGetId(
            array(
                &#39;plan_name&#39;=&gt;$d[&#39;plan_name&#39;],
                &#39;plan_description&#39;=&gt;$d[&#39;plan_description&#39;],
                &#39;plan_status&#39;=&gt;&#39;A&#39;,
                &#39;plan_base_cost&#39;=&gt;$d[&#39;plan_base_cost&#39;],
                &#39;plan_cnt_clients&#39;=&gt;$d[&#39;plan_cnt_clients&#39;],
                &#39;plan_cnt_debtors&#39;=&gt;$d[&#39;plan_cnt_debtors&#39;],
                &#39;plan_cnt_users&#39;=&gt;$d[&#39;plan_cnt_users&#39;],
                &#39;plan_cnt_storage&#39;=&gt;$d[&#39;plan_cnt_storage&#39;],
                &#39;plan_additional_clients&#39;=&gt;$d[&#39;plan_additional_clients&#39;],
                &#39;plan_additional_debtors&#39;=&gt;$d[&#39;plan_additional_debtors&#39;],
                &#39;plan_additional_users&#39;=&gt;$d[&#39;plan_additional_users&#39;],
                &#39;plan_additional_storage&#39;=&gt;$d[&#39;plan_additional_storage&#39;],
                &#39;plan_date_created&#39;=&gt;$today
                )
            );
    }



    public function getByID($id=0)
    {
        return DB::table(&#39;account_plans&#39;)-&gt;where([&#39;id&#39;=&gt;$id])-&gt;get();
    }

}</pre>
<p>The basic code shows two methods, InsertPlan() and getByID(), (with no comments). We will add more methods as we go (and comments) but these two methods will help us start building basic functionality for use in our Controller.</p>
<p>You will also notice there are two other variables defined in the&nbsp;Model file,&nbsp;<strong>$timestampes</strong>&nbsp;and an array called&nbsp;<strong>$fillable</strong>. <strong>&quot;Timestamps&quot;</strong> are automatically defined when you use Artisan to create a Migration and the framework will try to update a&nbsp;timestamp&nbsp;column it assumes is there, so settings this to false disables this behaviour. This line is not normally incuded in the pre-built Model, you need to add it and set it to false.&nbsp;</p>
<p>&quot;<strong>Fillable</strong>&quot;&nbsp;is for mass assignment protection, if the variables in the table are not defined&nbsp;in &quot;<strong>fillable</strong>&quot;, you cannot update them and attempts to do so will cause a Mass Assignment Exception in your application. You can also define an array called &quot;<strong>guarded</strong>&quot; to define columns that cannot be updated en-mass.</p>
<p>Lets look at the&nbsp;insert method, apart from the data we pass in, columns such as&nbsp;&quot;status&quot; and &quot;date_created&quot; are assigned set values&nbsp;during the insert&nbsp;which is a logical action to do. In our application, setting these makes the account plan go&nbsp;active immediately.</p>
<p>When the controller invokes this object it will use the following syntax:</p>
<pre class="prettyprint lang-php " data-pbcklang="php" data-pbcktabsize="4" style="line-height: 20.8px;">
$AccountPlans = new AppAccountPlans();</pre>
<p>To then access a method (in this example the getByID() method, we&nbsp;will call the method using:</p>
<pre class="prettyprint lang-php " data-pbcklang="php" data-pbcktabsize="4">
$rows = $AccountPlans-&gt;getByID($account_plan_id);</pre>
<p>In its present form the Model has both methods for talking to the Database and it has protected variables to hold database parameters that can represent a single row in the table. Ideally an Insert, Update or getByID() method should update these values to reflect the row data in the Model, this effectively makes the Model a Data Transfer Object (DTO) which will be useful in our application down the track.</p>
<p>If we update our Model to also be a DTO then the code to do this will look something like:</p>
<pre class="prettyprint lang-php " data-pbcklang="php" data-pbcktabsize="4">
 public function InsertPlan($d)
    {
        $this-&gt;plan_name = $d[&#39;plan_name&#39;];
        $this-&gt;plan_description = $d[&#39;plan_description&#39;];
        $this-&gt;plan_status = &#39;A&#39;;
        $this-&gt;plan_base_cost = $d[&#39;plan_base_cost&#39;];
        $this-&gt;plan_cnt_clients = $d[&#39;plan_cnt_clients&#39;];
        $this-&gt;plan_cnt_debtors = $d[&#39;plan_cnt_debtors&#39;];
        $this-&gt;plan_cnt_users = $d[&#39;plan_cnt_users&#39;];
        $this-&gt;plan_cnt_storage = $d[&#39;plan_cnt_storage&#39;];
        $this-&gt;plan_additional_clients = $d[&#39;plan_additional_clients&#39;];
        $this-&gt;plan_additional_debtors = $d[&#39;plan_additional_debtors&#39;];
        $this-&gt;plan_additional_users = $d[&#39;plan_additional_users&#39;];
        $this-&gt;plan_additional_storage = $d[&#39;plan_additional_storage&#39;];
        $this-&gt;plan_date_created = $today;

        $today = date(&quot;Y-m-d&quot;);
        $this-&gt;id = DB::table(&#39;account_plans&#39;)-&gt;insertGetId(
            array(
                &#39;plan_name&#39;=&gt;$d[&#39;plan_name&#39;],
                &#39;plan_description&#39;=&gt;$d[&#39;plan_description&#39;],
                &#39;plan_status&#39;=&gt;&#39;A&#39;,
                &#39;plan_base_cost&#39;=&gt;$d[&#39;plan_base_cost&#39;],
                &#39;plan_cnt_clients&#39;=&gt;$d[&#39;plan_cnt_clients&#39;],
                &#39;plan_cnt_debtors&#39;=&gt;$d[&#39;plan_cnt_debtors&#39;],
                &#39;plan_cnt_users&#39;=&gt;$d[&#39;plan_cnt_users&#39;],
                &#39;plan_cnt_storage&#39;=&gt;$d[&#39;plan_cnt_storage&#39;],
                &#39;plan_additional_clients&#39;=&gt;$d[&#39;plan_additional_clients&#39;],
                &#39;plan_additional_debtors&#39;=&gt;$d[&#39;plan_additional_debtors&#39;],
                &#39;plan_additional_users&#39;=&gt;$d[&#39;plan_additional_users&#39;],
                &#39;plan_additional_storage&#39;=&gt;$d[&#39;plan_additional_storage&#39;],
                &#39;plan_date_created&#39;=&gt;$today
                )
            );
        return $this-&gt;id;
    }
</pre>
<p>We can also add the code block to the &quot;update&quot; and &quot;getByID()&quot; methods and our object will be updated accordingly when these methods are called. We can even add a Constructor and pass in the row ID and fill the object that way if required.</p>
<h2>Accessing and Manipulating Data</h2>
<p>If we wanted to get a single row from our application, we can call the getByID() method in our model&nbsp;as follows:</p>
<pre class="prettyprint lang-php " data-pbcklang="php" data-pbcktabsize="4" style="line-height: 20.8px;">
$row = $AccountPlans-&gt;getByID($account_plan_id)[0];</pre>
<p>Which at a lower level in the Model calls:&nbsp;</p>
<pre class="prettyprint lang-php " data-pbcklang="php" data-pbcktabsize="4" style="line-height: 20.8px;">
public function getByID($id)
{
    return DB::table(&#39;account_plans&#39;)-&gt;where([&#39;id&#39;=&gt;$id])-&gt;get();
}</pre>
<p>The basic operations an application will typically perform on a database that will result in changes&nbsp;are Insert&#39;s, Update&#39;s and Deletes. Selects on the other&nbsp;hand will only read from the database and if no index is specified on the columns that form the selection then the SQL engine will perform a sequential read of the tables involved which can have significant performance implications.</p>
<p>We already have a basic insert using Fluent syntax, this form uses an array of columns and returns the inserted row ID. Lets add a delete method:</p>
<pre class="prettyprint lang-php " data-pbcklang="php" data-pbcktabsize="4">
public function DeleteByID($id)
{
    return DB::table(&#39;account_plans&#39;)-&gt;where([&#39;id&#39;=&gt;$id])-&gt;delete();
}</pre>
<p>The where clause uses the row ID which is a primary key and the method will return the number of deleted rows. Inside the where clause you can see the &#39;id&#39; parameters are encased in an array [] syntax. You will also see that the delete() method is chained to the where() method similar to our getByID() method above. When using the Fluent Query Builder, chaining will be used many times to join operations together.</p>
<p>Lets now look at an Update method, in this case we will use most of the columns in our UpdateAccountPlan() method (without saving the data into the Model):</p>
<pre class="prettyprint lang-php " data-pbcklang="php" data-pbcktabsize="4">
    public function UpdateAccountPlan($d)
    {
        return DB::table(&#39;account_plans&#39;)-&gt;where([&#39;id&#39;=&gt;$d[&#39;id&#39;]])-&gt;update(
        array(
                &#39;plan_name&#39;=&gt;$d[&#39;plan_name&#39;],
                &#39;plan_description&#39;=&gt;$d[&#39;plan_description&#39;],
                &#39;plan_status&#39;=&gt;$d[&#39;plan_status&#39;],
                &#39;plan_base_cost&#39;=&gt;$d[&#39;plan_base_cost&#39;],
                &#39;plan_cnt_clients&#39;=&gt;$d[&#39;plan_cnt_clients&#39;],
                &#39;plan_cnt_debtors&#39;=&gt;$d[&#39;plan_cnt_debtors&#39;],
                &#39;plan_cnt_users&#39;=&gt;$d[&#39;plan_cnt_users&#39;],
                &#39;plan_cnt_storage&#39;=&gt;$d[&#39;plan_cnt_storage&#39;],
                &#39;plan_additional_clients&#39;=&gt;$d[&#39;plan_additional_clients&#39;],
                &#39;plan_additional_debtors&#39;=&gt;$d[&#39;plan_additional_debtors&#39;],
                &#39;plan_additional_users&#39;=&gt;$d[&#39;plan_additional_users&#39;],
                &#39;plan_additional_storage&#39;=&gt;$d[&#39;plan_additional_storage&#39;]
                )
            );
&nbsp;   }
</pre>
<p>As per the delete() call, there is a where clause which uses our ID of the row, passed in the array called $d. We don&#39;t update the date created field so its left out of the update statement. There is nothing wrong with creating other update methods such as:</p>
<pre class="prettyprint lang-php " data-pbcklang="php" data-pbcktabsize="4">
public function UpdateStatus($id,$status)
{
    return DB::table(&#39;account_plans&#39;)-&gt;where([&#39;id&#39;=&gt;$d[&#39;id&#39;]])-&gt;update([&#39;plan_status&#39;=&gt;$status]);
}</pre>
<p>If we chain &quot;where&quot; clauses we create an &quot;AND&quot; condition, for a logical &quot;OR&quot; clause we can use orWhere() instead and we can use <a href="https://laravel.com/docs/5.2/queries#advanced-where-clauses" target="_blank" rel="noopener noreferrer">Advanced Where Clauses</a> to build as complex a query as we need.</p>
<p>A simple AND clause would look like:</p>
<pre class="prettyprint lang-php " data-pbcklang="php" data-pbcktabsize="4" style="line-height: 20.8px;">
public function GetClientsDebtors($client_count, $debtor_count)
{
    return DB::table(&#39;account_plans&#39;)
    -&gt;where([&#39;plan_cnt_clients&#39;=&gt;$client_count])
    -&gt;where([&#39;plan_cnt_debtor&#39;=&gt;$debtor_count])
    -&gt;get();
}</pre>
<p>Finding dates always seams to be an issue for people, but if you use YYYY-MM-DD formatting then using logic such as whereBetween() will return rows between these dates but not including the dates.</p>
<pre class="prettyprint lang-php " data-pbcklang="php" data-pbcktabsize="4" style="line-height: 20.8px;">
return DB::table(&#39;account_plans&#39;)-&gt;whereBetween(&#39;plan_date_created&#39;, [&#39;2015-08-01&#39;, &#39;2015-08-20&#39;])-&gt;get();</pre>
<p>So that&#39;s our basic Create,&nbsp;Update and Delete methods covered, lets look at some selects on this table, lets find all rows which have less than 10 clients and 10 users:</p>
<pre class="prettyprint lang-php " data-pbcklang="php" data-pbcktabsize="4">
In our controller:

$AccountPlans = new AppAccountPlans();
$rows = $AccountPlans-&gt;ClientUserCount(10,10);
foreach($rows as $row)
{
    echo &quot;Plan ID is: $row-&gt;id &quot;;
}

And Our method in our Model:

public function ClientUserCount($clients=1,$users=1)
{
    return DB::table(&#39;account_plans&#39;)
        -&gt;where([&#39;plan_cnt_clients&#39;=&gt;$clients ])
        -&gt;where([ &#39;plan_cnt_users&#39;=&gt;$users ])
        -&gt;get();
}</pre>
<p>By chaining our where() clauses one after the other we have created the AND logic needed to select on multiple columns.</p>
<p>We can extend the where clause to also use an IN clause, which is a popular method of restricting a query to a subset of records. Lets say we have a group of accounts that use account_plan 100, and we want to get all the clients under each account using that plan. So we need to build a list of accounts first, then use the list to get the clients.</p>
<pre class="prettyprint lang-php " data-pbcklang="php" data-pbcktabsize="4">
public function getClientsByPlanID($plan_id)
{
    $accounts = DB::table(&#39;accounts&#39;)-&gt;where([&#39;account_plan_id&#39;=&gt;$plan_id])-&gt;lists(&#39;id&#39;);
    return DB::table(&#39;clients&#39;)-&gt;whereIn(&#39;client_account_id&#39;, $accounts)-&gt;get();
}</pre>
<p>The first line gets a list of &nbsp;&#39;id&#39; columns&#39;s from the &#39;accounts&#39; table that have a plan ID of what ever we passed into the function.</p>
<p>The&nbsp;<strong>whereIn()</strong> statement matches the list given to the column name in the &#39;clients&#39; table and returns rows using the get().</p>
<p>So far a lot of our where clauses have been &quot;this == that&quot; so if you need to use the &#39;LIKE&#39; operator, such as the function below for finding all DEMO users in our &quot;users&quot; table, then the where clause takes the&nbsp;form:</p>
<pre class="prettyprint lang-php " data-pbcklang="php" data-pbcktabsize="4">
public function getDemoUsers()
{
    return DB::table(&#39;users&#39;)-&gt;where(&#39;usr_type&#39;,&#39;LIKE&#39;,&quot;DE%&quot;)-&gt;get();
}</pre>
<p>We could adds lots more examples here especially for inner joins, outer joins, unions, aggregators, groupBy&nbsp;and a host of SQL standard operations. One very handy feature is the increment and decrement operation. This method will select, increment and&nbsp;update&nbsp;an integer column (as an option you can also pass the increment value if greater than 1):&nbsp;</p>
<pre class="prettyprint lang-php " data-pbcklang="php" data-pbcktabsize="4">
public function IncrementAssigned($id)
{
    return DB::table(&#39;users&#39;)-&gt;where([&#39;id&#39;=&gt;$id])-&gt;increment(&#39;user_assigned&#39;);
}</pre>
<p>But lets divert our efforts to using the Model as a DTO and wrap up.</p>
<p>Earlier in this article we mentioned our protected variables that represent 1 row of data. We&nbsp;also mentioned that the Insert, Update and getByID()&nbsp;methods were ideal places to update the data held in the class. To make a DTO useable you will need to decide if you provide public access to the variables or provide individual accessor methods. The advantage of accessor methods is when you use an tool that has an intelligent IDE, it can provide syntax highlighting, auto-complete&nbsp;and documentation options. If you use the &quot;magic hooks&quot; method by providing a __get() method you circumvent these useful features.</p>
<p>For reference, the PHP &quot;Magic Methods&quot; code for accesing internal class variables looks like this:</p>
<pre class="prettyprint lang-php " data-pbcklang="php" data-pbcktabsize="4" style="line-height: 20.8px;">
A PHP class accessor method using __get()

	public function __get($name)
	{
		if(isset($this-&gt;$name))
		{
			return $this-&gt;$name;
		}
		else
		{
			return false;
		}
	}</pre>
<h2>Moving Forward</h2>
<p>Each table in your project should have its own Model file. Its best to use the artisan tools as it may introduce features in later versions that add more versatility to the models it creates. The only issue I have with the creation of the model is it&#39;s placed in the &#39;app&#39; directory rather than a special purpose &quot;app/Models&quot; directory. To fix this, I create an entry in my <strong>composer.json</strong> file to enable the inclusion of the classes in app/Models. The line to add looks like this:</p>
<pre class="prettyprint lang-javascript " data-pbcklang="javascript" data-pbcktabsize="4">
   &quot;autoload&quot;: {
        &quot;classmap&quot;: [
            &quot;database&quot;,
            &quot;app/Models&quot;
        ],
        &quot;psr-4&quot;: {
      </pre>
<p>You will need to do a clearing of the artisan caches using <strong>php artisan cache:clear</strong> and also <strong>config:clear</strong>. After that run a <strong>composer dump-autoload</strong> and the next time your application runs the model files in app/Models will be useable. You will need to move each newly created model into this directory as the artisan tool will still create them in the default location.</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
