{"id":2970,"date":"2023-08-11T11:28:09","date_gmt":"2023-08-11T09:28:09","guid":{"rendered":"https:\/\/nyamsprod.com\/blog\/?p=2970"},"modified":"2023-08-11T11:29:04","modified_gmt":"2023-08-11T09:29:04","slug":"uri-packages-reloaded","status":"publish","type":"post","link":"https:\/\/nyamsprod.com\/blog\/uri-packages-reloaded\/","title":{"rendered":"URI packages reloaded"},"content":{"rendered":"\n<p>Yesterday I announced that the new major version of the league URI packages were released.<br>Because I am not the best expert in marketing I presume that people assume that only one<br>package was released while in fact 3 packages were released at the same time.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/github.com\/thephpleague\/uri-interfaces\/releases\/tag\/7.0.0\" target=\"_blank\" rel=\"noopener\" title=\"\">URI Interfaces<\/a> (v7 to replace v2)<\/li>\n\n\n\n<li><a href=\"https:\/\/github.com\/thephpleague\/uri\/releases\/tag\/7.0.0\" target=\"_blank\" rel=\"noopener\" title=\"\">URI<\/a> (v7 to replace v6)<\/li>\n\n\n\n<li><a href=\"https:\/\/github.com\/thephpleague\/uri-components\/releases\/tag\/7.0.0\" target=\"_blank\" rel=\"noopener\" title=\"\">URI components<\/a> (v7 to replace v2)<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">New architecture<\/h2>\n\n\n\n<p>As you might notice they all share the same version number and some packages just jumped major version released. The reason behind the jump is rather simple, all 3 packages have been developed as mono-repo for more than a year so it was about time that I normalise their release cycle.<\/p>\n\n\n\n<p>And while on the surface this is just a number change behind the scene for the past couple months I have been rewriting and re-organising the architecture of those 3 packages to ease maintenance but more important to boost the packages usage. A great example of that is the example I have shown in one of my announcement<br>post:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: php; title: ; notranslate\" title=\"\">\nuse League\\Uri\\BaseUri;\nuse League\\Uri\\Modifier;\n\n$uri = &quot;https:\/\/www.bbc.co.uk&quot;;\n$relativeUri = &quot;path\/to\/..\/..\/the\/sky\/?foo.bar&quot;;\n$appendQuery = &quot;foo.bar=tata&quot;;\n\n$resolvedUri = BaseUri::from($uri)-&gt;resolve($relativeUri);\n$newUri = Modifier::from($resolvedUri)\n    -&gt;appendQuery($appendQuery)\n    -&gt;removeLabels(1)\n    -&gt;removeTrailingSlash()\n    -&gt;getUriString();\n\necho $newUri;\n\/\/ displays https:\/\/www.bbc.uk\/the\/sky?foo.bar&amp;foo.bar=tata\n<\/pre><\/div>\n\n\n<p>It might surprise some of you but this was already possible using the previous packages<br>versions. The code would then look like this:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: php; title: ; notranslate\" title=\"\">\nuse League\\Uri\\Uri;\nuse League\\Uri\\UriModifier;\nuse League\\Uri\\UriResolver;\n\n$uri = &quot;https:\/\/www.bbc.co.uk&quot;;\n$relativeUri = &quot;path\/to\/..\/..\/the\/sky\/?foo.bar&quot;;\n$appendQuery = &quot;foo.bar=tata&quot;;\n\n$baseUri = Uri::createFromString($uri);\n$relativedUri = Uri::createFromString($relativeUri);\n$resolvedUri = UriResolver::resolve($relativedUri, $baseUri);\n$newUri = UriModifier::appendQuery($resolvedUri,  $appendQuery);\n$newUri = UriModifier::removeLabels($newUri, 1);\n$newUri = UriModifier::removeTrailingSlash($newUri);\n$newUri = $newUri-&gt;__toString();\n\necho $newUri;\n\/\/ displays https:\/\/www.bbc.uk\/the\/sky?foo.bar&amp;foo.bar=tata\n<\/pre><\/div>\n\n\n<p>Apart from chaining, the main differences between those two style of code is that in v7 we are less strict on the input argument type, it should at least be a string or a <code>Stringable<\/code> object, we are still as strict on the returned value. This means that the code is smart enough to detect the input and if it is not a known URI object it will attempt to convert the input into one before performing the intended action. In contrast, with the older version, we expected the developper consuming the library to do it for us before submitting the URI the to package API.<\/p>\n\n\n\n<p>To achieve the new behaviour I had to re-organised the packages. Before, The URI and and URI<br>components were fully decoupled. You could download and install each package independently.<br>This is no longer true, each package is now built on top of the other. The URI package<br>requires the URI interfaces package and the URI component package requires the URI package.<br>With this change it means that, for instance, the URI component <code>Modifier<\/code> class knows how to<br>instantiate at any given time a URI. This was not possible before.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Same code, new features<\/h2>\n\n\n\n<p>Another improvement because of the new coupling between classes is that I could re-organised the classes between packages. For instance, all the parsers (the URI parser and the Query parser) are now part of the URI Interface packages. The role of this package has evolved since its first release. It used to be a package that only contains contracts used by the other two packages, now it is also a package that exposes common tools to use when handling URI, parsers fall into that description. In addition, the new architecture gave me the opportunity to rewrite and expose other tools independent of URI packages.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: php; title: ; notranslate\" title=\"\">\nuse League\\Uri\\Idna\\Converter as IdnConverter;\nuse League\\Uri\\IPv4\\Converter as Ipv4Converter;\n\necho IdnConverter::toAscii(&#039;b\u00e9b\u00e9.be&#039;)-&gt;domain(); \/\/display &quot;xn--bb-bjab.be&quot;\necho Ipv4Converter::fromEnvironment()-&gt;toDecimal(&#039;192.87.125&#039;); \/\/display &quot;192.87.0.125&quot;\n<\/pre><\/div>\n\n\n<p>Those two features were already present in the codebase but the rewrite and architectural<br>changes enabled their exposition and improved their usage inside and outside the packages.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Avoid re-inventing the wheel<\/h2>\n\n\n\n<p>One of the most difficult thing when complying to RFC and specifications is that most of them handle<br>gracefully errors and mistakes. Which means that it may be hard for developers to know if something<br>is not the expected result or not. In this new version, I try to improve the developer experience when possible using the following pattern:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: php; title: ; notranslate\" title=\"\">\nuse League\\Uri\\UriTemplate;\n$template = &#039;https:\/\/api.example.com\/{version}\/search\/{term}\/{?q*,limit}&#039;;\n\n$params = &#x5B;\n    &#039;term&#039; =&gt; &#x5B;&#039;john&#039;, &#039;doe&#039;],\n    &#039;q&#039; =&gt; &#x5B;&#039;a&#039;, &#039;b&#039;],\n    &#039;limit&#039; =&gt; &#039;10&#039;,\n];\n\n$uriTemplate = new UriTemplate($template);\necho $uriTemplate-&gt;expand($params);\n\/\/ display https:\/\/api.example.com\/\/search\/john,doe\/?q=a&amp;q=b&amp;limit=10 with missing version\n\/\/ this is valid and follow the specifications\n\necho $uriTemplate-&gt;expandOrFail($params);\n\/\/ will throw a TemplateCanNotBeExpanded exception with the following message\n\/\/ Missing variables `version`\n<\/pre><\/div>\n\n\n<p>The new <code>expandOrFail<\/code> method is stricter than the RFC compliant <code>expand<\/code> method and throw if a variable is missing. It will be easier for developer to recognise the method behaviour because it is a well established signature in some PHP communities but more importantly it avoids adding extra boolean argument to a well establish method which makes the intent clearer. In summary, when possible, stricter method are provided with the <code>orFail<\/code> suffix.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Backward compatibility<\/h2>\n\n\n\n<p>What&#8217;s great about all these changes is that you will not have to rewrite your application, as the new version is fully backward compatible with the previous packages. Which all your current code is still valid with the new version even if your IDE of choice will more than likely flag the code as being deprecated.<br>This should give you plenty of time to upgrade your current codebase but if you are new to the package I encourage you to not look in the past and to embrace the new public API which frees you for most of the basic usage from learning how URI works and let&#8217;s you focus on your actual application logic.<\/p>\n\n\n\n<p>While this post is not aiming at presenting all the new features, you can head over the<br><a href=\"https:\/\/uri.thephpleague.com\">documentation website<\/a> to get the full public API, I hope it gave you the underlying motivation for this new version which was to make the code easier to interact with and more intuitive.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Last but not least<\/h2>\n\n\n\n<p>The <a href=\"https:\/\/github.com\/thephpleague\/uri-src\" target=\"_blank\" rel=\"noopener\" title=\"\">URI packages<\/a> are open source project with a MIT License so contributions are more than welcome and will be fully credited. These contributions can be anything from reporting an issue, requesting or adding missing features or simply improving or correcting some typo on the documentation website.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Yesterday I announced that the new major version of the league URI packages were released.Because I am not the best expert in marketing I presume that people assume that only onepackage was released while in fact 3 packages were released at the same time. New architecture As you might notice they all share the same [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"footnotes":""},"categories":[588],"tags":[824,766,412,785,794,820,786],"class_list":["post-2970","post","type-post","status-publish","format-standard","hentry","category-humeurs","tag-oop","tag-open-source","tag-php","tag-thephpleague","tag-uri","tag-uri-template","tag-url"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/nyamsprod.com\/blog\/wp-json\/wp\/v2\/posts\/2970","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/nyamsprod.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/nyamsprod.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/nyamsprod.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/nyamsprod.com\/blog\/wp-json\/wp\/v2\/comments?post=2970"}],"version-history":[{"count":5,"href":"https:\/\/nyamsprod.com\/blog\/wp-json\/wp\/v2\/posts\/2970\/revisions"}],"predecessor-version":[{"id":2983,"href":"https:\/\/nyamsprod.com\/blog\/wp-json\/wp\/v2\/posts\/2970\/revisions\/2983"}],"wp:attachment":[{"href":"https:\/\/nyamsprod.com\/blog\/wp-json\/wp\/v2\/media?parent=2970"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/nyamsprod.com\/blog\/wp-json\/wp\/v2\/categories?post=2970"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/nyamsprod.com\/blog\/wp-json\/wp\/v2\/tags?post=2970"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}