Friday, July 13, 2018

Note : Using hidden for Laravel's model $append

Eloquent's mutator has been very helpful for making an additional attribute to a model. What is Eloquent mutator? According to Laravel's documentation, it says 

Accessors and mutators allow you to format Eloquent attribute values when you retrieve or set them on model instances.

Mutator is use along with an accessor, before accessor I usually use a method to return a custom field. For instance, I wanted my user model to return full name or lastname, firstname field. I would do the following


class User extends Model {
          public function fullname(){
                   return $this->firstname . " " . $this->lastname;
         }
}

My issue from above code is that I have to execute it each time I wanted to use it. Wouldn't it be nice if it's already attached along with your other attributes? How to do it?

Based on Laravel's documentation, accessor must be defined like a getter.

<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{

    public function getFullNameAttribute()
    {
        return ucfirst($this->firstname) . " " . ucfirst($this->lastname);
    }

}
To attach it to the request just like the other attributes $appends property shall be added to the model.

The model will look something like this.
<?php 
namespace App; 
use Illuminate\Database\Eloquent\Model;
class User extends Model {
    protected $appends = array('fullname');
 
Since I'm using the append, mutators and accessors to a related table I noticed that related table will also be attached. Like in my post table, my post will have a user object attached into it. Check out the screenshot below. You will notice that user is attached to the post model. But I only wanted to append my custom field author.



Solutions:


  1. Add 'user' to the hidden property of the model and it will automatically hide the user object like this.
  2. Loop to the post collection and use the model method "makeHidden()". like this
           foreach($posts as $post){
                $post->makeHidden('user');
           }


And now the result will be something like this.

By using makeHidden, you can dynamically hide the mutator related table like user in my case. If it's in the hidden property of the model then it will not be in the attributes anymore. Unless the opposite  of makeHidden makeVisible method is use on the model.


Tuesday, July 10, 2018

Note: Fix on error BroadcastException in PusherBroadcaster.php line 106


While following a blog post on how to make a real-time Notification via Broadcasting using Pusher, it's expected to encounter some errors.

Basically I wanted to try how Laravel's Broadcasting works and use it in the future too. I didn't dwell on learning it before because some of the projects I worked with doesn't require a real-time updates. Though I've tested Firebase before but just testing if it connects to my Laravel App and nothing else. The fact that it was just a free trial account.

So today, I've finally tried a Pusher.com and Laravel's Broadcasting by following this blog. I though everything works but I noticed my Pusher's dashboard was not receiving any message at all.

The major error I've encountered is screenshot and copy-pasted below.

(1/1) BroadcastException in PusherBroadcaster.php line 106 at PusherBroadcaster->broadcast(array(object(PrivateChannel)), 'App\\Events\\MessageSent', array('user' => array('id' => 3, 'email' => 'meail@com.com', 'created_at' => '2018-06-23 08:50:41', 'updated_at' => '2018-06-23 08:50:41', 'firstname' => 'Ian', 'middlename' => null, 'lastname' => 'Villanueva', 'mobile_number' => null, 'status' => 0, 'birthdate' => null, 'address' => null, 'city_id' => null, 'country_id' => null, 'province_id' => null, 'profile_pic' => null, 'created_by' => null, 'updated_by' => null), 'message' => array('id' => 48, 'user_id' => 3, 'message' => 'coffee', 'created_at' => '2018-07-10 09:58:53', 'updated_at' => '2018-07-10 09:58:53'), 'socket' => null)) in BroadcastEvent.php line 49



As you can see above, there are no specific error to know how to fix it. Thanks to this Github discussion I was able to fixed it. And this for adding the ssl certificate to my localhost XAMMP.

Since, I got it working next up will be using it to ReactJS app and probably React Native later.


Monday, July 2, 2018

Putting validation rules at your models

Validation is one of the vital part of saving data coming from user. For instance you want to accept an email format but the user didn't supply the right data, that would be a disaster in a way, right?

Laravel's validation features has been there since the beginning but might as well use it. Basic usage of validation are as follows.

Include the Validator into your controller, in my case I like to use the following code snippet. 

$validator = Validator::make($request->all(),  [
        'title' => 'required|unique:posts|max:255',
        'body' => 'required',
    ]
);

          if ($validator->fails()) {
                    return response()->json([
                        'result' => $validator->messages(),
                        'message' => "Encountered validation error."
                    ], 400);

                  // redirect can also be put here.
            }

//code here if validation didn't fail


Code above starts by creating custom validation as stated from Laravel manual then checks if the validation failed. The creation of validation part can be repetitive in some cases and adding more conditions can be tricky since you have to look where controller did you use the rules.

I think it was from CakePHP that validation rules are put inside models so I applied similar thing.

In my models, I would put the following sample rules,

   protected static $rules = [
'title' => 'required|unique:posts|max:255',
'body' => 'required'
    ];

and a static function that basically returns the rules.

    public static function getRules() {
        return static::$rules;
    }

The in my controller's function, I would simply use

 $validator = Validator::make($input, Post::getRules());
Now, I can access or use my validation anywhere and update my rules in just one place which is the model.

In some cases, updating record is different from your create/new record rules so you can also put  the following function to your model

    public function getUpdateRules() {
        $updateRules = [];
        foreach(self::getRules() as $field => $rule) {
            $newRule = [];
            $ruleParts = explode('|',$rule);
            foreach($ruleParts as $part) {
                if(strpos($part,'unique:') === 0) {
                    if ( ! $this->isDirty($field)) {
                        $part = $part . ',' . $field . ',' . $this->getAttribute($field) . ',' . $field;
                    }
                }
                $newRule[] = $part;
            }
            $updateRules[$field] = join('|', $newRule);
        }
        return $updateRules;
    }

Credits: Found the code getUpdateRules function at StackOverflow.

That's it for now.