<?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>Forem: Alhassan Kamil</title>
    <description>The latest articles on Forem by Alhassan Kamil (@nayi10).</description>
    <link>https://forem.com/nayi10</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%2F424496%2Fad2ff830-3b68-4e6f-b39e-ff86ab7f77ac.png</url>
      <title>Forem: Alhassan Kamil</title>
      <link>https://forem.com/nayi10</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/nayi10"/>
    <language>en</language>
    <item>
      <title>Publishing a Course Isn't That Difficult Like You Think, AND It Pays</title>
      <dc:creator>Alhassan Kamil</dc:creator>
      <pubDate>Wed, 27 Jul 2022 17:58:46 +0000</pubDate>
      <link>https://forem.com/nayi10/publishing-a-course-isnt-that-difficult-like-you-think-and-it-pays-13n4</link>
      <guid>https://forem.com/nayi10/publishing-a-course-isnt-that-difficult-like-you-think-and-it-pays-13n4</guid>
      <description>&lt;p&gt;As a programmer, you may think you're too much into writing code and getting systems built, so you have no time for writing courses. You're not alone. I thought the same until about a year and a few months ago when everything changed, for the better.&lt;/p&gt;

&lt;p&gt;I was always the consumer of courses but never a producer. Oh, I even thought I wasn't good enough to publish courses. What I failed to understand is that you learn more by teaching than you do by learning.&lt;/p&gt;

&lt;h2&gt;
  
  
  I Failed In an Instant, Then I Got Up 🚀
&lt;/h2&gt;

&lt;p&gt;Fast forward in 2019-2020, I got to know about &lt;a href="https://raywenderlich.com"&gt;raywenderlich.com&lt;/a&gt; at a time they were looking for technical editors for Flutter. I became interested and applied. Unfortunately, I couldn't qualify since my social profiles were not looking great and I didn't have enough content to prove my worth too.&lt;/p&gt;

&lt;p&gt;Then came 2021. I had an email from the team at &lt;a href="https://raywenderlich.com"&gt;raywenderlich.com&lt;/a&gt; again that it's been a year since I was rejected and I may try again. &lt;/p&gt;

&lt;p&gt;At first, I said no, thinking it was one of the spam emails I constantly received. But then, Annette replied that I should let her know if I ever change my mind. That was when I remembered that I applied for this the past year. And that's when my story began!&lt;/p&gt;

&lt;h2&gt;
  
  
  The Beginning of My Adventure
&lt;/h2&gt;

&lt;p&gt;I went through a tryout and finally got a chance to &lt;a href="https://www.raywenderlich.com/21955673-non-nullable-dart-understanding-null-safety"&gt;tech-edit an article&lt;/a&gt;. It was overwhelming at first, but I grew to like it for the fact that I learned more than I could ever do if I had to read a tutorial.&lt;/p&gt;

&lt;p&gt;My second article came like a breeze and I was already loving everything about tech-editing, especially at &lt;a href="https://raywenderlich.com"&gt;raywenderlich&lt;/a&gt;. It even made me get more interested in writing. So I started my own &lt;a href="https://nayiwrites.com/"&gt;blog&lt;/a&gt; and began my writing process.&lt;/p&gt;

&lt;p&gt;Within a few months, I had an email from &lt;a href="https://www.educative.io/"&gt;Educative.io&lt;/a&gt; asking me to publish &lt;a href="https://www.educative.io/courses/mastering-alpinejs"&gt;a course on AlpineJs&lt;/a&gt;. I gladly did and here's the next part of my story.&lt;/p&gt;

&lt;h2&gt;
  
  
  Publishing My First Course
&lt;/h2&gt;

&lt;p&gt;Publishing my first course wasn't that easy, but it wasn't too difficult either. It took months for it to get through various stages. It got to a time I almost became fed up waiting but I eventually understood what it takes to publish a great course.&lt;/p&gt;

&lt;p&gt;Finally, we published the course in May 2022. Honestly, I've benefited from the course more than I've ever done with any of the projects I created for clients. What's more, I'm still getting paid monthly for promoting the course, unlike the one-time payment I get from developing software for clients.&lt;/p&gt;

&lt;p&gt;The course is titled &lt;a href="https://www.educative.io/courses/mastering-alpinejs"&gt;Mastering AlpineJS in a Day or Less&lt;/a&gt;, if you care to know. And, it was my first paid course so you know how proud I became after it was published.&lt;/p&gt;

&lt;h2&gt;
  
  
  Going Forward...
&lt;/h2&gt;

&lt;p&gt;After I submitted my work for editing on Educative.io, my interest in authoring technical content grew exponentially. So I asked my team lead at raywenderlich.com to give me a chance to write an article. He did, and I published my first article: &lt;a href="https://www.raywenderlich.com/31602619-building-dart-apis-with-google-cloud-run"&gt;Building Dart APIs With Google Cloud Run&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Ever since, I've been an active part of the raywenderlich.com Flutter team and an author at Educative.io and I'm loving it. I've never looked back and I like the fact that I get paid for learning and doing what I love so much. &lt;/p&gt;

&lt;p&gt;I hope this article gingers you up to start writing, not only for the pay but for the learning benefits too. Let me know your story in the comments. What are your experiences? &lt;/p&gt;

</description>
      <category>writing</category>
      <category>programming</category>
    </item>
    <item>
      <title>Creating Your First Blog With TALL - Part Eight</title>
      <dc:creator>Alhassan Kamil</dc:creator>
      <pubDate>Fri, 30 Apr 2021 10:04:00 +0000</pubDate>
      <link>https://forem.com/nayi10/creating-your-first-blog-with-tall-part-eight-279b</link>
      <guid>https://forem.com/nayi10/creating-your-first-blog-with-tall-part-eight-279b</guid>
      <description>&lt;p&gt;This episode is the eighth in the &lt;strong&gt;Creating Your First Blog With TALL&lt;/strong&gt; series. You'll finish up with the admin area by implementing the edit page for a post. You'll also ensure that only admins are able to access the admin dashboard by using Laravel &lt;a href="https://laravel.com/docs/8.x/middleware" rel="noopener noreferrer"&gt;middleware&lt;/a&gt; in this episode.&lt;/p&gt;

&lt;p&gt;At the end of the episode, you should be able to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;update database records using Eloquent.&lt;/li&gt;
&lt;li&gt;restrict access to certain parts of your Laravel web app using middleware.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It's important to note that the project up to this phase is available &lt;a href="https://github.com/nayi10/tall-blog" rel="noopener noreferrer"&gt;here on GitHub&lt;/a&gt;. So if you're late to the party, you can clone it and continue with us. :)&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating the Edit Post Component
&lt;/h2&gt;

&lt;p&gt;In the previous episode, you made sure admin users were able to create, delete and publish/unpublish posts. You're going to add another important feature in this tutorial: allow the admin to edit a post after it's been created.&lt;/p&gt;

&lt;p&gt;This feature is particularly useful if you ever need to correct an error after you publish a post. Or, if your blog is in the technology landscape and you need to update posts in relation to changes in your technology stack. So it's necessary that a blog has this feature.&lt;/p&gt;

&lt;p&gt;This component is almost the same as the &lt;code&gt;NewPost&lt;/code&gt; component we created in the last episode(they both have the same form fields). As a result, we'd be reusing the view file for the &lt;code&gt;NewPost&lt;/code&gt; component with a few modifications.&lt;/p&gt;

&lt;p&gt;Create the &lt;code&gt;EditPost&lt;/code&gt; Livewire component by running the Artisan command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;php artisan make:livewire Dashboard.EditPost --inline
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You have made it an inline component because the view for the &lt;code&gt;NewPost&lt;/code&gt; component will be reused.&lt;/p&gt;

&lt;p&gt;Open the component class and replace its contents with this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php //tall-blog/app/Http/Livewire/Dashboard/EditPost.php

namespace App\Http\Livewire\Dashboard;

use App\Models\Post;
use Livewire\Component;

class EditPost extends Component
{
    public $post;
    public $isEdit = true;

    protected $rules = [
        'post.title' =&amp;gt; 'required|string',
        'post.category' =&amp;gt; 'required',
        'post.body' =&amp;gt; 'required|string|min:500',
        'post.excerpt' =&amp;gt; 'required|min:100:max:250',
        'post.is_published' =&amp;gt; 'boolean',
    ];

    public function mount($id)
    {
        $this-&amp;gt;post = Post::find($id);
    }

    public function render()
    {
        return view('livewire.dashboard.new-post');
    }

