<?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>Mitchell McKenna</title>
	<atom:link href="http://mitchmckenna.com/blog/feed/" rel="self" type="application/rss+xml" />
	<link>http://mitchmckenna.com/blog</link>
	<description>Tech, programming and personal interests.</description>
	<lastBuildDate>Tue, 17 Jan 2023 08:45:29 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	
<site xmlns="com-wordpress:feed-additions:1">133590506</site>	<item>
		<title>Git Hooks: Check Code Quality &#038; Unit Tests on Every Commit</title>
		<link>http://mitchmckenna.com/blog/2023/01/git-hooks-check-code-quality-unit-tests-on-every-commit/</link>
					<comments>http://mitchmckenna.com/blog/2023/01/git-hooks-check-code-quality-unit-tests-on-every-commit/#respond</comments>
		
		<dc:creator><![CDATA[Mitchell McKenna]]></dc:creator>
		<pubDate>Tue, 17 Jan 2023 08:04:17 +0000</pubDate>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[code quality]]></category>
		<category><![CDATA[code standards]]></category>
		<category><![CDATA[git]]></category>
		<category><![CDATA[linting]]></category>
		<category><![CDATA[php]]></category>
		<guid isPermaLink="false">http://mitchmckenna.com/blog/?p=1479</guid>

					<description><![CDATA[Automatically lint your code, check unit tests, and run static analysers every time you run “git commit”. It’s a developer’s local CI pipeline.]]></description>
										<content:encoded><![CDATA[
<p><strong>Automatically lint your code, check unit tests, and run static analysis every time you run “git commit”. It’s a developer’s local CI pipeline.</strong></p>



<p>Let me know if this sounds familiar. Your project is following a coding standard but commits keep making it into master that don’t follow the coding standard. Or during a code review, you realize the author of the merge request hasn’t run it through a linter yet or that the unit tests are now failing. Instead of you having to be “that guy who asks everybody to clean up their code or fix the unit tests”, you could automate these code quality checks. Plus think of the time saved in the back and forth in the code review. The code review no-longer needs to be about code style or if the tests pass, and can instead focus on what matters; is the implementation sound, is there a better way it could be done, and is it properly tested? </p>



<p>You might say &#8220;well my IDE catches this type of stuff&#8221;, and it&#8217;s a common practice to run your linter and unit tests in your IDE. However, for IDE tooling, most code quality tools are up to the developer to set up or not. Plus, sometimes developers miss the warnings in their IDE’s or forget to run the tests before pushing up their merge request. That’s why having automatic code quality checks in the continuous integration (CI) pipeline is a great final catch before the code makes it into master. And don&#8217;t get me wrong, I think you should have these checks there as well, but if you wait for the CI pipeline to catch these before you fix them, it’s a much slower process than checking them locally. Especially if you have multiple issues, waiting for the CI pipeline multiple times can slow down your development process. Continuous local validation is quicker than remote.  </p>



<p>Plus, wouldn’t it be better if this was caught before the pull request was created? Better yet, before the commit was created? Avoiding messy one-off fix commits or having to squash them constantly? This is where a <strong>pre-commit hook</strong> can come in handy. Let’s look at three great options to leverage git hooks as a solution.</p>



<p>Side note: If you’re curious why you should follow a coding standard, and how to set up a linter for PHP on the command line or in your IDE, checkout my previous article: <a href="http://mitchmckenna.com/blog/2020/04/is-your-code-up-to-sniff/">Is Your Code Up To Sniff?</a></p>



<h2 class="wp-block-heading">Git Pre-commit Hooks</h2>



<p>Git provides hooks that allow you to run a script before commiting, before pushing, after merging, etc. If the script doesn’t report a success, it stops you from completing that git action until the script reports a successful execution. The git hook we’re specifically interested in is the pre-commit hook. A pre-commit hook runs when you type “git commit” but won’t bring up the prompt for entering a git commit message if the hook script doesn’t report a success first.</p>



<p>We’ll look at 3 popular tools to achieve this; GrumPHP, Husky (JS), and pre-commit.com (python). Husky is definitely the most popular of the three, but pre-commit.com has been gaining ground with support for multiple languages, and I feel like GrumPHP is really starting to catch on in the PHP community. You might think “why would I need a tool? Just call the lint command from the pre-commit hook” but the 3 biggest reasons to use these tools are:</p>



<ol class="wp-block-list">
<li><strong>Auto-install</strong></li>
</ol>



<p>How do you get your team to install the pre-commit hook? Do you ask each of them to manually install it, and to follow instructions on how to do it in your readme? Here’s the clever part: these tools can install the pre-commit hook automatically when developers use Composer or NPM; something they’d have to do to run your codebase anyway.</p>



<ol class="wp-block-list" start="2">
<li><strong>Only Lint Changed Files</strong></li>
</ol>



<p>A key feature to these tools is that you only want to lint the files which have changed (not the entire project), so that the pre-commit hook can run as fast as possible and not get in the way of getting your commit done. Which is important because running a linter across your entire codebase can take a minute or two if you’re working on big codebases, and having to wait that long each time you’re trying to get a commit created can drive people crazy.&nbsp;</p>



<ol class="wp-block-list" start="3">
<li><strong>Task Parallelization</strong></li>
</ol>



<p>If you’re doing multiple tasks (eg. linting and running unit tests) in your pre-commit hook, but these tools can run all the tasks in parallel so they complete much faster.</p>



<h2 class="wp-block-heading">GrumPHP</h2>



<figure class="wp-block-image size-large"><img data-recalc-dims="1" fetchpriority="high" decoding="async" width="700" height="523" data-attachment-id="1488" data-permalink="http://mitchmckenna.com/blog/2023/01/git-hooks-check-code-quality-unit-tests-on-every-commit/grumphp/" data-orig-file="https://i0.wp.com/mitchmckenna.com/blog/wp-content/uploads/2020/06/grumphp.png?fit=1334%2C996" data-orig-size="1334,996" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="GrumPHP" data-image-description="" data-image-caption="" data-medium-file="https://i0.wp.com/mitchmckenna.com/blog/wp-content/uploads/2020/06/grumphp.png?fit=300%2C224" data-large-file="https://i0.wp.com/mitchmckenna.com/blog/wp-content/uploads/2020/06/grumphp.png?fit=700%2C523" src="https://i0.wp.com/mitchmckenna.com/blog/wp-content/uploads/2020/06/grumphp.png?resize=700%2C523" alt="" class="wp-image-1488" srcset="https://i0.wp.com/mitchmckenna.com/blog/wp-content/uploads/2020/06/grumphp.png?resize=1024%2C765 1024w, https://i0.wp.com/mitchmckenna.com/blog/wp-content/uploads/2020/06/grumphp.png?resize=300%2C224 300w, https://i0.wp.com/mitchmckenna.com/blog/wp-content/uploads/2020/06/grumphp.png?resize=768%2C573 768w, https://i0.wp.com/mitchmckenna.com/blog/wp-content/uploads/2020/06/grumphp.png?resize=700%2C523 700w, https://i0.wp.com/mitchmckenna.com/blog/wp-content/uploads/2020/06/grumphp.png?w=1334 1334w" sizes="(max-width: 700px) 100vw, 700px" /></figure>



<p><a href="https://github.com/phpro/grumphp">GrumPHP</a> is “a PHP code-quality tool” with many features, one of which includes registering a pre-commit to use PHP_CodeSniffer or PHP CS Fixer to lint your code. Though there’s much more it can do on every commit, such as running a PHPUnit (or Pest) test suite, linting the commit message format, normalizing the composer.json file, or running PHPStan or Psalm for static code analysis. You can find a full-list of tasks GrumPHP can perform <a href="https://github.com/phpro/grumphp/blob/master/doc/tasks.md#tasks-1">here</a>.</p>



<p>Some popular open source packages utilizing GrumPHP are <a href="https://github.com/fruitcake/laravel-cors">fruitcake/laravel-cors</a> and <a href="https://omnipay.thephpleague.com/">league/omnipay</a> to name a few.</p>



<h3 class="wp-block-heading">Basic Config Example</h3>



<p>Starting off, a great basic config would be to check for syntax errors and code styling. We’ll use `phplint` to check for syntax errors and `phpcs` to run PHP_CodeSniffer for linting code style.</p>



<div class="wp-block-group"><div class="wp-block-group__inner-container is-layout-flow wp-block-group-is-layout-flow">
<pre class="wp-block-code"><code>// grumphp.yml
grumphp:
    tasks:
        { phplint: null, phpcs: null }</code></pre>
</div></div>



<h3 class="wp-block-heading">Advanced Config Example</h3>



<p>While the previous example was a great starting point, you’ll most likely want to take advantage of some of the more advanced features:</p>



<ul class="wp-block-list">
<li>Turn on auto-fixers (no need to run fix commands, GrumPHP can fix the issues for you!)</li>



<li>Add PHPUnit (or Pest) for unit testing.</li>



<li>Add PHPStan for static code analysis.</li>



<li>Add ESLint if your project uses frontend javascript eg. React, Vue, etc</li>



<li>Optional: Turn off ASCII output (GrumPHP uses <a href="https://github.com/phpro/grumphp/blob/master/resources/ascii/grumphp-grumpy.txt">fun ASCII art</a> in its pass/fail output, but as cool as the ASCII output is, maybe you need to be a little bit more “profesh” if using this in a work environment).</li>
</ul>



<pre class="wp-block-code"><code>grumphp: {
    ascii: null,
    fixer: { enabled: true, fix_by_default: true },
    tasks: {
        phplint: null,
        phpcs: null,
        phpstan: null,
        phpunit: null,
        eslint: null
    }
}</code></pre>



<h3 class="wp-block-heading">Notes for Speed</h3>



<p>PHPUnit and static code analysis can be slower tasks. You may wish to tweak or drop these types of pre-commit tasks if you find they&#8217;re slowing down your commit workflow too much.</p>



<h4 class="wp-block-heading">PHPUnit</h4>



<p>PHPUnit can be slow because it runs all your tests. Ideally, it would only check the test related to the code that changed, but it doesn’t know what other files and tests might be affected by the changed files, so it has to run them all. If you find your commits taking too long, alternatively, you could run only a subset of your unit tests by breaking them up into <a href="https://phpunit.readthedocs.io/en/9.5/organizing-tests.html#composing-a-test-suite-using-xml-configuration">multiple test suites</a> to make it complete at a satisfactory speed (maybe create a test suite that just includes critical or faster tests).&nbsp;</p>



<p>Aside: It would be awesome if PHPUnit had the ability to run all tests for a given class (open source project opportunity here)! You could probably write a script to look for tests in two ways;</p>



<ol class="wp-block-list">
<li>Run any test at “/tests/Unit/{same path as class}Test.php”. This assumes you follow the same folder and naming structure in /tests/Unit/ as you do in /app or /src, but I think that’s relatively common.</li>



<li>Run any test with @covers annotations for this class</li>
</ol>



<h4 class="wp-block-heading">Static Code Analysis</h4>



<p>Unlike PHPUnit for Static Code Analysis it only runs on the changed files, but the process is just generally slower (it&#8217;s compute heavy, though they can leverage cache so multiple runs are quicker). I’ve opted for just PHPStan and not Psalm as well, as I found Psalm slower on my Laravel projects.</p>



<h3 class="wp-block-heading">Alternative to GrumPHP: CaptainHook</h3>



<p>CaptainHook is another popular git hook management tool in the PHP community. CaptainHook explains how it compares to GrumPHP on <a href="https://captainhookphp.github.io/captainhook/compare.html#grumphp">their site</a>. If you plan on having a lot of custom tasks, this might be worth exploring as it’s a little more about managing cli commands, kind of like Husky for Javascript which we’ll talk about next actually. Captain Hook also has support for other git hooks as well (not just pre-commit0, while GrumPHP focuses on pre-commit hooks. A popular package utilizing CaptainHook is <a href="https://packagist.org/packages/ramsey/uuid">ramsey/uuid</a>.</p>



<h2 class="wp-block-heading">Husky + lint-staged</h2>



<figure class="wp-block-image size-large"><img data-recalc-dims="1" decoding="async" width="700" height="581" data-attachment-id="1502" data-permalink="http://mitchmckenna.com/blog/2023/01/git-hooks-check-code-quality-unit-tests-on-every-commit/carbon-2/" data-orig-file="https://i0.wp.com/mitchmckenna.com/blog/wp-content/uploads/2021/02/carbon-2.png?fit=1522%2C1264" data-orig-size="1522,1264" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="carbon-2" data-image-description="" data-image-caption="" data-medium-file="https://i0.wp.com/mitchmckenna.com/blog/wp-content/uploads/2021/02/carbon-2.png?fit=300%2C249" data-large-file="https://i0.wp.com/mitchmckenna.com/blog/wp-content/uploads/2021/02/carbon-2.png?fit=700%2C581" src="https://i0.wp.com/mitchmckenna.com/blog/wp-content/uploads/2021/02/carbon-2.png?resize=700%2C581" alt="" class="wp-image-1502" srcset="https://i0.wp.com/mitchmckenna.com/blog/wp-content/uploads/2021/02/carbon-2.png?resize=1024%2C850 1024w, https://i0.wp.com/mitchmckenna.com/blog/wp-content/uploads/2021/02/carbon-2.png?resize=300%2C249 300w, https://i0.wp.com/mitchmckenna.com/blog/wp-content/uploads/2021/02/carbon-2.png?resize=768%2C638 768w, https://i0.wp.com/mitchmckenna.com/blog/wp-content/uploads/2021/02/carbon-2.png?resize=700%2C581 700w, https://i0.wp.com/mitchmckenna.com/blog/wp-content/uploads/2021/02/carbon-2.png?w=1522 1522w, https://i0.wp.com/mitchmckenna.com/blog/wp-content/uploads/2021/02/carbon-2.png?w=1400 1400w" sizes="(max-width: 700px) 100vw, 700px" /></figure>



<p>Is your project partially or completely written in Javascript? <a href="https://github.com/typicode/husky">Husky</a> might be the tool for you instead of GrumPHP! Husky can manage git hooks to run both JS linters and unit testing, though it can do your PHP or other language pre-commit tasks too. What really brings the power to Husky is <a href="https://github.com/okonet/lint-staged">lint-staged</a>. lint-staged adds to Husky that concept of only running your hooks against the files that have changed.</p>



<p>Here’s some popular projects using Husky + lint-staged: <a href="https://github.com/facebook/create-react-app/blob/master/package.json">Create React App</a>, <a href="https://github.com/angular/angular/blob/master/package.json">Angular</a>, <a href="https://github.com/electron/electron/blob/master/package.json">Electron</a>, <a href="https://github.com/babel/babel/blob/main/package.json">Babel</a>, and <a href="https://github.com/webpack/webpack/blob/master/package.json">Webpack</a>. There’s even php community members using it, as an example check out <a href="https://sebastiandedeyne.com/running-php-cs-fixer-on-every-commit-with-husky-and-lint-staged">Sebastian De Deyne’s blog post</a> on using Husky for a PHP project.</p>



<p><strong>Unique features:&nbsp;</strong></p>



<ul class="wp-block-list">
<li><a href="https://medium.com/hackernoon/announcing-lint-staged-with-support-for-partially-staged-files-abc24a40d3ff">lint-staged supports partially staged files</a> so it will only look at the changed lines that are staged (not the whole file that’s been staged).</li>



<li>If the fixer didn’t cause an error, any changes will be auto-added before commit (no need to make `git add` one of the subtasks). It will rollback any changes if it runs into an error.</li>



<li>By default a backup stash will be created before running the tasks, and all task modifications will be reverted if any one of your pre-commit tasks reports an error. You can use the &#8211;no-stash option to disable creating the stash, and instead leave all modifications in the index when it aborts the commit.</li>
</ul>



<p><strong>Jest is great as a pre-commit hook:</strong></p>



<p>As far as unit tests go, Jest provides a very cool argument &#8211;findRelatedTests which informs Jest to run only those test cases which get impacted by the changed files. This can make it significantly faster than other unit testing frameworks like PHPUnit mentioned above, because those ones have to run the whole test suite.</p>



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



<p>Husky setup:</p>



<pre class="wp-block-code"><code>// .husky/pre-commit
 #!/bin/sh
. "$(dirname "$0")/_/husky.sh"
lint-staged</code></pre>



<p>lint-staged setup:</p>



<pre class="wp-block-code"><code>// package.json
{
   "lint-staged": {
     "**/*.js": &#91;
       "eslint --fix",
       “jest --bail --findRelatedTests"
     ]
   }
}</code></pre>



<h2 class="wp-block-heading">Using Husky for PHP Tasks</h2>



<p>As noted earlier, Husky can be used to run php pre-commit tasks too. This is because anything you can run on the command line, husky can run as a pre-commit task.&nbsp;Here&#8217;s an example of what a Husky setup might look like for running a bunch of php tasks equivalent to when we setup GrumPHP:</p>



<pre class="wp-block-code"><code>// .husky/pre-commit - Add phpunit
 #!/bin/sh
. "$(dirname "$0")/_/husky.sh"
npm run phpunit
lint-staged</code></pre>



<pre class="wp-block-code"><code>// package.json - Run PHP Lint, PHP CS Fixer, PHPStan, and ESLint
{
  "lint-staged": {
    "*.php": &#91;
      "./vendor/bin/parallel-lint",
      "./vendor/bin/php-cs-fixer fix",
      "./vendor/bin/phpstan analyse"
    ],
    "resources/js/*.{js,jsx,ts,tsx}": "eslint --fix"
  }
}</code></pre>



<p><strong>PHPUnit and Other Long Running Tasks</strong></p>



<p>Notice we’re running phpunit as a separate pre-commit task. This is because lint-staged passes all changed files as params to it’s tasks, this would pass the list of changed files to phpunit (not a list of test files), so we want to run PHPUnit on all tests since we can’t tell which ones have been affected.&nbsp;</p>



<p><strong>Pre-Push Hooks</strong></p>



<p>If you commit often and squash (I’m looking at you “wip wip squash” devs) you may prefer to move PHPUnit to a pre-push commit hook instead. This is actually handy and not something GrumPHP can do because <a href="https://github.com/phpro/grumphp/pull/258">GrumPHP doesn’t have support for pre-push</a> git hooks.&nbsp;</p>



<p><strong>PHP_CodeSniffer</strong></p>



<p>PHP_CodeSniffer doesn’t work well with Husky. This is because the code fixer `phpcbf` returns an exit code of 1 after fixing but Husky expects an exit code of 0 for all successful tasks (PHP_CodeSniffer <a href="https://github.com/squizlabs/PHP_CodeSniffer/issues/2898">will fix this in v4</a>). In the meantime, php-cs-fixer is a better option, I prefer it over PHP_CodeSniffer as it has more linter rules, although they <a href="https://github.com/FriendsOfPHP/PHP-CS-Fixer/issues/4502">don’t have PSR12 support yet</a> (PSR2 is fine for now).</p>



<h2 class="wp-block-heading">Pre-commit.com</h2>



<p>If your company has codebases in languages other than Javascript and PHP, Pre-commit.com might be a good alternative to GrumPHP or Husky. Pre-commit.com aims to be a language agnostic solution for pre-commit hooks. I originally disregarded Pre-commit.com as an option because it’s written in Python and I don’t have codebases in Python, but it doesn’t require python (or pip) to install it as it can be easily installed via brew &#8220;<code>brew install pre-commit</code>&#8220;, and it has git hooks for projects in way more languages than Python (<a href="https://pre-commit.com/#supported-languages">20+ languages</a> actually).</p>



<p>Another neat concept with Pre-commit.com is you install it globally one time on your computer and then any project you git clone which has a .pre-commit-config.yaml in it, it can automatically run pre-commit hooks on if you enable this feature. Click here to see how to <a href="https://pre-commit.com/#automatically-enabling-pre-commit-on-repositories">automatically enable pre-commit on repositories</a> so that any time you git clone a repo with a .pre-commit-config.yaml file in it, it will automatically install and run those pre-commit hooks on.</p>



<p>Php isn’t listed under the languages supported but there are hooks for php maintained by 3rd party contributors. The main ones all still work, and I haven’t run into an issue with them, but just a heads up they are not maintained and a successor fork hasn’t really taken over in popularity so far.</p>



<p>Here&#8217;s an example pre-commit.com hook setup for php and javascript tasks similar to the examples for GrumPHP and Husky above:&nbsp;</p>



<pre class="wp-block-code"><code>// .pre-commit-config.yaml
minimum_pre_commit_version: 2.18.0
repos:
 - repo: https://github.com/digitalpulp/pre-commit-php
   rev: 1.4.0
   hooks:
     - id: php-lint
     - id: php-cs
     - id: php-unit
     - id: php-stan
 - repo: github.com/pre-commit/mirrors-eslint
   rev: 8.25.0
   hooks:
     - id: eslint</code></pre>



<p><strong>Advanced Example</strong></p>



<p>If you’re a fan of <a href="https://www.conventionalcommits.org/en/v1.0.0/">Conventional Commits</a> we can have commit messages linted as well:</p>



<pre class="wp-block-code"><code>// .pre-commit-config.yaml
minimum_pre_commit_version: 2.18.0
default_stages:
 - commit
 - push
default_install_hook_types:
 - pre-commit
 - commit-msg
repos:
 - repo: https://github.com/digitalpulp/pre-commit-php
   rev: 1.4.0
   hooks:
     - id: php-lint
     - id: php-cs
     - id: php-unit
     - id: php-stan
 - repo: github.com/pre-commit/mirrors-eslint
   rev: 8.25.0
   hooks:
     - id: eslint
 - repo: https://github.com/compilerla/conventional-pre-commit
   rev: v1.2.0
   hooks:
     - id: conventional-pre-commit
       stages: &#91; commit-msg ]</code></pre>



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



<p>So which one would I use, GrumPHP, Husky or Pre-commit.com? If your project is primarily PHP, use GrumPHP. If your project is primarily javascript, use Husky. If your company has codebases in 3 or more languages (or any of them are python) it might be handy to standardize on pre-commit.com. I do have to say though, as the newer kid in this space, I really love GrumPHP’s implementation. GrumPHP has a ton of common tasks built-in, there’s a good chance if you have a common setup, you don’t have to pass any custom params or manually script up anything. GrumPHP makes the config file very simple and easy to read. Husky leaves it up to the developer to discover or think up pre-commit tasks to use, but that also makes it more versatile, especially if you have unique pre-commit tasks you want to run. Whichever one you choose, just try it out, I&#8217;m confident you&#8217;ll get hooked.</p>
]]></content:encoded>
					
					<wfw:commentRss>http://mitchmckenna.com/blog/2023/01/git-hooks-check-code-quality-unit-tests-on-every-commit/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1479</post-id>	</item>
		<item>
		<title>Is Your Code Up To Sniff?</title>
		<link>http://mitchmckenna.com/blog/2020/04/is-your-code-up-to-sniff/</link>
					<comments>http://mitchmckenna.com/blog/2020/04/is-your-code-up-to-sniff/#respond</comments>
		
		<dc:creator><![CDATA[Mitchell McKenna]]></dc:creator>
		<pubDate>Wed, 08 Apr 2020 14:54:26 +0000</pubDate>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[code quality]]></category>
		<category><![CDATA[code standards]]></category>
		<category><![CDATA[linting]]></category>
		<category><![CDATA[php]]></category>
		<guid isPermaLink="false">http://mitchmckenna.com/blog/?p=1370</guid>

					<description><![CDATA[PHP Code Standards Following coding standards in PHP is now easier than ever. Let&#8217;s go over the benefits of following a coding standard, how to enforce it, and look at how modern tooling and new features in IDE’s like PHPStorm makes it nicer than ever before. Why Follow a Coding Standard? Stop Wasting TimeIf you&#8217;ve [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p><strong>PHP Code Standards</strong></p>



<figure class="wp-block-image"><img decoding="async" src="https://lh5.googleusercontent.com/6HPAtv8NbvLvbntTHsqcbDF49ib4Jmabk39zMK3s92a94Nht1ifq3sV_j0n--ucS89bznavpfHyYDIAx-rzQN8Bu0T5gFGD19nLFanX5oT5v81p4pt1LUx9fj01yBkIuHxwR8Syu" alt=""/></figure>



<p>Following coding standards in PHP is now easier than ever. Let&#8217;s go over the benefits of following a coding standard, how to enforce it, and look at how modern tooling and new features in IDE’s like PHPStorm makes it nicer than ever before.</p>



<h2 class="wp-block-heading">Why Follow a Coding Standard?</h2>



<ol class="wp-block-list"><li><strong>Stop Wasting Time</strong><br />If you&#8217;ve ever worked with another developer or worked on a team, no doubt you&#8217;ve debated coding styles. Focus on what&#8217;s important (getting things done) and stop debating:<br />&#8211; Tabs vs spaces<br />&#8211; camelCase vs snake_case<br />&#8211; Opening brackets {} on new line or same line<br />&#8211; Control structure format<br />&#8211; TRUE/FALSE/NULL vs true/false/null<br />&#8211; Spacing that could go anywhere and everywhere<br />&#8211; &#8230; the list is never ending.</li><li><strong>More Readable Code</strong><br />Easier to read code comes from using a consistent code style. Your brain isn’t distracted by the personal preferences of the previous developer. In Jason McCreary’s book ‏<a href="https://basecodefieldguide.com/">Basecode</a>, he does an excellent job of explaining a concept which Kevlin Henney has coined “<a href="https://www.infoq.com/presentations/7-ineffective-coding-habits/">visual honesty</a>”. It’s the concept that you should be able to generally tell what’s happening in a function just by the shape of the code blocks. He illustrates this by showing that if all the characters were <a href="https://twitter.com/gonedark/status/951477799289786369">replaced with X’s</a>, when code is formatted properly, you can still recognize what’s happening. I had noticed the benefits of this before, but had a hard time putting it into words; what an excellent way to demonstrate it!</li><li><strong>Save Money</strong><br />Time is money, whether it&#8217;s your time or the company&#8217;s. Save time in both new developer on-boarding,<strong> </strong>as well as on code maintenance.<strong> </strong>New hire ramp-up time can be reduced if your codebase is in a popular format. It increases the chances the new developer has previous experience developing, reading and writing code in that format. For maintenance, code reviews are simpler, as there are less stylistic changes from developer to developer. As code reviews and new hires are a constant, this savings in developer time translates to real cost savings for the business over time.</li></ol>



<h2 class="wp-block-heading">EditorConfig</h2>



<p>At the very least, a project in any language should add an <a href="https://editorconfig.org">EditorConfig</a>. EditorConfig is a widely adopted open standard that helps maintain <em>general</em> coding styles. It’s a file which sits in the root of your project that many IDE’s will automatically (or with a plugin) read settings to set tabs vs spaces, tab length to 4 spaces, etc. PHPStorm now has EditorConfig support built-in since <a href="https://blog.jetbrains.com/phpstorm/2019/07/phpstorm-2019-2-release/#editorconfig">PHPStorm 2019.2</a>, VS Code has a <a href="https://marketplace.visualstudio.com/items?itemName=EditorConfig.EditorConfig">plugin</a>, and so does <a href="https://editorconfig.org/#download">almost all code editors</a>.&nbsp;</p>



<p>EditorConfig can only specify generic coding style settings, for the rest of the article we’ll look at standards and tools that go a lot further, specific to PHP.</p>



<h2 class="wp-block-heading">PSR-12</h2>



<p>In 2009, all the popular frameworks came together (<a href="https://www.php-fig.org" class="aioseop-link">PHP-FIG</a>) and agreed on common coding standards PSR-1 and PSR-2. Since then, PSR-2 (which builds upon PSR-1) had become the defacto coding standard in PHP, which is nice because you know any framework or 3rd-party php package you come across will follow the same coding style.&nbsp;</p>



<p>In August 2019, <a href="https://twitter.com/phpfig/status/1160902933854203904">PSR-12 was approved</a>, adding rules for new language features introduced in PHP 7. PSR-12 is now the recommended standard to follow.</p>



<p><strong>But We Can’t Follow PSR-12 Because Of ________</strong></p>



<p>Here’s some of the popular reasons holding team’s back from following PSR-12:</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p><em>“We have so much code already, it’d be too much work to convert it all.”</em></p></blockquote>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p><em>“We have certain folders we can’t (or don’t want to) touch.”</em></p></blockquote>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p><em>“There’s certain rules in PSR-12 that would break our code”</em></p></blockquote>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p><em>“There’s rules in PSR-12 my team strongly disagrees with.”</em></p></blockquote>



<p>Historically, it’s been difficult to perform large stylistic changes on an existing code base. Luckily there are tools which can convert all your files for you! We’ll walk through these tools in “Linters”.&nbsp;</p>



<p>There might be disagreement around the merit of specific rules within a coding standard. The tooling today easily addresses these concerns. It’s super easy to <em>extend</em><strong> </strong>the PSR-12 coding standard and exclude certain folders or rules. We’ll walk through how to do this in <a class="aioseop-link" href="#phpcs-xml-config-file">Creating a Configuration File</a>.</p>



<h2 class="wp-block-heading">Linters</h2>



<h3 class="wp-block-heading">PHP_CodeSniffer</h3>



<p>PHP_CodeSniffer is a linter command line tool for following PHP coding standards. You can install it globally so that from any project you can run the <code>phpcs</code> command to analyze files and <code>phpcbf</code> to fix them. Starting in version <a class="aioseop-link" href="https://github.com/squizlabs/PHP_CodeSniffer/releases/tag/3.5.0">3.5 has support for PSR-12</a>.</p>



<p><strong>Install PHP_CodeSniffer (Globally)</strong></p>



<pre class="wp-block-preformatted">// Install globally
composer global require "squizlabs/php_codesniffer=*"</pre>



<pre class="wp-block-preformatted">// Set the coding standard
phpcs --standard=PSR12</pre>



<pre class="wp-block-preformatted">// Scan a specific file<br />phpcs app/Controllers/HomeController.php&nbsp;</pre>



<pre class="wp-block-preformatted">// Scan all files
phpcs .</pre>



<pre class="wp-block-preformatted">// Fix a specific file<br />phpbf app/Controllers/HomeController.php&nbsp;</pre>



<pre class="wp-block-preformatted">// Fix all files<br />phpcbf .</pre>



<p><strong>Install PHP_CodeSniffer (Project Dependency)</strong></p>



<p>Having it installed globally is handy, the command is short so no matter what project you jump into it’s easy to remember. But I recommend <em>also</em> installing it as a composer dev dependency in your project. This way, no matter what, it’s installed for all your teammates and you all have the same version. </p>



<pre class="wp-block-preformatted">// Install locally
composer require --dev "squizlabs/php_codesniffer=*"</pre>



<p>Then you can run it the same way as demonstrated globally above, you just need to specify the vendor bin path where composer installs it to. </p>



<pre class="wp-block-preformatted">// Scan<br />vendor/bin/phpcs --standard=PSR12 app/Controllers/HomeController.php</pre>



<pre class="wp-block-preformatted">// Fix
vendor/bin/phpcbf --standard=PSR12 app/Controllers/HomeController.php</pre>



<p>We can avoid potentially forgetting to pass <code>--standard=PSR12</code> by <a class="aioseop-link" href="#phpcs-xml-config-file">creating a phpcs.xml configuration file</a> like we&#8217;ll demonstrate below.</p>



<p>If you find it annoying to type out the entire vendor path or have a hard time remembering the vendor path, maybe create a <a href="http://mitchmckenna.com/blog/wp-admin/post.php?post=1370&amp;action=edit#composer-run-script">composer run-script</a> which we&#8217;ll also go over below.</p>



<p>Even so, I&#8217;ll be honest, I usually just use the globally installed version; it&#8217;s easier to just type <code>phpcs</code>, and PHP_CodeSniffer doesn&#8217;t change too much from version to version. But I install it as a dev dependency anyway so that it&#8217;s there if I need it to run it on a server or another system. Plus there&#8217;s an added benefit that by setting it as a dev dependency and creating the composer run-script, our teammates IDE’s can <a href="#set-the-coding-standard-automatically" class="aioseop-link">set the coding standard automatically</a> for them.</p>



<h4 class="wp-block-heading" id="phpcs-xml-config-file">Create a phpcs.xml Configuration File</h4>



<p>Like I said above, you may <em>Extend PSR-12</em> if you want to exclude files or folders, or exclude certain rules. By placing a <code>phpcs.xml</code> file at the root of your project, anyone who runs <code>phpcs</code> doesn&#8217;t have to worry about passing any arguments to set the coding standard to PSR-12 or any custom settings for your project. PHP_CodeSniffer will automatically read them from this config file instead. </p>



<p>As a simple example, here’s how you create a custom standard that extends PSR-12 but excludes the 120 character line length limit, adds a rule to disallow long array syntax, and ignores a /views/ folder. </p>



<p><strong>phpcs.xml</strong></p>



<pre class="wp-block-code"><code>&lt;?xml version="1.0"?&gt;
&lt;ruleset name="My Company Coding Standard"&gt;
   &lt;description&gt;PSR12 with tweaks.&lt;/description&gt;
   &lt;rule ref="PSR12"&gt;
       &lt;exclude name="Generic.Files.LineLength.TooLong"/&gt;
   &lt;/rule&gt;
   &lt;rule ref="Generic.Arrays.DisallowLongArraySyntax"/&gt;
   &lt;exclude-pattern&gt;*/views/*&lt;/exclude-pattern&gt;
&lt;/ruleset&gt;</code></pre>



<p>Here’s a more complex example: <a href="https://github.com/squizlabs/PHP_CodeSniffer/blob/master/phpcs.xml.dist">https://github.com/squizlabs/PHP_CodeSniffer/blob/master/phpcs.xml.dist</a></p>



<p>And full documentation can be found here: <a class="aioseop-link" href="https://github.com/squizlabs/PHP_CodeSniffer/wiki/Annotated-Ruleset">https://github.com/squizlabs/PHP_CodeSniffer/wiki/Annotated-Ruleset</a></p>



<h4 class="wp-block-heading" id="composer-run-script">Create a Composer Script</h4>



<p>Remembering the path to the local installation of <code>phpcs</code> and typing it out every time can get tedious, not to mention remembering to pass the flag for what standard to use if you don&#8217;t need a <code>phpcs.xml</code>, so you can create a composer script to make it easier:</p>



<pre class="wp-block-code"><code>"scripts": {
   "phpcs": "vendor/bin/phpcs --standard=PSR12 app"
}</code></pre>



<p>Then you only have to run:</p>



<pre class="wp-block-preformatted">composer phpcs</pre>



<p>This has 2 additional benefits:</p>



<ol class="wp-block-list"><li><a class="aioseop-link" href="https://blog.jetbrains.com/phpstorm/2020/01/phpstorm-2020-1-early-access-program-is-now-open/">PHPStorm 2020.1</a> will provide <img data-recalc-dims="1" decoding="async" src="https://i0.wp.com/d3nmt5vlzunoa1.cloudfront.net/phpstorm/files/2020/01/gutter_play_tr.png?w=17&#038;ssl=1" class="alignnone wp-image-15301"  alt="gutter_play_tr" /> play buttons to run composer run-scripts with just one click.</li><li>PHPStorm can <a class="aioseop-link" href="#set-the-coding-standard-automatically">automagically set your standard</a> in PHPStorm.</li></ol>



<h3 class="wp-block-heading">PHP CS Fixer</h3>



<p>PHP CS Fixer is an alternative linter to PHP_CodeSniffer. It doesn’t have PSR-12 yet, but they are <a href="https://github.com/FriendsOfPHP/PHP-CS-Fixer/issues/4502" class="aioseop-link">working to add PSR-12 support</a>. It does, however, include all the other same popular standards that PHP_CodeSniffer supports, like PSR-12&#8217;s predecessor PSR-2 and others.&nbsp;</p>



<p>As well, PHP CS Fixer also includes support for the <a href="https://symfony.com/doc/current/contributing/code/standards.html">Symfony coding standard</a>. It takes the PSR-2 coding standard (PSR-12 soon) and builds upon it with coding opinions common in their framework’s community. I personally really like it, except I do tweak a couple settings. I like to turn off <a href="https://en.wikipedia.org/wiki/Yoda_conditions">yoda_style</a>, and turn on a couple handy fixers that PHP_CodeSniffer doesn’t have, like sorting import statements alphabetically, and removing unnecessary fully qualified class names.&nbsp;</p>



<p>Unlike PHP_CodeSniffer where you set the standard/rules in an xml file, for PHP CS Fixer you set them in a PHP file (either .php_cs or .php_cs.dist). Here’s an example for PHP CS Fixer on how to set the standard as the Symfony coding standard and make the other tweaks I just mentioned:</p>



<p><strong>.php_cs.dist</strong></p>



<pre class="wp-block-code"><code>&lt;?php
$finder = PhpCsFixer\Finder::create()
   -&gt;exclude([
       'views',
   ])
   -&gt;in(__DIR__);
return PhpCsFixer\Config::create()
   -&gt;setRules([
       '@Symfony' =&gt; true,
       'array_syntax' =&gt; ['syntax' =&gt; 'short'],
       'concat_space' =&gt; ['spacing' =&gt; 'one'],
       'yoda_style' =&gt; false,
       'fully_qualified_strict_types' =&gt; true,
       'ordered_imports' =&gt; true,
       'phpdoc_align' =&gt; false,
       'phpdoc_separation' =&gt; false,
   ])
   -&gt;setFinder($finder);</code></pre>



<p>Documentation for these and other settings can be here: <a href="https://github.com/FriendsOfPHP/PHP-CS-Fixer#config-file">https://github.com/FriendsOfPHP/PHP-CS-Fixer#config-file</a></p>



<h2 class="wp-block-heading">IDE Support</h2>



<h3 class="wp-block-heading">PHPStorm</h3>



<p>PHPStorm + PHP Linters = <img src="https://s.w.org/images/core/emoji/16.0.1/72x72/1f525.png" alt="🔥" class="wp-smiley" style="height: 1em; max-height: 1em;" />. IntelliJ has made linters a first class citizen in their PHPStorm IDE. There’s no plugin needed. You can utilize PHP_CodeSniffer or PHP CS Fixer right inside the IDE so you don’t have to run commands on the command line. What’s nice about this integration is that it will help you follow the PSR-12 coding standard in real-time as you write code. </p>



<p>Here’s the 3 steps you’ll need to do in order to get PHPStorm setup with either PHP_CodeSniffer or PHP CS Fixer:</p>



<ol class="wp-block-list"><li><strong>Set the “Code Style”</strong></li></ol>



<p>By setting the code style we make sure that when you <a href="https://www.jetbrains.com/help/phpstorm/reformat-and-rearrange-code.html">reformat entire classes</a>, <a href="https://www.jetbrains.com/help/phpstorm/generating-code.html">generate code</a>, or <a href="https://www.jetbrains.com/help/phpstorm/refactoring-source-code.html">refactor code</a>, PHPStorm will follow PSR-12 when it rewrites your code for you. Starting in <a href="https://blog.jetbrains.com/phpstorm/2019/11/phpstorm-2019-3-release#psr">PHPStorm 2019.3</a>, PSR-12 is available as one of the built-in code styles to pick from.</p>



<p>Preferences &gt; Editor &gt; Code Style &gt; PHP &gt; “Set from…” &gt; Predefined Style &gt; PSR12</p>



<ol class="wp-block-list" start="2"><li><strong>Turn on “Code Quality Tools”</strong></li></ol>



<p>We need to validate that PHPStorm knows where the linter is installed for when it needs to use it to lint your code.</p>



<p>Preferences &gt; Languages &amp; Frameworks &gt; PHP &gt; Quality Tools &gt; Code Sniffer</p>



<p>Click the ellipsis (&#8230;) and use the validate button to make sure it can detect where PHP_CodeSniffer is installed.</p>



<ol class="wp-block-list" start="3"><li><strong>Turn on “Inspections”</strong></li></ol>



<p>By turning on Inspections for the linter, PHPStorm will put a squiggly line below any code for any issues the linter detects. Opening the intention actions menu on an inspection will even provide an action to fix the issue for you starting in <a href="https://youtrack.jetbrains.com/issue/WI-25815%20https://blog.jetbrains.com/phpstorm/2019/01/phpstorm-2019-1-early-access-program-is-open/">PHPStorm 2019.1</a> for PHP_CodeSniffer (and <a href="https://blog.jetbrains.com/phpstorm/2018/09/phpstorm-2018-3-early-access-program-is-open/">PHPStorm 2018.3 for PHP-CS-Fixer</a>). You can see this in action in the gif at the top of this article!</p>



<p>Preferences &gt; Editor &gt; Inspections &gt; PHP &gt; Quality Tools &gt; PHP_CodeSniffer Validation <img src="https://s.w.org/images/core/emoji/16.0.1/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>



<h4 class="wp-block-heading" id="set-the-coding-standard-automatically">Set the Coding Standard Automatically for Teammates</h4>



<p>PHPStorm recently made it super easy to have the coding standard set automatically for all your team members by simply adding a line to your composer.json:</p>



<p><a href="https://www.jetbrains.com/help/phpstorm/using-php-code-sniffer.html#configure-tool-inspection-composer" class="aioseop-link">https://www.jetbrains.com/help/phpstorm/using-php-code-sniffer.html#configure-tool-inspection-composer</a></p>



<p>Note: You’re teammates must use Composer through PHPStorm (eg. Tools &gt; Composer &gt; Install/Update) for it to automatically set the path and turn on the inspections for them.</p>



<h3 class="wp-block-heading">Visual Studio Code</h3>



<p>PHPStorm is probably the most popular IDE for PHP, but Visual Studio Code (VS Code) is becoming a very popular (and free) IDE for PHP developers. You can install the <a href="https://marketplace.visualstudio.com/items?itemName=ikappas.phpcs">phpcs plugin</a> for PHP_CodeSniffer integration or the <a href="https://marketplace.visualstudio.com/items?itemName=junstyle.php-cs-fixer">php cs fixer plugin</a> for PHP CS Fixer integration.</p>



<h3 class="wp-block-heading">Sublime Text, Vim, Atom &amp; Others</h3>



<p>Sublime Text has <a href="https://benmatselby.dev/sublime-phpcs/">sublime-phpcs</a>. Vim has <a href="https://github.com/vim-syntastic/syntastic" class="aioseop-link">Syntastic</a> or <a href="https://github.com/dense-analysis/ale" class="aioseop-link">Ale</a>. Atom has a <a href="https://atom.io/packages/linter-phpcs">linter-phpcs</a> package. As for PHP CS Fixer, they have a list of <a href="https://github.com/FriendsOfPHP/PHP-CS-Fixer#helpers" class="aioseop-link">plugins for various editors</a> right on their Github readme.&nbsp;</p>



<h2 class="wp-block-heading">Taking It a Step Further</h2>



<p>So now you’ve got linting working on the command-line, you&#8217;ve reformatted your codebase to PSR-12, and your IDE of choice is setup to lint in real-time! Now how do you keep your codebase PSR-12 compliant? Ever opened up a class to find others had committed a bunch of code that doesn&#8217;t follow PSR-12? Do you find yourself having to run <code>phpcs</code> across the whole codebase every couple months?</p>



<p>In my next blog post we&#8217;ll go over how to make sure PSR-12 errors never makes it into master again. I&#8217;ll go a step further and show how you can catch PSR-12 violations before they even make it into a commit! <a class="aioseop-link" href="http://mitchmckenna.com/blog/category/programming/feed/">Subscribe via RSS</a>, or <a class="aioseop-link" href="https://twitter.com/mitchellmckenna">follow me on twitter</a> to find out about the next blog post comes out!</p>
]]></content:encoded>
					
					<wfw:commentRss>http://mitchmckenna.com/blog/2020/04/is-your-code-up-to-sniff/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1370</post-id>	</item>
		<item>
		<title>Laravel API Resources + JSON API Spec</title>
		<link>http://mitchmckenna.com/blog/2017/09/laravel-api-resources-json-api-spec/</link>
					<comments>http://mitchmckenna.com/blog/2017/09/laravel-api-resources-json-api-spec/#comments</comments>
		
		<dc:creator><![CDATA[Mitchell McKenna]]></dc:creator>
		<pubDate>Thu, 21 Sep 2017 21:02:33 +0000</pubDate>
				<category><![CDATA[Laravel]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[JSONAPI]]></category>
		<category><![CDATA[RESTAPI]]></category>
		<guid isPermaLink="false">http://mitchmckenna.com/blog/?p=1190</guid>

					<description><![CDATA[API Resources are a new feature in Laravel 5.5 to convert objects to JSON responses. Here's how to write API Resources that follow JSON API spec  […]]]></description>
										<content:encoded><![CDATA[<p><img data-recalc-dims="1" decoding="async" data-attachment-id="1241" data-permalink="http://mitchmckenna.com/blog/2017/09/laravel-api-resources-json-api-spec/laravel-api-resource-json-api-logos/" data-orig-file="https://i0.wp.com/mitchmckenna.com/blog/wp-content/uploads/2017/09/laravel-api-resource-json-api-logos.png?fit=600%2C220" data-orig-size="600,220" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="laravel-api-resource-json-api-logos" data-image-description="" data-image-caption="" data-medium-file="https://i0.wp.com/mitchmckenna.com/blog/wp-content/uploads/2017/09/laravel-api-resource-json-api-logos.png?fit=300%2C110" data-large-file="https://i0.wp.com/mitchmckenna.com/blog/wp-content/uploads/2017/09/laravel-api-resource-json-api-logos.png?fit=600%2C220" class="aligncenter size-full wp-image-1241" src="https://i0.wp.com/mitchmckenna.com/blog/wp-content/uploads/2017/09/laravel-api-resource-json-api-logos.png?resize=600%2C220" alt="" width="600" height="220" /></p>
<p>Laravel 5.5 launched with API Resources, a new feature for building APIs. API Resources serve as a way to transform models and collections to JSON formatted API responses. It standardizes how to define the output format of models and includes helper methods for common tasks like customizing metadata, headers and pagination. You can read how to write API Resources in the <a href="https://laravel.com/docs/5.5/eloquent-resources">Laravel docs</a>.</p>
<p><a href="http://jsonapi.org/">JSON API</a> is a spec created from common conventions for building JSON powered APIs. The goal of JSON API spec is to help teams avoid wasting time debating API structure and features. JSON API encourages RESTful design, readability/<wbr>discoverability, and object relationships through a flat document structure. There’s examples for almost every feature on the <a href="http://jsonapi.org/format/">Specification</a> page, and you can learn a lot about why JSON API is designed the way that it is by reading through the <a href="http://jsonapi.org/faq/#why-not-use-the-hal-specification">FAQ</a> page.</p>
<p>JSON API was <a href="https://github.com/laravel/framework/pull/19449#issuecomment-308717548">considered for the default format</a> of API Resources, however in the end it was decided to be too much work for the average use-case of a Laravel-powered API. For this reason, API Resources don’t automatically output to JSON API format &#8211; but it is very similar, even including the same root offsets. In this article we’ll take a look at what it takes to make API Resources fully JSON API compliant.</p>
<h2>Making API Resources JSON API Compliant</h2>
<p>API Resources use the following same root offsets as JSON API: <code>data</code>, <code>meta</code> and <code>links</code>.</p>
<ul>
<li><code>data</code> – the primary resource (or collection of resources)</li>
<li><code>meta</code> – additional information about a resource that is not an attribute or relationship</li>
<li><code>links</code> linkage eg. “self” link or pagination urls</li>
</ul>
<p>With Laravel&#8217;s API Resources, you can generate two types of classes: resources and resource collections. A resource class is for outputting a single model you pass to it, and a resource collection is for multiple models (eg. a paginated list of items). A resource, without customizing it, will just call <code>toArray()</code> on the model and place the result under the <code>data</code> offset. A resource collection will do the same for each model, and add them as an array to the <code>data</code> offset. A resource collection will also automagically add <a href="https://laravel.com/docs/5.5/eloquent-resources#pagination">pagination</a> information to the <code>meta</code> and <code>links</code> offsets.</p>
<p>API Resources don’t however include automation for JSON API’s <a href="http://jsonapi.org/format/#document-compound-documents">compound documents</a> and their <code>relationships</code> / <code>included</code> offsets; a requirement in JSON API. Let’s take a look at at how we can write a resource and a resource collection to comply with the JSON API spec. We’ll use a sales platform concept for examples where we have orders of products, and for simplicity we’ll say an order can only be for one or more of a single product.</p>
<h3>Resources</h3>
<p>First let’s take a look at an endpoint which returns a single resource (eg. <code>/orders/1</code>). In this example we have an <code>Order</code> model, and each <code>Order</code> has a one-to-one relationship with a <code>Product</code>. By default when a model is passed to a resource class like <code>OrderResource</code>, it outputs a response in the structure of the one on the left in the table below. Compare this to the equivalent response in JSON API format on the right:</p>
<table>
<tbody>
<tr>
<td>API Resource (Default)</td>
<td>JSON API Spec (End Goal)</td>
</tr>
<tr>
<td style="width: 50%;">
<pre style="margin-bottom: 0px;"><code style="font-size: 10px;">{
  "data": {
    "id": 1,
    "order_id": 246752514,
    "product_id": 2,
    "quantity": 9,
    "created_at": "2009-12-22 21:40:02",
    "updated_at": "2017-08-18 22:07:53",
    "product": {
      "id": 2,
      "name": "Nike Shoes",
      "created_at": "2017-08-17 19:49:32",
      "updated_at": "2017-08-17 19:49:32"
    }
  }
}</code></pre>
</td>
<td style="width: 50%;">
<pre style="margin-bottom: 0px;"><code style="font-size: 10px;">{
  "data": {
    "type": "order",
    "id": "1",
    "attributes": {
      "order_id": 246752514,
      "quantity": 9,
      "created_at": 1261518002,
      "updated_at": 1503094073
    },
    "relationships": {
      "product": {
        "data": {
          "type": "product",
          "id": "2"
        }
      }
    }
  },
  "included": [
    {
      "type": "product",
      "id": "2",
      "attributes": {
        "name": "Nike Shoes",
        "created_at": 1502999372,
        "updated_at": 1502999372
      }
    }
  ]
}</code></pre>
</td>
</tr>
</tbody>
</table>
<blockquote><p>
Note: If you are new to JSON API, it may appear that JSON API’s version of the output is at a disadvantage in response size, but keep in mind the product may not be <a href="http://jsonapi.org/format/#fetching-includes">included</a> by default. In addition, JSON API is providing added clarity that the related product’s data will not be able to be PATCH’ed on this endpoint; it should instead be updated via it’s own resource’s endpoint (eg. <code>PATCH /products/6</code>). You could add a <a href="http://jsonapi.org/format/#document-links"><code>links</code></a> offset to the product object with a <code>self</code> url to further encourage <a href="http://jsonapi.org/recommendations/#including-links">discoverability</a>.
</p></blockquote>
<h6>How to write <code>Resource</code> classes to output to JSON API format</h6>
<p>After <a href="https://laravel.com/docs/5.5/eloquent-resources#generating-resources">creating the resource</a> class, update the <code>toArray()</code> function to serialize the model in the correct format. This includes setting the <code>type</code> and <code>id</code> fields required by JSON API, and putting the rest of the resource’s data under <code>attributes</code>.  You can also add a <code>with()</code>function to include any additional root offsets. We&#8217;ll use <code>with()</code> to add the related <code>Product</code> resource in the <code>included</code> offset. Here’s an example of what the <code>OrderResource</code> class would look like:</p>
<pre><code>class OrderResource extends Resource
{
   public function toArray($request)
   {
       return [
           'type' =&gt; 'order',
           'id' =&gt; (string) $this-&gt;id,
            'attributes' =&gt; [
                'name' =&gt; $this-&gt;name,
                'created_at' =&gt; $this-&gt;created_at,
                'updated_at' =&gt; $this-&gt;updated_at,
           ],
           'relationships' =&gt; [
              'product' =&gt; [
                  'data' =&gt; [
                      'type' =&gt; 'product',
                      'id' =&gt; (string) $this-&gt;product_id
                   ]
              ]
           ]
        ];
    }

    public function with($request)
    {
        return ['included' =&gt; [new ProductResource($this-&gt;product)]];
    }
}
</code></pre>
<p>Now when you use the <code>OrderResource</code> you’ll automatically get JSON API compliant output.</p>
<h3>Resource Collections</h3>
<p>Now let’s take a look at endpoints that return a collection of resources (eg. <code>/orders?page=2</code>). On the left we have the the default output from a <code>ResourceCollection</code> class <code>OrderCollection</code>, and on the right what the equivalent would look like following JSON API format:</p>
<table>
<tbody>
<tr>
<td>ResourceCollection (Default)</td>
<td>JSON API Spec (End Goal)</td>
</tr>
<tr>
<td style="width: 50%;">
<pre style="margin-bottom: 0px;"><code style="font-size: 10px;">{
  "data": [
    {
      "id": 18,
      "order_id": 344501705,
      "product_id": 6,
      "quantity": 2,
      "created_at": "2010-01-22 03:36:03",
      "updated_at": "2015-07-23 12:19:02",
      "product": {
        "id": 6,
        "name": "Tommy Jersey",
        "created_at": "2017-08-17 19:49:32",
        "updated_at": "2017-08-17 19:49:32"
      }
    },
    {
      "id": 19,
      "order_id": 446228260,
      "product_id": 6,
      "quantity": 2,
      "created_at": "2010-01-22 07:23:13",
      "updated_at": "2010-01-22 07:25:52",
      "product": {
        "id": 6,
        "name": "Tommy Jersey",
        "created_at": "2017-08-17 19:49:32",
        "updated_at": "2017-08-17 19:49:32"
      }
    }
  ],
  "links": {
    "first": "http://api.dev/orders?page=1",
    "last": "http://api.dev/orders?page=330",
    "prev": "http://api.dev/orders?page=6",
    "next": "http://api.dev/orders?page=8"
  },
  "meta": {
    "current_page": 7,
    "from": 13,
    "last_page": 330,
    "path": "http://api.dev/orders",
    "per_page": "2",
    "to": 14,
    "total": 659
  }
}
</code></pre>
</td>
<td style="width: 50%;">
<pre style="margin-bottom: 0px;"><code style="font-size: 10px;">{
  "data": [
    {
      "type": "order",
      "id": "18",
      "attributes": {
        "order_id": 344501705,
        "quantity": 2,
        "created_at": 1264131363,
        "updated_at": 1437653942
      },
      "relationships": {
        "product": {
          "data": {
            "type": "product",
            "id": "6"
          }
        }
      }
    },
    {
      "type": "order",
      "id": "19",
      "attributes": {
        "order_id": 446228260,
        "quantity": 2,
        "created_at": 1264144993,
        "updated_at": 1264145152
      },
      "relationships": {
        "product": {
          "data": {
            "type": "product",
            "id": "6"
          }
        }
      }
    }
  ],
  "links": {
    "first": "http://api.dev/orders?page=1",
    "last": "http://api.dev/orders?page=330",
    "prev": "http://api.dev/orders?page=6",
    "next": "http://api.dev/orders?page=8"
  },
  "meta": {
    "current_page": 7,
    "from": 13,
    "last_page": 330,
    "path": "http://api.dev/orders",
    "per_page": "2",
    "to": 14,
    "total": 659
  },
  "included": [
    {
      "type": "product",
      "id": "6",
      "attributes": {
        "name": "Tommy Jersey",
        "created_at": 1502999372,
        "updated_at": 1502999372
      }
    }
  ]
}</code></pre>
</td>
</tr>
</tbody>
</table>
<h6>How to write <code>ResourceCollection</code> classes in JSON API format</h6>
<p>For endpoints that return a collection of resources, we can reuse the individual <code>Resource</code> classes like the one we wrote in the previous section and map each model to it. For including related resources, keep in mind the benefit of having them under the <code>included</code> offset instead of embedding them recursively is so the data isn’t duplicated over and over. For example, in the output above the product “Tommy Jersey” is duplicated in each order. To make sure you don’t have duplicates in the <code>included</code> offset, you can use the <code>unique()</code> method on collections. Here’s an example of what the <code>OrderCollection</code> class would look like:</p>
<pre><code>class OrderCollection
{
   public function toArray($request)
   {
       return [
           'data' =&gt; $this-&gt;collection-&gt;map(function ($order) use ($request) {
               return (new OrderResource($order))-&gt;toArray($request);
           })
       ];
   }


   public function with($request)
   {
       return [
           'included' =&gt; $this-&gt;collection-&gt;pluck('product')-&gt;unique()-&gt;values()-&gt;map(function ($product) {
               return new ProductResource($product);
           })
       ];
   }
}</code></pre>
<p>At this point we have responses for both individual resources and their collections which comply with the JSON API spec! You can find a fully working version of the code above in the <code>feature/api-resources</code> branch of an example API codebase <a href="https://github.com/MitchellMcKenna/product-sales-api/tree/feature/api-resources">here</a>.</p>
<h2>What JSON API Features Are Missing?</h2>
<p>With these changes, you now have an API that outputs in valid JSON API format, but API Resources don’t automatically support some of the more advanced (optional) features such as giving clients control over <a href="http://jsonapi.org/format/#fetching-includes">inclusion of related resources</a> using the “include” query param, or the ability for clients to reduce payload size by specifying to return only the fields they need using <a href="http://jsonapi.org/format/#fetching-sparse-fieldsets">sparse fieldsets</a>.</p>
<p>Prior to the release of API Resources in Laravel 5.5, <a href="http://fractal.thephpleague.com/">Fractal</a> was a popular PHP package which offered an alternative implementation of a transformation layer in APIs. It has support for outputting to JSON API format built-in by default. As well, Fractal includes the more advanced features we mentioned above like the “include” query param, and sparse fieldsets. In my next blog post I’ll explore if you can swap out Fractal for native Laravel API Resources, AND if you should.</p>
<p><a href="http://mitchmckenna.com/blog/category/programming/feed/">Subscribe</a> or <a href="https://twitter.com/mitchellmckenna">follow me</a> on twitter so you don’t miss the next one!</p>
]]></content:encoded>
					
					<wfw:commentRss>http://mitchmckenna.com/blog/2017/09/laravel-api-resources-json-api-spec/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1190</post-id>	</item>
		<item>
		<title>Reduce Validation Bloat in Laravel Controllers</title>
		<link>http://mitchmckenna.com/blog/2017/08/reduce-validation-bloat-in-laravel-controllers/</link>
					<comments>http://mitchmckenna.com/blog/2017/08/reduce-validation-bloat-in-laravel-controllers/#respond</comments>
		
		<dc:creator><![CDATA[Mitchell McKenna]]></dc:creator>
		<pubDate>Fri, 04 Aug 2017 16:05:35 +0000</pubDate>
				<category><![CDATA[Laravel]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Lumen]]></category>
		<category><![CDATA[Validation]]></category>
		<guid isPermaLink="false">http://mitchmckenna.com/blog/?p=1148</guid>

					<description><![CDATA[In Laravel or Lumen, I've often noticed that a significant portion of my controllers can be <a href="https://laravel.com/docs/5.4/validation">validation</a> calls. To solve this, I moved validation rules to a config file. By doing so, you can often simplify validation to just a single line of code […]]]></description>
										<content:encoded><![CDATA[<p>In Laravel or Lumen, I&#8217;ve often noticed that a significant portion of my controllers can be <a href="https://laravel.com/docs/5.4/validation">validation</a> calls. To solve this, I moved validation rules to a config file. By doing so, you can often simplify validation to just a single line of code.</p>
<p>This allows you to go from this:</p>
<pre><code>$this-&gt;validate($request, [
    'title' =&gt; 'required|unique:posts|max:255',
    'excerpt' =&gt; 'max:255',
    'body' =&gt; 'required',
    'category' =&gt; 'required',
    'tags' =&gt; 'array',
    'status' =&gt; 'required|in:draft,scheduled,published',
    'publish_at' =&gt; 'nullable|date',
]);
</code></pre>
<p>To just one line of code like this:</p>
<p><code>$this-&gt;validate($request, config('validation.post.create'));</code></p>
<h3>How To Pull Validation From A Config File</h3>
<p>Create <code>/config/validation.php</code> and add your rules:</p>
<pre><code>&lt;?php
return [ 
    'post' =&gt; [
        'create' =&gt; [
            'title' =&gt; 'required|unique:posts|max:255',
            'excerpt' =&gt; 'max:255',
            'body' =&gt; 'required',
            'category' =&gt; 'required',
            'tags' =&gt; 'array',
            'status' =&gt; 'required|in:draft,scheduled,published',
            'publish_at' =&gt; 'nullable|date',
        ]
    ]
];</code></pre>
<p><i><b>Lumen:</b> You&#8217;ll need to load the config file manually. Open <code>/bootstrap/app.php</code> and after the line <code>$app-&gt;withEloquent();</code> add this: <code>$app-&gt;configure('validation');</code></i>.</p>
<p>Enjoy.</p>
<p style="text-align: center">&hellip;</p>
<blockquote><p>Wait, What about <a href="https://laravel.com/docs/5.4/validation#form-request-validation">form request</a> objects? They can be used to move validation bloat out of controllers too!</p></blockquote>
<p>True, I&#8217;m a big fan of how form requests move validation and data transformation to a separate step before controller execution. However, I think you&#8217;ll find having all these different request objects (often just for the purpose of returning validation rules), can be overkill when you could just pull it from a config file. Not to mention, <a href="https://lumen.laravel.com/docs/5.4/validation">Lumen doesn&#8217;t support form requests</a>, so this is a great alternative if you&#8217;re using Lumen.</p>
<p><a href="https://twitter.com/mitchellmckenna">Follow me</a> on Twitter, or subscribe to <a href="/blog/category/programming/laravel/feed/">Laravel</a>/<a href="/blog/category/programming/feed/">Programming</a> for future posts.</p>
]]></content:encoded>
					
					<wfw:commentRss>http://mitchmckenna.com/blog/2017/08/reduce-validation-bloat-in-laravel-controllers/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1148</post-id>	</item>
	</channel>
</rss>
