<?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: Tom Witkowski</title>
    <description>The latest articles on DEV Community by Tom Witkowski (@gummibeer).</description>
    <link>https://dev.to/gummibeer</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%2F367542%2F0a844312-af40-4750-bcab-44fb2b12d792.png</url>
      <title>DEV Community: Tom Witkowski</title>
      <link>https://dev.to/gummibeer</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/gummibeer"/>
    <language>en</language>
    <item>
      <title>PHP-Doc in Blade-Views</title>
      <dc:creator>Tom Witkowski</dc:creator>
      <pubDate>Sun, 20 Dec 2020 19:30:30 +0000</pubDate>
      <link>https://dev.to/gummibeer/php-doc-in-blade-views-3pei</link>
      <guid>https://dev.to/gummibeer/php-doc-in-blade-views-3pei</guid>
      <description>&lt;p&gt;In my &lt;a href="https://gummibeer.dev/blog/2020/telegram-newsletter-command"&gt;Telegram Newsletter&lt;/a&gt; post I've used PHP-doc type-hints without explaining them as I'm doing it every day.&lt;br&gt;
In the comments &lt;a href="https://twitter.com/alexfwulf/status/1339576771222642689"&gt;@alexfwulf&lt;/a&gt; mentioned that this was learning for him. So I'm dedicating a whole post on that topic.&lt;/p&gt;

&lt;p&gt;With Laravel 7 we got Blade Components which are beautiful but also introduced even more ways to inject variables in a Blade View and for components we get some default variables.&lt;/p&gt;

&lt;p&gt;Even before it was hard to know which variables are available in a Blade View and even harder what type they're.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://laravel-idea.com"&gt;Laravel IDEA&lt;/a&gt; plug-in gets better and better in resolving them. But isn't perfect so some manual work is still required.&lt;br&gt;
My solution is to put PHP-doc variable type-hints to the start of my Blade files.&lt;br&gt;
This way I immediately know which variables I can use and what type they're.&lt;/p&gt;

&lt;p&gt;I'm using a single line and PHP-tag per type-hint. This way it's easier to copy or remove them.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt; &lt;span class="cd"&gt;/** @var \Illuminate\Support\Collection|\App\Models\User[] $users */&lt;/span&gt; &lt;span class="cp"&gt;?&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt; &lt;span class="cd"&gt;/** @var string $name */&lt;/span&gt; &lt;span class="cp"&gt;?&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After I've added all the tags I can use the variables and can use PhpStorm awesome suggestions/autocompletion.&lt;/p&gt;

&lt;h2&gt;
  
  
  Blade components
&lt;/h2&gt;

&lt;p&gt;I start every Blade component with one to two tags as these are default component variables.&lt;br&gt;
Primary the &lt;code&gt;$attributes&lt;/code&gt; variable has a lot of undocumented methods you can use to do cool things like cherry-picking special attributes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt; &lt;span class="cd"&gt;/** @var \Illuminate\View\ComponentAttributeBag $attributes */&lt;/span&gt; &lt;span class="cp"&gt;?&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt; &lt;span class="cd"&gt;/** @var \Illuminate\Support\HtmlString $slot */&lt;/span&gt; &lt;span class="cp"&gt;?&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>laravel</category>
      <category>blade</category>
      <category>tipstricks</category>
    </item>
    <item>
      <title>Blade-Component: Webmentions</title>
      <dc:creator>Tom Witkowski</dc:creator>
      <pubDate>Sun, 20 Dec 2020 19:28:13 +0000</pubDate>
      <link>https://dev.to/gummibeer/blade-component-webmentions-egb</link>
      <guid>https://dev.to/gummibeer/blade-component-webmentions-egb</guid>
      <description>&lt;p&gt;While developing my new website including this blog I've decided to go with a static site and don't want to handle comments and so on.&lt;br&gt;
But I still wanted to include user contributed content below the articles.&lt;/p&gt;

&lt;p&gt;So I searched for solutions and found some articles by my friends at Spatie how they've implemented &lt;a href="https://webmention.io/"&gt;webmention.io&lt;/a&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://sebastiandedeyne.com/adding-webmentions-to-my-blog/"&gt;Adding webmentions to my blog&lt;/a&gt; by &lt;a href="https://twitter.com/sebdedeyne"&gt;@sebdedeyne&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://sebastiandedeyne.com/webmentions-on-a-static-site-with-github-actions/"&gt;Webmentions on a static site with GitHub Actions&lt;/a&gt; by &lt;a href="https://twitter.com/sebdedeyne"&gt;@sebdedeyne&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://freek.dev/1406-how-to-add-webmentions-to-a-laravel-powered-blog"&gt;How to add webmentions to a Laravel powered blog&lt;/a&gt; by &lt;a href="https://twitter.com/freekmurze"&gt;@freekmurze&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As I've created this site with Laravel 7 I wanted to create a simple to use Blade Component that will do everything for me.&lt;br&gt;
The result is a PHP file that loads the webmentions and maps them into three collections - likes, reposts and comments - and a blade file that renders them.&lt;/p&gt;