    public function save()
    {
        $this-&amp;gt;validate();
        $this-&amp;gt;post-&amp;gt;save();
        session()-&amp;gt;flash("message", "Post update successful");
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What you're basically doing here is fetching the post you want to edit from the database. You did this using the &lt;code&gt;mount&lt;/code&gt; method. &lt;code&gt;$post&lt;/code&gt; refers to this post and you're making it available in the view, as happens with every supported &lt;code&gt;public&lt;/code&gt; variable in a Livewire component. Note that all properties of the &lt;code&gt;$post&lt;/code&gt; variable will now equally be available in the view. This makes it easy for you to take advantage of the model binding previously used in the new post view.&lt;/p&gt;

&lt;p&gt;You use &lt;code&gt;$isEdit&lt;/code&gt; to track the component you're working with in the view. Remember you're reusing the new post component's view. So &lt;code&gt;$isEdit&lt;/code&gt; is there to check whether you're dealing with the &lt;code&gt;NewPost&lt;/code&gt; component class or the &lt;code&gt;EditPost&lt;/code&gt; component class.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;$rules&lt;/code&gt; property is similar to the one used in the &lt;code&gt;NewPost&lt;/code&gt; component, albeit without a few fields. These fields are not included because they don't need to be updated when a post is updated.&lt;/p&gt;

&lt;p&gt;Then you come to the &lt;code&gt;save&lt;/code&gt; method. This validates the fields you want to update against the rules you defined in the &lt;code&gt;$rules&lt;/code&gt; property. It then saves everything and flashes a success message to the session, notifying the view that the update was successful.&lt;/p&gt;

&lt;p&gt;You'll now have to make three important changes to the new post view at &lt;strong&gt;resources/views/livewire/dashboard/new-post.blade.php.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;First, you'll have to display the success message from the session after a post is updated. Secondly, you need to display "Edit post" as title if you're editing a post or "New post" if you're creating a new one. Lastly, you'll have to modify the &lt;strong&gt;Submit&lt;/strong&gt; button's text to either show "Submit" if the post is being edited or "Next" if you're creating a new post.&lt;/p&gt;

&lt;p&gt;Replace the &lt;strong&gt;New post&lt;/strong&gt; heading with the following code snippet just below the opening &lt;code&gt;div&lt;/code&gt; at the top of &lt;strong&gt;resources/views/livewire/dashboard/new-post.blade.php:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php //tall-blog/resources/views/livewire/dashboard/new-post-blade.php
...
&amp;lt;h1 class="mb-3 text-xl font-semibold text-gray-600"&amp;gt;
    {{ isset($isEdit) ? "Edit post": "New post" }}
&amp;lt;/h1&amp;gt;
@if (session()-&amp;gt;has('message'))
    &amp;lt;div class="flex flex-row justify-between p-2 mb-4 text-green-900 
         ﻿bg-green-600 bg-opacity-25 rounded-md"&amp;gt;
        {{ session('message') }}
    &amp;lt;/div&amp;gt;
@endif
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This displays the success message as soon as it's flashed to the session.&lt;/p&gt;

&lt;p&gt;Next, update the text of the &lt;strong&gt;Submit&lt;/strong&gt; button to the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php //tall-blog/resources/views/livewire/dashboard/new-post-blade.php
...
{{ __(isset($isEdit) &amp;amp;&amp;amp; $isEdit ? "Submit": "Next") }}
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This shows "&lt;strong&gt;Submit&lt;/strong&gt;" if you're editing a post, else "&lt;strong&gt;Next&lt;/strong&gt;" is shown. This is so because for a new post, the button submits the form and then redirects to the upload featured image page.&lt;/p&gt;

&lt;p&gt;Save all files to continue.&lt;/p&gt;

&lt;p&gt;Congratulations! You're now done with all things concerning components for your blog.&lt;/p&gt;

&lt;p&gt;Your next task is to configure the route for the edit post component. Remember the route currently returns the dashboard view. Do replace the existing route with the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php //tall-blog/routes/web.php
...﻿
Route::get('post/edit/{id}', EditPost::class)-&amp;gt;name('edit-post');
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make sure you include &lt;strong&gt;EditPost&lt;/strong&gt; and all the other files at the top of the &lt;strong&gt;web.php&lt;/strong&gt; route file. Now start your database server. Don't forget to start the built-in PHP server too. Point your browser to &lt;a href="http://127.0.0.1:8000" rel="noopener noreferrer"&gt;http://127.0.0.1:8000&lt;/a&gt;, login and click any &lt;strong&gt;Edit&lt;/strong&gt; post button to see the edit page in action:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgkp2r7sadvmj45trpd8l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgkp2r7sadvmj45trpd8l.png" alt="Edit page with fields prefilled"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Changing any field and submitting the form shows the update success message:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk2ookljmca0tb4wjmf8q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk2ookljmca0tb4wjmf8q.png" alt="Post update successful"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Working With Middleware
&lt;/h2&gt;

&lt;p&gt;As at now, every user that registers with your blog can login and perform any tasks you the owner can perform. This include creating new posts, deleting existing posts, publishing or unpublishing posts and editing existing posts. These actions are very dangerous for any user to do without your knowledge. You'd want any user registered with your blog to be prohibited from performing these tasks. Laravel allows you to do just that easily using middleware.&lt;/p&gt;

&lt;p&gt;Laravel middleware provides a mechanism for you to scrutinize and filter incoming HTTP requests. This has many advantages. First, it allows you to control incoming requests that can compromise your website. It also allows you to restrict and/or give access to some parts of your website to specific user groups.&lt;/p&gt;

&lt;p&gt;Laravel includes a lot of middleware in the framework. This ranges from authentication, CSRF protection, CORS to a handful of other middleware used by the framework behind the scenes.&lt;/p&gt;

&lt;p&gt;You create a middleware with the &lt;code&gt;make:middleware&lt;/code&gt; Artisan command like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;php artisan make:middleware MiddlewareName
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This creates a &lt;strong&gt;MiddlewareName&lt;/strong&gt; middleware in your &lt;strong&gt;app/Http/Middleware&lt;/strong&gt; directory.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating the Admin Middleware
&lt;/h3&gt;

&lt;p&gt;In this section, you're going to create an &lt;code&gt;AdminMiddleware&lt;/code&gt;. The admin middleware will be used to restrict access to the admin dashboard for only admin users. In our case, there's going to be only one admin user in the system. Any other user who logs in to the system will be redirected to the blog homepage.&lt;/p&gt;

&lt;p&gt;Create the middleware by running the Artisan command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;php artisan make:middleware AdminMiddleware
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now open the file. Make sure it is equal to this code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php //tall-blog/app/Http/Middleware/AdminMiddleware.php
namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;

class AdminMiddleware
{
   /**
    * Handle an incoming request.
    *
    * @param \Illuminate\Http\Request $request
    * @param \Closure $next
    * @return mixed
    */
   public function handle(Request $request, Closure $next)
   {
       if ($request-&amp;gt;user()-&amp;gt;user_type !== 'admin') {
           return redirect()-&amp;gt;to(route('home'));
       }
       return $next($request);
   }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every Laravel middleware has the handle method which handles the incoming request. Within the method, you can perform any tasks before or after the request is handled by the application.&lt;/p&gt;

&lt;p&gt;Your &lt;code&gt;AdminMiddleware&lt;/code&gt; checks if the user performing the request is an administrator. If not so, they're redirected to the homepage. Otherwise, the request is passed on to the application to be handled using the &lt;code&gt;$next&lt;/code&gt; closure.&lt;/p&gt;

&lt;h3&gt;
  
  
  Registering the AdminMiddleware
&lt;/h3&gt;

&lt;p&gt;For the admin middleware to work, you have to register it. There are two ways to doing this. First, you register global middleware (middleware that runs for all requests in the application) by adding it to the &lt;code&gt;$middleware&lt;/code&gt; list property in your app's &lt;strong&gt;app/Http/Kernel.php&lt;/strong&gt; file. For middleware that should only run during some specific requests or on some routes, you register it by adding it to the &lt;code&gt;$routeMiddleware&lt;/code&gt; list property.&lt;/p&gt;

&lt;p&gt;Since the admin middleware is run only on requests to the admin dashboard, you'll use the second approach. Add the &lt;code&gt;AdminMiddleware&lt;/code&gt; class to the &lt;code&gt;$routeMiddleware&lt;/code&gt; list property in the &lt;strong&gt;app/Http/Kernel.php&lt;/strong&gt; file with the key 'admin':&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    /**
     * The application's route middleware.
     *
     * These middleware may be assigned to groups or used individually.
     *
     * @var array
     */
    protected $routeMiddleware = [
        'admin' =&amp;gt; \App\Http\Middleware\AdminMiddleware::class,
        'auth' =&amp;gt; \App\Http\Middleware\Authenticate::class,
        'auth.basic' =&amp;gt; \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
        'cache.headers' =&amp;gt; \Illuminate\Http\Middleware\SetCacheHeaders::class,
        'can' =&amp;gt; \Illuminate\Auth\Middleware\Authorize::class,
        'guest' =&amp;gt; \App\Http\Middleware\RedirectIfAuthenticated::class,
        'password.confirm' =&amp;gt; \Illuminate\Auth\Middleware\RequirePassword::class,
        'signed' =&amp;gt; \Illuminate\Routing\Middleware\ValidateSignature::class,
        'throttle' =&amp;gt; \Illuminate\Routing\Middleware\ThrottleRequests::class,
        'verified' =&amp;gt; \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
    ];
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once this is done, your next task is to assign the middleware to the dashboard route group. Open the &lt;strong&gt;routes/web.php&lt;/strong&gt; file and add it to the existing &lt;code&gt;auth:sanctum&lt;/code&gt; middleware:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;'middleware' =&amp;gt; ['auth:sanctum', 'admin']
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make sure your &lt;strong&gt;routes/web.php&lt;/strong&gt; route file looks exactly like this now:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php

use App\Http\Livewire\CategoryPosts;
use App\Http\Livewire\Dashboard\FeaturedImageUpload;
use App\Http\Livewire\Dashboard\NewPost;
use App\Http\Livewire\Detail;
use App\Http\Livewire\Dashboard\EditPost;
use App\Http\Livewire\ShowPosts;
use Illuminate\Support\Facades\Route;

/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/

Route::get('/', ShowPosts::class)-&amp;gt;name('home');

Route::get('categories/{category}', CategoryPosts::class)-&amp;gt;name('category');

Route::group(['prefix' =&amp;gt; 'dashboard', 
   'middleware' =&amp;gt; ['auth:sanctum', 'admin']], function () {
    Route::get('/', function () {
        return view('dashboard');
    })-&amp;gt;name('dashboard');

    Route::get('post/add', NewPost::class)-&amp;gt;name('new-post');

    Route::get('post/upload/{id}', FeaturedImageUpload::class)-&amp;gt;name('upload-featured-image');

    Route::get('post/edit/{id}', EditPost::class)-&amp;gt;name('edit-post');
});

Route::get('{slug}', Detail::class)-&amp;gt;name('post-detail');
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save all files. Now refresh your browser and you should be redirected to the homepage:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.bandughana.com%2Fstorage%2Fcanvas%2Fimages%2F62T7oY0jb0Izxc5Q6RnKdVB3FlMy7Al00JUhWrXS.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.bandughana.com%2Fstorage%2Fcanvas%2Fimages%2F62T7oY0jb0Izxc5Q6RnKdVB3FlMy7Al00JUhWrXS.gif" alt="Redirect to homepage"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Updating the Users Table
&lt;/h2&gt;

&lt;p&gt;Though in the previous section you were logged in, you were still redirected to the homepage. This is going to be the fate of any new user who registers for your blog at the moment. This includes you because the website doesn't yet recognize you as an admin.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;AdminMiddleware&lt;/code&gt; only allows users whose &lt;code&gt;user_type&lt;/code&gt; is 'admin'. Currently, however, this column isn't in the &lt;code&gt;users&lt;/code&gt; table. Therefore, you're redirected to the homepage since the constraint isn't met.&lt;/p&gt;

&lt;p&gt;To add the &lt;code&gt;user_type&lt;/code&gt; column to the &lt;code&gt;users&lt;/code&gt; table and make your self an admin, create an &lt;strong&gt;add_user_type_column&lt;/strong&gt; migration using the Artisan command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;php artisan make:migration add_user_type_column --table=users
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open the migration file and make sure it contains this code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class AddUserTypeColumn extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::table('users', function (Blueprint $table) {
            $table-&amp;gt;enum('user_type', ['admin', 'normal'])-&amp;gt;default('normal');
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::table('users', function (Blueprint $table) {
            $table-&amp;gt;dropColumn('user_type');
        });
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This adds the &lt;code&gt;user_type&lt;/code&gt; column to the users table and makes 'normal' as the default user type. This means anyone registering for the blog will be a normal person. Also, notice how the column is made an &lt;code&gt;enum&lt;/code&gt;. This ensures only the two values are allowed.&lt;/p&gt;

&lt;p&gt;Now run the migration to migrate the changes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;php artisan migrate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inspect your database and you should be able to see the column added. You must then change the user type for the row containing your account details to 'admin' instead of the default 'normal' type.&lt;/p&gt;

&lt;p&gt;You should save all files and click the &lt;strong&gt;Login&lt;/strong&gt; menu link to login. Because you're already logged in, you'll be sent directly to the dashboard:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.bandughana.com%2Fstorage%2Fcanvas%2Fimages%2FWwVV7aMtZran2fNzOJ2Wrt6ciX62pvETlEgdNe6v.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.bandughana.com%2Fstorage%2Fcanvas%2Fimages%2FWwVV7aMtZran2fNzOJ2Wrt6ciX62pvETlEgdNe6v.gif" alt="Dashboard now accessible"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Congratulations once again! You have successfully finished developing your blog with the TALL stack. I believe you've learnt a lot in the process. You should clap for yourself for coming this far!&lt;/p&gt;

&lt;p&gt;This completes today's episode of this series. The next episode will be about optimizing your Laravel application before deployment. I'll teach you how to make your app faster, efficient and secure before deploying to your server.&lt;/p&gt;

&lt;p&gt;See you for that session soon. Bye!&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>tailwindcss</category>
      <category>alpinejs</category>
      <category>livewire</category>
    </item>
    <item>
      <title>Creating Your First Blog With TALL - Part Seven</title>
      <dc:creator>Alhassan Kamil</dc:creator>
      <pubDate>Fri, 30 Apr 2021 08:19:00 +0000</pubDate>
      <link>https://forem.com/nayi10/creating-your-first-blog-with-tall-part-seven-3nfa</link>
      <guid>https://forem.com/nayi10/creating-your-first-blog-with-tall-part-seven-3nfa</guid>
      <description>&lt;p&gt;Hey! Just so you know if today is your first time being here, this is a tutorial series and this one is the seventh episode of the tutorial series&lt;/p&gt;

&lt;p&gt;In the previous episode, you learnt how to create a responsive navigation bar for the blog using Tailwind CSS and Alpinejs. You also learnt how to layout a post detail page using utility classes from Tailwind CSS. As is always the case, this episode builds on that by teaching you how to create posts using Laravel Livewire.&lt;/p&gt;

&lt;p&gt;At the end of this episode, you should be able to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;delete, publish and unpublish posts using Livewire actions.&lt;/li&gt;
&lt;li&gt;add new posts to the database using Eloquent.&lt;/li&gt;
&lt;li&gt;style forms with Tailwind CSS.&lt;/li&gt;
&lt;li&gt;use Laravel Livewire model binding to bind properties from Livewire components to forms in the view files.&lt;/li&gt;
&lt;li&gt;validate forms using Livewire.&lt;/li&gt;
&lt;li&gt;upload files using Laravel Livewire.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: I've noticed that the &lt;code&gt;slug&lt;/code&gt; wasn't added to the &lt;code&gt;Post&lt;/code&gt; model and the create posts migration. If you didn't also notice and correct it, kindly add &lt;code&gt;slug&lt;/code&gt; to the &lt;code&gt;$fillable&lt;/code&gt; array in &lt;strong&gt;app/Models/Post.php&lt;/strong&gt; and modify the create posts migration accordingly(make the &lt;code&gt;featured_image&lt;/code&gt;column too nullable). Then run &lt;code&gt;php artisan migrate:refresh&lt;/code&gt; to rollback and rerun the migrations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: The above truncates all your data, including users data. We're taking this approach because updating only the &lt;code&gt;slug&lt;/code&gt; column means we have to provide a &lt;code&gt;slug&lt;/code&gt; for all posts. We also want to tidy up our posts table of the auto-generated data. &lt;/p&gt;

&lt;p&gt;However, you'd need to recreate your account to continue with the tutorial.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;First things first!&lt;/strong&gt; Remember the view for the dashboard page was &lt;strong&gt;resources/views/dashboard.blade.php&lt;/strong&gt;, and that was what you returned in the route for the dashboard page. Remember also that the default Jetstream &lt;strong&gt;welcome.blade.php&lt;/strong&gt; component view was inserted into this view, making the default Jetstream dashboard display the welcome page.&lt;/p&gt;

&lt;p&gt;Locate and delete this snippet from the &lt;strong&gt;resources/views/dashboard.blade.php&lt;/strong&gt; to remove the welcome component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;x-jet-welcome /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You're going to display posts you've already added in the dashboard, that's why you have to delete the welcome page.&lt;/p&gt;

&lt;p&gt;Now you could just display the posts like how you did in the homepage but this is an admin area, so you wouldn't want to clutter the dashboard page. What will be more appropriate is to display minimal details of the posts in a table. This way, you can even add, edit and delete buttons to take actions on each post. This is the approach we're going to take.&lt;/p&gt;

&lt;h2&gt;
  
  
  Updating the web.php Routes File
&lt;/h2&gt;

&lt;p&gt;For us to be able to preview the pages we're going to create in the next sections, the &lt;strong&gt;routes/web.php&lt;/strong&gt; file needs to be updated. Please make sure its contents match the route definitions below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;use App\Http\Livewire\CategoryPosts;
// use App\Http\Livewire\Dashboard\FeaturedImageUpload;
// use App\Http\Livewire\Dashboard\NewPost;
use App\Http\Livewire\Detail;
use App\Http\Livewire\ShowPosts;
use Illuminate\Support\Facades\Route;

/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/

Route::get('/', ShowPosts::class)-&amp;gt;name('home');

Route::get('categories/{category}', CategoryPosts::class)-&amp;gt;name('category');

Route::group(['prefix' =&amp;gt; 'dashboard', 'middleware' =&amp;gt; 'auth:sanctum'], function () {
    Route::get('/', function () {
        return view('dashboard');
    })-&amp;gt;name('dashboard');

    // Route::get('post/add', NewPost::class)-&amp;gt;name('new-post');

    // Route::get('post/upload/{id}', 
        // FeaturedImageUpload::class
    // )-&amp;gt;name('upload-featured-image');

    Route::get('post/edit/{id}', function ($id) {
        return view('dashboard');
    })-&amp;gt;name('edit-post');
});

Route::get('{slug}', Detail::class)-&amp;gt;name('post-detail');
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You've commented the new post and featured image upload routes for now since these components are not yet available. After completely working on a component, you'll have to uncomment it here to make the route work.&lt;/p&gt;

&lt;h2&gt;
  
  
  Displaying Posts in the Dashboard
&lt;/h2&gt;

&lt;p&gt;Create a new &lt;code&gt;Posts&lt;/code&gt; Livewire component to display posts in the dashboard page:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;php artisan make:livewire Posts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open the file and make sure it is equal to this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;use App\Models\Post;
use Livewire\Component;
use Livewire\WithPagination;

class Posts extends Component
{
    use WithPagination;

    public function render()
    {
        $posts = Post::paginate(10);
        return view('livewire.dashboard.posts', 
                ['posts' =&amp;gt; $posts]
            );
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You're using the &lt;code&gt;WithPagination&lt;/code&gt; Livewire trait in this component. This trait makes paginating data using Livewire a breeze. You didn't make &lt;code&gt;$posts&lt;/code&gt; a public variable because Livewire doesn't support using types other than the  &lt;code&gt;Stringable&lt;/code&gt;, &lt;code&gt;Collection&lt;/code&gt;, &lt;code&gt;DateTime&lt;/code&gt;, &lt;code&gt;Model&lt;/code&gt;, &lt;code&gt;EloquentCollection&lt;/code&gt; PHP types and the JavaScript data types this way(the paginate method returns a &lt;code&gt;LengthAwarePaginator&lt;/code&gt;, not a collection of models).&lt;/p&gt;

&lt;p&gt;Change the contents of the corresponding view to the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div class="m-4"&amp;gt;
    &amp;lt;div class="flex flex-row justify-between"&amp;gt;
        &amp;lt;h2 class="text-xl font-bold text-gray-600"&amp;gt;Posts&amp;lt;/h2&amp;gt;
        &amp;lt;a href="{{ route('new-post') }}" class="px-2 py-1 text-white bg-green-700 rounded"&amp;gt;New&amp;lt;/a&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;lt;div class="p-3"&amp;gt;
        &amp;lt;!-- Session checks --&amp;gt;
        @if (session()-&amp;gt;has('message'))
            &amp;lt;!-- Show message --&amp;gt;
            &amp;lt;div class="p-2 text-green-900 bg-green-600 bg-opacity-25 rounded-md"&amp;gt;{{ session('message') }}&amp;lt;/div&amp;gt;
        @endif
        &amp;lt;table class="table w-full"&amp;gt;
            &amp;lt;thead class="text-sm text-gray-600 border-b border-gray-200"&amp;gt;
                &amp;lt;th&amp;gt;Category&amp;lt;/th&amp;gt;
                &amp;lt;th&amp;gt;Title&amp;lt;/th&amp;gt;
                &amp;lt;th&amp;gt;Status&amp;lt;/th&amp;gt;
                &amp;lt;th&amp;gt;Actions&amp;lt;/th&amp;gt;
            &amp;lt;/thead&amp;gt;
            &amp;lt;tbody class="text-sm text-gray-600"&amp;gt;
                @foreach ($posts as $post)
                &amp;lt;tr class="table-row px-2 border-b border-gray-200 hover:bg-gray-100"&amp;gt;
                    &amp;lt;td class="py-4"&amp;gt;{{ $post-&amp;gt;category }}&amp;lt;/td&amp;gt;
                    &amp;lt;td&amp;gt;
                        {{ ucwords($post-&amp;gt;title) }}
                    &amp;lt;/td&amp;gt;
                    &amp;lt;td class="text-center"&amp;gt;
                        {{ $post-&amp;gt;is_published ? "Published" : "Pending" }}
                    &amp;lt;/td&amp;gt;
                    &amp;lt;td class="text-center"&amp;gt;
                        &amp;lt;button class="p-1 text-xs text-gray-100 bg-red-600 rounded-sm"
                        wire:click="delete({{ $post-&amp;gt;id }})"&amp;gt;
                            Delete
                        &amp;lt;/button&amp;gt;
                        &amp;lt;button class="p-1 text-xs text-gray-100 bg-yellow-700 rounded-sm" wire:click="publish({{ $post-&amp;gt;id }})"&amp;gt;
                            {{ !$post-&amp;gt;is_published ? "Publish" : "Unpublish" }}
                        &amp;lt;/button&amp;gt;
                        &amp;lt;a href="{{ route('edit-post', $post-&amp;gt;id) }}"
                            class="bg-blue-600 px-2 py-1.5 text-xs rounded text-white"&amp;gt;Edit&amp;lt;/a&amp;gt;
                    &amp;lt;/td&amp;gt;
                &amp;lt;/tr&amp;gt;
                @endforeach
            &amp;lt;/tbody&amp;gt;
        &amp;lt;/table&amp;gt;
        &amp;lt;div class="my-3"&amp;gt;
            {{ $posts-&amp;gt;links() }}
        &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The view of a Livewire component must be laid out in a single top-level element, that's why we put everything in the &lt;code&gt;div&lt;/code&gt; element. We've added a heading and a button linking to the page we'd use for creating new posts.&lt;/p&gt;

&lt;p&gt;Remember Laravel helpers are also available in the views, so you're using the &lt;code&gt;Session::has&lt;/code&gt; helper here to check for and display a message (which is from a session) when a post is deleted or published. Also, note the use of the &lt;code&gt;@if @endif&lt;/code&gt; conditional block. This ensures the message is only displayed if there's a session that has the message variable.&lt;/p&gt;

&lt;p&gt;Ignoring HTML, the next block iterates through the &lt;code&gt;$posts&lt;/code&gt; and displays each post in a table row (&lt;code&gt;tr&lt;/code&gt;). We have decided to display only a few columns from the &lt;strong&gt;posts&lt;/strong&gt; table to make the table less cluttered.&lt;/p&gt;

&lt;p&gt;Lastly from the loop, the &lt;strong&gt;Action&lt;/strong&gt; column has three buttons: &lt;strong&gt;Delete&lt;/strong&gt; for deleting this post, &lt;strong&gt;Publish/Unpublish&lt;/strong&gt; for publishing/unpublishing this post, and &lt;strong&gt;Edit&lt;/strong&gt; for editing the post.&lt;/p&gt;

&lt;p&gt;While &lt;strong&gt;Edit&lt;/strong&gt; is ordinarily a link to the edit post page, &lt;strong&gt;Delete&lt;/strong&gt; and &lt;strong&gt;Publish/Unpublish&lt;/strong&gt; bind the delete and publish methods in the &lt;code&gt;Posts&lt;/code&gt; component to their &lt;code&gt;wire:click&lt;/code&gt; event directives. The &lt;code&gt;wire:click&lt;/code&gt; directive attaches the given method to the click event of the button element.&lt;/p&gt;

&lt;p&gt;The last snippet is the &lt;code&gt;$posts-&amp;gt;links()&lt;/code&gt;. This adds the pagination links and is the same way a traditional Laravel app will display pagination. In other words, the difference between the syntax of a Livewire pagination and a traditional Laravel pagination is the use of the &lt;code&gt;WithPagination&lt;/code&gt; trait. However, while pagination with Livewire doesn't refresh the whole page, Laravel's does and this is one advantage of using Livewire pagination.&lt;/p&gt;

&lt;p&gt;Add the delete and publish methods to complete the &lt;code&gt;Posts&lt;/code&gt; component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public function delete(int $id)
{
    $post = Post::find($id);
    unlink(storage_path("app/public/posts/".$post-&amp;gt;featured_image));
    $post-&amp;gt;delete();
    session()-&amp;gt;flash("message", "Post has been deleted");
}

public function publish(int $id)
{
    $post = Post::find($id);
    $status = $post-&amp;gt;is_published ? "unpublished": "published";
    $post-&amp;gt;is_published = !$post-&amp;gt;is_published;
    $post-&amp;gt;published_date = now();
    $post-&amp;gt;save();
    session()-&amp;gt;flash("message", "Post $status successfully");
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;delete&lt;/code&gt; method first finds the post from the database using the post ID passed to it from the view. It then deletes the post's featured image from the storage folder using the &lt;code&gt;storage_path&lt;/code&gt; helper to locate the file and the PHP &lt;code&gt;unlink&lt;/code&gt; function for actually deleting the file. Lastly, we delete the post and flash a success method to the session.&lt;/p&gt;

&lt;p&gt;Similarly, in the publish method you retrieve the post using its ID, set the status variable that specifies which word to use between 'published' and 'unpublished' in the success message, toggle the &lt;code&gt;is_published&lt;/code&gt; column of the post, set the &lt;code&gt;published_date&lt;/code&gt; column to the current date and then save the post back to the database. Finally, you flash the success message to the session for display in the view.&lt;/p&gt;

&lt;p&gt;Save, start your servers and open your browser. Logging in to the dashboard should now show you posts available:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzpeeybcnu99ew5i0w55o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzpeeybcnu99ew5i0w55o.png" alt="Posts in Admin Dashboard"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Adding New Posts
&lt;/h2&gt;

&lt;p&gt;Your next task is to allow the administrator to create new posts when they're logged in. The new post route was added to make this possible. You even added a button that'll send you to the page where you can add a new post at the top of the posts table in the dashboard page. Though, as at now clicking this button sends you to the correct page, the page doesn't have this functionality. It currently returns the dashboard page.&lt;/p&gt;

&lt;p&gt;Create a &lt;code&gt;NewPost&lt;/code&gt; Livewire component to handle adding a new post:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;php artisan make:livewire Dashboard.NewPost
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, make sure the &lt;code&gt;NewPost&lt;/code&gt; component contains the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php

namespace App\Http\Livewire\Dashboard;

use App\Models\Post;
use Illuminate\Support\Facades\Auth;
use Livewire\Component;

class NewPost extends Component
{
    public $post;

    protected $rules = [
        'post.title' =&amp;gt; 'required|string',
        'post.category' =&amp;gt; 'required',
        'post.body' =&amp;gt; 'required|string|min:500',
        'post.excerpt' =&amp;gt; 'required|min:100:max:250',
        'post.is_published' =&amp;gt; 'boolean'
    ];

    protected $messages = [
        'required' =&amp;gt; 'This field is required',
        'min' =&amp;gt; 'Value must be more than :min chars',
        'max' =&amp;gt; 'Maximum value is 250 chars'
    ];

    public function render()
    {
        return view('livewire.dashboard.new-post');
    }

    public function save()
    {
        $this-&amp;gt;validate();

        $post = Post::create([
            'title' =&amp;gt; $this-&amp;gt;post['title'],
            'excerpt' =&amp;gt; $this-&amp;gt;post['excerpt'],
            'category' =&amp;gt; $this-&amp;gt;post['category'],
            'body' =&amp;gt; $this-&amp;gt;post['body'],
            'published_date' =&amp;gt; now(),
            'user_id' =&amp;gt; Auth()-&amp;gt;user()-&amp;gt;id,
            'is_published' =&amp;gt; $this-&amp;gt;post['is_published']
        ]);

        $id = $post-&amp;gt;save();
        return redirect()-&amp;gt;to(route('upload-featured-image', ['id' =&amp;gt; $id]));
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pretty many things are going on here. We have the &lt;code&gt;$post&lt;/code&gt; member variable which holds all fields of a blog post. &lt;code&gt;$rules&lt;/code&gt; define what validation rules should be applied to each field. You see that each rule has the &lt;code&gt;post.{field}&lt;/code&gt; format as its key with the constraints that should be applied to it being the value. Occasionally, you'd only have the field as the key when you're dealing with a small and/or disjointed number of fields.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$messages&lt;/code&gt; show the provided messages for each constraint instead of the default Laravel validation error messages.&lt;/p&gt;

&lt;p&gt;And finally, we have the &lt;code&gt;save&lt;/code&gt; method that validates the form data against the &lt;code&gt;$rules&lt;/code&gt; we specified earlier. When validation passes, you create a new post using the &lt;code&gt;create&lt;/code&gt; method, save the post and redirect to the featured image upload page with the post id.&lt;/p&gt;

&lt;p&gt;You'll now have to create the form in the &lt;strong&gt;resources/views/livewire/dashboard/new-post.blade.php&lt;/strong&gt; view. Enter this code in that view to do so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div class="p-4 mx-auto mt-3 bg-gray-100 md:p-8 md:w-4/5 md:mt-0"&amp;gt;
    &amp;lt;h1 class="mb-3 text-xl font-semibold text-gray-600"&amp;gt;New post&amp;lt;/h1&amp;gt;
    &amp;lt;form wire:submit.prevent="save"&amp;gt;
        &amp;lt;div class="overflow-hidden bg-white rounded-md shadow"&amp;gt;
            &amp;lt;div class="px-4 py-3 space-y-8 sm:p-6"&amp;gt;
                &amp;lt;div class="grid grid-cols-6 gap-6"&amp;gt;
                    &amp;lt;div class="col-span-6 sm:col-span-3"&amp;gt;
                        &amp;lt;x-jet-label for="title"&amp;gt;
                            {{ __("Post title") }}
                        &amp;lt;/x-jet-label&amp;gt;
                        &amp;lt;x-jet-input class="w-full" type="text" 
                           ﻿wire:model="post.title" placeholder="Post title" /&amp;gt;
                        &amp;lt;x-jet-input-error for="post.title" /&amp;gt;
                    &amp;lt;/div&amp;gt;

                    &amp;lt;div class="col-span-6 sm:col-span-3"&amp;gt;
                        &amp;lt;x-jet-label&amp;gt;
                            {{ __("Excerpt") }}
                        &amp;lt;/x-jet-label&amp;gt;
                        &amp;lt;x-jet-input type="text" class="w-full" wire:model="post.excerpt" 
                           ﻿placeholder="Excerpt" /&amp;gt;
                        &amp;lt;x-jet-input-error for="post.excerpt" /&amp;gt;
                    &amp;lt;/div&amp;gt;
                &amp;lt;/div&amp;gt;
                &amp;lt;div class="grid grid-cols-6 gap-6"&amp;gt;
                    &amp;lt;div class="col-span-6 sm:col-span-3"&amp;gt;
                        &amp;lt;x-jet-label for="category" 
                            ﻿class="block text-sm font-medium text-gray-700"&amp;gt;
                            {{ __("Category") }}
                        &amp;lt;/x-jet-label&amp;gt;
                        &amp;lt;x-jet-input id="category" wire:model="post.category" type="text"
                            placeholder="Category" class="w-full" /&amp;gt;
                        &amp;lt;x-jet-input-error for="post.category" /&amp;gt;
                    &amp;lt;/div&amp;gt;
                    &amp;lt;div class="col-span-6 mt-4 sm:col-span-1"&amp;gt;
                        &amp;lt;x-jet-label class="text-sm font-medium text-gray-700"&amp;gt;
                            &amp;lt;x-jet-input wire:model="post.is_published" type="checkbox" 
                              class="form-checkbox" /&amp;gt;
                            {{ __("Publish") }}
                        &amp;lt;/x-jet-label&amp;gt;
                        &amp;lt;x-jet-input-error for="post.is_published" /&amp;gt;
                    &amp;lt;/div&amp;gt;
                &amp;lt;/div&amp;gt;
                &amp;lt;div class="flex flex-col"&amp;gt;
                    &amp;lt;x-jet-label for="body"&amp;gt;
                        {{ __("Body") }}
                    &amp;lt;/x-jet-label&amp;gt;
                    &amp;lt;textarea id="body" rows="4" wire:model="post.body" 
                       ﻿class="border-gray-300 rounded-sm form-textarea"&amp;gt;
                    ﻿&amp;lt;/textarea&amp;gt;
                    &amp;lt;x-jet-input-error for="post.body" /&amp;gt;
                &amp;lt;/div&amp;gt;
            &amp;lt;/div&amp;gt;
            &amp;lt;div class="px-4 py-3 text-right bg-gray-50 sm:px-6"&amp;gt;
                &amp;lt;x-jet-button class="inline-flex justify-center"&amp;gt;
                    {{ __("Next") }}
                &amp;lt;/x-jet-button&amp;gt;
            &amp;lt;/div&amp;gt;
        &amp;lt;/div&amp;gt;
    &amp;lt;/form&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From this, &lt;code&gt;wire:submit.prevent="save"&lt;/code&gt; ensures that when the form is submitted, the &lt;code&gt;save&lt;/code&gt; method is called. Of course, this is the method that saves the post into the database. The other thing worth mentioning is that the &lt;code&gt;.prevent&lt;/code&gt; event modifier prevents refreshing the browser(which is the default behavior when you submit a form). Thus, it's equivalent to the &lt;code&gt;event.preventDefault()&lt;/code&gt; JavaScript modifier.&lt;/p&gt;

&lt;p&gt;You're making use of the Jetstream components for the form's elements here. The &lt;code&gt;&amp;lt;x-jet-label ...&amp;gt;&lt;/code&gt; elements represent the Jetstream label component which we make use here. The &lt;code&gt;&amp;lt;x-jet-input ...&amp;gt;&lt;/code&gt; is an input component while the nearby &lt;code&gt;&amp;lt;x-jet-input-error ...&amp;gt;&lt;/code&gt; displays errors associated with that input field. We also have the &lt;code&gt;&amp;lt;x-jet-button ...&amp;gt;&lt;/code&gt; component which submits the form. All these components can be found in the &lt;strong&gt;resources/views/vendor/jetstream/components&lt;/strong&gt; folder at the root of the project(we talked about this in the earlier episodes).&lt;/p&gt;

&lt;p&gt;We decided to use the ready-made Jetstream components because apart from that being easier, it reduces the time we'd have spent crafting and designing the form ourselves. This also helps us to follow the &lt;a href="https://en.wikipedia.org/wiki/Don%27t_repeat_yourself" rel="noopener noreferrer"&gt;DRY&lt;/a&gt; principles.&lt;/p&gt;

&lt;p&gt;Save all files and try to click the &lt;strong&gt;New post&lt;/strong&gt; button to see the form in action. Try to submit without providing the required fields, or by providing invalid data and you should see errors displayed next to each invalid field.&lt;/p&gt;

&lt;p&gt;This is how the form looks like:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4q84zy01elxaq00wg9v0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4q84zy01elxaq00wg9v0.png" alt="New post form"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The last thing left for us to work on is the featured image upload page. This is necessary because when you submit the form with valid data, it sends you to the next page for the upload. This will be covered in the next section.&lt;/p&gt;
&lt;h2&gt;
  
  
  Uploading Files
&lt;/h2&gt;

&lt;p&gt;Just like many other things, Livewire supports file uploads out of the box. It handles file uploads like you would with other form input fields. The only different thing you need to add to take advantage of this feature is to add the &lt;code&gt;WithFileUploads&lt;/code&gt; trait to your Livewire component.&lt;/p&gt;

&lt;p&gt;Create a new &lt;code&gt;FeaturedImageUpload component&lt;/code&gt; in the &lt;code&gt;Dashboard&lt;/code&gt; namespace:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;php artisan make:livewire Dashboard.FeaturedImageUpload
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open the component class and modify it to equal the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php

namespace App\Http\Livewire\Dashboard;

use App\Models\Post;
use Livewire\Component;
use Livewire\WithFileUploads;
use Illuminate\Support\Str;

class FeaturedImageUpload extends Component
{
    use WithFileUploads;
    public $photo;
    public $post;

    protected $rules = [
        'photo' =&amp;gt; 'required|image|max:2048'
    ];

    public function mount($id)
    {
        $this-&amp;gt;post = Post::find($id);
    }

    public function render()
    {
        return view('livewire.dashboard.featured-image-upload');
    }

    public function upload()
    {
        $this-&amp;gt;validate();

        $image = $this-&amp;gt;photo-&amp;gt;storeAs('posts/', Str::random(30));
        $this-&amp;gt;post-&amp;gt;featured_image = $image;
        $this-&amp;gt;post-&amp;gt;save();
        session()-&amp;gt;flash("message", "Featured image successfully uploaded");
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With the &lt;code&gt;WithFileUploads&lt;/code&gt; trait, you can take advantage of the fluent file upload feature Livewire provides. &lt;code&gt;$photo&lt;/code&gt; is the featured image we're dealing with while &lt;code&gt;$post&lt;/code&gt; is the blog post we're creating. You see we're using &lt;code&gt;mount&lt;/code&gt; to fetch this post.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;upload&lt;/code&gt; method is where we're actually doing the upload. First we validate the form to ensure there's an upload and the uploaded file is an image not more than 2MB. Secondly, we store the image in the &lt;strong&gt;storage/app/posts&lt;/strong&gt; directory with a randomly generated string as its name. After saving the image, the &lt;code&gt;storeAs&lt;/code&gt; method returns the path to the uploaded image, which we assigned to the post. Finally, we save the post with the updated featured image and flash a success message to the session.&lt;/p&gt;

&lt;p&gt;Open the view file and enter this code into it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div class="p-4 mx-auto mt-3 h-4/5 md:p-8 md:w-3/5"&amp;gt;
    &amp;lt;h2 class="my-2 text-lg font-semibold text-gray-700"&amp;gt;Upload featured image&amp;lt;/h2&amp;gt;
    &amp;lt;form wire:submit.prevent="upload" enctype="multipart/form-data"&amp;gt;
        &amp;lt;div class="bg-white rounded shadow"&amp;gt;
            @if (session()-&amp;gt;has('message'))
                &amp;lt;div class="p-2 m-2 text-green-900 bg-green-600 bg-opacity-25 rounded-md"&amp;gt;
                    {{ session('message') }} &amp;lt;a href="{{ route('new-post') }}"&amp;gt;Add another one&amp;lt;/a&amp;gt;
                &amp;lt;/div&amp;gt;
            @endif
            &amp;lt;div class="p-8"&amp;gt;
                &amp;lt;x-jet-label for="photo" class="flex items-center justify-center text-3xl border-2 border-dashed rounded-sm w-3/3 h-60 bg-gray-50"&amp;gt;
                {{ __('Choose image') }}
                &amp;lt;x-jet-input type="file" id="photo" accept="jpg,png,gif"
                wire:model="photo" class="w-0 h-0"/&amp;gt;
                &amp;lt;/x-jet-label&amp;gt;
                &amp;lt;x-jet-input-error for="photo" /&amp;gt;
                &amp;lt;/div&amp;gt;
            &amp;lt;div class="px-4 py-3 text-right bg-gray-50 sm:px-6"&amp;gt;
                &amp;lt;x-jet-button class="inline-flex justify-center"&amp;gt;
                    {{ __("Upload") }}
                &amp;lt;/x-jet-button&amp;gt;
            &amp;lt;/div&amp;gt;
        &amp;lt;/div&amp;gt;
    &amp;lt;/form&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There's nothing new here, except that we specified the &lt;code&gt;enctype&lt;/code&gt; attribute to &lt;code&gt;multipart/form-data&lt;/code&gt;. This is necessary to make file uploads successful.&lt;/p&gt;

&lt;p&gt;Save the files. Create and submit a new post to see the featured image upload page:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzwjd6qq2pv3vg1nx1r6q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzwjd6qq2pv3vg1nx1r6q.png" alt="Featured image upload"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Polishing Things Up
&lt;/h2&gt;

&lt;p&gt;Previously, because we're automatically generating the posts for display, we used a static image in the &lt;strong&gt;public&lt;/strong&gt; directory for all posts. Now that we're using the form to create posts the links to the images will be broken. This is because Livewire doesn't upload files to the &lt;strong&gt;public&lt;/strong&gt; directory: it uploads it in the &lt;strong&gt;storage&lt;/strong&gt; directory.&lt;/p&gt;

&lt;p&gt;From the &lt;code&gt;FeaturedImageUpload&lt;/code&gt; component, we said that images are uploaded to the &lt;strong&gt;storage/app/public/posts&lt;/strong&gt; folder. However, you already know that for files to be accessible to the public, they need to be in the &lt;strong&gt;public&lt;/strong&gt; folder. This is achieved by creating &lt;strong&gt;symlinks&lt;/strong&gt; since file storage is done in the storage folder.&lt;/p&gt;

&lt;p&gt;To create the symlink, add this to the &lt;code&gt;$link&lt;/code&gt; array in &lt;strong&gt;config/filesystems.php&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public_path('posts') =&amp;gt; storage_path('app/posts'),
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, save the file and run the &lt;code&gt;storage:link&lt;/code&gt; Artisan command to create the link:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;php artisan storage:link
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our last work is to change the image source in both &lt;strong&gt;resources/views/livewire/post-item.blade.php&lt;/strong&gt; and &lt;strong&gt;resources/views/livewire/detail.blade.php&lt;/strong&gt; from:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;img src="{{ asset("storage/posts/$post-&amp;gt;featured_image") }}" ...&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;img src="{{ asset($post-&amp;gt;featured_image) }}" ...&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should now be able to see the images if you navigate to the home, category or detail page.&lt;/p&gt;

&lt;p&gt;Congratulations! This brings us to the end of the seventh episode. In our next episode, we'll create and set up the remaining pages in the admin area.&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>livewire</category>
      <category>tailwindcss</category>
      <category>alpinejs</category>
    </item>
    <item>
      <title>Creating Your First Blog With TALL - Part Six</title>
      <dc:creator>Alhassan Kamil</dc:creator>
      <pubDate>Tue, 06 Apr 2021 01:58:00 +0000</pubDate>
      <link>https://forem.com/nayi10/creating-your-first-blog-with-tall-part-six-2dgk</link>
      <guid>https://forem.com/nayi10/creating-your-first-blog-with-tall-part-six-2dgk</guid>
      <description>&lt;p&gt;Hello! Welcome to this tutorial series. First of all, sorry for the delay in publishing this tutorial. I was quite busy for the last week and couldn't do it. Fortunately, I'm back this week to continue where we left.&lt;/p&gt;

&lt;p&gt;This tutorial will build upon the previous episode. Remember you were able to create the home, item and categories pages using Livewire components in the last episode. You learnt how to display all posts in the homepage and show posts from a particular category in the categories page. You also learnt how to reuse Livewire components at multiple places by using the post item component in both the home and category pages.&lt;/p&gt;

&lt;p&gt;In this episode, you'll turn your focus to displaying the details of individual posts. When you click a post from either the home page or the category page, the details page shows the details of the post.&lt;/p&gt;

&lt;p&gt;At the end of this episode, you should be able to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;run select queries for a single row from the database using Eloquent.&lt;/li&gt;
&lt;li&gt;use Tailwind CSS to create a responsive layout for a post.&lt;/li&gt;
&lt;li&gt;create a mobile-first top navigation bar and nav menu for any website using Tailwind CSS.&lt;/li&gt;
&lt;li&gt;use Alpine.js to make the navigation menu mobile-friendly.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;OK, let's start our journey.:)&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating the Detail Component
&lt;/h2&gt;

&lt;p&gt;When a user clicks a post in either the home page or categories page, the person should be redirected to the &lt;strong&gt;Detail&lt;/strong&gt; page. This is where they'll be able to read the post.&lt;/p&gt;

&lt;p&gt;Technically speaking, the link to the detail page will pass the post's slug along and this will be captured by the Laravel Router and then passed to the &lt;strong&gt;Detail&lt;/strong&gt; Component. This is what you'll use to retrieve the post from the database. &lt;/p&gt;

&lt;p&gt;Enter the command to create the &lt;strong&gt;Detail&lt;/strong&gt; component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;php artisan make:livewire Detail
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now open the &lt;strong&gt;Detail&lt;/strong&gt; component from &lt;strong&gt;app/Http/Livewire&lt;/strong&gt;. Make sure it contains this code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php

namespace App\Http\Livewire;

use App\Models\Post;
use Livewire\Component;

class Detail extends Component
{
    public $post;

    public function mount($slug)
    {
        $this-&amp;gt;post = Post::firstWhere('slug', $slug);
    }
    public function render()
    {
        return view('livewire.detail')
            -&amp;gt;layout("layouts/guest");
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First of all, you're using the &lt;code&gt;Post&lt;/code&gt; model. You used the &lt;code&gt;firstWhere&lt;/code&gt; method to get the post by its slug. This ensures only the first post matching the slug is returned(you're sure the post is what you asked for because each post has a unique slug). &lt;/p&gt;

&lt;p&gt;If you can remember, in the last episode I made mention that Livewire automatically makes &lt;code&gt;public&lt;/code&gt; properties in a component available in the view. Therefore, the &lt;code&gt;$post&lt;/code&gt; member variable is readily available in &lt;code&gt;detail.blade.php&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We also said that the &lt;code&gt;mount&lt;/code&gt; method is called once the component is mounted. Therefore, it is the best place to initialize properties, run database queries and carry out other initialization in the component. When you bind a route with parameters to a Livewire component, the &lt;code&gt;mount&lt;/code&gt; method can also be used to capture the argument(s) from the route and make them available to the component.&lt;/p&gt;

&lt;p&gt;This is exactly what you've used the &lt;code&gt;Detail&lt;/code&gt; component's &lt;code&gt;mount&lt;/code&gt; method for - to capture the &lt;code&gt;$slug&lt;/code&gt; parameter passed to the route.&lt;/p&gt;

&lt;p&gt;Since the &lt;code&gt;$post&lt;/code&gt; variable is available in the detail view, we now have to edit the &lt;strong&gt;resources/views/livewire/detail.blade.php&lt;/strong&gt; view file to display the post.&lt;/p&gt;

&lt;p&gt;Open the view file and enter this code into it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div class="mx-auto md:w-4/5 lg:w-3/5"&amp;gt;
    &amp;lt;h2 class="mt-2 text-xl font-bold lg:text-2xl"&amp;gt;
        {{ $post-&amp;gt;title }}
    &amp;lt;/h2&amp;gt;
    &amp;lt;div class="flex flex-row my-3"&amp;gt;
        &amp;lt;div class="mr-2 text-gray-700"&amp;gt;
            {{ $post-&amp;gt;user-&amp;gt;name }}
        &amp;lt;/div&amp;gt;

        &amp;lt;div class="w-2 h-2 my-auto mr-1 text-xl 
                bg-gray-300 rounded-full"&amp;gt;&amp;lt;/div&amp;gt;

        &amp;lt;div class="my-auto mr-2 text-sm 
                text-gray-500" title="Category"&amp;gt;
            {{ ucwords($post-&amp;gt;category) }}
        &amp;lt;/div&amp;gt;

        &amp;lt;div class="w-2 h-2 my-auto mr-1 text-xl bg-gray-300 
                rounded-full"&amp;gt;&amp;lt;/div&amp;gt;

        &amp;lt;div class="my-auto text-sm text-gray-500"&amp;gt;
            {{ $post-&amp;gt;published_date }}
        &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;lt;img src="{{ asset("storage/posts/$post-&amp;gt;featured_image") }}" 
            alt="{{ $post-&amp;gt;title }}" 
                class="w-full my-4 rounded-sm max-h-96"&amp;gt;
    &amp;lt;div&amp;gt;
        {!! $post-&amp;gt;body !!}
    &amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is what each class utility means from the view:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;mx-auto&lt;/code&gt;: centers the element it's been applied to on the horizontal axis. This is the same as applying &lt;code&gt;auto&lt;/code&gt; to both &lt;code&gt;margin-left&lt;/code&gt; and &lt;code&gt;margin-right&lt;/code&gt;. &lt;code&gt;my-auto&lt;/code&gt; will center it in vertical direction while &lt;code&gt;m-auto&lt;/code&gt; does same on both axis.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;w-{number}&lt;/code&gt; applies &lt;code&gt;width: {number}&lt;/code&gt; to the element and &lt;code&gt;h-{number}&lt;/code&gt; also applies &lt;code&gt;height: {number}&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;sm:&lt;/code&gt;, &lt;code&gt;md:&lt;/code&gt;, &lt;code&gt;lg:&lt;/code&gt; prefixes apply responsive variants of the utility classes. So &lt;code&gt;md:w-4/5&lt;/code&gt; makes this element occupy 4/5th of the screen size in medium-sized devices.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;m{side}-{number}&lt;/code&gt; is used to set margin of size &lt;code&gt;{number}&lt;/code&gt; to &lt;code&gt;{side}&lt;/code&gt;. The value for &lt;code&gt;{side}&lt;/code&gt; can be &lt;code&gt;t&lt;/code&gt; for top, &lt;code&gt;b&lt;/code&gt; for bottom, &lt;code&gt;r&lt;/code&gt; for right, &lt;code&gt;l&lt;/code&gt; for left, &lt;code&gt;x&lt;/code&gt; for horizontal, &lt;code&gt;y&lt;/code&gt; for vertical or nothing at all to represent all sides.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;text-xl&lt;/code&gt; and &lt;code&gt;text-2xl&lt;/code&gt; makes the text extra-large and extra-extra-large(2x extra-large). Other text size utilities include &lt;code&gt;text-xs&lt;/code&gt;, &lt;code&gt;text-sm&lt;/code&gt;, &lt;code&gt;text-base&lt;/code&gt;, &lt;code&gt;text-lg&lt;/code&gt;, &lt;code&gt;text-3xl&lt;/code&gt; up to &lt;code&gt;text-9xl&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;I discussed &lt;code&gt;flex&lt;/code&gt; and &lt;code&gt;flex-row&lt;/code&gt; in the &lt;a href="https://blog.bandughana.com/posts/creating-your-first-blog-with-tall-part-five" rel="noopener noreferrer"&gt;previous episode&lt;/a&gt;. As a reminder, these arrange children of the element in a flex row.&lt;/li&gt;
&lt;li&gt;All other utilities have been discussed before in the previous episodes.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Routing to the Detail Page
&lt;/h2&gt;

&lt;p&gt;Now that the detail page is ready, all you have to do is change the action for the &lt;code&gt;post-detail&lt;/code&gt; route. Open the &lt;strong&gt;routes/web.php&lt;/strong&gt; routes file and change the &lt;code&gt;post-detail&lt;/code&gt; named route from this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Route::get('{slug}', function ($slug) {
    return view('welcome');
})-&amp;gt;name('post-detail');
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;to the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Route::get('{slug}', Detail::class)-&amp;gt;name('post-detail');
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save all the files and start both your database server and the built-in PHP server. The latter can be started with this command if you've forgotten:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;php artisan serve
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you should be able to see something like this if you click any post from the home page:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fydnhwk2q8b0kvmhahuxg.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fydnhwk2q8b0kvmhahuxg.gif" alt="Homepage to detail page"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a Navigation Bar for the Tall Blog
&lt;/h2&gt;

&lt;p&gt;Though our blog is able to display pages as expected, wouldn't it be nice if you could navigate to the categories page and back to the home page without using the browser's back button? Or, perhaps, from the detail page to either categories or home pages? This would not only improve the user experience of the blog, it would also make it consistent with other websites on the internet.&lt;/p&gt;

&lt;p&gt;Consequently, you're going to create navigation component for the navbar. However, this is not going to be a Livewire component: it's going to be a Laravel component. It's going to be a Laravel component because that's more suitable for such cases than a Livewire component.&lt;/p&gt;

&lt;p&gt;Create an anonymous &lt;code&gt;nav&lt;/code&gt; component in the &lt;strong&gt;resources/views/components&lt;/strong&gt; directory. Name it &lt;strong&gt;nav.blade.php&lt;/strong&gt; and put this code into it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;nav x-data="{ isOpen: false }" @keydown.escape="isOpen = false"
    class="z-10 flex flex-wrap justify-between w-full p-4 shadow-md"&amp;gt;

    &amp;lt;div class="mr-6 text-xl font-bold"&amp;gt;
        &amp;lt;a href="{{ route('home') }}"
        class="grid grid-cols-3 gap-1 transition duration-500 hover:text-purple-500"&amp;gt;
            &amp;lt;x-jet-application-logo class="w-8 h-8 border border-blue-300 rounded-full" /&amp;gt;
            &amp;lt;div class="col-span-2"&amp;gt;Tall Blog&amp;lt;/div&amp;gt;
        &amp;lt;/a&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;lt;button x-on:click="isOpen = !isOpen" type="button" class="px-2 lg:hidden"
        :class="{ 'transition transform-180': isOpen }"&amp;gt;
        &amp;lt;svg class="w-6 h-6 fill-current" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"&amp;gt;
            &amp;lt;path x-show="isOpen"
                d="M18.278 16.864a1 1 0 0 1-1.414 1.414l-4.829-4.828-4.828 4.828a1 1 0 0 1-1.414-1.414l4.828-4.829-4.828-4.828a1 1 0 0 1 1.414-1.414l4.829 4.828 4.828-4.828a1 1 0 1 1 1.414 1.414l-4.828 4.829 4.828 4.828z" /&amp;gt;
            &amp;lt;path x-show="!isOpen"
                d="M4 5h16a1 1 0 0 1 0 2H4a1 1 0 1 1 0-2zm0 6h16a1 1 0 0 1 0 2H4a1 1 0 0 1 0-2zm0 6h16a1 1 0 0 1 0 2H4a1 1 0 0 1 0-2z" /&amp;gt;
        &amp;lt;/svg&amp;gt;
    &amp;lt;/button&amp;gt;
    &amp;lt;div class="flex-grow w-full transition-all duration-500 ease-in lg:flex lg:items-center lg:w-auto"
        :class="{ 'block shadow-3xl': isOpen, 'hidden': !isOpen }" @click.away="isOpen = false" x-show.transition="true"&amp;gt;
        &amp;lt;ul class="items-center justify-end flex-1 pt-4 space-y-4 lg:pt-0 list-reset lg:flex lg:space-y-0"&amp;gt;
            &amp;lt;li class="py-2 md:py-0"&amp;gt;
                &amp;lt;a href="{{ route('home') }}" class="mx-4 text-lg hover:text-indigo-500"&amp;gt;Home&amp;lt;/a&amp;gt;
            &amp;lt;/li&amp;gt;
            &amp;lt;li class="py-2 md:py-0"&amp;gt;
                &amp;lt;a href="{{ route('home') }}" class="mx-4 text-lg hover:text-indigo-500"&amp;gt;
                    Login
                &amp;lt;/a&amp;gt;
            &amp;lt;/li&amp;gt;
        &amp;lt;/ul&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
&amp;lt;/nav&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code is pretty large. But don't worry, apart from a few snippets you've encountered most of the others before. &lt;/p&gt;

&lt;p&gt;From the code:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The first attribute in the &lt;code&gt;nav&lt;/code&gt; element is an Alpine.js attribute. What it does is that it defines a variable called &lt;code&gt;isOpen&lt;/code&gt; with an initial boolean value of &lt;code&gt;false&lt;/code&gt;. This is used to toggle the navigation menu on mobile devices.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;@keydown.escape="isOpen = false"&lt;/code&gt; is also an Alpine.js snippet that sets the &lt;code&gt;isOpen&lt;/code&gt; to false when the Escape key is pressed while the nav menu is open on mobile. This will close the menu.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Next is the &lt;code&gt;class&lt;/code&gt; attribute. Again, this makes use of Tailwind CSS utilities a lot. Explanation each utility is as follows:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;z-10&lt;/code&gt; sets the &lt;code&gt;z-index&lt;/code&gt; CSS property. Accepted values are within [&lt;code&gt;z-0&lt;/code&gt;, &lt;code&gt;z-10&lt;/code&gt;,&lt;code&gt;z-20&lt;/code&gt;, &lt;code&gt;z-30&lt;/code&gt;, &lt;code&gt;z-40&lt;/code&gt;, &lt;code&gt;z-50&lt;/code&gt; and &lt;code&gt;z-auto&lt;/code&gt;].&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;flex-wrap&lt;/code&gt; is the Tailwind way of applying &lt;code&gt;flex-wrap: wrap&lt;/code&gt; to a flex element.&lt;/li&gt;
&lt;li&gt;all the other utilities have been looked at already.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The next &lt;code&gt;div&lt;/code&gt; element serves as a container for the logo and site title. The &lt;code&gt;font-bold&lt;/code&gt; utility you applied to it here makes the title font bold. Here are the others:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;We decided to display the logo and site title in a grid of three columns with a gap between them(indicated by &lt;code&gt;grid grid-cols-3 gap-1&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Also, the &lt;code&gt;transition duration-500 hover:text-purple-500&lt;/code&gt; adds a purple color transition of length 500ms to the title text on hover.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;application-logo&lt;/code&gt; Jetstream component has been reused here and is almost similar to the way you used it in the second episode. The only difference now is that you have added a blue border(indicated by &lt;code&gt;border border-blue-300&lt;/code&gt;) to it.&lt;/li&gt;
&lt;li&gt;The site title is the last element in this container. It takes two of the three grid columns, as indicated by the &lt;code&gt;col-span-2&lt;/code&gt; utility class.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Our next element is the button that displays and hides the menu on mobile devices:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You applied the &lt;code&gt;x-on:click&lt;/code&gt; Alpine.js handler on it. This fires the &lt;code&gt;onClick&lt;/code&gt; event, giving you the chance to toggle the &lt;code&gt;isOpen&lt;/code&gt; variable (&lt;code&gt;isOpen = !isOpen&lt;/code&gt;) to its opposite value(from true to false or vice versa).&lt;/li&gt;
&lt;li&gt;By specifying &lt;code&gt;lg:hidden&lt;/code&gt; you're hiding this element on large screen devices.&lt;/li&gt;
&lt;li&gt;The next encounter is the &lt;code&gt;:class&lt;/code&gt; Alpine.js attribute. This appends the values you define within it to the element's &lt;code&gt;class&lt;/code&gt; HTML attribute, allowing you  to add certain classes based on JavaScript variables. You've made use of this by adding a 180-degrees transform and transition to this button when &lt;code&gt;isOpen&lt;/code&gt; is true.&lt;/li&gt;
&lt;li&gt;The SVG element is made up of two path objects - a close sign and a hamburger sign representing closed and opened states of the menu, respectively. Thus, the first sign (close) is shown when &lt;code&gt;isOpen&lt;/code&gt; is true while the second sign (hamburger) is shown when &lt;code&gt;isOpen&lt;/code&gt; is false.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Finally, we come to the &lt;code&gt;div&lt;/code&gt; that contains the menu. The only new things here(on the Alpine side) are the attributes &lt;code&gt;@click.away="isOpen = false"&lt;/code&gt; and &lt;code&gt;x-show.transition="true"&lt;/code&gt;. The &lt;code&gt;@click.away&lt;/code&gt; implies clicking away from this &lt;code&gt;div&lt;/code&gt; closes the menu(it sets &lt;code&gt;isOpen&lt;/code&gt; to false). &lt;code&gt;x-show.transition="true"&lt;/code&gt; adds transition to the element when it's showing.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now add the &lt;code&gt;nav&lt;/code&gt; component to &lt;strong&gt;resources/views/layouts/guest.blade.php&lt;/strong&gt; layout file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;x-nav/&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This should come just after the opening &lt;code&gt;body&lt;/code&gt; tag. Save all files and reload your webpages to see the navigation bar:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqc2h19qfz8xx7kre6vlu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqc2h19qfz8xx7kre6vlu.png" alt="Navbar"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This brings us to the end of this episode. In our next episode, we'll create and set up the pages making up the dashboard for the blog.&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>tailwindcss</category>
      <category>alpinejs</category>
      <category>livewire</category>
    </item>
    <item>
      <title>Creating Your First Blog With TALL - Part Five</title>
      <dc:creator>Alhassan Kamil</dc:creator>
      <pubDate>Mon, 29 Mar 2021 22:43:00 +0000</pubDate>
      <link>https://forem.com/nayi10/creating-your-first-blog-with-tall-part-five-38mi</link>
      <guid>https://forem.com/nayi10/creating-your-first-blog-with-tall-part-five-38mi</guid>
      <description>&lt;p&gt;Hello and welcome to this episode of the tutorial series. In the previous episode you learnt how to create factories and seed our database with sample data. This episode will begin with building the UI part of our blog using Laravel Livewire components.&lt;/p&gt;

&lt;p&gt;At the end of the tutorial, you should be able to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Describe what a Livewire component is.&lt;/li&gt;
&lt;li&gt;  Create and modify Livewire components to suit your needs.&lt;/li&gt;
&lt;li&gt;  Use Tailwind CSS utility classes to practically layout elements in your Blade view files.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As usual, fasten up your seat belt and let's dive in. :)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: There is a starter project up to this episode which can be accessed on Github &lt;a href="https://github.com/nayi10/tall-blog" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Part Two Recap
&lt;/h3&gt;

&lt;p&gt;Remember in part two of this tutorial series we configured the public facing routes to return the default Laravel Jetstream &lt;strong&gt;welcome&lt;/strong&gt; page. If you also remember, there were exactly two routes for the public facing pages of our blog - the home and the category pages. The homepage will be a listing of our blog posts while the category page will list all blog posts of a particular category. You can always read part two of this tutorial series &lt;a href="https://blog.bandughana.com/posts/creating-your-first-blog-with-tall-part-two" rel="noopener noreferrer"&gt;here&lt;/a&gt; if you missed that part.&lt;/p&gt;

&lt;p&gt;You're going to work on those two pages and replace the &lt;strong&gt;welcome&lt;/strong&gt; page with a more interesting listing of your blog posts for this episode, albeit with introduction to some Tailwind CSS utilities. OK. Read on.&lt;/p&gt;

&lt;h3&gt;
  
  
  Introduction to Livewire Components
&lt;/h3&gt;

&lt;p&gt;Livewire components are reusable pieces of code that you can define once and use in different parts of your application. They are just like Laravel components but comes with the power of both Laravel and Livewire. By default, a Livewire component is created with a corresponding view file. Livewire component classes are also placed in the &lt;strong&gt;app/Http/Livewire&lt;/strong&gt; directory while their corresponding views are placed in the &lt;strong&gt;resources/views/livewire&lt;/strong&gt; directory.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating Livewire Components
&lt;/h3&gt;

&lt;p&gt;Livewire components are created by running the &lt;code&gt;make:livewire&lt;/code&gt; or &lt;code&gt;livewire:make&lt;/code&gt; Artisan commands in your terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;php artisan make:livewire PostItem
// or ...
php artisan livewire:make PostItem
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This creates the most basic Livewire component, which extends the base Livewire &lt;code&gt;Component&lt;/code&gt; class and contains a &lt;code&gt;render&lt;/code&gt; method - used for rendering views and inline text:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php // tall-blog/app/Http/Livewire/PostItem.php 
namespace App\\Http\\Livewire;

use Livewire\\Component;

class PostItem extends Component {
    public function render() {
        return view('livewire.post-item');
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and the corresponding view:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{{\-- tall-blog/resources/views/livewire/post-item.blade.php --}}
&amp;lt;div&amp;gt;
    {{\-- If you look to others for fulfillment, you will never truly be fulfilled. --}}
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Adding the &lt;code&gt;--inline&lt;/code&gt; option tells Livewire that your component is an &lt;em&gt;inline&lt;/em&gt; component and won't be returning any view in its &lt;code&gt;render&lt;/code&gt; method. So this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;php artisan make:livewire PostItem --inline
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;yields something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
public function render() {
    return &amp;lt;&amp;lt;&amp;lt;'blade'
            &amp;lt;div&amp;gt;&amp;lt;/div&amp;gt;
        blade;
}
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is important to understand that &lt;code&gt;public&lt;/code&gt; properties in a Livewire component are readily available in the component's view file, so you don't need to pass it through the &lt;code&gt;view&lt;/code&gt; method like you're used to do if you've worked with pure Laravel controllers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// This:
class PostItem extends Component {
    public $post;﻿
    public function render() {
        return view('livewire.post-item');
    }﻿
}

// is the same as this:
﻿class PostItem extends Component {
    public $post;﻿
    public function render() {
        return view('livewire.post-item', ['post' =&amp;gt; $post]);
    }﻿
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Rendering Livewire Components
&lt;/h3&gt;

&lt;p&gt;Livewire components are meant to be reusable. As a result, you can use them anywhere you would a Laravel component. Rendering a component can be done by either using the &lt;code&gt;&amp;lt;livewire:component-name /&amp;gt;&lt;/code&gt; tag syntax or by using the &lt;code&gt;@livewire('component-name')&lt;/code&gt; blade directive syntax:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div&amp;gt;
    &amp;lt;livewire:post-item /&amp;gt;
&amp;lt;/div&amp;gt;
{{-- Or --}}
&amp;lt;div&amp;gt;
    @livewire('post-item')
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Passing Parameters to Components
&lt;/h3&gt;

&lt;p&gt;You can pass parameters to a component by specifying those parameters like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;livewire:post-item :post="$post" /&amp;gt;
{{-- or --}}
@livewire('post-item', ['post' =&amp;gt; $post])
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the &lt;code&gt;$post&lt;/code&gt; variable will be available in the &lt;strong&gt;PostItem&lt;/strong&gt; component and view.&lt;/p&gt;

&lt;h3&gt;
  
  
  Accessing Route Parameters
&lt;/h3&gt;

&lt;p&gt;In a situation whereby you need to access route parameters like you would in a traditional Laravel controller, Livewire allows you to do that in the &lt;code&gt;mount&lt;/code&gt; method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class MyComponent extends Component {
    public $userId;

    public function mount($userId) {
        $this-&amp;gt;userId = $userId;
    }
﻿
    public function render() {
        return view('livewire.my-component');
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This feature makes it so powerful for Livewire components to mimic the behavior of Laravel controllers and also makes it easy to make full page components.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating Our Blog's Components
&lt;/h2&gt;

&lt;p&gt;Now that you have a solid understanding of Livewire components, let's move on to work on our blog. If you haven't yet done so from above, create your first Livewire component for the project by running this command in your terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;php artisan make:livewire PostItem
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This component represents one post item from a list in the home and category pages. Open the component class in &lt;strong&gt;app/Http/Livewire/PostItem.php&lt;/strong&gt; and add a public &lt;code&gt;$post&lt;/code&gt; property to the beginning. The component class should look similar to this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php // tall-blog/app/Http/Livewire/PostItem.php
namespace App\Http\Livewire;

use Livewire\Component;

class PostItem extends Component {
    public $post;

    public function render() {
        return view('livewire.post-item');
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As pointed out above, the &lt;code&gt;$post&lt;/code&gt; property will now be readily available in the view file for use since it is declared &lt;code&gt;public&lt;/code&gt;. Open the corresponding blade view file in &lt;strong&gt;resources/views/livewire/post-item.blade.php&lt;/strong&gt;. Make sure it contains the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{{-- tall-blog/resources/views/livewire/post-item.blade.php --}}
&amp;lt;article class="flex flex-col mb-2 rounded-md shadow-md md:mb-0"&amp;gt;
    &amp;lt;a href="{{ route('post-detail', ['slug' =&amp;gt; $post-&amp;gt;slug]) }}"&amp;gt;
        &amp;lt;img src='{{ asset("storage/posts/$post-&amp;gt;featured_image") }}' 
            alt="{{ $post-&amp;gt;title }}" class="w-full h-56 rounded-t-md"&amp;gt;
    &amp;lt;/a&amp;gt;
    &amp;lt;div class="p-3"&amp;gt;
        &amp;lt;h3 class="text-lg font-semibold text-gray-900"&amp;gt;
            &amp;lt;a href="{{ route('post-detail', ['slug' =&amp;gt; $post-&amp;gt;slug]) }}"&amp;gt;
                {{ $post-&amp;gt;title }}
            &amp;lt;/a&amp;gt;
        &amp;lt;/h3&amp;gt;
        &amp;lt;p class="text-gray-800"&amp;gt;
            &amp;lt;a href="{{ route('post-detail', ['slug' =&amp;gt; $post-&amp;gt;slug]) }}"&amp;gt;
                {{ $post-&amp;gt;excerpt }}
            &amp;lt;/a&amp;gt;
        &amp;lt;/p&amp;gt;
        &amp;lt;div class="flex flex-row justify-between mt-2"&amp;gt;
            &amp;lt;a href="{{ route('category', ['category' =&amp;gt; $post-&amp;gt;category]) }}" 
                 class="px-2 text-sm text-indigo-900 bg-indigo-100 rounded"&amp;gt;
                {{ $post-&amp;gt;category }}
            &amp;lt;/a&amp;gt;
            &amp;lt;small&amp;gt;
                {{ $post-&amp;gt;published_date }}
            &amp;lt;/small&amp;gt;
        &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
&amp;lt;/article&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First of all, you can see that we're making use of the &lt;code&gt;$post&lt;/code&gt; variable in this file, which contains a blog post entry. We're utilizing Tailwind CSS class utilities to style the root &lt;code&gt;&amp;lt;article&amp;gt;&lt;/code&gt; element. In this case, we have laid its contents in a &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Flexible_Box_Layout/Basic_Concepts_of_Flexbox" rel="noopener noreferrer"&gt;Flexbox&lt;/a&gt; with a &lt;code&gt;flex-direction&lt;/code&gt; of &lt;code&gt;col&lt;/code&gt; - meaning we want to lay the contents from the top to bottom. &lt;code&gt;mb-2&lt;/code&gt; is a utility class for 8-pixels margin-bottom value with &lt;code&gt;rounded-md&lt;/code&gt; and &lt;code&gt;shadow-md&lt;/code&gt; representing medium rounded and medium shadowed shapes respectively.&lt;/p&gt;

&lt;p&gt;Next is the anchor element (&lt;code&gt;a&lt;/code&gt; tag). We're referencing a named Route to route to the post detail page(using the &lt;code&gt;route&lt;/code&gt; helper function) which uses the post's slug to construct the link. Remember we didn't create the post detail route so you would need to add it just below the homepage route:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Route::get('/', function () {
     return view('welcome');
})-&amp;gt;name('home');

// Add below route
Route::get('{slug}', function ($slug) {
    return view('welcome');
})-&amp;gt;name('post-detail');
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next in the tree is the image, whose width we have made full (100%) with &lt;code&gt;w-full&lt;/code&gt; and whose height we have decided will be &lt;code&gt;h-56&lt;/code&gt; (equivalent to 224px) with its top rounded. The post image's &lt;code&gt;src&lt;/code&gt; attribute points to an image in the &lt;strong&gt;posts&lt;/strong&gt; folder which is in the &lt;code&gt;storage&lt;/code&gt; symlink we created earlier. &lt;code&gt;asset&lt;/code&gt; is also one of the helper functions that allows you to display assets(css, images, js) files in your blade views. The file itself is uploaded in the &lt;strong&gt;posts&lt;/strong&gt; folder while its name is saved into the database.&lt;/p&gt;

&lt;p&gt;The next block contains the title, excerpt, category and published date all wrapped in a nicely padded(with &lt;code&gt;p-3&lt;/code&gt;) &lt;code&gt;div&lt;/code&gt; element. Both the title and excerpt use a different shade of gray text color from Tailwind CSS's color utilities. The last thing worth noting is the fact that the category and published date of our post are also wrapped in a Flexbox &lt;code&gt;div&lt;/code&gt; container which runs from left to right (&lt;code&gt;row&lt;/code&gt;) with a &lt;code&gt;justify-between&lt;/code&gt; utility which ensures that these two elements are placed at the extreme ends of both left and right of the containing &lt;code&gt;div&lt;/code&gt; element.&lt;/p&gt;




&lt;p&gt;The post item component is now done. Let's create another component that will list all the posts on the homepage. This component will fetch all the posts from the database and display each in the post item component we created above. Enter the command to create the &lt;strong&gt;show-posts&lt;/strong&gt; component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;php artisan make:livewire ShowPosts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open the created component at &lt;strong&gt;app/Http/Livewire/ShowPosts.php&lt;/strong&gt; and make sure its contents is equal to this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php // tall-blog/app/Http/Livewire/ShowPosts.php
namespace App\Http\Livewire;

use App\Models\Post;
use Livewire\Component;

class ShowPosts extends Component {
    public $posts;

    public function mount() {
        $this-&amp;gt;posts = Post::where('is_published', true)-&amp;gt;get();
    }
    public function render() {
        return view('livewire.show-posts')-&amp;gt;layout("layouts/guest");
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;$posts&lt;/code&gt; property holds all our posts from the database, which we fetch when this component is mounted (this is why the query is put in the &lt;code&gt;mount&lt;/code&gt; method). We're only interested in posts that are published. We have also specified the layout to use (i.e &lt;strong&gt;guest&lt;/strong&gt; layout file). By default, Livewire uses the &lt;strong&gt;resources/views/layouts/app.blade.php&lt;/strong&gt; layout file. However, because Jetstream adds authentication and other checks to that layout, using the app layout file without those checks in place will lead to errors, that's the reason we're using the &lt;strong&gt;resources/views/layouts/guest.blade.php&lt;/strong&gt; layout file.&lt;/p&gt;

&lt;p&gt;Now open the corresponding &lt;strong&gt;resources/views/livewire/show-posts.bladed.php&lt;/strong&gt; blade view and enter the following in it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div class="gap-4 m-2 md:grid md:grid-cols-2 lg:grid-cols-4"&amp;gt;
    @foreach ($posts as $post)
        @livewire('post-item', ['post' =&amp;gt; $post], key($post-&amp;gt;id))
    @endforeach
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This one is simpler than you might have guessed. We're looping through the &lt;code&gt;$posts&lt;/code&gt; collection and rendering each using the &lt;code&gt;PostItem&lt;/code&gt; component we created earlier, passing the &lt;code&gt;$post&lt;/code&gt; to its &lt;code&gt;post&lt;/code&gt; parameter and giving its key the post id. The key is used to uniquely differentiate the current post item from the others and is very necessary when you, for example, want to toggle a post's visibility.&lt;/p&gt;

&lt;p&gt;On the Tailwind part, we're displaying the posts in&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; a block container on small screens,&lt;/li&gt;
&lt;li&gt; a grid container with two columns in medium screen devices and&lt;/li&gt;
&lt;li&gt; a grid container with four columns in large+ screen devices&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;All these with a 16-px gap between each item. Of course, and an 8-pixel margin.&lt;/p&gt;

&lt;p&gt;Now change the homepage route to the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
Route::get('/', App\Http\Livewire\ShowPosts::class)-&amp;gt;name('home');
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hook up your terminal, run &lt;code&gt;php artisan serve&lt;/code&gt; and open your browser to &lt;a href="http://127.0.0.1:8000" rel="noopener noreferrer"&gt;http://127.0.0.1:8000&lt;/a&gt; and you should see posts in the homepage:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flsk9h4bwzm7uzfoo6e16.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flsk9h4bwzm7uzfoo6e16.png" alt="Blog Homepage"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now create the last Livewire component, which will display all posts from a particular category, by running this Artisan command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;php artisan make:livewire CategoryPosts --inline
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We have made the &lt;code&gt;CategoryPosts&lt;/code&gt; component inline because it is going to reuse the &lt;strong&gt;show-posts&lt;/strong&gt; component view file. Since there is nothing different between the two except filtering from the database, it is simpler using this approach.&lt;/p&gt;

&lt;p&gt;Modify the &lt;code&gt;CategoryPosts&lt;/code&gt; component to match the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php 
// tall-blog/app/Http/Livewire/CategoryPosts.php

namespace App\Http\Livewire;

use App\Models\Post;
use Livewire\Component;

class CategoryPosts extends Component {
    public $posts;

    public function mount($category) {
        $this-&amp;gt;posts = Post::where('category', $category)
             -&amp;gt;where('is_published', true)
             -&amp;gt;get();
    }
    public function render() {
        return view('livewire.show-posts')
                 -&amp;gt;layout("layouts/guest");
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is almost the same as the &lt;code&gt;ShowPosts&lt;/code&gt; component except that we've changed the query to fetch based on the given category query string passed to the &lt;code&gt;mount&lt;/code&gt; method. Change the category route to the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
Route::get('categories/{category}', CategoryPosts::class)-&amp;gt;name('category');
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Start the built-in PHP server if it's not running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;php artisan serve
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now go back to your homepage and click on any category. It should send you to the category page displaying posts in the same category:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzr7jubt2xtij5gkdws9r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzr7jubt2xtij5gkdws9r.png" alt="Category Page Showing the est Category"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This brings us to the end of this episode. I hope you really enjoyed the tutorial and I'd love to see you reading the next episode. We post updates on both our &lt;a href="https://twitter.com/bandughana/" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; and &lt;a href="https://www.facebook.com/bandughana" rel="noopener noreferrer"&gt;Facebook&lt;/a&gt; pages. If you don't mind, you can follow any of our social media pages to get notified when a new post is published.&lt;/p&gt;

&lt;p&gt;Twitter: &lt;a href="https://twitter.com/bandughana/" rel="noopener noreferrer"&gt;https://twitter.com/bandughana&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Facebook: &lt;a href="https://www.facebook.com/bandughana" rel="noopener noreferrer"&gt;https://www.facebook.com/bandughana&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thank you and see you for the next post.&lt;/p&gt;

</description>
      <category>tailwindcss</category>
      <category>alpinejs</category>
      <category>laravel</category>
      <category>livewire</category>
    </item>
    <item>
      <title>Creating Your First Blog With TALL - Part Four</title>
      <dc:creator>Alhassan Kamil</dc:creator>
      <pubDate>Thu, 18 Mar 2021 01:12:00 +0000</pubDate>
      <link>https://forem.com/nayi10/creating-your-first-blog-with-tall-part-four-d79</link>
      <guid>https://forem.com/nayi10/creating-your-first-blog-with-tall-part-four-d79</guid>
      <description>&lt;p&gt;Welcome back to today's episode. You learnt everything about setting up your database: creating models, different approaches to running database queries and running migrations in the last episode. This episode builds on that by teaching you how to create database factories and seed our database tables with sample data we can use for our blog.&lt;/p&gt;

&lt;p&gt;You should be able to learn the following at the end of this tutorial:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What model factories are.&lt;/li&gt;
&lt;li&gt;How to create and write model factories.&lt;/li&gt;
&lt;li&gt;What database seeders are.&lt;/li&gt;
&lt;li&gt;How to create and write database seeders.&lt;/li&gt;
&lt;li&gt;How to run database seeders in order to seed our blog's database with some sample data.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Model Factories
&lt;/h2&gt;

&lt;p&gt;Model factories in Laravel allow you to generate dummy/fake data using the &lt;a href="https://github.com/fzaninotto/Faker"&gt;Faker&lt;/a&gt; PHP library. The Faker library allows generating random data by specifying various attributes. With factories you define fake data to be generated for each attribute/column of your model. This not only saves you time of manually inserting database records, but enables you to save thousands of records in your database within seconds.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating Factories
&lt;/h3&gt;

&lt;p&gt;Factories are created using the Laravel make:factory Artisan command, like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;php artisan make:factory PostFactory
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This creates the &lt;code&gt;PostFactory&lt;/code&gt; factory in the &lt;strong&gt;database/factories&lt;/strong&gt; folder with no model specified. To specify a model the factory belongs to, you can append the --model option to the above command. You can also create a factory when creating a new model with -f option and that model will eventually be created when the factory is run, as we did in the previous tutorial.&lt;/p&gt;

&lt;p&gt;If you open the &lt;strong&gt;database/factories/PostFactory.php&lt;/strong&gt; file you should notice the factory class definition is similar to this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php

namespace Database\Factories;

use App\Models\Post;
use Illuminate\Database\Eloquent\Factories\Factory;

class PostFactory extends Factory
{
    /**
     * The name of the factory's corresponding model.
     *
     * @var string
     */
    protected $model = Post::class;

    /**
     * Define the model's default state.
     *
     * @return array
     */
    public function definition()
    {
        return [
            //
        ];
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A Laravel factory basically extends the base Factory class and defines two important members: a &lt;code&gt;$model&lt;/code&gt; the factory will be creating and a &lt;code&gt;definition&lt;/code&gt; method that defines the values to be applied when the factory is executed. The &lt;code&gt;$model&lt;/code&gt; property will be automatically filled when you create the factory with the &lt;code&gt;make:factory&lt;/code&gt; command by specifying the &lt;code&gt;--model&lt;/code&gt; option and when you specify the &lt;code&gt;-f&lt;/code&gt; option when creating a model.&lt;/p&gt;

&lt;h3&gt;
  
  
  Writing Factories
&lt;/h3&gt;

&lt;p&gt;Though our factory is created, we'll have to tell Laravel how we want our data to be generated when this factory is run. To do that, we have to define each attribute/column of the &lt;code&gt;Post&lt;/code&gt; model/post table and its corresponding value as an associative array of key-value pairs in the &lt;code&gt;definition&lt;/code&gt; method of our factory.&lt;/p&gt;

&lt;p&gt;The base Laravel Factory class has a Faker instance and so each factory has access to this Faker instance. You generate values for each of your columns using this Faker instance. So, the definition for our &lt;code&gt;Post&lt;/code&gt; model's attributes will look like below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// tall-blog/database/factories/PostFactory.php
...
...
...
    /**
     * Define the model's default state.
     *
     * @return array
     */
    public function definition()
    {
        return [
            'category' =&amp;gt; $this-&amp;gt;faker-&amp;gt;text(100),
            'body' =&amp;gt; $this-&amp;gt;faker-&amp;gt;paragraphs(15, true),
            'title' =&amp;gt; $this-&amp;gt;faker-&amp;gt;sentence(15),
            'excerpt' =&amp;gt; $this-&amp;gt;faker-&amp;gt;sentences(3, true),
            'featured_image' =&amp;gt; "post.png",
            'published_date' =&amp;gt; $this-&amp;gt;faker-&amp;gt;date(),
            'user_id' =&amp;gt; 1,
        ];
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You notice that we've "hard-coded" some values such as the &lt;code&gt;user_id&lt;/code&gt; and the &lt;code&gt;featured_image&lt;/code&gt; fields. This is because auto-generating these values will not be the best since they depend on other factors. We've also left out the &lt;code&gt;is_published&lt;/code&gt; field since we provided a default &lt;code&gt;false&lt;/code&gt; value for it and want a post to stay unpublished until we decide to publish it.&lt;/p&gt;

&lt;p&gt;One thing we'd want to add to our factory is a published &lt;a href="https://laravel.com/docs/8.x/database-testing#factory-states"&gt;state&lt;/a&gt;. This can be used to modify the default value of the &lt;code&gt;is_published&lt;/code&gt; column(which, by default, is &lt;code&gt;false&lt;/code&gt;) whenever we want to make a particular post as published. Add this method at the end of the &lt;code&gt;PostFactory&lt;/code&gt; class to do that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// tall-blog/database/factories/PostFactory.php
...
...
... 
/**
     * Indicates the post is published.
     *
     * @return \Illuminate\Database\Eloquent\Factories\Factory
     */
    public function published()
    {
        return $this-&amp;gt;state(function (array $attributes) {
            return [
                'is_published' =&amp;gt; true,
                'published_date' =&amp;gt; now(),
            ];
        });
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You see that this method uses the &lt;code&gt;state&lt;/code&gt; method provided by the base factory class, which accepts a closure containing the attributes we defined for this factory in the &lt;code&gt;definition&lt;/code&gt; method as argument and returns the attributes to modify. Here we're just changing the &lt;code&gt;is_published&lt;/code&gt; column to &lt;code&gt;true&lt;/code&gt; and providing the current date time as the published date.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using Factories
&lt;/h3&gt;

&lt;p&gt;After creating and defining your factories, the next thing is to use them to create models. This can be achieved by using the &lt;code&gt;factory&lt;/code&gt; method provided by the &lt;code&gt;HasFactory&lt;/code&gt; trait we talked about in the previous episode like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//Creates a post without persisting to database
$post = Post::factory()-&amp;gt;make();

// Same as above, but creates five(5) posts
$post = Post::factory()-&amp;gt;count(5)-&amp;gt;make();

// Same as above, but sets the published state to true
$post = Post::factory()-&amp;gt;count(5)-&amp;gt;published()-&amp;gt;make()﻿;

//Creates a post and persists it to database
$post = Post::factory()-&amp;gt;create();

// Same as persisting, but creates five(5) posts
$post = Post::factory()-&amp;gt;count(5)-&amp;gt;create();

// Same as persisting, but sets the published state to true
$post = Post::factory()-&amp;gt;count(5)-&amp;gt;published()-&amp;gt;create()﻿;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Database Seeders
&lt;/h2&gt;

&lt;p&gt;While model factories let you create sample data for your models, database seeders actually insert these data into the database, though seeders don't necessarily have to depend on factories to insert data. This means you can either use factories to seed data into your database or manually utilize Eloquent and the Query Builder to do so.&lt;/p&gt;

&lt;p&gt;Seeders are placed in the &lt;strong&gt;database/seeders&lt;/strong&gt; directory of your Laravel installation and, by default, contain a single &lt;code&gt;run&lt;/code&gt; method - which is called when the &lt;code&gt;db:seed&lt;/code&gt; command is executed. By default, Laravel creates a &lt;code&gt;DatabaseSeeder&lt;/code&gt; class for you out of the box. You can use this class to run other seeders by providing them to the &lt;code&gt;call&lt;/code&gt; method. This allows you to properly organize and arrange your seeders in any order you desire and also helps you run many seeders at once.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating Database Seeders
&lt;/h3&gt;

&lt;p&gt;Just like other features of the Laravel framework, database seeders are created by running Artisan commands. You execute the &lt;code&gt;make:seeder&lt;/code&gt; Artisan command and provide the name of the seeder to create, like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;php artisan make:seeder PostSeeder
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Writing Database Seeders
&lt;/h3&gt;

&lt;p&gt;As I already mentioned above, seeders, by default, contains a single &lt;code&gt;run&lt;/code&gt; method that is executed when the &lt;code&gt;db:seed&lt;/code&gt; command is run. In the &lt;code&gt;run&lt;/code&gt; method you insert your data by manually running Eloquent queries or by using factories. We're using the latter for this tutorial.&lt;/p&gt;

&lt;p&gt;To insert data, we're going to make use of the &lt;code&gt;PostFactory&lt;/code&gt; we created in the previous sections. Within the &lt;code&gt;run&lt;/code&gt; method put this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// tall-blog/database/seeders/PostSeeder.php
...
...
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        Post::factory()
                -&amp;gt;count(20)
                -&amp;gt;published()
                -&amp;gt;create();
    }
...
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We're creating 20 records of the &lt;code&gt;Post&lt;/code&gt; model into our database whilst specifying that each post's state must be published, as opposed to the default unpublished behavior.&lt;/p&gt;

&lt;p&gt;The last thing we want to do is open the &lt;code&gt;DatabaseSeeder&lt;/code&gt; class and add the &lt;code&gt;PostSeeder&lt;/code&gt; class to the &lt;code&gt;call&lt;/code&gt; method's arguments in the &lt;code&gt;run&lt;/code&gt; method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// tall-blog/database/seeders/DatabaseSeeder.php
...
...
    /**
     * Seed the application's database.
     *
     * @return void
     */
    public function run()
    {
        $this-&amp;gt;call([
            PostSeeder::class,
        ]);
    }
...
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Though we could just run the &lt;code&gt;PostSeeder&lt;/code&gt; without adding it here, doing it this way keeps your seeders organized and decoupled and can be run from a single central point.&lt;/p&gt;

&lt;h3&gt;
  
  
  Running the Seeder
&lt;/h3&gt;

&lt;p&gt;Now that our seeder and factory are defined, we can proceed to seed our database with sample data. As pointed out already, seeders are run using the &lt;code&gt;db:seed&lt;/code&gt; command and optionally providing the &lt;code&gt;--class&lt;/code&gt; option, which is used to specify the seeder class we want to run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;php artisan db:seed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I didn't provide the &lt;code&gt;--class&lt;/code&gt; option because Laravel runs the &lt;code&gt;DatabaseSeeder&lt;/code&gt; class by default if it is not provided. Running the above will produce an output such as this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kamil@kamil-sc650:~/Projects/Web/tall-blog$ php artisan db:seed
Seeding: Database\Seeders\PostSeeder
Seeded: Database\Seeders\PostSeeder (3,633.28ms)
Database seeding completed successfully.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check your database to see the posts table filled with 20 posts.&lt;/p&gt;

&lt;p&gt;This brings us to the end of the fourth episode of Creating Your First Blog With TALL tutorial series. Our next episode will teach you how to create and write your first Livewire components. See you then.&lt;/p&gt;

</description>
      <category>tailwindcss</category>
      <category>laravel</category>
      <category>alpinejs</category>
      <category>livewire</category>
    </item>
    <item>
      <title>Creating Your First Blog With TALL - Part Three</title>
      <dc:creator>Alhassan Kamil</dc:creator>
      <pubDate>Sat, 13 Mar 2021 02:01:00 +0000</pubDate>
      <link>https://forem.com/nayi10/creating-your-first-blog-with-tall-part-three-5eoe</link>
      <guid>https://forem.com/nayi10/creating-your-first-blog-with-tall-part-three-5eoe</guid>
      <description>&lt;p&gt;Hello and welcome to the third episode of the &lt;strong&gt;Creating Your First Blog With TALL&lt;/strong&gt; tutorial series. You learnt how to configure Jetstream, setup database connection, create routes, create a symlink and change the default Jetstream logo in the previous episode.&lt;/p&gt;

&lt;p&gt;In this episode, you're going to learn how to setup and run migrations to create the tables for our blog and create the needed models for the project. At the end, you should be able to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Get a basic understanding of the alternative ways Laravel lets you run database queries.&lt;/li&gt;
&lt;li&gt; Know and explain what Laravel Eloquent models and migrations are.&lt;/li&gt;
&lt;li&gt; Create models and migrations for any Laravel project&lt;/li&gt;
&lt;li&gt; Run migrations for our project&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Okay. Take a sip of coffee and let's dive in right away. :)&lt;/p&gt;

&lt;h2&gt;
  
  
  The Alternative Ways Database Queries are Run in Laravel
&lt;/h2&gt;

&lt;p&gt;If you're coming from the traditional way of developing web apps using plain PHP, you may be blown away by how much Laravel eases the pain of handling database operations. Think about having to manually write SQL queries, take care of SQL vulnerabilities like SQL injection, and many others that you'll have to deal with, all taken care of by the framework.&lt;/p&gt;

&lt;p&gt;In Laravel, you not only have to not manually write SQL commands in your PHP code, you have several options on how you want to run your database queries, including what you're used to when developing using plain PHP (albeit in a very simplified, easier way). You can write Laravel database operations using either raw SQL, the Laravel &lt;a href="https://laravel.com/docs/8.x/queries"&gt;Query Builder&lt;/a&gt; or &lt;a href="https://laravel.com/docs/8.x/eloquent#introduction"&gt;Eloquent&lt;/a&gt; models. We'll only look at the latter two in this tutorial. You can learn more about running raw SQL queries &lt;a href="https://laravel.com/docs/8.x/database#running-queries"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using Query Builder to Run Database Queries
&lt;/h3&gt;

&lt;p&gt;The Query Builder is a general and convenient way of creating and running database queries. It can be used to run most of the database query operations supported by your database driver through the &lt;a href="https://laravel.com/api/5.8/Illuminate/Support/Facades/DB.html"&gt;DB&lt;/a&gt; facade. The &lt;code&gt;DB&lt;/code&gt; facade provides a convenient &lt;code&gt;table&lt;/code&gt; method you can use to run queries against a given table. Other methods of the &lt;code&gt;DB&lt;/code&gt; facade such as &lt;a href="https://laravel.com/docs/8.x/queries#insert-statements"&gt;insert&lt;/a&gt;, &lt;a href="https://laravel.com/docs/8.x/queries#update-statements"&gt;update&lt;/a&gt;, &lt;a href="https://laravel.com/docs/8.x/queries#select-statements"&gt;select&lt;/a&gt;, &lt;a href="https://laravel.com/docs/8.x/queries#retrieving-a-single-row-column-from-a-table"&gt;where&lt;/a&gt;, &lt;a href="https://laravel.com/docs/8.x/queries#delete-statements"&gt;delete&lt;/a&gt;, &lt;a href="https://laravel.com/docs/8.x/queries#running-database-queries"&gt;get&lt;/a&gt; etc can then be chained to the &lt;code&gt;table&lt;/code&gt; method to run those respective queries like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;use Illuminate\Support\Facades\DB;

// Select all users
$users = DB::table('users')-&amp;gt;get();

// Select only approved users
$users = DB::table('users')-&amp;gt;where('approved', true)-&amp;gt;get();﻿

// Delete all users
DB::table('users')-&amp;gt;delete();

// Insert a new user
DB::table('users')-&amp;gt;insert([
    'username' =&amp;gt; 'awesomeuser',
    'email' =&amp;gt; 'awesomeuser@example.com'﻿
]);﻿﻿

// Update an existing user
$userAffected = DB::table('users')
              -&amp;gt;where('id', 2)
              -&amp;gt;update(['username' =&amp;gt; 'mynewawesomename']);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Using Eloquent to Run Database Queries
&lt;/h3&gt;

&lt;p&gt;Laravel Eloquent is an &lt;a href="https://en.wikipedia.org/wiki/Object-relational_mapping"&gt;Object-Relational Mapper&lt;/a&gt; (ORM) that enables you to run database queries using models. Models allow you to store data and handles the logic that goes with it. With Eloquent, each table has a corresponding model class that deals with querying and storing data in that table. Since the rest of this tutorial will entirely be on using Eloquent, I'll leave explanation of Eloquent models here and continue with the other sections.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating Eloquent Models and Migrations
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Eloquent Models
&lt;/h3&gt;

&lt;p&gt;As I pointed out above, Eloquent models help you to store data and its related logic. Models act like data warehouse operators - any data entering/leaving the warehouse goes through them, they keep track of and update records, they can filter and sort items out, they know how to sanitize and check data for integrity and so much more.&lt;/p&gt;

&lt;h3&gt;
  
  
  Database Migrations
&lt;/h3&gt;

&lt;p&gt;The Laravel docs does so well in explaining what migrations are and I won't repeat myself here. This is what the docs say about migrations:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Migrations are like version control for your database, allowing your team to define and share the application's database schema definition. If you have ever had to tell a teammate to manually add a column to their local database schema after pulling in your changes from source control, you've faced the problem that database migrations solve.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  How to Create Eloquent Models
&lt;/h3&gt;

&lt;p&gt;Like many other Laravel features, you can create Eloquent models by running &lt;a href="https://laravel.com/docs/8.x/artisan"&gt;Artisan commands&lt;/a&gt; from the terminal. To create a model, use the &lt;code&gt;make:model&lt;/code&gt; command like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;php artisan make:model ModelName
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Where &lt;code&gt;ModelName&lt;/code&gt; is the actual name of the model you want to create. This creates the given model (which extends &lt;code&gt;\Illuminate\Database\Eloquent\Model&lt;/code&gt;) in the &lt;strong&gt;app\Models&lt;/strong&gt; directory. You can optionally pass &lt;code&gt;-m&lt;/code&gt;, &lt;code&gt;-c&lt;/code&gt;, &lt;code&gt;-f&lt;/code&gt;, &lt;code&gt;-s&lt;/code&gt; to respectively create a &lt;a href="https://laravel.com/docs/8.x/migrations#introduction"&gt;migration&lt;/a&gt;, &lt;a href="https://laravel.com/docs/8.x/controllers"&gt;controller&lt;/a&gt;, &lt;a href="https://laravel.com/docs/8.x/database-testing#defining-model-factories"&gt;factory&lt;/a&gt; or a &lt;a href="https://laravel.com/docs/8.x/seeding"&gt;database seeder&lt;/a&gt;(we'll explain these later in the coming series) in addition to the given model, or even combine these options, like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;php artisan make:model ModelName -m // creates migration too
php artisan make:model ModelName -c // creates controller too
php artisan make:model ModelName -f // also creates a factory
php artisan make:model ModelName -s // also creates a database seeder
php artisan make:model ModelName -mfcs // creates migration, factory, controller and seeder
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  How to Create Migrations
&lt;/h3&gt;

&lt;p&gt;Migrations are created by running the &lt;code&gt;make:migration&lt;/code&gt; Artisan command, passing the name of the migration and an optional &lt;code&gt;--path&lt;/code&gt; argument to specify where the migration should be placed. So creating a migration for &lt;code&gt;ModelName&lt;/code&gt; above will look like below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;php artisan make:migration create_model_names_table
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will create a &lt;strong&gt;create_model_names_table&lt;/strong&gt; migration in the &lt;strong&gt;database/migrations&lt;/strong&gt; directory with two methods: &lt;code&gt;up&lt;/code&gt; and &lt;code&gt;down&lt;/code&gt;. &lt;code&gt;up&lt;/code&gt; is used to add tables, indices and columns while &lt;code&gt;down&lt;/code&gt; reverses these actions. For an in-depth understanding of migrations and models, please consult the official &lt;a href="https://laravel.com/docs/8.x/"&gt;docs&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating Models and Migrations for Our Blog
&lt;/h3&gt;

&lt;p&gt;Now that you have learnt what models and migrations are and how to create them, lets move on to create the models and migrations our blog will need. Because this is an introductory tutorial, our blog will only have one &lt;code&gt;Post&lt;/code&gt; model in addition to the built-in &lt;code&gt;User&lt;/code&gt; model (in a real world blog you'll definitely want to add other models such as category and tag models, but we don't wanna make this tutorial complicated and so we'll keep things as simple as possible.). And because there is a relationship between a blog post and the user who wrote it, we'll have to establish a database relationship here.&lt;/p&gt;

&lt;p&gt;In any blogging system, a blog post belongs to a particular user. A user can have as many blog posts as they choose to. In this case of ours, a blog post cannot belong to multiple users, so we have a one-to-many relationship between users and posts. Laravel supports different kinds of entity relationships and one-to-many is just one of them we'll use in this tutorial.&lt;/p&gt;

&lt;p&gt;To define the relationship a user has on posts, open the &lt;strong&gt;app/Models/User.php&lt;/strong&gt; file and add this method to the end of it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// tall-blog/app/Models/User.php
...
...
...
/**
* Get the posts for this user
*/
public function posts() {
    return $this-&amp;gt;hasMany(Post::class);
}
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This creates a one-to-many relationship to the &lt;code&gt;Post&lt;/code&gt; model and allows us to get a user's posts by calling &lt;code&gt;$user-&amp;gt;posts&lt;/code&gt; on an existing &lt;code&gt;$user&lt;/code&gt; object. If you see errors that the &lt;code&gt;Post&lt;/code&gt; class doesn't exist just ignore it since that's what we're going to create next.&lt;/p&gt;

&lt;p&gt;Create the &lt;code&gt;Post&lt;/code&gt; model by running the &lt;code&gt;make:model&lt;/code&gt; command and by specifying the &lt;code&gt;-m&lt;/code&gt;, &lt;code&gt;-s&lt;/code&gt;, and &lt;code&gt;-f&lt;/code&gt; options:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;php artisan make:model Post -mfs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will create the &lt;code&gt;Post&lt;/code&gt; model in &lt;strong&gt;app/Models&lt;/strong&gt;. In addition, a new migration will be created in the &lt;strong&gt;database/migrations&lt;/strong&gt; directory, a new model factory in &lt;strong&gt;database/factories&lt;/strong&gt; and a database seeder in &lt;strong&gt;database/seeders&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Open the &lt;code&gt;app/Models/Post.php&lt;/code&gt; model file and make sure its contents is exactly as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// tall-blog/app/Models/Post.php
&amp;lt;?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Post extends Model {
    use HasFactory;

    /**
     * Columns that are mass assignable
     */
    protected $fillable = [
        'title', 'excerpt', 'body', 'category',
        'featured_image', 'published_date',
        'is_published', 'user_id'
    ];

    /**
     * Returns the user for this post
     */
    public function user() {
        return $this-&amp;gt;belongsTo(User::class)-&amp;gt;withDefault();
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First of all, we're importing the &lt;code&gt;HasFactory&lt;/code&gt; facade and the base Model class. Using the &lt;code&gt;HasFactory&lt;/code&gt; facade here means the &lt;code&gt;Post&lt;/code&gt; class has access to the &lt;code&gt;factory&lt;/code&gt; method of the &lt;code&gt;HasFactory&lt;/code&gt; facade, which is used to create factories. Our &lt;code&gt;Post&lt;/code&gt; class extends the base &lt;code&gt;Model&lt;/code&gt; class, which every model extends and therefore, will inherit all the methods available in the &lt;code&gt;Model&lt;/code&gt; class. We have also defined the &lt;code&gt;$fillable&lt;/code&gt; array property of the base &lt;code&gt;Model&lt;/code&gt; class, which lists the attributes of the &lt;code&gt;Post&lt;/code&gt; model that are &lt;a href="https://laravel.com/docs/8.x/eloquent#mass-assignment"&gt;mass assignable&lt;/a&gt;. Remember these attributes are also the columns for our posts table.&lt;/p&gt;

&lt;p&gt;Lastly, we have defined a &lt;a href="https://laravel.com/docs/8.x/eloquent-relationships#one-to-many-inverse"&gt;reverse one-to-many relationship&lt;/a&gt; between a post and its owner - a user. Just like the one-to-many relationship we defined for the &lt;code&gt;User&lt;/code&gt; model, adding the reverse relationship this way enables us to query an existing &lt;code&gt;Post&lt;/code&gt; object's user by simply calling &lt;code&gt;$post-&amp;gt;user&lt;/code&gt;.&lt;/p&gt;




&lt;p&gt;We already learnt how to create migrations and we have even created the &lt;strong&gt;create_posts_table&lt;/strong&gt; migration above when we run the &lt;code&gt;make:model&lt;/code&gt; with the &lt;code&gt;-m&lt;/code&gt; option specified. As I mentioned already, this migration is located in the &lt;strong&gt;database/migrations&lt;/strong&gt; directory. Open it(Laravel prepends the current date to a migration's name when you create it, so you'd have to consider that when you're looking for the migration) and ensure the &lt;code&gt;up&lt;/code&gt; method looks exactly as below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// tall-blog/database/migrations/2021_03_10_141045_create_posts_table.php 
/**
 * Run the migrations.
 *
 * @return void
*/
public function up() {
    Schema::create('posts', function (Blueprint $table) {
        $table-&amp;gt;id();
        $table-&amp;gt;string('category');
        $table-&amp;gt;string('excerpt');
        $table-&amp;gt;longText('body');
        $table-&amp;gt;string('title');
        $table-&amp;gt;boolean('is_published')-&amp;gt;default(false);
        $table-&amp;gt;string('featured_image');
        $table-&amp;gt;dateTime('published_date');
        $table-&amp;gt;foreignId('user_id')-&amp;gt;constrained();
        $table-&amp;gt;timestamps();
    });
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All we're doing here is creating the '&lt;strong&gt;posts&lt;/strong&gt;' table using the &lt;code&gt;create&lt;/code&gt; method from the &lt;code&gt;Schema&lt;/code&gt; facade. This method accepts the table to create as the first argument and a closure that uses the given &lt;code&gt;Blueprint&lt;/code&gt; to define columns for the table. Ignoring all the column types (which you can learn &lt;a href="https://laravel.com/docs/8.x/migrations#available-column-types"&gt;here&lt;/a&gt;), we're also specifying an auto-incrementing ID column(from &lt;code&gt;$table-&amp;gt;id()&lt;/code&gt;) for our table, a foreign ID constraint that references the &lt;strong&gt;'users'&lt;/strong&gt; table at the database level(from &lt;code&gt;$table-&amp;gt;foreignId('user_id')-&amp;gt;constrained()&lt;/code&gt;), and a timestamps columns (from &lt;code&gt;$table-&amp;gt;timestamps()&lt;/code&gt;) that will automatically create a &lt;strong&gt;created_at&lt;/strong&gt; and &lt;strong&gt;updated_at&lt;/strong&gt; columns for us.&lt;/p&gt;

&lt;p&gt;Save the file. Ensure your database server is running and run the migrations to create the posts table:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;php artisan migrate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If everything went well, you should get an output such as this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kamil@kamil-sc650:~/Projects/Web/tall-blog$ php artisan migrate
Migrating: 2020_05_21_100000_create_teams_table
Migrated: 2020_05_21_100000_create_teams_table (3,058.26ms)
Migrating: 2020_05_21_200000_create_team_user_table
Migrated: 2020_05_21_200000_create_team_user_table (1,294.05ms)
Migrating: 2020_05_21_300000_create_team_invitations_table
Migrated: 2020_05_21_300000_create_team_invitations_table (3,464.26ms)
Migrating: 2021_03_10_141045_create_posts_table
Migrated: 2021_03_10_141045_create_posts_table (3,663.84ms)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can check to see the created tables in the &lt;code&gt;tall_blog&lt;/code&gt; database by using the terminal client for your database server or a GUI program such as &lt;a href="https://www.phpmyadmin.net/"&gt;phpMyAdmin&lt;/a&gt;, if you're using MySQL.&lt;/p&gt;

&lt;p&gt;This brings us to the end of this episode of the &lt;strong&gt;Creating Your First Blog With TALL&lt;/strong&gt; tutorial series and I hope you enjoyed the tutorial. In the next episode, you'll learn how to create model factories and database seeders in order to fill our database with sample data.&lt;/p&gt;

&lt;p&gt;See you for the next post.&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>tailwindcss</category>
      <category>alpinejs</category>
      <category>livewire</category>
    </item>
    <item>
      <title>Creating Your First Blog With TALL - Part Two</title>
      <dc:creator>Alhassan Kamil</dc:creator>
      <pubDate>Sun, 07 Mar 2021 02:56:00 +0000</pubDate>
      <link>https://forem.com/nayi10/creating-your-first-blog-with-tall-part-two-2l1b</link>
      <guid>https://forem.com/nayi10/creating-your-first-blog-with-tall-part-two-2l1b</guid>
      <description>&lt;p&gt;You're warmly welcome to the second part of &lt;strong&gt;Creating Your First Blog With TALL (Tailwind CSS, Alpinejs, Laravel, Livewire)&lt;/strong&gt; tutorial series. In the previous episode, we delved into some basic introduction to the TALL stack and set our development machine up for building websites with the TALL stack. We also looked at what each item in the stack does. For the benefit of doubt, you can always read part one of this tutorial series &lt;a href="https://blog.bandughana.com/posts/creating-your-first-blog-with-tall-part-one" rel="noopener noreferrer"&gt;here&lt;/a&gt; if you haven't done so.&lt;/p&gt;

&lt;p&gt;For this part of the tutorial series, you'll build upon the first part by configuring Laravel Jetstream and Fortify, database connection, routes, creating a symlink to the &lt;strong&gt;public&lt;/strong&gt; folder to make file uploads possible and changing the default application logo.&lt;/p&gt;

&lt;p&gt;At the end of this tutorial, you'll learn:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;How to configure Jetstream and Fortify to enable profile photo uploads and email verification respectively.&lt;/li&gt;
&lt;li&gt;How to configure a freshly installed Laravel database connection using the &lt;strong&gt;.env&lt;/strong&gt; file.&lt;/li&gt;
&lt;li&gt;How to create routes in a Laravel application.&lt;/li&gt;
&lt;li&gt;How to create a symlink to the &lt;strong&gt;public&lt;/strong&gt; folder for file uploads.&lt;/li&gt;
&lt;li&gt;How to change the default Laravel Jetstream app logo to your own logo.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In the previous edition, I indicated we're going to create models and migrations but it seems this episode has gotten too long and adding that will make it worse, so I decided to send that part to the next session. OK, let's get going. :)&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuring Jetstream and Fortify
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Configuring Jetstream
&lt;/h3&gt;

&lt;p&gt;When you ran &lt;code&gt;php artisan jetstream:install&lt;/code&gt; in the first part of this tutorial series, Jetstream configuration files were published to your project's &lt;strong&gt;config&lt;/strong&gt; folder. These include config files for both Jetstream (named &lt;strong&gt;jetstream.php&lt;/strong&gt;) and Laravel Fortify (named &lt;strong&gt;fortify.php&lt;/strong&gt;). The &lt;strong&gt;jetstream.php&lt;/strong&gt; file is what we're going to configure in this section.&lt;/p&gt;

&lt;p&gt;If you had gone to your profile page in the Jetstream dashboard after logging in, you'd notice that there is no field provided for you to upload your profile photo. The only fields you see are your name and email address:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl9tseg8hp7hjy6izsm89.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl9tseg8hp7hjy6izsm89.png" alt="No profile photo upload option"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Though uploading profile pictures is not available in the dashboard, Jetstream provides support for it out of the box and we're going to enable that feature.&lt;/p&gt;

&lt;p&gt;To enable profile photo upload, while in the project root, go to the &lt;strong&gt;config&lt;/strong&gt; folder and open &lt;strong&gt;jetstream.php&lt;/strong&gt;. Scroll down until you find the &lt;strong&gt;features&lt;/strong&gt; array. Uncomment &lt;code&gt;Features::profilePhotos()&lt;/code&gt;  so that the features array looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// tall-blog/config/jetstream.php    
/*
    |--------------------------------------------------------------------------
    | Features
    |--------------------------------------------------------------------------
    |
    | Some of Jetstream's features are optional. You may disable the features
    | by removing them from this array. You're free to only remove some of
    | these features or you can even remove all of these if you need to.
    |
    */

    'features' =&amp;gt; [
        // Features::termsAndPrivacyPolicy(),
        Features::profilePhotos(),
        // Features::api(),
        // Features::teams(['invitations' =&amp;gt; true]),
        Features::accountDeletion(),
    ],
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save the file and refresh your browser. You should now see a &lt;strong&gt;Photo&lt;/strong&gt; field with a &lt;strong&gt;SELECT A NEW PHOTO&lt;/strong&gt; button you can click to choose a picture:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl9foc3ab4er1m7glcwn4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl9foc3ab4er1m7glcwn4.png" alt="Photo field now available"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As with all lines in Laravel configuration files, the &lt;strong&gt;features&lt;/strong&gt; array has a comment block that explains what this line in the configuration does. Uncommenting a feature from this array enables it for your project and removing it or commenting it out does the reverse.&lt;/p&gt;
&lt;h3&gt;
  
  
  Configuring Fortify
&lt;/h3&gt;

&lt;p&gt;While Jetstream deals with the user interface part of our scaffold, Fortify handles the authentication part. Thus, it's now time for us to enable email verification for all users so that users won't just provide invalid email addresses to register for our blog. &lt;/p&gt;

&lt;p&gt;This is also done in a &lt;strong&gt;features&lt;/strong&gt; array, just like in Jetstream, but in a different configuration file - &lt;strong&gt;fortify.php&lt;/strong&gt;. Open the &lt;strong&gt;fortify.php&lt;/strong&gt; configuration file in the &lt;strong&gt;config&lt;/strong&gt; folder and ensure the &lt;code&gt;Features::emailVerification()&lt;/code&gt; line is uncommented:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// tall-blog/config/fortify.php 
/*
    |--------------------------------------------------------------------------
    | Features
    |--------------------------------------------------------------------------
    |
    | Some of the Fortify features are optional. You may disable the features
    | by removing them from this array. You're free to only remove some of
    | these features or you can even remove all of these if you need to.
    |
    */

    'features' =&amp;gt; [
        Features::registration(),
        Features::resetPasswords(),
        Features::emailVerification(),
        Features::updateProfileInformation(),
        Features::updatePasswords(),
        Features::twoFactorAuthentication([
            'confirmPassword' =&amp;gt; true,
        ]),
    ],
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save the file and refresh your browser. Now every user who have registered on your blog will have to verify their email address for their account to be complete.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuring the .env File
&lt;/h2&gt;

&lt;p&gt;Like many modern frameworks, Laravel keeps some common and secret configuration information in a &lt;strong&gt;.env&lt;/strong&gt; file, also  known as an environment file. These information include database connection details, cache driver details, mail configuration information, API keys and other app-level configuration details such as the app name, url and app secret key. All these, plus more, are housed in the &lt;strong&gt;.env&lt;/strong&gt; file, which by default, is kept in the root of your project.&lt;/p&gt;

&lt;p&gt;Note: The &lt;strong&gt;.env&lt;/strong&gt; file may not be visible if you don't enable showing of hidden files on your computer. If that's the case, follow the documentation on how to enable display of hidden files for your operating system.&lt;/p&gt;

&lt;p&gt;Specifically, what we want to do is change the default database connection and app-level details to the desired values so our blog can function properly. We do this by changing the values in the &lt;strong&gt;APP_&lt;/strong&gt; and &lt;strong&gt;DB_&lt;/strong&gt; prefix keys. These, in addition to the &lt;strong&gt;LOG_&lt;/strong&gt; prefix keys, are mostly located in the top section of the &lt;strong&gt;.env&lt;/strong&gt; file. Change those &lt;strong&gt;DB_&lt;/strong&gt; and &lt;strong&gt;APP_&lt;/strong&gt; prefixed keys so they look the same as below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# tall-blog/.env

APP_NAME="Tall Blog"
APP_ENV=local
APP_KEY=base64:wobqK/lLWqFYTNkUDRhtr5TDPqSyNC1p4YaV5CTFIR4=
APP_DEBUG=true
APP_URL=127.0.0.1:8000

LOG_CHANNEL=stack
LOG_LEVEL=debug

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=tall_blog
DB_USERNAME=root
DB_PASSWORD=root1234
...
...
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save the file and let's look at what each line means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Line 1 is the app name. This is where you specify the name you want to give your blog.&lt;/li&gt;
&lt;li&gt;Line 2 is the environment you're running. Here you specified that your app is running in the local environment. You may set this to other values such as &lt;em&gt;staging&lt;/em&gt;, &lt;em&gt;production&lt;/em&gt;, etc as and when you need to do so.&lt;/li&gt;
&lt;li&gt;Line 3 sets the &lt;strong&gt;APP_KEY&lt;/strong&gt; to a random 32-bit character string used for encrypting and securing sessions, tokens and other user level encryption.&lt;/li&gt;
&lt;li&gt;Line 4 defines whether debugging is enabled (true, in this case) or not while Line 5 sets the app url.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;LOG_&lt;/strong&gt; keys on lines 7 and 8 are used for error logging configuration information. We specify the channel as 'stack'(which aggregates multiple log channels into a single channel) and the logging level as debug(verbose) since we're running in development environment.&lt;/li&gt;
&lt;li&gt;Lines 10-15 are our database configs and are mostly self-explanatory:

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;DB_CONNECTION&lt;/strong&gt; is the database connection name. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DB_HOST&lt;/strong&gt; is the database host we'll running our database server on.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DB_PORT&lt;/strong&gt; is the &lt;a href="https://en.wikipedia.org/wiki/Port_(computer_networking)" rel="noopener noreferrer"&gt;port&lt;/a&gt; the database host server runs on.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DB_DATABASE&lt;/strong&gt; is the name our database we'll be connecting to in our blog.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DB_USERNAME&lt;/strong&gt; and **DB_PASSWORD are the username and password, respectively, we'll use in connecting to our database.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To be able to follow along, you'll need to have a database server, preferably MySQL server, running on your computer with the &lt;strong&gt;&lt;code&gt;tall_blog&lt;/code&gt;&lt;/strong&gt; database and user with username &lt;strong&gt;&lt;code&gt;root&lt;/code&gt;&lt;/strong&gt; and password &lt;strong&gt;&lt;code&gt;root1234&lt;/code&gt;&lt;/strong&gt; created. You can get a ready-made MySQL server bundled with other servers in a stack such as &lt;a href="https://www.apachefriends.org/download.html" rel="noopener noreferrer"&gt;XAMPP&lt;/a&gt;, &lt;a href="https://bitnami.com/stack/lamp/installer" rel="noopener noreferrer"&gt;LAMP&lt;/a&gt;, &lt;a href="https://bitnami.com/stack/mamp/installer" rel="noopener noreferrer"&gt;MAMP&lt;/a&gt; or &lt;a href="https://bitnami.com/stack/wamp/installer" rel="noopener noreferrer"&gt;WAMP&lt;/a&gt;. These stacks are very easy to setup and use, and fulfills all requirements of the Laravel framework.&lt;/p&gt;

&lt;p&gt;If you'd rather want to have everything Laravel requires and more, which won't mess up with your system, you can try either &lt;a href="https://laravel.com/docs/8.x/homestead" rel="noopener noreferrer"&gt;Laravel Homestead&lt;/a&gt; or &lt;a href="https://laravel.com/docs/8.x/valet" rel="noopener noreferrer"&gt;Laravel Valet&lt;/a&gt; (for Mac). Homestead is a Vagrant box that incorporates all your server software on top of the &lt;a href="https://ubuntu.com/" rel="noopener noreferrer"&gt;Ubuntu distro&lt;/a&gt; in a &lt;a href="https://www.vagrantup.com/" rel="noopener noreferrer"&gt;Vagrant&lt;/a&gt; provisioned &lt;a href="https://en.wikipedia.org/wiki/Virtual_machine" rel="noopener noreferrer"&gt;Virtual Machine&lt;/a&gt;. It runs on Linux, Windows and Mac systems. Valet, on the other hand, runs only on Mac and is even simpler to setup, very fast and very lightweight. So you may consider Valet if you're on Mac. The other obvious advantage of using Homestead or Valet is that you get a development environment that is similar to your production server. So you'd expect lesser hassles during deployment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding Routes to Our Application
&lt;/h2&gt;

&lt;p&gt;One of the benefits of modern frameworks is their routing capabilities and Laravel is not an exception. Routing in Laravel allows you to intercept HTTP requests and redirect those requests to the appropriate actionable closure or controller for handling.&lt;/p&gt;

&lt;p&gt;Routing in any web application is as important as designing good user interfaces and putting everything in place to have a professional looking website. Frameworks with elegant routing systems take the pain of manually linking to hundreds and thousands of pages out of developers and simplify this process into pattern-based, definitive routes - making handling multitudes of similar urls a breeze.&lt;/p&gt;

&lt;p&gt;In Laravel, all routes definitions are held in the &lt;strong&gt;routes&lt;/strong&gt; folder. Web routes(user facing webpage routes) are defined in a file named &lt;strong&gt;web.php&lt;/strong&gt; and this is where you'd spend most of your time when defining routes for your web application. When we installed Laravel, a default route for our homepage was already defined for us, that's why we're able to test out our installation.&lt;/p&gt;

&lt;p&gt;Since we have decided to create our own routes, open and remove everything in the &lt;strong&gt;web.php&lt;/strong&gt; file and replace the file's contents with the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// tall-blog/routes/web.php
&amp;lt;?php

use Illuminate\Support\Facades\Route;
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/

Route::get('/', function () {
    return view('welcome');
});

Route::get('categories/{category}', function ($category) {
    return view('welcome');
});

Route::group(['prefix' =&amp;gt; 'dashboard', 'middleware' =&amp;gt; 'auth:sanctum'], function () {
    Route::get('/', function () {
        return view('dashboard');
    })-&amp;gt;name('dashboard');

    Route::get('post/add', function () {
        return view('dashboard');
    });

    Route::get('category/add', function () {
        return view('dashboard');
    });
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We started by making use of the &lt;code&gt;Illuminate\Support\Facades\Route&lt;/code&gt; facade. This is all we need from Laravel to define our routes. The &lt;code&gt;Route&lt;/code&gt; facade contains a lot of useful methods for defining our routes, popular among them are methods representing various popular &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods" rel="noopener noreferrer"&gt;HTTP request methods&lt;/a&gt; such as &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/GET" rel="noopener noreferrer"&gt;GET&lt;/a&gt;, &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST" rel="noopener noreferrer"&gt;POST&lt;/a&gt;,  &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PUT" rel="noopener noreferrer"&gt;PUT&lt;/a&gt;, and &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/DELETE" rel="noopener noreferrer"&gt;DELETE&lt;/a&gt;. Methods that have no representation in the &lt;code&gt;Routes&lt;/code&gt; facade but are in the HTTP specification can be specified by using the &lt;code&gt;Route::any()&lt;/code&gt; method.&lt;/p&gt;

&lt;p&gt;All our routes are defined with the &lt;code&gt;Route::get()&lt;/code&gt; method, corresponding to the HTTP GET method. The &lt;code&gt;Route::get()&lt;/code&gt; method makes a GET request to the given &lt;a href="https://en.wikipedia.org/wiki/Uniform_Resource_Identifier" rel="noopener noreferrer"&gt;URI&lt;/a&gt; argument to be processed by the provided action argument. The action argument can be a &lt;a href="https://www.php.net/manual/en/functions.anonymous.php" rel="noopener noreferrer"&gt;closure&lt;/a&gt;, a &lt;a href="https://laravel.com/docs/8.x/controllers" rel="noopener noreferrer"&gt;controller&lt;/a&gt; or any PHP object that returns a value. For now, we decided to use closures because we haven't created any controller yet.&lt;/p&gt;

&lt;p&gt;In the first route definition, we're routing to the homepage of our blog, for which we returned a &lt;a href="https://laravel.com/docs/8.x/views" rel="noopener noreferrer"&gt;view&lt;/a&gt; from a closure. The &lt;code&gt;view&lt;/code&gt; &lt;a href="https://laravel.com/docs/8.x/helpers" rel="noopener noreferrer"&gt;helper function&lt;/a&gt; looks for the given view in the &lt;strong&gt;resources/views&lt;/strong&gt; folder, parses it and returns its contents as HTML. &lt;/p&gt;

&lt;p&gt;Our second route does the same thing, only that it routes to a given category. The &lt;code&gt;{category}&lt;/code&gt; part in this URI is an example of a &lt;a href="https://laravel.com/docs/8.x/routing#route-parameters" rel="noopener noreferrer"&gt;route parameter&lt;/a&gt;. Route parameters are passed to the action closure or controller and are available to them. An example request to this route will be &lt;code&gt;http://127.0.0.1:8000/categories/web-design&lt;/code&gt;. In this example, the 'web-design' part will be made available to our closure.&lt;/p&gt;

&lt;p&gt;Our third part of the routes is a bit complex. We're using route &lt;a href="https://laravel.com/docs/8.x/routing#route-groups" rel="noopener noreferrer"&gt;groups here&lt;/a&gt;. Defining routes this way let you group all your routes that have a common attribute ('prefix' and 'middleware' here) into an organized, single block of routes that are easier to trace and maintain. Thus, all the routes in this route group are for the dashboard part of our application - so they have the common prefix 'dashboard' before them.&lt;/p&gt;

&lt;p&gt;We've also applied the &lt;code&gt;auth:sanctum&lt;/code&gt; middleware to this route group. Meaning, all requests to any of the routes within this group will have to be authenticated in order to work.&lt;/p&gt;

&lt;p&gt;Our first route in the group is the dashboard page itself. We decided to make it a &lt;a href="https://laravel.com/docs/8.x/routing#named-routes" rel="noopener noreferrer"&gt;named route&lt;/a&gt;. Naming routes makes it easier for you to refer to them in any part of your code without having to concatenate strings together. Currently, it returns the default dashboard view, as all other routes in the group. The last two routes are for adding posts and categories respectively(whose views we haven't implemented yet).&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating A Symlink
&lt;/h2&gt;

&lt;p&gt;Our next task is to create a &lt;a href="https://en.wikipedia.org/wiki/Symbolic_link" rel="noopener noreferrer"&gt;symbolic link&lt;/a&gt;(symlink) from the &lt;strong&gt;storage/app/public&lt;/strong&gt; folder to the &lt;strong&gt;public&lt;/strong&gt; folder. This makes uploads in the &lt;strong&gt;storage/app/public&lt;/strong&gt; folder available in the &lt;strong&gt;public&lt;/strong&gt; folder(technically, this is not true since symlinks only point to the actual files and are not a copy of the actual files). To create the symlink, enter this command in your favorite terminal while in your project root:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;php artisan storage:link
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This should create the storage symlink in your &lt;strong&gt;public&lt;/strong&gt; folder:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0p155p2llh9fxdhwulfw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0p155p2llh9fxdhwulfw.png" alt="Storage symlink"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Changing the App Logo
&lt;/h2&gt;

&lt;p&gt;If you had noticed when you were to login/register, the default Jetstream logo was displayed on both the registration and login pages. In deed, it's also utilized in the app dashboard.&lt;/p&gt;

&lt;p&gt;If you're serious about being professional in your work, you wouldn't want to be showing this logo to your users. Jetstream doesn't stand in your way, either, to customize this logo to your liking. To be able to customize the logo, though, we have to publish Jetstream views. Enter this to do so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;php artisan vendor:publish --tag=jetstream-views
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After running the above command, you should now see a new &lt;strong&gt;resources/views/vendor/jetstream&lt;/strong&gt; folder with sub-folders housing various &lt;a href="https://laravel.com/docs/8.x/blade" rel="noopener noreferrer"&gt;blade&lt;/a&gt; template views. All these blade views in the &lt;strong&gt;components&lt;/strong&gt; sub-folder are Laravel components (learn more about components &lt;a href="https://laravel.com/docs/8.x/blade#components" rel="noopener noreferrer"&gt;here&lt;/a&gt;). Our interest, for now, is on the files &lt;strong&gt;resources/views/vendor/jetstream/components/application-logo.blade.php&lt;/strong&gt;, &lt;strong&gt;resources/views/vendor/jetstream/components/authentication-card-logo.blade.php&lt;/strong&gt;, and &lt;strong&gt;resources/views/vendor/jetstream/components/application-mark.blade.php&lt;/strong&gt; since they hold the default Jetstream logos.&lt;/p&gt;

&lt;p&gt;First, open and delete everything in &lt;strong&gt;resources/views/vendor/jetstream/components/application-logo.blade.php&lt;/strong&gt;, make sure it contains only the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// tall-blog/resources/views/vendor/jetstream/components/application-logo.blade.php
&amp;lt;img {{ $attributes }} src="{{ asset('logo.png') }}"/&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save the file. Here, we're just linking to an image named &lt;strong&gt;logo.png&lt;/strong&gt;(can be downloaded &lt;a href="https://drive.google.com/file/d/1IcvTuNDgJiFBu-iZgsMaCRmo12nslqQ7/view?usp=sharing" rel="noopener noreferrer"&gt;here&lt;/a&gt;) using the HTML &lt;code&gt;img&lt;/code&gt; tag in the &lt;strong&gt;public&lt;/strong&gt; folder. You can see that we used the Laravel &lt;code&gt;asset()&lt;/code&gt; helper function (which, of course loads assets) to link to the image. The &lt;code&gt;{{&lt;/code&gt; and &lt;code&gt;}}&lt;/code&gt; blade template tags basically act like the PHP &lt;code&gt;echo&lt;/code&gt; statement. &lt;code&gt;$attributes&lt;/code&gt; is a placeholder for a list of HTML attributes we may like to specify when we're to use this component.&lt;/p&gt;

&lt;p&gt;Now open &lt;strong&gt;resources/views/vendor/jetstream/components/authentication-card-logo.blade.php&lt;/strong&gt; and ensure its contents match below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// tall-blog/resources/views/vendor/jetstream/components/authentication-card-logo.blade.php
﻿&amp;lt;a href="/"&amp;gt;
    &amp;lt;x-jet-application-logo class="w-24 h-24 rounded-full"/&amp;gt;
&amp;lt;/a&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What we do here is making use of our application logo. We wouldn't want the logo to be oversized, so we use Tailwind CSS' width and height utilities to resize it and make it a circular shape. Since all the views in the &lt;strong&gt;resources/views/vendor/jetstream/components&lt;/strong&gt; folder are Laravel components in the Jetstream namespace, we display the logo using a blade component tag here with the &lt;code&gt;&amp;lt;x-jet-[component-name]/&amp;gt;&lt;/code&gt; syntax. Otherwise, component tags start with the string &lt;code&gt;x-&lt;/code&gt; followed by the kebab case name of the component.&lt;/p&gt;

&lt;p&gt;Let's now turn our attention to the last file we need to change - &lt;strong&gt;resources/views/vendor/jetstream/components/application-mark.blade.php&lt;/strong&gt;. This file holds the logo displayed in the dashboard our application. Please open it and replace its content with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// tall-blog/resources/views/vendor/jetstream/components/application-mark.blade.php
&amp;lt;x-jet-application-logo class="w-20 h-20"/&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the same as we did for the authentication card, the only difference is that we've reduced the size of the logo and didn't add the circular shape.&lt;/p&gt;

&lt;p&gt;Now if you visit the login and registration pages you'll see the change:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Focsm5hlynl31bffink2r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Focsm5hlynl31bffink2r.png" alt="Login page with brand logo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fisbece5bvh45z7gibh20.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fisbece5bvh45z7gibh20.png" alt="Registration page with branded logo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is the dashboard page:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F39xygeavfov250gugngp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F39xygeavfov250gugngp.png" alt="Dashboard with branded logo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Congratulations on the journey so far. It's been a rough one and I am happy you read to this end. In our next episode, you're going to learn how to create models and migrations. You'll also learn how to run these migrations in order to create the tables we'll need for this blog. Thank you and see you for the next episode.&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>livewire</category>
      <category>alpinejs</category>
      <category>tailwindcss</category>
    </item>
    <item>
      <title>Creating Your First Blog With TALL - Part One</title>
      <dc:creator>Alhassan Kamil</dc:creator>
      <pubDate>Wed, 03 Mar 2021 15:32:00 +0000</pubDate>
      <link>https://forem.com/nayi10/create-your-first-blog-with-the-tall-tailwind-css-alpine-js-laravel-laravel-livewire-stack-12kp</link>
      <guid>https://forem.com/nayi10/create-your-first-blog-with-the-tall-tailwind-css-alpine-js-laravel-laravel-livewire-stack-12kp</guid>
      <description>&lt;p&gt;Welcome to the first part of &lt;strong&gt;Creating Your First Blog With TALL (Tailwind CSS, Alpinejs, Laravel, Livewire)&lt;/strong&gt; tutorial series. This tutorial takes you through introduction to the TALL stack, how it can help you ship products faster and setting up the TALL stack in your development environment.&lt;/p&gt;

&lt;p&gt;After the end of this tutorial, you'll learn:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; What constitutes the TALL stack and what each is in developing web apps&lt;/li&gt;
&lt;li&gt; The benefits you gain when using the TALL stack to create web apps&lt;/li&gt;
&lt;li&gt; How to setup the TALL stack using &lt;a href="https://jetstream.laravel.com" rel="noopener noreferrer"&gt;Laravel Jetstream&lt;/a&gt; on your development machine.&lt;/li&gt;
&lt;li&gt; How to add Jetstream authentication and configure it for our new Laravel app&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In addition, you'll be prepared enough for the next part of this tutorial series.&lt;/p&gt;

&lt;p&gt;Let's get going.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This tutorial assumes you already have &lt;a href="https://getcomposer.org" rel="noopener noreferrer"&gt;Composer&lt;/a&gt; installed on your system. If Composer isn't installed on your computer, follow the instructions on their &lt;a href="https://getcomposer.org" rel="noopener noreferrer"&gt;website&lt;/a&gt; to install it. Prior knowledge in Laravel and entering terminal commands is also assumed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction to the TALL stack
&lt;/h2&gt;

&lt;p&gt;The TALL stack is a combination of both front-end and back-end libraries/frameworks that makes developing web apps a breeze. TALL is an acronym for &lt;a href="https://tailwindcss.com" rel="noopener noreferrer"&gt;&lt;strong&gt;Tailwind CSS&lt;/strong&gt;&lt;/a&gt;, &lt;a href="https://github.com/alpinejs/alpine" rel="noopener noreferrer"&gt;&lt;strong&gt;Alpine.js&lt;/strong&gt;&lt;/a&gt;, &lt;a href="https://www.laravel.com" rel="noopener noreferrer"&gt;&lt;strong&gt;Laravel&lt;/strong&gt;&lt;/a&gt; and &lt;a href="https://laravel-livewire.com" rel="noopener noreferrer"&gt;&lt;strong&gt;Livewire&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As you might have guessed, the back-end framework here is Laravel, while Alpine.js and Tailwind CSS are front-end libraries. Laravel Livewire is a bridge between the front-end and the Laravel back-end and brings dynamic data binding to Laravel so you can achieve reactivity and interactivity from the user facing parts of your website with Laravel, instead of using JavaScript.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tailwind CSS
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://tailwindcss.com" rel="noopener noreferrer"&gt;Tailwind CSS&lt;/a&gt; is a utility-based CSS framework that takes the hassles of using CSS out of your way. While using Tailwind CSS, you may decide not to write a single line of CSS code. This means you're not even required to have an extensive knowledge of CSS (apart from basic knowledge of CSS classes and other attributes) to use Tailwind CSS.&lt;/p&gt;

&lt;p&gt;With Tailwind CSS, the possibilities of what you can design are unlimited. What you can do is only limited by your level of creativity and imagination!&lt;/p&gt;

&lt;h3&gt;
  
  
  Alpinejs
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/alpinejs/alpine" rel="noopener noreferrer"&gt;Alpinejs&lt;/a&gt; is the Tailwind of JavaScript libraries. It's a very small JavaScript library you can use in place of larger ones such as &lt;a href="https://vuejs.org" rel="noopener noreferrer"&gt;Vue.js&lt;/a&gt; and React to achieve interactivity and responsiveness for your web app.&lt;/p&gt;

&lt;p&gt;Alpinejs takes the utility-first approach used by Tailwind CSS to make using JavaScript in your webpages easier. Instead of writing functions and class in a script tag or a .js file, you expressively write your JavaScript code in &lt;a href="https://en.wikipedia.org/wiki/HTML" rel="noopener noreferrer"&gt;HTML&lt;/a&gt; tags as if they were &lt;a href="https://en.wikipedia.org/wiki/HTML#Attributes" rel="noopener noreferrer"&gt;HTML attributes&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Laravel
&lt;/h3&gt;

&lt;p&gt;The &lt;a href="https://laravel.com" rel="noopener noreferrer"&gt;Laravel&lt;/a&gt; framework is a &lt;a href="https://www.php.net" rel="noopener noreferrer"&gt;PHP&lt;/a&gt; framework that brings simplicity, robustness and productivity to developing modern websites. Laravel is a matured framework with a very large community of developers, extensive but simple to grasp documentation and several official packages that helps in your website development cycle.&lt;/p&gt;

&lt;p&gt;Using Laravel means that it is easy to get answers to questions you may face when developing your websites. You also have access to a large ecosystem of free, opensource packages that make it faster to ship and deploy web apps to production. What's more, you get all the benefits PHP has on the web such as more hosting and deployment options, server affordability, support and many others.&lt;/p&gt;

&lt;h3&gt;
  
  
  Laravel Livewire
&lt;/h3&gt;

&lt;p&gt;Laravel &lt;a href="https://www.laravel-livewire.com" rel="noopener noreferrer"&gt;Livewire&lt;/a&gt; lets you develop modern, dynamic, reactive user interfaces without having to learn new JavaScript frameworks such as &lt;a href="https://vuejs.org" rel="noopener noreferrer"&gt;Vue.js&lt;/a&gt; and &lt;a href="https://reactjs.org" rel="noopener noreferrer"&gt;React&lt;/a&gt;. You write all your code in PHP/Laravel and Livewire handles the JavaScript part for you.&lt;/p&gt;

&lt;p&gt;If you have worked with Vue.js before, you probably know how data binding helps make your work easier as developer. Livewire supports data binding (best known as model binding) to forms, adding form validations, hassle-free file uploads, beautiful pagination and a bunch of other features.&lt;/p&gt;

&lt;p&gt;Livewire separates your code into components so you get a well-structured, modular code when using it. Similar to Laravel components, the idea of Livewire components is such that each component carries out a particular action, but you're free to use components as the only view for webpages and even perform different actions in a component.&lt;/p&gt;

&lt;h2&gt;
  
  
  Benefits of the TALL stack
&lt;/h2&gt;

&lt;p&gt;I believe you can already deduce the benefits of each of these tools from their explanations above. If you can't still figure out, here are some of the advantages of the TALL stack:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Helps you ship web apps faster.&lt;/li&gt;
&lt;li&gt; Makes you more productive as a web developer&lt;/li&gt;
&lt;li&gt; Takes care of all parts of the web development cycle: front-end, back-end and &lt;a href="https://en.wikipedia.org/wiki/User_experience" rel="noopener noreferrer"&gt;UX&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt; Takes care of securing your web applications.&lt;/li&gt;
&lt;li&gt; Takes interactivity and responsive web design to a new level&lt;/li&gt;
&lt;li&gt; And so many others&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Setting up Our Development Environment
&lt;/h2&gt;

&lt;p&gt;Laravel &lt;a href="https://jetstream.laravel.com" rel="noopener noreferrer"&gt;Jetstream&lt;/a&gt; is a Laravel scaffolding package providing authentication and API support out of the box for Laravel web applications. Jetstream comes bundled with either the &lt;a href="https://inertiajs.com" rel="noopener noreferrer"&gt;Inertia&lt;/a&gt; stack or Livewire, plus Tailwind CSS and Alpine.js. We'll be using the Livewire stack for this tutorial series.&lt;/p&gt;

&lt;p&gt;To install the Jetstream starter kit, we first have to download the Laravel installer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;composer global require laravel/installer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This downloads the Laravel executable into Composer's system-wide &lt;strong&gt;&lt;em&gt;vendor&lt;/em&gt;&lt;/strong&gt; directory. To make the executable available globally, we have to add the Composer &lt;strong&gt;&lt;em&gt;vendor/bin&lt;/em&gt;&lt;/strong&gt; directory to our &lt;strong&gt;&lt;em&gt;$PATH&lt;/em&gt;&lt;/strong&gt;. Depending on your development machine, the Composer &lt;strong&gt;&lt;em&gt;vendor/bin&lt;/em&gt;&lt;/strong&gt; directory is in one of the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; macOS: &lt;strong&gt;&lt;em&gt;$HOME/.composer/vendor/bin&lt;/em&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt; Windows: &lt;strong&gt;&lt;em&gt;%USERPROFILE%\AppData\Roaming\Composer\vendor\bin&lt;/em&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt; Linux: &lt;strong&gt;&lt;em&gt;$HOME/.config/composer/vendor/bin or $HOME/.composer/vendor/bin&lt;/em&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For adding this directory to your &lt;strong&gt;$PATH&lt;/strong&gt;, please consult the documentation for your Operating System.&lt;/p&gt;

&lt;p&gt;Once you have added Composer &lt;strong&gt;&lt;em&gt;vendor/bin&lt;/em&gt;&lt;/strong&gt; directory to your path, navigate to a folder you'd like your project to be hosted, such as &lt;strong&gt;home/Projects&lt;/strong&gt; on Linux or &lt;strong&gt;Documents/Projects&lt;/strong&gt; on Windows. Create a new Laravel project with the following command in a terminal/Command Prompt:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;laravel new tall-blog
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Wait for the required dependencies to be installed. When the installation is done, you should get something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kamil@kamil-sc650:~/Projects/Web$ laravel new tall-blog
 _                              _
| |                            | |
| |    __ _ _ __ __ ___  _____| |
| |   / _` | '__/ _` \ \ / / _ \ |
| |___| (_| | | | (_| |\ V / __/ |
|______\__,_|_| \__,_| \_/ \___|_|

Creating a "laravel/laravel" project at "./tall-blog"
Installing laravel/laravel (v8.5.9)
 - Installing laravel/laravel (v8.5.9): Extracting archive
Created project in /home/kamil/Projects/Web/tall-blog
&amp;gt; @php -r "file_exists('.env') || copy('.env.example', '.env');"
Loading composer repositories with package information
Updating dependencies
Lock file operations: 105 installs, 0 updates, 0 removals
 - Locking asm89/stack-cors (v2.0.2)
 - Locking brick/math (0.9.2)
 - Locking dnoegel/php-xdg-base-dir (v0.1.1)
 - Locking doctrine/inflector (2.0.3)
 - Locking doctrine/instantiator (1.4.0)
 - Locking doctrine/lexer (1.2.1)
 - Locking dragonmantank/cron-expression (v3.1.0)
 - Locking egulias/email-validator (2.1.25)
 - Locking facade/flare-client-php (1.3.7)
 ...
Writing lock file
Installing dependencies from lock file (including require-dev)                                                   
Package operations: 105 installs, 0 updates, 0 removals
 - Downloading symfony/var-dumper (v5.2.3)
 - Downloading symfony/string (v5.2.3)
 - Downloading symfony/console (v5.2.3)
 - Downloading symfony/css-selector (v5.2.3)
 - Downloading symfony/routing (v5.2.3)
 - Downloading symfony/process (v5.2.3)
 - Downloading symfony/mime (v5.2.3)
 - Downloading symfony/http-foundation
 ...
 - Installing doctrine/inflector (2.0.3): Extracting archive
 - Installing doctrine/lexer (1.2.1): Extracting archive
 - Installing symfony/polyfill-ctype (v1.22.0): Extracting archive
 - Installing webmozart/assert (1.9.1): Extracting archive
 - Installing dragonmantank/cron-expression (v3.1.0): Extracting archive
 - Installing symfony/polyfill-php80 (v1.22.0): Extracting archive
 - Installing symfony/polyfill-mbstring (v1.22.0): Extracting archive
 - Installing symfony/var-dumper (v5.2.3): Extracting archive
 - Installing symfony/polyfill-intl-normalizer (v1.22.0): Extracting archive
 - Installing symfony/polyfill-intl-grapheme (v1.22.0): Extracting archive
 - Installing symfony/string (v5.2.3): Extracting archive
 - Installing psr/container (1.0.0): Extracting archive
 - Installing symfony/service-contracts (v2.2.0): Extracting archive
 ...
63 package suggestions were added by new dependencies, use `composer suggest` to see details.                    
Generating optimized autoload files
&amp;gt; Illuminate\Foundation\ComposerScripts::postAutoloadDump
&amp;gt; @php artisan package:discover --ansi
Discovered Package: facade/ignition
Discovered Package: fideloper/proxy
Discovered Package: fruitcake/laravel-cors
Discovered Package: laravel/sail
Discovered Package: laravel/tinker
Discovered Package: nesbot/carbon
Discovered Package: nunomaduro/collision
Package manifest generated successfully.
74 packages you are using are looking for funding.
Use the `composer fund` command to find out more!
&amp;gt; @php artisan key:generate --ansi
Application key set successfully.

Application ready! Build something amazing.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you've got errors during the previous stage, make sure your system meets the system requirements specified &lt;a href="https://laravel.com/docs/8.x/deployment#server-requirements" rel="noopener noreferrer"&gt;here&lt;/a&gt; on the Laravel website.&lt;/p&gt;

&lt;p&gt;Spin up the built-in PHP server and let's see our starter website:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;php artisan serve
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now open &lt;a href="http://127.0.0.1:8000" rel="noopener noreferrer"&gt;http://127.0.0.1:8000&lt;/a&gt; to see our newly crafted Laravel site.&lt;/p&gt;

&lt;p&gt;Our next task is to install Laravel Jetstream. While still in the root of our project, enter this in your terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;composer require laravel/jetstream
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Again, if everything went smoothly, you get something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kamil@kamil-sc650:~/Projects/Web$ cd tall-blog &amp;amp;&amp;amp; composer require laravel/jetstream
Using version ^2.1 for laravel/jetstream
./composer.json has been updated
Running composer update laravel/jetstream
Loading composer repositories with package information
Updating dependencies
Lock file operations: 9 installs, 0 updates, 0 removals
 - Locking bacon/bacon-qr-code (2.0.3)
 - Locking dasprid/enum (1.0.3)
 - Locking jaybizzle/crawler-detect (v1.2.104)
 - Locking jenssegers/agent (v2.6.4)
 - Locking laravel/fortify (v1.7.5)
 - Locking laravel/jetstream (v2.1.3)
 - Locking mobiledetect/mobiledetectlib (2.8.35)
 - Locking paragonie/constant_time_encoding (v2.4.0)
 - Locking pragmarx/google2fa (8.0.0)
Writing lock file
Installing dependencies from lock file (including require-dev)                                                   
Package operations: 9 installs, 0 updates, 0 removals
 - Downloading laravel/jetstream (v2.1.3)
 - Installing dasprid/enum (1.0.3): Extracting archive
 - Installing bacon/bacon-qr-code (2.0.3): Extracting archive
 - Installing jaybizzle/crawler-detect (v1.2.104): Extracting archive
 - Installing paragonie/constant_time_encoding (v2.4.0): Extracting archive
 - Installing pragmarx/google2fa (8.0.0): Extracting archive
 - Installing laravel/fortify (v1.7.5): Extracting archive
 - Installing mobiledetect/mobiledetectlib (2.8.35): Extracting archive
 - Installing jenssegers/agent (v2.6.4): Extracting archive
 - Installing laravel/jetstream (v2.1.3): Extracting archive
Generating optimized autoload files
&amp;gt; Illuminate\Foundation\ComposerScripts::postAutoloadDump
&amp;gt; @php artisan package:discover --ansi
Discovered Package: facade/ignition
Discovered Package: fideloper/proxy
Discovered Package: fruitcake/laravel-cors
Discovered Package: jenssegers/agent
Discovered Package: laravel/fortify
Discovered Package: laravel/jetstream
Discovered Package: laravel/sail
Discovered Package: laravel/tinker
Discovered Package: nesbot/carbon
Discovered Package: nunomaduro/collision
Package manifest generated successfully.
75 packages you are using are looking for funding.
Use the `composer fund` command to find out more!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Congratulations! The Jetstream package has been installed. Now we have to run the &lt;code&gt;jetstream:install&lt;/code&gt; Artisan command with &lt;code&gt;livewire&lt;/code&gt; as an option to use Jetstream with the Livewire stack:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;php artisan jetstream:install livewire
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can append &lt;code&gt;--teams&lt;/code&gt; to the above command if your blog needs a team support. After pressing &lt;em&gt;Enter/Return&lt;/em&gt;, you should get an output such as this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kamil@kamil-sc650:~/Projects/Web/tall-blog$ php artisan jetstream:install livewire
Migration created successfully!
./composer.json has been updated
Running composer update livewire/livewire laravel/sanctum
Loading composer repositories with package information
Updating dependencies
Lock file operations: 2 installs, 0 updates, 0 removals
 - Locking laravel/sanctum (v2.9.0)
 - Locking livewire/livewire (v2.3.16)
Writing lock file
Installing dependencies from lock file (including require-dev)
Package operations: 2 installs, 0 updates, 0 removals
 - Downloading livewire/livewire (v2.3.16)
 0/1 [&amp;gt;---------------------------]  0%
 1/1 [============================] 100% - Installing laravel/sanctum (v2.9.0): Extracting archive
 - Installing livewire/livewire (v2.3.16): Extracting archive
 0/2 [&amp;gt;---------------------------]  0%
 2/2 [============================] 100%Generating optimized autoload files
&amp;gt; Illuminate\Foundation\ComposerScripts::postAutoloadDump
&amp;gt; @php artisan package:discover --ansi
Discovered Package: facade/ignition
Discovered Package: fideloper/proxy
Discovered Package: fruitcake/laravel-cors
Discovered Package: jenssegers/agent
Discovered Package: laravel/fortify
Discovered Package: laravel/jetstream
Discovered Package: laravel/sail
Discovered Package: laravel/sanctum
Discovered Package: laravel/tinker
Discovered Package: livewire/livewire
Discovered Package: nesbot/carbon
Discovered Package: nunomaduro/collision
Package manifest generated successfully.
76 packages you are using are looking for funding.
Use the `composer fund` command to find out more!
Copied Directory [/vendor/laravel/sanctum/database/migrations] To [/database/migrations]
Copied File [/vendor/laravel/sanctum/config/sanctum.php] To [/config/sanctum.php]
Publishing complete.

Livewire scaffolding installed successfully.
Please execute "npm install &amp;amp;&amp;amp; npm run dev" to build your assets.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After this, we also need to install and build &lt;a href="https://npmjs.com" rel="noopener noreferrer"&gt;NPM&lt;/a&gt; dependencies and migrate our database. Enter this into your terminal to do that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install
npm run dev
php artisan migrate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When &lt;a href="https://npmjs.com" rel="noopener noreferrer"&gt;NPM&lt;/a&gt; dependencies have been installed, built and migrations run, our blog scaffolding process is now done. Out of the box, we've got both traditional and two-factor authentication, session management and API support for our Laravel blog for free :).&lt;/p&gt;

&lt;p&gt;If not running, start up the built-in PHP server using &lt;code&gt;php artisan serve&lt;/code&gt; and point your browser to &lt;code&gt;http://127.0.0.1:8000&lt;/code&gt; . You should be able to get something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcnj47ck8mew2rg7eaotu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcnj47ck8mew2rg7eaotu.png" alt="Jetstream Homepage"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This means our blog scaffolding process has been successful. Click on &lt;strong&gt;Register&lt;/strong&gt; link in the top right corner of the navigation bar to register for a new account:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo7fdxdgxcbq0f7lk5iki.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo7fdxdgxcbq0f7lk5iki.png" alt="Registration page"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Enter your details and click &lt;strong&gt;Register&lt;/strong&gt; button to register and login.&lt;/p&gt;

&lt;p&gt;If everything went on successful, you'll be redirected to the ready-made Jetstream dashboard:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzorgb4nefv5mo7l49fz5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzorgb4nefv5mo7l49fz5.png" alt="Dashboard"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Feel free to explore the features of your newly created Jetstream powered dashboard. In particular, you'd definitely want to go through the navigation bar menu links to see what they have to offer.&lt;/p&gt;




&lt;p&gt;This completes the first episode of our &lt;strong&gt;Creating your first blog with TALL&lt;/strong&gt; tutorial series. Our next episode will be configuring Jetstream and Fortify (used for authentication) in order to enable profile photos and email verification support, setup database and other configurations in the &lt;strong&gt;.env&lt;/strong&gt; file, configure our routes, create a &lt;strong&gt;symlink&lt;/strong&gt; to the &lt;strong&gt;public&lt;/strong&gt; folder to make file uploads possible, change the default application logo, and create the necessary models and migrations for our blog.&lt;/p&gt;

&lt;p&gt;Thank you for reading! See you for the next tutorial.&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>alpinejs</category>
      <category>livewire</category>
      <category>tailwindcss</category>
    </item>
  </channel>
</rss>
