Pt 4: Build a Conversations System with Laravel and Lucid Architecture

in #utopian-io7 years ago (edited)

Pt 4: Build a Conversations System with Laravel and Lucid Architecture

We covered a lot of ground in the previous post in this series. Today, we'll go even deeper into building our Conversations System.

What Will I Learn?

Today, we will be tackling these beauties below. We will:

  • Build the CreateMessageFeature.
  • Build testable Jobs for our CreateMessageFeature
  • Write contracts and implementation for the Repositories we will be building today.

Difficulty

This tutorial is rated: Intermediate.

Requirements

  1. PHP version 5.6.4 or greater
  2. Composer version 1.4.1 or greater
  3. Lucid Laravel version 5.3.*
  4. Reasonable familiarity with Lucid architecture concepts and Object Oriented Programming.

Let's Blast Off!

If you remember, in our last post, we created Jobs, Repositories, and Contracts for our MessagesFeature.php file. Today, we'll be focusing on the CreateMessageFeature. This Feature helps us add a message to a conversation with another user. We also have a few jobs that we are yet to create. Let's get to work! If you don't have your CreateMessageFeature available at the moment, simply hit the terminal again

C:\xampp\htdocs\conviex\vendor\bin>lucid make:feature CreateMessage web

This command should create a CreateMessageFeature accessible at C:\xampp\htdocs\conviex\src\Services\Web\Features. Let's add some code to it! Add these lines to the top of the CreateMessageFeature.php to import the classes we'll need

use Auth;
use Illuminate\Validation\ValidationException;

use App\Domains\Http\Jobs\SendBackWithErrorJob;
use App\Domains\Http\Jobs\SendToLocationJob;

use App\Domains\Message\Jobs\ValidateMessageCreationJob;
use App\Domains\Message\Jobs\CreateMessageJob;

Add this code to the handle method

    # We retrieve the authenticated user.
    $author = Auth::user();

    $data = $request->input();

    try
    {
        # Is the data provided by our user valid?
        $this->run(ValidateMessageCreationJob::class, [
            'data'  =>  $data
        ]);

        # We create the message and store it in the $message variable.
        $message = $this->run(CreateMessageJob::class, [
            'data'  =>  $data
        ]);

        # We run a redirect to the conversation with the id of our newly created message.
        return $this->run(SendToLocationJob::class, [
            'location' => "/conversations/$message->conversation_id#message-$message->id"
        ]);

    } catch (ValidationException $e) {

        return $this->run(SendBackWithErrorJob::class, [
            'errors' => $e->validator,
            'data' => [
              'message' => 'You have validation errors',
              'input' => $request->input()
            ]
        ]);

    }
}

CreateMessageFeature Shot

Great! Our user can now participate in a conversation with another person but we've got all these jobs to build. Let's tackle the SendBackWithErrorJob, shall we? Head over to the terminal and run this command

C:\xampp\htdocs\conviex\vendor\bin>lucid make:job SendBackWithError Http

C:\xampp\htdocs\conviex\vendor\bin>lucid make:job ValidateMessageCreation Message

C:\xampp\htdocs\conviex\vendor\bin>lucid make:job CreateMessage Message

These are the files generated by these commands:

  • C:\xampp\htdocs\conviex\src\Domains\Http\Jobs\SendBackWithErrorJob.php

  • C:\xampp\htdocs\conviex\src\Domains\Message\Jobs\ValidateMessageCreationJob.php

  • C:\xampp\htdocs\conviex\src\Domains\Message\Jobs\CreateMessageJob.php

This command should create a SendBackWithErrorJob.php accessible at C:\xampp\htdocs\conviex\src\Domains\Http\Jobs. Let's add some code to it!

Firstly, add these to the top of the file

use Redirect;

use Illuminate\Http\Request;

Add these lines to the SendBackWithErrorJob class

protected $errors;
protected $data;

/**
 * Create a new job instance.
 *
 * @return void
 */
public function __construct($errors, $data = false)
{
    $this->errors = $errors;
    $this->data = $data;
}

/**
 * Execute the job.
 *
 * @return void
 */
public function handle(Request $request)
{

  if (count($this->data)) {
    $request->session()->flash('appStatus', json_encode([
      'message' => $this->data['message'],
      'type' => $this->data['type']
    ]));
  }

  if ($this->data['input'])
  {
      return Redirect::back()
           ->withErrors($this->errors)
           ->withInput($this->data['input']);
  }


  return Redirect::back()
          ->withErrors($this->errors)
          ->withInput();
}

This class simply flashes any messages we've got to the session() cache and then runs a redirect back to our previous location with any errors or input for our form. Saves a ton going forward.

Next, we have to edit the ValidateMessageCreationJob. This Job simply helps us ensure our input is correct. Add these line of code to the top of the ValidateMessageCreationJob class.

use App\Domains\Message\Validators\MessageCreationValidator;

Next, add these lines to the body of the ValidateMessageCreationJob

protected $data;
/**
 * Create a new job instance.
 *
 * @return void
 */
public function __construct($data)
{
    $this->data = $data;
}

/**
 * Execute the job.
 *
 * @return void
 */
public function handle(MessageCreationValidator $validator)
{
    return $validator->validate($this->data);
}

We must tackle a new concept we just introduced. To run validations in Lucid, you need a Validator bearing the rules for validation. The Validator can be injected same as we can inject a Repository into our Jobs. We must now create the MessageCreationValidator. To do this, simply create a file called MessageCreationValidator.php at C:\xampp\htdocs\conviex\src\Domains\Message\Validators. Now that we've done that, let's add this code

<?php

namespace App\Domains\Message\Validators;