&lt;p&gt;The approach is pretty simple as webmention does the hard job for us.&lt;br&gt;
At first I load all webmentions for the given or current URL.&lt;br&gt;
As the API is paginated I'm using a &lt;code&gt;do-while&lt;/code&gt; loop to load all pages.&lt;br&gt;
After that I'm splitting the results in three collections.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-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;App\View\Components&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Support\Collection&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Support\Facades\Http&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Support\Str&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\View\Component&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;Webmentions&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Component&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;Collection&lt;/span&gt; &lt;span class="nv"&gt;$likes&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;Collection&lt;/span&gt; &lt;span class="nv"&gt;$reposts&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;Collection&lt;/span&gt; &lt;span class="nv"&gt;$comments&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="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;?string&lt;/span&gt; &lt;span class="nv"&gt;$url&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="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$url&lt;/span&gt; &lt;span class="o"&gt;??=&lt;/span&gt; &lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;url&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="nv"&gt;$webmentions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;collect&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nv"&gt;$page&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="k"&gt;do&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nv"&gt;$entries&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Http&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'https://webmention.io/api/mentions.jf2'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                &lt;span class="s1"&gt;'token'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'services.webmention.token'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                &lt;span class="s1"&gt;'domain'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;parse_url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;PHP_URL_HOST&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                &lt;span class="s1"&gt;'per-page'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="s1"&gt;'page'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()[&lt;/span&gt;&lt;span class="s1"&gt;'children'&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;span class="nv"&gt;$webmentions&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;...&lt;/span&gt;&lt;span class="nv"&gt;$entries&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="nv"&gt;$page&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$entries&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="nv"&gt;$webmentions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$webmentions&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;array&lt;/span&gt; &lt;span class="nv"&gt;$entry&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;parse_url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$entry&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'wm-target'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="kc"&gt;PHP_URL_PATH&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s1"&gt;'/'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nb"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;parse_url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;PHP_URL_PATH&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s1"&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="n"&gt;likes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$webmentions&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;array&lt;/span&gt; &lt;span class="nv"&gt;$entry&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$entry&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'wm-property'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="s1"&gt;'like-of'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;mapInto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Like&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;sortByDesc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'date'&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="n"&gt;reposts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$webmentions&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;filter&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="kt"&gt;array&lt;/span&gt; &lt;span class="nv"&gt;$entry&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;bool&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;$entry&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'wm-property'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="s1"&gt;'repost-of'&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="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$entry&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'wm-property'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="s1"&gt;'mention-of'&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="nb"&gt;empty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$entry&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="s1"&gt;'text'&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;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;})&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;mapInto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Repost&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;sortByDesc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'date'&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="n"&gt;comments&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$webmentions&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;array&lt;/span&gt; &lt;span class="nv"&gt;$entry&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;in_array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$entry&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'wm-property'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'mention-of'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'in-reply-to'&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;array&lt;/span&gt; &lt;span class="nv"&gt;$entry&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;empty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$entry&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="s1"&gt;'text'&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;mapInto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Comment&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;sortBy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'date'&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="n"&gt;render&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="nf"&gt;view&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'components.webmentions'&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 Blade view is super opinionated so I will reduce it to the important part.&lt;br&gt;
You automatically have access to all public properties of the component class.&lt;br&gt;
To use autocompletion in my blade files I'm always adding the variables to the top of the blade file as a doc-comment.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt; &lt;span class="cd"&gt;/** @var \Illuminate\View\ComponentAttributeBag $attributes */&lt;/span&gt; &lt;span class="cp"&gt;?&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt; &lt;span class="cd"&gt;/** @var \Illuminate\Support\Collection|\App\Webmentions\Like[] $likes */&lt;/span&gt; &lt;span class="cp"&gt;?&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt; &lt;span class="cd"&gt;/** @var \Illuminate\Support\Collection|\App\Webmentions\Repost[] $reposts */&lt;/span&gt; &lt;span class="cp"&gt;?&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt; &lt;span class="cd"&gt;/** @var \Illuminate\Support\Collection|\App\Webmentions\Comment[] $comments */&lt;/span&gt; &lt;span class="cp"&gt;?&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this you can loop over the items and render them however you want.&lt;br&gt;
And can use the new blade component wherever you need it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;x-webmentions&lt;/span&gt; &lt;span class="na"&gt;:url=&lt;/span&gt;&lt;span class="s"&gt;"$url"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>laravel</category>
      <category>blade</category>
    </item>
    <item>
      <title>Human readable Intervals</title>
      <dc:creator>Tom Witkowski</dc:creator>
      <pubDate>Sun, 13 Dec 2020 18:25:59 +0000</pubDate>
      <link>https://dev.to/gummibeer/human-readable-intervals-1459</link>
      <guid>https://dev.to/gummibeer/human-readable-intervals-1459</guid>
      <description>&lt;p&gt;Every Laravel application has several configuration values that represent a given amount of seconds or minutes.&lt;br&gt;
