<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: David Llop</title>
    <description>The latest articles on DEV Community by David Llop (@lloople).</description>
    <link>https://dev.to/lloople</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F22415%2F23eb8464-fe9d-42fa-9364-ba68f8bcaf08.jpg</url>
      <title>DEV Community: David Llop</title>
      <link>https://dev.to/lloople</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/lloople"/>
    <language>en</language>
    <item>
      <title>A Chatbot for OhDear!</title>
      <dc:creator>David Llop</dc:creator>
      <pubDate>Sat, 17 Nov 2018 00:00:00 +0000</pubDate>
      <link>https://dev.to/lloople/a-chatbot-for-ohdear-2kan</link>
      <guid>https://dev.to/lloople/a-chatbot-for-ohdear-2kan</guid>
      <description>&lt;p&gt;One day I tried to show a post of mine to a coworker and then I realised my website was down. I had nothing to warn me if that happens at that time and it was kinda embarrassing. Solving it was as easy as login to DigitalOcean and restart the droplet, but it looked very unprofessional.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;For how long was my site down? How many people were unable to read my awesome posts?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That was when I decided that I needed some kind of automatic monitor for my website up time.&lt;/p&gt;

&lt;p&gt;I remembered &lt;a href="https://twitter.com/freekmurze"&gt;Freek&lt;/a&gt; tweeting about &lt;a href="https://ohdear.app"&gt;OhDear!&lt;/a&gt;, a new monitoring tool made by him and &lt;a href="https://twitter.com/mattiasgeniar"&gt;Mattias&lt;/a&gt;, and I decided to take a look.&lt;/p&gt;

&lt;p&gt;The documentation looked awesome so I joined as a free 10 days trial to check if it was useful for me. It turned out to be the perfect solution I needed. Taking a look at the docs and learning how to use it (pretty easy indeed) I saw the API section. It ended up being a well structured and simple API. I've worked building API's and consuming them for almost 3 years in the past and I wanted to work on something new. Then this project came to my mind.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A chatbot to interact with this API. To check your website status and receive messages if something is wrong.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I always create my bots to interact just with Telegram by now, I know how it works and it's easy to test the result. This project could work with Facebook Messenger in a future, I'm not discarding that feature 🤔&lt;/p&gt;

&lt;p&gt;Once I've installed a fresh copy of &lt;a href="https://botman.io"&gt;BotMan&lt;/a&gt; and prepare the app I realised I'd never tested code that interacts with an API that was not mine. I learned TDD and Unit Testing after that API developer period. BotMan offers a great &lt;a href="https://botman.io/2.0/testing"&gt;Testing Solution&lt;/a&gt; to work with. In fact, it's easier to develop a chatbot with tests since you can check the result instantly.&lt;/p&gt;

&lt;p&gt;Then I remembered a few lessons in &lt;a href="https://twitter.com/adamwathan"&gt;Adam Wathan&lt;/a&gt;'s course &lt;a href="https://course.testdrivenlaravel.com"&gt;Test Driven Laravel&lt;/a&gt; regarding this matter. You create a class that will return the same payload as the API you want to integrate. Usually your &lt;code&gt;Fake&lt;/code&gt; class will extend the current working class to override those methods that perform the actual API call. And that's what &lt;a href="https://github.com/Lloople/bot-mr-dear/tree/master/tests/Fakes"&gt;I've done for this test suite&lt;/a&gt;. This way I was able to develop the entire project without querying OhDear's app.&lt;/p&gt;

&lt;p&gt;OhDear offers a &lt;a href="https://github.com/ohdearapp/ohdear-php-sdk"&gt;PHP Open Source package&lt;/a&gt; to interact with their API. I needed to extend a few classes to adapt them into my needs but the rest was pretty easy.&lt;/p&gt;

&lt;p&gt;They also have a package to interact with &lt;a href="https://github.com/ohdearapp/laravel-ohdear-webhooks"&gt;OhDear WebHooks&lt;/a&gt;, but this time I was unable to use this package. It's built to work with a secret key saved in a configuration file. My app, otherwise, it's made to interact with multiple users at a time, and each users has a different secret key. I'm currently storing that information encrypted into the database. When a webhook request is received it already contains the username. For example &lt;code&gt;https://deployedbot.com/freekmurze&lt;/code&gt;. Then I check the payload with the user's secret key in order to proceed or return an authorization error.&lt;/p&gt;

&lt;p&gt;I built this project using the &lt;a href="https://laravel.com/docs/5.7/controllers#single-action-controllers"&gt;Single Action Controllers&lt;/a&gt; approach and I'm pretty happy with the result, It's something I'll consider in future projects for sure.&lt;/p&gt;

&lt;p&gt;Most of the times there are just one controller per namespace in this project. But the benefit is also visible in the routes file, since it looks neat and you can use your IDE to click on the controllers name and go directly.&lt;/p&gt;