use App\Foundation\AppValidator;

class MessageCreationValidator extends AppValidator {

protected $rules = [
    'body' =>  'required',
];

}

This Validator is simple enough—just a class extending our AppValidator parent with a protected array of rules. We're doing great, but we've only got one problem now—our AppValidator doesn't exist yet. Let's create the AppValidator.php file at C:\xampp\htdocs\conviex\src\Foundation

<?php

namespace App\Foundation;

use Lucid\Foundation\Validation;
use Lucid\Foundation\InvalidInputException;
use Illuminate\Validation\ValidationException;

/**
 * Base Validator class, to be extended by specific validators.
 * Decorates the process of validating input. Simply declare
 * the $rules and call validate($attributes) and you have an
 * \Illuminate\Validation\Validator instance.
 */
class AppValidator
{
    protected $rules = [];
    protected $messages = [];

    protected $validation;

    public function __construct(Validation $validation)
    {
        $this->validation = $validation;
    }

    /**
     * Validate the given input.
     *
     * @param array $input The input to validate
     * @param array $rules Specify custom rules (will override class rules)
     *
     * @return bool
     *
     * @throws \Lucid\Foundation\InvalidInputException
     */
    public function validate($input, array $rules = [])
    {
        $validation = $this->validation($input, $rules);

        if ($validation->fails()) {
            throw new ValidationException($validation);
        }

        return true;
    }

    /**
     * Get a validation instance out of the given input and optionatlly rules
     * by default the $rules property will be used.
     *
     * @param array $input
     * @param array $rules
     *
     * @return \Illuminate\Validation\Validator
     */
    public function validation($input, array $rules = [])
    {
        if (empty($rules)) {
            $rules = $this->rules;
        }

        if (empty($messages)) {
            $messages = $this->messages;
        }

        return $this->validation->make($input, $rules, $messages);
    }
}

Let's save our AppValidator.php and with that we're done with validation.

We now need to work on the CreateMessageJob. This Job will help us insert a message into the database. To get started, let's import this class at the top of the C:\xampp\htdocs\conviex\src\Domains\Message\Jobs\CreateMessageJob.php file

use App\Data\Contracts\MessageRepositoryInterface;

Then add these lines to the CreateMessageJob class

protected $data;
/**
 * Create a new job instance.
 *
 * @return void
 */
public function __construct($data)
{
    $this->data = $data;
}

/**
 * Execute the job.
 *
 * @return void
 */
public function handle(MessageRepositoryInterface $message)
{
    return $message->create($this->data);
}

Create Message Shot

That's awesome! We're injecting a MessageRepositoryInterface contract that we've not created yet. Let's fix that. Create a file called MessageRepositoryInterface.php at C:\xampp\htdocs\conviex\src\Data\Contracts and add the following code

<?php

namespace App\Data\Contracts;

interface MessageRepositoryInterface
{
}

That's all the code we'll be requiring for the MessageRepositoryInterface contract. It's great we have created a contract, however, we need to create its implementation too. Let's create the EloquentMessageRepository.php repository at C:\xampp\htdocs\conviex\src\Data\Repositories and add the below lines of code.

<?php

namespace App\Data\Repositories;

use Framework\Message;

use App\Data\Contracts\MessageRepositoryInterface;

class EloquentMessageRepository extends Repository implements MessageRepositoryInterface
{
    public function __construct()
    {
        $this->message = new Message;

        parent::__construct($this->message);
    }

}

The last thing we must do to complete the CreateMessageFeature is the binding of our EloquentMessageRepository to the MessageRepositoryInterface. To do that, head over to C:\xampp\htdocs\conviex\src\Foundation\ServiceProvider.php and add the following lines of code

Firstly, import these classes at the top

use App\Data\Contracts\MessageRepositoryInterface;

use App\Data\Repositories\EloquentMessageRepository;

Next, add these lines to the ServiceProvider class

    $this->app->bind(MessageRepositoryInterface::class, function () {
        return new EloquentMessageRepository();
    });

With that, we're done with the CreateMessageFeature and its dependencies.

Conclusion

In this post, we did a brief flashback to content from our previous entry in this series. We worked on the CreateMessageFeature and all the Jobs, Repositories, Contracts, Validators and ServiceProviders associated with with it.

Our next post will be the fun part. We will design and build the layout for our Conversations System. We will also add some convenience methods to our models and do other wonderful stuff.

Stay tuned for the next installment and keep being awesome!



Posted on Utopian.io - Rewarding Open Source Contributors

Sort:  

Thank you for the contribution. It has been approved.

You can contact us on Discord.
[utopian-moderator]

Hey @creatrixity I am @utopian-io. I have just upvoted you!

Achievements

  • You have less than 500 followers. Just gave you a gift to help you succeed!
  • Seems like you contribute quite often. AMAZING!

Suggestions

  • Contribute more often to get higher and higher rewards. I wish to see you often!
  • Work on your followers to increase the votes/rewards. I follow what humans do and my vote is mainly based on that. Good luck!

Get Noticed!

  • Did you know project owners can manually vote with their own voting power or by voting power delegated to their projects? Ask the project owner to review your contributions!

Community-Driven Witness!

I am the first and only Steem Community-Driven Witness. Participate on Discord. Lets GROW TOGETHER!

mooncryption-utopian-witness-gif

Up-vote this comment to grow my power and help Open Source contributions like this one. Want to chat? Join me on Discord https://discord.gg/Pc8HG9x

Coin Marketplace

STEEM 0.16
TRX 0.15
JST 0.029
BTC 55350.85
ETH 2319.50
USDT 1.00
SBD 2.33