Like the &lt;code&gt;session.lifetime&lt;/code&gt;, &lt;code&gt;auth.password_timeout&lt;/code&gt;, &lt;code&gt;queue.connections.*.retry_after&lt;/code&gt; and a lot more.&lt;br&gt;
By default all these values are a single integer like &lt;code&gt;10800&lt;/code&gt;, some of them even missing the unit in the description.&lt;/p&gt;
&lt;h2&gt;
  
  
  Multiplication
&lt;/h2&gt;

&lt;p&gt;I bet that most of you know and have already done the easiest way - replace the single integer with a multiplication like &lt;code&gt;3 * 60 * 60&lt;/code&gt; which is the same as &lt;code&gt;10800&lt;/code&gt;.&lt;br&gt;
Another benefit is that you can guess what's the interval as it's &lt;code&gt;days * minutes * seconds&lt;/code&gt;.&lt;br&gt;
But there are still problems:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;it requires brain capacity to parse the multiplication&lt;/li&gt;
&lt;li&gt;not all intervals are seconds - how would you differentiate between &lt;code&gt;10 * 60&lt;/code&gt; (10 hours in minutes) and &lt;code&gt;10 * 60&lt;/code&gt; (10 minutes in seconds)&lt;/li&gt;
&lt;li&gt;it gets even harder when you need an interval like "2 days 6 hours" in seconds &lt;code&gt;(2 * 24 * 60 * 60) + (6 * 60 * 60)&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Luckily there's a solution for both issues.&lt;/p&gt;
&lt;h2&gt;
  
  
  Carbon Interval
&lt;/h2&gt;

&lt;p&gt;Some time ago &lt;a href="https://twitter.com/marcelpociot"&gt;@marcelpociot&lt;/a&gt; posted this &lt;a href="https://twitter.com/marcelpociot/status/1176018954986426368"&gt;solution on Twitter&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you don't know the class already - the &lt;a href="https://github.com/briannesbitt/Carbon"&gt;nesbot/carbon&lt;/a&gt; (required by Laravel itself) provides the &lt;code&gt;\Carbon\CarbonInterval&lt;/code&gt; class (&lt;a href="https://carbon.nesbot.com/docs/#api-interval"&gt;docs&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;This class comes with a human-readable fluent API to write your interval however you want.&lt;br&gt;
The important part is the magic property &lt;code&gt;totalSeconds&lt;/code&gt; - similar properties exist for minutes, days and so on.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Carbon\CarbonInterval&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nc"&gt;CarbonInterval&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;days&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="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;hours&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;totalSeconds&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 helpful in every part of your application - not only the configuration but also the real app code, for example cache TTL, signed URL expiration and wherever you need a given amount of seconds, minutes or other time units.&lt;/p&gt;

&lt;h2&gt;
  
  
  Constants
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://twitter.com/devfrey"&gt;@devfrey&lt;/a&gt; asked how this works with constants.&lt;br&gt;&lt;br&gt;
Short: it doesn't.&lt;br&gt;&lt;br&gt;
I would recommend using the multiplication or single integer solution with an explanatory comment. I'm always using two comments - one above the &lt;code&gt;const&lt;/code&gt; which describes the value and one at the end of the line that contains the unit.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// 5 minutes&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="no"&gt;DEFAULT_TTL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&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="c1"&gt;// seconds&lt;/span&gt;

&lt;span class="c1"&gt;// 7 days&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="no"&gt;REMINDER_DELAY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;24&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="c1"&gt;// minutes&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Environment Variables
&lt;/h2&gt;