&lt;p&gt;When you work on a chatbot that you want to test, you have two options:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Write the message twice, in controller and tests, and remember to update both if something is modified.&lt;/li&gt;
&lt;li&gt;Store your messages somewhere you can call in your controller and tests.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I decided to go with number 2, and also decided to store the messages in Laravel translations files. This project is not multi-lingual (for now 😉) but I think that having the messages there makes it easy to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Refactor the message.&lt;/li&gt;
&lt;li&gt;Read code, it's easy to see &lt;code&gt;ohdear.token.stored&lt;/code&gt; than a whole sentence.&lt;/li&gt;
&lt;li&gt;Test the message is sent to the user.&lt;/li&gt;
&lt;li&gt;Re-use the message in another conversation.&lt;/li&gt;
&lt;li&gt;Translate the whole app in a future, since you have all the texts in a single place.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This bot is currently running and you can talk to it &lt;a href="http://t.me/MrDear_bot"&gt;here&lt;/a&gt; or by searching &lt;code&gt;Mr. Dear&lt;/code&gt; on Telegram. You can also deploy it into your own server since it's Open Source. You would find instructions about how to do that in the &lt;a href="https://github.com/lloople/bot-mr-dear"&gt;README.md&lt;/a&gt; of the project.&lt;/p&gt;