&lt;p&gt;In some cases you possibly want to use a &lt;code&gt;.env&lt;/code&gt; variable to define your config interval and it should be possible to change the insert units - for example for development/testing purposes.&lt;br&gt;
So by default it's &lt;code&gt;7 days&lt;/code&gt; but you want to be able to set it to &lt;code&gt;5 minutes&lt;/code&gt; without adjusting your code or complex conditions.&lt;br&gt;
The solution is the static &lt;code&gt;\Carbon\CarbonInterval::fromString()&lt;/code&gt; method that accepts a string, similar but different to &lt;code&gt;strtotime()&lt;/code&gt; function.&lt;/p&gt;

&lt;p&gt;In one of our projects we had to prevent password reset for 7 days after it was successfully reset. But for sure we had to use something like 5-10 minutes on our local machines and several hours on our staging system.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Carbon\CarbonInterval&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;

    &lt;span class="s1"&gt;'password_reset_decay'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;CarbonInterval&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;fromString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'PASSWORD_RESET_DECAY'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'7 days'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;totalSeconds&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

    &lt;span class="c1"&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 in your &lt;code&gt;.env&lt;/code&gt; file you can define the values like the following.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="c"&gt;# production
&lt;/span&gt;&lt;span class="py"&gt;PASSWORD_RESET_DECAY&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"7 days"&lt;/span&gt;
&lt;span class="c"&gt;# staging
&lt;/span&gt;&lt;span class="py"&gt;PASSWORD_RESET_DECAY&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"1 day"&lt;/span&gt;
&lt;span class="c"&gt;# development
&lt;/span&gt;&lt;span class="py"&gt;PASSWORD_RESET_DECAY&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"6 hours"&lt;/span&gt;
&lt;span class="c"&gt;# local
&lt;/span&gt;&lt;span class="py"&gt;PASSWORD_RESET_DECAY&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"10 minutes"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>php</category>
      <category>laravel</category>
      <category>tipstricks</category>
    </item>
    <item>
      <title>Telegram Newsletter Command</title>
      <dc:creator>Tom Witkowski</dc:creator>
      <pubDate>Sun, 13 Dec 2020 18:22:11 +0000</pubDate>
      <link>https://dev.to/gummibeer/telegram-newsletter-command-45ij</link>
      <guid>https://dev.to/gummibeer/telegram-newsletter-command-45ij</guid>
      <description>&lt;p&gt;After I've published my first post and got kind feedback from several readers I wanted to add something like a newsletter for my blog.&lt;/p&gt;

&lt;p&gt;My goal is that it should inform the subscribers short after a post is published about the new post. Emails aren't an option as I hate emails and it's also not that easy and cheap to potentially scale them.&lt;br&gt;
So I've searched for a different solution and thought about Telegram which has a powerful but still easy API and even creating a bot is as easy as sending messages to &lt;a href="https://t.me/BotFather"&gt;BotFather&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The next criteria are that I don't have any permanently running app for this site and my content is stored in markdown files. So it should work without any database and I need a runner that allows me to schedule commands.&lt;br&gt;
The runner was quickly found, the same that deploys this site and does some checks - GitHub Actions.&lt;/p&gt;
&lt;h2&gt;
  
  
  Setting up Telegram
&lt;/h2&gt;

&lt;p&gt;That's probably the easiest part as you only send some messages and have to create a new Telegram channel.&lt;/p&gt;
&lt;h3&gt;
  
  
  Bot
&lt;/h3&gt;

&lt;p&gt;The commands I've sent to &lt;a href="https://t.me/BotFather"&gt;BotFather&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/newbot
/setdomain
/setuserpic
/setabouttext
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After I've followed all the instructions I had my own &lt;code&gt;GummibeerBot&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Channel
&lt;/h3&gt;

&lt;p&gt;So now we need a channel that the bot will send the messages to. That's possible via the normal UI.&lt;br&gt;
You must create a &lt;code&gt;public&lt;/code&gt; channel as bots can't send messages to private channels. And you also want others to be able to join easily - otherwise it wouldn't be a newsletter. 😉&lt;/p&gt;

&lt;p&gt;After you've created your channel you must add the bot as an administrator with the ability to send messages.&lt;br&gt;
To do so open the channel =&amp;gt; click on the name =&amp;gt; click on administrators and add a new one.&lt;/p&gt;
&lt;h2&gt;
  
  
  Console Command
&lt;/h2&gt;