</description>
      <category>chatbot</category>
      <category>php</category>
      <category>laravel</category>
      <category>botman</category>
    </item>
    <item>
      <title>Laravel Multitenancy: Route Model Binding</title>
      <dc:creator>David Llop</dc:creator>
      <pubDate>Mon, 29 Oct 2018 00:00:00 +0000</pubDate>
      <link>https://dev.to/lloople/laravel-multitenancy-route-model-binding-5ea9</link>
      <guid>https://dev.to/lloople/laravel-multitenancy-route-model-binding-5ea9</guid>
      <description>&lt;p&gt;Why write code like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public function edit($articleId)
{
    $article = Article::findOrFail($articleId);

    return view('articles.edit', compact('article')); 
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;When you can simply do&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public function edit(Article $article)
{
    return view('articles.edit', compact('article'));
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;I'm a huge fan of &lt;a href="https://laravel.com/docs/5.7/routing#route-model-binding"&gt;this Laravel feature&lt;/a&gt; since I discovered it. You just need to typehint the model in the functiondeclaration and the framework will handle the &lt;code&gt;findOrFail&lt;/code&gt; for you. That's it.&lt;/p&gt;

&lt;p&gt;But it has a problem though, sometimes you need to check for other fields.&lt;/p&gt;

&lt;p&gt;Using our previous example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public function edit($articleId)
{
    $article = Article::where('tenant_id', auth()-&amp;gt;user()-&amp;gt;tenant_id)-&amp;gt;findOrFail($articleId);

    return view('articles.edit', compact('article'));
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Would look cleaner than&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public function edit(Article $article)
{
    abort_unless($article-&amp;gt;tenant_id === auth()-&amp;gt;user()-&amp;gt;tenant_id);

    return view('articles.edit', compact('article'));
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This is a common scenario. You have an app to edit articles, and you have to prevent your users to edit otherusers's articles. Basic security rule. But you don't like that kind of code you need to read twice to understand what it does at a first glance.&lt;/p&gt;

&lt;p&gt;Well, you could use &lt;a href="https://laravel.com/docs/5.7/eloquent#global-scopes"&gt;Global Scopes&lt;/a&gt; for sure, but they have a problem: a global scope will be applied to all the queries onthat model, no matter where in the app they occur. So when you need to query all the articles for some statistics or maintenance,you will need to add &lt;code&gt;withoutGlobalScope&lt;/code&gt; to that query every single time.&lt;/p&gt;

&lt;p&gt;The solution my team and I found was to override the default behaviour of Route Model Binding. Of course Laravel offers youa simple solution, you just have to override a method in your model to have it up and running.&lt;/p&gt;

&lt;p&gt;This is the default behaviour:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/**
 * Retrieve the model for a bound value.
 *
 * @param mixed $value
 * @return \Illuminate\Database\Eloquent\Model|null
 */
public function resolveRouteBinding($value)
{
    return $this-&amp;gt;where($this-&amp;gt;getRouteKeyName(), $value)-&amp;gt;first();
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And this is what we will need to declare in our &lt;code&gt;Article&lt;/code&gt; model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/**
 * Retrieve the model for a bound value.
 *
 * @param mixed $value
 * @return \Illuminate\Database\Eloquent\Model|null
 */
public function resolveRouteBinding($value)
{
    return $this-&amp;gt;where($this-&amp;gt;getRouteKeyName(), $value)
        -&amp;gt;where('tenant_id', auth()-&amp;gt;user()-&amp;gt;tenant_id)
        -&amp;gt;first();
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;I know what you're about to say&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;But David, it's easy to understand what the code does if we check this in the controller&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Yeah sure, I'll not do this for every kind of filtering like reedeming a &lt;code&gt;PromoCode&lt;/code&gt; with an expiration date. But when youhave a multitenancy app this kind of delegation is appreciated.&lt;/p&gt;

&lt;p&gt;I'm with the philosophy of:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A Controller should receive only Entities which it can work without checking conditionals.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I apply this rule also for &lt;code&gt;Request&lt;/code&gt; validation using &lt;a href="https://laravel.com/docs/5.7/validation#form-request-validation"&gt;Form Requests&lt;/a&gt;.You'll find times in which this rule cannot be applied due to some sort of complicated and arcane checks, of course, butthat's what programming is about 🙂.&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>multitenancy</category>
      <category>routing</category>
      <category>php</category>
    </item>
    <item>
      <title>Solving my own needs with code</title>
      <dc:creator>David Llop</dc:creator>
      <pubDate>Fri, 12 Oct 2018 00:00:00 +0000</pubDate>
      <link>https://dev.to/lloople/solving-my-own-needs-with-code-3eje</link>
      <guid>https://dev.to/lloople/solving-my-own-needs-with-code-3eje</guid>
      <description>&lt;p&gt;I remember joining the web development studies as a way to craft something with computers, something that &lt;br&gt;
is used worldwide daily. Some of my friends were telling me to join native programming or mobile apps, as &lt;br&gt;
I'd be able to build apps for myself, if needed. And I remember thinking:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I can do things for myself on the web, can't I?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I started web development because I liked it back in 2012, I knew that even before writing a single line of code. &lt;br&gt;
I'm happy with my current job and I'm working on some side projects at home too. Sometimes I do it to be on the edge checking out new frameworks, features, packages... But most of the time when I write code at home it's for my own use. Don't get me wrong, I also try to help other people with those projects if it's possible.&lt;/p&gt;

&lt;p&gt;My biggest project which paid off, without any doubt, is a &lt;a href="https://github.com/Lloople/bot-girocleta"&gt;chatbot I use everyday to know if I'll find a bike in the city bike system I live, in Girona&lt;/a&gt;. I was tired of waking up, walking to the bikes station, realising there's not a single one available for me and walking back to the next station, which is not on the same route.&lt;/p&gt;

&lt;p&gt;This bot is used by 5 other users and is open to everyone who wants to use it. I'm thinking about talking about it with more people and users I could find on the stations getting a bike.&lt;/p&gt;

&lt;p&gt;I also developed a &lt;a href="https://github.com/Lloople/bot-mr-debts"&gt;chatbot for getting control about your debts with friends&lt;/a&gt;. &lt;br&gt;
You only need to add it to the chat group you have with your friends and say &lt;code&gt;@friend owes me 100&lt;/code&gt; or &lt;code&gt;I owe 100 to @friend&lt;/code&gt;. The idea came when we wanted to register our debts but couldn't decide which app to use that &lt;br&gt;
works for both Android and iOS. We ended up finding an app, but I decided to build this chatbot anyways as an exercise &lt;br&gt;
for myself.&lt;/p&gt;

&lt;p&gt;Some years ago, I built my own CMS (like a lot of people out there) as an experiment, and it resulted in a pretty neat tool I used to build a few websites with it and even gain some money.&lt;/p&gt;

&lt;p&gt;I already mentioned this at the end of &lt;a href="https://davidllop.com/creating-a-chatbot-with-botman"&gt;this previous post&lt;/a&gt;, but Matt Stauffer gave a talk at Laracon Online 2018 about this topic which I found pretty interesting and it encouraged me to continue doing this, for the major good and my own.&lt;/p&gt;

</description>
      <category>coding</category>
      <category>needs</category>
      <category>sideprojects</category>
      <category>learning</category>
    </item>
    <item>
      <title>Make your Laravel Jobs multi-tenancy friendly</title>
      <dc:creator>David Llop</dc:creator>
      <pubDate>Thu, 19 Jul 2018 00:00:00 +0000</pubDate>
      <link>https://dev.to/lloople/make-your-laravel-jobs-multi-tenancy-friendly-1i99</link>
      <guid>https://dev.to/lloople/make-your-laravel-jobs-multi-tenancy-friendly-1i99</guid>
      <description>

&lt;p&gt;Our team is working hard on a project which can connect to different databases depending on the client.&lt;br&gt;
Here is the wikipedia link: &lt;a href="https://en.wikipedia.org/wiki/Multitenancy"&gt;multi-tenancy&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The term "software multitenancy" refers to a software architecture in which a single instance of &lt;br&gt;
software runs on a server and serves multiple tenants.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So the point here is that we have a single installation of our app and depending on the user logged in, it will show the respective data.&lt;/p&gt;

&lt;p&gt;When you send a job to a queue, Laravel serializes the class to save it using your chosen driver until a Worker can fire it.&lt;br&gt;
When the job is fired, it tries to restore the models you passed in the constructor from the database using &lt;br&gt;
the &lt;code&gt;SerializesModel&lt;/code&gt; trait.&lt;/p&gt;

&lt;p&gt;This works totally fine, but sometimes you get a non-trivial requirement, and this time it was our turn.&lt;/p&gt;

&lt;p&gt;We don't have a connection defined for each client in &lt;code&gt;config/databases.php&lt;/code&gt; configuration file. Instead, we have &lt;br&gt;
the database name in a &lt;code&gt;clients&lt;/code&gt; table with the other information, and each &lt;code&gt;User&lt;/code&gt; has a &lt;code&gt;client_id&lt;/code&gt; to create the relation. &lt;br&gt;
We use a middleware at the beginning of each request to set the connection attributes in the configuration. &lt;/p&gt;

&lt;p&gt;The problem began when we started working with jobs: due to the fact that there's no client logged in, there's no way to determine&lt;br&gt;
which connection must be set up. After an intense research, and digging through the framework's code, we figured out a &lt;br&gt;
solution which fitted our needs.&lt;/p&gt;

&lt;p&gt;I'm going to show some examples with the &lt;code&gt;database&lt;/code&gt; driver, since it's the one we chose for our app. But I'm sure you can&lt;br&gt;
apply the same modifications to your driver of choice.&lt;/p&gt;

&lt;p&gt;Our goal here is to set up each job with the connection it needs, so the job must know which client it belongs to.&lt;/p&gt;

&lt;p&gt;This step is easy: since we use the database driver, we just need to run this command:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;php artisan queue:table
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Then we modify the migration file and we add our 'client_id' before migrating&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nx"&gt;Schema&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'jobs'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Blueprint&lt;/span&gt; &lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;bigIncrements&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'id'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'queue'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;index&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;integer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'client_id'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;unsigned&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;nullable&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;But how will the framework know the way to correctly populate this new field whenever it dispatches a new job? This is where the tricky part starts:&lt;/p&gt;

&lt;p&gt;In our &lt;code&gt;config/app.php&lt;/code&gt;, we need to specify our custom &lt;code&gt;QueueServiceProvider&lt;/code&gt; instead of &lt;code&gt;Illuminate&lt;/code&gt;'s:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="s1"&gt;'providers'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;
    &lt;span class="nx"&gt;Illuminate\Pipeline\PipelineServiceProvider&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;App\Queue\QueueServiceProvider&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;Illuminate\Redis\RedisServiceProvider&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;From now on, we will organize the extended classes of Illuminate's Queue in the &lt;code&gt;App\Queues&lt;/code&gt; namespace&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This provider is very simple, it just needs to extends the original class. &lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nx"&gt;App\Queue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nx"&gt;App\Queue\Connectors\DatabaseConnector&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;QueueServiceProvider&lt;/span&gt; &lt;span class="k"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;\Illuminate\Queue\QueueServiceProvider&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;registerDatabaseConnector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$manager&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$manager&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;addConnector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'database'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;DatabaseConnector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'db'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We need to override &lt;code&gt;DatabaseConnector&lt;/code&gt; in order to use our own, which overrides &lt;code&gt;connect&lt;/code&gt; to use our &lt;code&gt;DatabaseQueue&lt;/code&gt;&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nx"&gt;App\Queue\Connectors&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nx"&gt;App\Queue\DatabaseQueue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DatabaseConnector&lt;/span&gt; &lt;span class="k"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;\Illuminate\Queue\Connectors\DatabaseConnector&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;array&lt;/span&gt; &lt;span class="nv"&gt;$config&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;DatabaseQueue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;connections&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$config&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'connection'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="nv"&gt;$config&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'table'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="nv"&gt;$config&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'queue'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="nv"&gt;$config&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'retry_after'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now we need to override the method &lt;code&gt;buildDatabaseRecord&lt;/code&gt; to check if we have a client and, if we do, &lt;br&gt;
fill up that field on the &lt;code&gt;jobs&lt;/code&gt; table.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nx"&gt;App\Queue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nx"&gt;App\Queue\Jobs\DatabaseJob&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DatabaseQueue&lt;/span&gt; &lt;span class="k"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;\Illuminate\Queue\DatabaseQueue&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;buildDatabaseRecord&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$queue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$payload&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$availableAt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$attempts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$queueRecord&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="s1"&gt;'queue'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$queue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s1"&gt;'attempts'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$attempts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s1"&gt;'reserved_at'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s1"&gt;'available_at'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$availableAt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s1"&gt;'created_at'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;currentTime&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
            &lt;span class="s1"&gt;'payload'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$payload&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;];&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nv"&gt;$queueRecord&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'client_id'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$queueRecord&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Okay, so now our jobs have a &lt;code&gt;client_id&lt;/code&gt; assigned, the only remaining thing is... &lt;br&gt;
How do we set up the client connection before a job is fired? Yes, you guessed it, &lt;br&gt;
we will need to extend another Illuminate class for that&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nx"&gt;App\Queue\Jobs&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nx"&gt;App\Models\Client&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nx"&gt;App\Helpers\ClientConnector&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DatabaseJob&lt;/span&gt; &lt;span class="k"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;\Illuminate\Queue\Jobs\DatabaseJob&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;fire&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;job&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;client_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nv"&gt;$client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Client&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;findOrFail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;job&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;client_id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="nx"&gt;ClientConnector&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;connectByClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$client&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;parent&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;fire&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Lastly, we need to come back to our own &lt;code&gt;DatabaseQueue&lt;/code&gt; and tell it to use our &lt;code&gt;DatabaseJob&lt;/code&gt; instead&lt;br&gt;
of Illuminate's Queue default by overriding the method &lt;code&gt;marshalJob&lt;/code&gt;&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;marshalJob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$queue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$job&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$job&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;markJobAsReserved&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$job&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;DatabaseJob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;container&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$job&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;connectionName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$queue&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;




</description>
      <category>laravel</category>
      <category>jobs</category>
      <category>multitenancy</category>
    </item>
    <item>
      <title>The importance of test consistency</title>
      <dc:creator>David Llop</dc:creator>
      <pubDate>Tue, 03 Jul 2018 00:00:00 +0000</pubDate>
      <link>https://dev.to/lloople/the-importance-of-test-consistency-303i</link>
      <guid>https://dev.to/lloople/the-importance-of-test-consistency-303i</guid>
      <description>&lt;p&gt;Recently I've discovered the benefits of including feature and unit tests in my applications which helps me find bugs faster.&lt;/p&gt;

&lt;p&gt;Today I found a small bug in one of the largest test suite our team has that I was unaware until today.&lt;/p&gt;

&lt;p&gt;This test suite contains many tests that work with dates, like hotel bookings or daily price changes. I discovered the &lt;br&gt;
issue today when the month changed from June to July, let me explain that.&lt;/p&gt;

&lt;p&gt;The user needs to be able to modify the price each week but only on certain days, for example every weekend of September. &lt;br&gt;
So the request receives a &lt;code&gt;date_begin&lt;/code&gt;, a &lt;code&gt;date_end&lt;/code&gt; and an array of &lt;code&gt;weekdays&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cd"&gt;/** @test */&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;only_weekdays_selected_are_created&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ... Preparing required variables and data on the database&lt;/span&gt;

    &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;actingAs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/prices/create'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="s1"&gt;'price'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;46&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;'date_begin'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;Carbon&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;addMonth&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;firstOfMonth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Carbon&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;MONDAY&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Y-m-d'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="s1"&gt;'date_end'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;Carbon&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;addMonth&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;firstOfMonth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Carbon&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;FRIDAY&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Y-m-d'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="s1"&gt;'weekdays'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'wed'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;]);&lt;/span&gt;

    &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;assertDatabaseHas&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'price_days'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="s1"&gt;'day'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;Carbon&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;addMonth&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;firstOfMonth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Carbon&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;WEDNESDAY&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Y-m-d'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="s1"&gt;'price'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;46&lt;/span&gt;
    &lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Have you spotted the bug yet? Well, I'll write it down anyway to force myself to remember it.&lt;/p&gt;

&lt;p&gt;The code is inserting the first Wednesday of the first &lt;em&gt;complete week&lt;/em&gt; into database, which is August 8 2018, and the &lt;br&gt;
assertion is looking for the first Wednesday, which is August 1 2018. &lt;/p&gt;

&lt;p&gt;After refactoring a bit, the issue is resolved but it forced me to handle this kind of assertions from another point of &lt;br&gt;
view. Since we are a small team of developers, and all of us needs to write tests on this project, I thought about creating &lt;br&gt;
some kind of &lt;code&gt;helper&lt;/code&gt; (it has become an easily used word in programming, don't you think?) to handle that date-stuff for us.&lt;/p&gt;

&lt;p&gt;I decided to create a class inside the tests folder and name it &lt;code&gt;TestCarbon&lt;/code&gt;. This name is nothing close to definitive &lt;br&gt;
by the way, but is the first thing that came into my mind since it's only for testing and it's related to Carbon.&lt;/p&gt;

&lt;p&gt;And this class looks very similar to this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight php"&gt;&lt;code&gt;
&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;Tests&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TestCarbon&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;today&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;Carbon&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;now&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;firstMondayOfNextMonth&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kt"&gt;self&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;today&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;addMonth&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;firstOfMonth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Carbon&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;MONDAY&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;firstWednesdayOfNextMonth&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kt"&gt;self&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;firstMondayOfNextMonth&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;addDays&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;firstFridayOfNextMonth&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kt"&gt;self&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;firstMondayOfNextMonth&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;addDays&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Then after refactoring the test, again, it looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cd"&gt;/** @test */&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;only_weekdays_selected_are_created&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ... Preparing required variables and data on the database&lt;/span&gt;

    &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;actingAs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/prices/create'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="s1"&gt;'price'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;46&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;'date_begin'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;TestCarbon&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;firstMondayOfNextMonth&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Y-m-d'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="s1"&gt;'date_end'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;TestCarbon&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;firstFridayOfNextMonth&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Y-m-d'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="s1"&gt;'weekdays'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'wed'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;]);&lt;/span&gt;

    &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;assertDatabaseHas&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'price_days'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="s1"&gt;'day'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;TestCarbon&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;firstWednesdayOfNextMonth&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Y-m-d'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="s1"&gt;'price'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;46&lt;/span&gt;
    &lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;I know I know, &lt;code&gt;firstWednesdayOfNextMonth&lt;/code&gt; is lying (at least in August 2018), but &lt;code&gt;firstWednesdayInsideFirstFullWeekOfNextMonth&lt;/code&gt; &lt;br&gt;
seemed too long for me 😅.&lt;/p&gt;

&lt;p&gt;I showed the code to the team and they thought it was a good addition to our test suite. They started to use it with their&lt;br&gt;
own tests and adding methods for returning the dates they use the most. It turned out that I had a few tests &lt;br&gt;
with similar dates but not the same as the three used by &lt;code&gt;TestCarbon&lt;/code&gt;. But with this class in mind, instead of &lt;br&gt;
creating new methods for new days, I modified those tests to match this dates and they're still passing. So I was able&lt;br&gt;
to remove some &lt;code&gt;magic dates&lt;/code&gt;, so to speak, from the code.&lt;/p&gt;

&lt;p&gt;Later, I thought about the &lt;a href="https://en.wikipedia.org/wiki/Magic_string"&gt;Magic string problem&lt;/a&gt; and I remembered an app in &lt;br&gt;
which I have a few tests interacting with strings all the time. It was about colors and they were passed &lt;br&gt;
through the request like &lt;code&gt;yellow&lt;/code&gt;, &lt;code&gt;green&lt;/code&gt;, &lt;code&gt;orange&lt;/code&gt;... This time though, while I was creating this &lt;code&gt;TestColors&lt;/code&gt; class &lt;br&gt;
into this test suite, I realised and thought&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;why I'm not using this for the main app too?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So I moved that class to a folder freely named &lt;code&gt;helpers&lt;/code&gt; and refactored both the code in the app and the tests. Now it's &lt;br&gt;
using this class which contains all the colors I need as constants such as &lt;code&gt;const YELLOW = 'yellow';&lt;/code&gt;. This allowed&lt;br&gt;
me to remove a lot of magic strings from all the application and everything looks even more consistent now.&lt;/p&gt;

</description>
      <category>testing</category>
      <category>consistency</category>
      <category>laravel</category>
    </item>
    <item>
      <title>Running old sites in Laravel Valet - Environment Variables</title>
      <dc:creator>David Llop</dc:creator>
      <pubDate>Sat, 17 Mar 2018 00:00:00 +0000</pubDate>
      <link>https://dev.to/lloople/running-old-sites-in-laravel-valet---environment-variables-4k96</link>
      <guid>https://dev.to/lloople/running-old-sites-in-laravel-valet---environment-variables-4k96</guid>
      <description>&lt;p&gt;A few days ago my Homestead machine decided to die and not booting again (I'm totally sure I broke something, &lt;a href="https://twitter.com/JoePFerguson"&gt;Joe P Ferguson&lt;/a&gt; does an amazing job with that Vagrant machine, the 2nd most downloaded on &lt;a href="https://app.vagrantup.com/boxes/search"&gt;vagrant boxes site&lt;/a&gt; 😱)&lt;/p&gt;

&lt;p&gt;The thing is, I already had &lt;a href="https://laravel.com/docs/5.6/valet"&gt;Laravel Valet&lt;/a&gt; installed in my Macbook, so I thought I could run the project on that one for this time.&lt;/p&gt;

&lt;p&gt;But old sites usually were made with Apache server in mind and they use environment variables and htaccess (I'll talk about this in another post).&lt;/p&gt;

&lt;p&gt;Since Valet does not currently support custom &lt;code&gt;.env&lt;/code&gt; files, I found a few custom ways of loading the variables, but all that methods messed up with the code and I don't want to be pending of deleting those lines from &lt;code&gt;index.php&lt;/code&gt; before committing to repository. It's too risky.&lt;/p&gt;

&lt;p&gt;But checking out the content of this &lt;a href="https://github.com/laravel/valet/pull/474"&gt;pull request&lt;/a&gt; I thought about a similar approach, without touching nginx configuration.&lt;/p&gt;

&lt;p&gt;As the &lt;a href="https://laravel.com/docs/5.6/valet#custom-valet-drivers"&gt;official documentation suggest&lt;/a&gt;, I created a file called &lt;code&gt;LocalValetDriver.php&lt;/code&gt; inside the app directory with the following content&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LocalValetDriver&lt;/span&gt; &lt;span class="k"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;LaravelValetDriver&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cd"&gt;/**
     * Determine if the driver serves the request.
     *
     * @param  string  $sitePath
     * @param  string  $siteName
     * @param  string  $uri
     * @return bool
     */&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;serves&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$sitePath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$siteName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$uri&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="cd"&gt;/**
     * Get the fully resolved path to the application's front controller.
     *
     * @param  string  $sitePath
     * @param  string  $siteName
     * @param  string  $uri
     * @return string
     */&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;frontControllerPath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$sitePath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$siteName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$uri&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$sitePath&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="s1"&gt;'/public/index.php'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Then inside &lt;code&gt;frontControllerPath&lt;/code&gt; I load the environment variables:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;frontControllerPath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$sitePath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$siteName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$uri&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;loadEnvironmentVariables&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$sitePath&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="s1"&gt;'/public/index.php'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;loadEnvironmentVariables&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// all env variables here&lt;/span&gt;
    &lt;span class="nb"&gt;putenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'VAR=value'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Ignoring the file from repositories (optional)
&lt;/h3&gt;

&lt;p&gt;The only remaining action is to add &lt;code&gt;LocalValetDriver&lt;/code&gt; to your global &lt;code&gt;gitignore&lt;/code&gt;. This action will prevent this file with sensible information (and also not project-related) to be uploaded to the repository.&lt;/p&gt;

&lt;p&gt;In case you don't have a file called &lt;code&gt;.gitignore_global&lt;/code&gt; in your home directory, you'll need to run this command first to link it with your git configuration&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git config --global core.excludesfile ~/.gitignore_global
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Add &lt;code&gt;LocalValetDriver.php&lt;/code&gt; to this file&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;echo "LocalValetDriver.php" &amp;gt;&amp;gt; ~/.gitignore_global
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



</description>
      <category>laravel</category>
      <category>valet</category>
    </item>
    <item>
      <title>Creating a ChatBot with BotMan</title>
      <dc:creator>David Llop</dc:creator>
      <pubDate>Thu, 18 Jan 2018 00:00:00 +0000</pubDate>
      <link>https://dev.to/lloople/creating-a-chatbot-with-botman-52ig</link>
      <guid>https://dev.to/lloople/creating-a-chatbot-with-botman-52ig</guid>
      <description>&lt;p&gt;Last month I was interested in all this chatbot thing, specially in the features Google Allo has. In that messaging app, you can set a reminder to get notifications about the weather daily in the morning, or to receive jokes / fun facts at specific times.&lt;/p&gt;

&lt;p&gt;I had a problem every day with my city bike system. The nearest station from home is used by a lot of people, and some morning there are no free bikes when I arrive there, so I need to walk to the next station (and reach late at work because I'm a lazy person and I always leave home at the last possible moment 😓).&lt;/p&gt;

&lt;p&gt;So I thought:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What about a bot that tells you every morning the number of free bikes at a preferred station? &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I checked the website of the city bike's company but it’s difficult to use from the smartphone. I needed a better way to know the information of the station every day.&lt;/p&gt;

&lt;p&gt;I follow &lt;a href="https://twitter.com/marcelpociot"&gt;Marcel Pociot&lt;/a&gt; on Twitter for almost two years, so I decided to check what  &lt;a href="https://botman.io"&gt;BotMan&lt;/a&gt; is about since I saw a lot of tweets mentioning it. It is a PHP framework to create bots in an easy way, and also installable in a Laravel app, it was the perfect solution for what I wanted to do! 🙌&lt;/p&gt;

&lt;p&gt;A month later, I have a chatbot currently running in production and telling me each morning the number of free bikes my station has, telling me the same information about the station near work from monday to friday. I went a bit further and added a bunch of cool features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You can share your location and the bot will show you the 3 nearest stations with a link to Google Maps to get directions (don’t worry I’m not storing that information and selling it to local companies).&lt;/li&gt;
&lt;li&gt;You can create aliases for a station so that it is easier to ask for information. There are 19 stations right now and it’s difficult to remember all the names, so you can create aliases like &lt;code&gt;gym&lt;/code&gt; or &lt;code&gt;home&lt;/code&gt; to ask for information about a specific station.&lt;/li&gt;
&lt;li&gt;I added some travel information. For example &lt;code&gt;from gym to home&lt;/code&gt;  and it will show you the availability of the two stations and the distance between them (just in a straight line, sorry guys I’m not Google 😅 ).&lt;/li&gt;
&lt;li&gt;You can define a station as a preferred one, so every time you say &lt;code&gt;hello&lt;/code&gt; the bot will show you the information of that station. It can’t be quicker in my opinion 🙂.&lt;/li&gt;
&lt;/ul&gt;



&lt;p&gt;&lt;a href="/media/posts/botgirocleta.gif" class="article-body-image-wrapper"&gt;&lt;img src="/media/posts/botgirocleta.gif" alt="Example of the bot"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Reminders are customizable for specific days of the week or timings, and you can choose between getting information about free bikes or free parkings. They are sent using &lt;a href="https://laravel.com/docs/5.6/scheduling"&gt;Laravel Task Scheduling&lt;/a&gt; feature. It’s amazing how simple it was to have it running.&lt;/p&gt;

&lt;p&gt;This is my most enjoyable hobby project. I’m still adding features to it and planning to talk about it with other bike users. My girlfriend is already using it and has some great ideas to add as future improvements.&lt;/p&gt;

&lt;p&gt;If you’re curious about building a chatbot or how they work, don’t hesitate to check &lt;a href="https://botman.io"&gt;BotMan&lt;/a&gt;’s website or send me a tweet, I'll help you as much as I can. 🤓&lt;/p&gt;

&lt;p&gt;I also want to mention &lt;a href="https://twitter.com/stauffermatt?lang=ca"&gt;Matt Stauffer&lt;/a&gt; for his great talk at &lt;a href="https://laracon.net"&gt;Laracon Online 2018&lt;/a&gt; about side projects and enjoying what you do (You can get access to this year’s videos for just $25 (20€). I saw it live and I totally recommend watching it.&lt;/p&gt;

</description>
      <category>botman</category>
      <category>chatbot</category>
      <category>laravel</category>
      <category>php</category>
    </item>
    <item>
      <title>Adding View models to a Laravel project</title>
      <dc:creator>David Llop</dc:creator>
      <pubDate>Mon, 01 Jan 2018 00:00:00 +0000</pubDate>
      <link>https://dev.to/lloople/adding-view-models-to-a-laravel-project-hod</link>
      <guid>https://dev.to/lloople/adding-view-models-to-a-laravel-project-hod</guid>
      <description>

&lt;p&gt;Since the beggining of 2017 I started to experiment with different kind of codes   and patterns I didn't used before.&lt;/p&gt;

&lt;p&gt;One of that changes came in November when I was developing the &lt;a href="https://github.com/lloople/blog"&gt;code of this other blog&lt;/a&gt;. I saw that I was duplicating a lot of code inside my controllers on the methods for &lt;code&gt;create&lt;/code&gt; and &lt;code&gt;edit&lt;/code&gt; a resource, in which I use the same blade file.&lt;/p&gt;

&lt;p&gt;Some data of that view depends on the model I'm editing or creating. For example, if it's an existing record the title should be &lt;code&gt;Edit post: {$post-&amp;gt;title}&lt;/code&gt; instead of &lt;code&gt;Create a post&lt;/code&gt;. That logic applies to the form action and form method too.&lt;/p&gt;

&lt;p&gt;I created a main &lt;code&gt;FormViewModel&lt;/code&gt;, and every view model dedicated to a form extends it.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;abstract&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FormViewModel&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nv"&gt;$model&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nv"&gt;$title&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nv"&gt;$action&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nv"&gt;$method&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Model&lt;/span&gt; &lt;span class="nv"&gt;$model&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$model&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;setTitle&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;setAction&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;setMethod&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This view models are forced to declare the methods called on the constructor&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;abstract&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;setTitle&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;abstract&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;setAction&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;abstract&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;setMethod&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This is an implementation of the &lt;code&gt;setTitle&lt;/code&gt; method in the &lt;code&gt;CategoryDetailViewModel&lt;/code&gt;:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;setTitle&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;exists&lt;/span&gt;
        &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="s2"&gt;"Edit Category: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
        &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"Create Category"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;They can also add more logic in their own constructor, like the &lt;code&gt;PostDetailViewModel&lt;/code&gt;:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Post&lt;/span&gt; &lt;span class="nv"&gt;$post&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;parent&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$post&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;published_at&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;exists&lt;/span&gt;
        &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;published_at&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Y-m-d\TH:i'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Carbon&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Y-m-d\TH:i'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;categories&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Category&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'id'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Using the view models is very easy, the controller only needs to pass this object to the view&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;edit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Theme&lt;/span&gt; &lt;span class="nv"&gt;$theme&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;view&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'backend.themes.edit'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="s1"&gt;'view'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;ThemeDetailViewModel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$theme&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;and the view use the object properties and methods&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="nx"&gt;section&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'content'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h1&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;$view&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;title&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nx"&gt;h1&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;

    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt; &lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"POST"&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"{{ &lt;/span&gt;&lt;span class="nv"&gt;$view-&amp;gt;action&lt;/span&gt;&lt;span class="s2"&gt; }}"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;method_field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$view&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;
        &lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;csrf_field&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;
        &lt;span class="o"&gt;...&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="nx"&gt;endsection&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;




</description>
      <category>viewmodels</category>
      <category>laravel</category>
      <category>net</category>
    </item>
    <item>
      <title>Hi, I'm David Llop</title>
      <dc:creator>David Llop</dc:creator>
      <pubDate>Wed, 12 Jul 2017 17:18:32 +0000</pubDate>
      <link>https://dev.to/lloople/hi-im-david-llop</link>
      <guid>https://dev.to/lloople/hi-im-david-llop</guid>
      <description>&lt;p&gt;I have been coding for 4 years.&lt;/p&gt;

&lt;p&gt;You can find me on Twitter as &lt;a href="https://twitter.com/Lloople"&gt;@Lloople&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I live in Girona, Spain.&lt;/p&gt;

&lt;p&gt;I work for GNA Hotel Solutions&lt;/p&gt;

&lt;p&gt;I mostly program in these languages: PHP, JavaScript.&lt;/p&gt;

&lt;p&gt;I am currently learning more about Laravel, Vue, TDD, Clean Code.&lt;/p&gt;

&lt;p&gt;Nice to meet you.&lt;/p&gt;

</description>
      <category>php</category>
      <category>laravel</category>
      <category>vue</category>
    </item>
  </channel>
</rss>