&lt;p&gt;I've used &lt;code&gt;artisan make:command PromotePost&lt;/code&gt; to create my new command - you can adjust the name however you want it.&lt;/p&gt;

&lt;p&gt;Our command has to do two things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;pick a post to promote - it has to be published, should be promotable and shouldn't be promoted earlier&lt;/li&gt;
&lt;li&gt;generate the message and send it to the Telegram channel&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  Configuration
&lt;/h3&gt;

&lt;p&gt;At first we have to configure our app to know about some secrets that shouldn't be part of our app code.&lt;/p&gt;

&lt;p&gt;I will use the &lt;code&gt;services&lt;/code&gt; config as it's perfect for simple service configurations like Telegram in this case.&lt;br&gt;
I will add the &lt;code&gt;bot_token&lt;/code&gt; (you've received during setting up the Telegram bot and the Telegram channel &lt;code&gt;chat_id&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="s1"&gt;'telegram'&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;'bot_token'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'TELEGRAM_BOT_TOKEN'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="s1"&gt;'chat_id'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'-xxxxxxxxxx'&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;The token is a secret you shouldn't share with anyone - so using the &lt;code&gt;.env&lt;/code&gt; here is a good choice.&lt;br&gt;
The chat ID isn't secret so it's up to you if you want to be able to adjust it via &lt;code&gt;.env&lt;/code&gt; or not. Using env here would be useful if you want to use a test channel during development for example.&lt;/p&gt;

&lt;p&gt;To retrieve the chat ID I've used a trick as the ID isn't copyable somewhere in the Telegram app.&lt;/p&gt;

&lt;p&gt;You should send a message to your bot in the channel you want him to send the messages in - I've used &lt;code&gt;@GummibeerBot test&lt;/code&gt;.&lt;br&gt;
After this you should run the following code - &lt;a href="https://tinkerwell.app/"&gt;Tinkerwell&lt;/a&gt; will be perfect for this but you can also use normal tinker or however you run one-shot code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$chatId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Http&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s1"&gt;'https://api.telegram.org/bot%s/getUpdates'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'services.telegram.bot_token'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()[&lt;/span&gt;&lt;span class="s1"&gt;'result'&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s1"&gt;'channel_post'&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s1"&gt;'chat'&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This should return the chat ID which looks something like &lt;code&gt;-xxxxxxxxxx&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Picking your post
&lt;/h3&gt;

&lt;p&gt;This part depends massively on your way you manage your posts and which attributes you use.&lt;br&gt;
I've added a &lt;code&gt;should_promote&lt;/code&gt; boolean attribute that indicates if this post should be promoted and a &lt;code&gt;promoted_at&lt;/code&gt; datetime attribute that will indicate when/if the post was already promoted.&lt;br&gt;
With these attributes you can use database query or collection filters to reduce your dataset.&lt;br&gt;
As I only want to promote one post at a time I'm using this snippet to get the post I want to send out.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$post&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$posts&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;sortBy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'created_at'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;first&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Send message via Telegram
&lt;/h3&gt;

&lt;p&gt;That's the most important part but it's still not complicated thanks to Laravel &lt;code&gt;Http&lt;/code&gt; helper class.&lt;/p&gt;

&lt;p&gt;To send a message via Telegram you have to use the &lt;a href="https://core.telegram.org/method/messages.sendMessage"&gt;sendMessage&lt;/a&gt; endpoint.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Support\Facades\Http&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Spatie\Emoji\Emoji&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nv"&gt;$response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Http&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nb"&gt;sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'https://api.telegram.org/bot%s/sendMessage'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'services.telegram.bot_token'&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="s1"&gt;'chat_id'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'services.telegram.chat_id'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="s1"&gt;'text'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Emoji&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;orangeBook&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="s1"&gt;' '&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;$post&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="kc"&gt;PHP_EOL&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;$post&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;url&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;I'm using the &lt;a href="https://github.com/spatie/emoji"&gt;spatie/emoji&lt;/a&gt; package here to get the "📙" emoji and append the post title and after a line break the URL to the post (be sure that your code generates an absolute URL to your production system).&lt;/p&gt;

&lt;p&gt;That's it - you've already sent the message to your Telegram channel and should see a message in it.&lt;/p&gt;

&lt;p&gt;After this you should update/save your promoted post to prevent it from being sent out multiple times.&lt;/p&gt;

&lt;p&gt;For everyone interested to see it in action you can join my &lt;a href="https://t.me/GummibeerDev"&gt;Telegram Newsletter&lt;/a&gt; channel.&lt;/p&gt;

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