Casting model to another model that extend the original - php

I'm trying to cast a model to another one that extends the same model.
Is there a build in way in Laravel this achieve this?
Example
In the code below I would like to cast User to ExtendedUser
class User extends Model
{
...
}
class ExtendedUser extends User
{
...
}

Related

How to use multiple implements in laravel model

How can I have multiple implements in my model?
my current model is like this:
class Post extends Model implements ViewableContract
{
........
}
now i need to add implements Feedable as well.
should i use comma in between or put them in brackets or what?
Yeah! you can use comma in between the ViewableContract and Feedable like this:
class Post extends Model implements ViewableContract, Feedable
{
.....
}

Laravel on some kind of Model Ready method

Well i don't know how to format the title of this post in very clear way, but here's my question:
Say i have
Posts::find('1);
Photos:find('1');
... and so on, every mode db request
now by default i can access db columns, for instance the id: through model->id
$Photos = Photos::find('1')->first();
echo $Photos->id; // will return 1
what i want is that i need all those kind of requests to add a custom field automatically like hashed_id, which is not in the database, which in return will make all models have a hashed_id as well, i know i can add that field to database and then grab it but i need it for different reasons/implementations
i did create a BaseModel and every Model will extend that BaseModel, so Photos extends BaseModel, BaseModel extends Model... and all that etc etc.
but i need some kind of constructor, upon retrieving data to process the data automatically without having to add -let's say- a hash_id() after retrieving the data.
something like, onAfterGet(), onReady()....sort of commands.
i hope my question is clear.
Thanks.
What you're looking for is an Accessor. Accesors can be used to add custom attributes to the model. Combine this with the $appends property and you have exactly what you need. The $appends property adds the custom accessor in every result.
You can do this by creating a base model like you've stated in the question or by using traits. I'll show you an example on how to achieve this using a base model.
Let's create base model called BaseModel. All other models that need this custom attribute will extend this.
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class BaseModel extends Model
{
protected $appends = ['hashed_id'];
public function getHashedIdAttribute()
{
return some_hash_function($this->id);
}
}
We have a Image model which extends our BaseModel.
<?php
namespace App;
class Image extends BaseModel
{
}
Now every result from the Image model will have the hashed_id field added by default.
Accesor documenation https://laravel.com/docs/5.4/eloquent-mutators#defining-an-accessor
If I understand you right, all you need to do is to define mutator, for example:
<?php
class Photo extends Model
{
/* ... model implementation ... */
public function getHashedIdAttribute()
{
return md5($this->id);
}
}
Then you can access property like it was in database:
echo Photo::find(5)->hashed_id;

Trying to get property of non-object in laravel 5.3 app though model relations seems appropriate

User model
class User extends Authenticatable{
public function enrollments() {
return $this->hasMany('App\enrollments','user_email');
}
}
Batch model
class batch extends Model{
protected $table = 'batch';
public function enrollments() {
return $this->hasMany('App\enrollments');
}
}
Enrollments model
class enrollments extends Model{
public function batch() {
return $this->belongsTo('App\batch');
}
public function user() {
return $this->belongsTo('App\User','email');
}
}
if I use $enrollment->batch->title, it works..
but if I use $enrollment->user->name, it gives an error
Trying to get property of non-object
Please help, I am stuck
Thanks in advance
EDIT
The problem arose after I changed the foreign key from between user and enrollment from id to email and renamed my column to user_email from user_id. Before that code was working fine.
Solved
Got the problem, It was with some data in enrollment which didn't have registered email with user.
This code will note work simply because User is not a child of Model. To fix it you must extend from Model. Authenticatable is an interface and there is an equivalent trait; there is no such class.
You must implement the interface if you want your user class to be Authenticatable. But to answer your question, extend the base model, Model.
class User extends Model {
public function enrollments() {
return $this->hasMany('App\enrollments','user_email');
}}
In addition:
If you need to log an existing user instance into your application,
you may call the login method with the user instance. The given object
must be an implementation of the
Illuminate\Contracts\Auth\Authenticatable contract. Of course, the
App\User model included with Laravel already implements this
interface:
https://laravel.com/docs/5.3/authentication

Add global method to all Eloquent Models in Laravel 5.2

I want add given method to all my Eloquent Models:
public function isNew(){
return $this->created_at->addWeek()->gt(Carbon::now());
}
Is this possible to do without bruteforce?
I could not find anything in the docs
Thanks
What you can do:
Create BaseModel class and put all similar methods in it. Then extend this BaseModel class in all models instead of Model class:
class Profile extends BaseModel
Use Global Scope.
Create trait and use it in all or some of your models.
Sure, you can do that. Just simply extend the Laravel's eloquent model like so:
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Model;
abstract class BaseModel extends Model
{
public function isNew() {
return $this->created_at->copy()->addWeek()->gt(Carbon::now());
}
}
Now your model should extend from this new BaseModel class instead:
class User extends BaseModel {
//
}
This way you can do something like this:
User::find(1)->isNew()
Note that I also call copy() method on the created_at property. This way your created_at property would be copied and won't be accidentally added 1 week ahead.
// Copy an instance of created_at and add 1 week ahead.
$this->created_at->copy()->addWeek()
Hope this help.

Multiple controllers with a single model

Heres what im trying to do
Ive got table that holds many different types of data for items. the model name for this is 'Object'
for example :
row 1 : item_type = event
row 2 : item_type = news
row 3 : item_type = booking
i want to write a controller 'event_controller' and use the 'Object' model with it and only deal with item_types of event. and another controller for news (news_controller) and use the same model.
how do i do this on cakephp.
Im coming into cake from codeigniter and in CI we can load any model we want into any controller can i do something similar with cake?
It's considered poor form to use var $uses in CakePHP 1.3+. It's been replaced by App::import (see below)
Given you have a Users controller with User model, and a Comments controller with Comment model. The accepted patterns are:
Using Associations
This is your best bet if the models can be logically associated.
// models/user.php
Class User extends AppModel {
public $hasMany = array('Comment');
}
// controllers/users_controller.php
Class UsersController extends AppController {
function allComments() {
$this->User->Comment->find('all'); // You can use this across multiple models (e.g. $this->User->Comment->NestedComment->find('all');
}
}
Instantiating the model object
This will load your model file, add the instance to CakePHP's object map, and returns the instance.
// models/user.php
Class User extends AppModel {}
// models/comment.php
Class Comment extends AppModel {}
// controllers/users_controller.php
Class UsersController extends AppController {
function allComments() {
$Comments =& ClassRegistry::init('Comment');
$Comments->find('all');
}
}
Using $this->loadModel
Internally this uses ClassRegistry::init, then also adds the model as a property of the controller.
// models/user.php
Class User extends AppModel {}
// models/comment.php
Class Comment extends AppModel {}
// controllers/users_controller.php
Class UsersController extends AppController {
function allComments() {
$this->loadModel('Comment');
$this->Comment->find('all'); // using load model allows you to access it via $this->Model
}
}
App::import
This is really just the CakePHP way of requiring a file. You'll still need to instantiate the object.
// models/user.php
Class User extends AppModel {}
// models/comment.php
Class Comment extends AppModel {}
// controllers/users_controller.php
App::import('Model', 'Comment');
Class UsersController extends AppController {
function allComments() {
$Comment = new Comment();
$Comment->find('all');
}
}
I hope this helps.
Edit: If you want to use the model object globally within the controller, you can use any of these patterns I specified within your beforeFilter().
I would like to suggest you to not to $uses statement. Instead of that you can use relations of the models like $this->Model->M0del1->....->someFunc(); if the relation exists.
If the relation between the models dos't exist then simply use $this->loadModel('ModelName'); in the specific function where-ever you need it.
If you use var $uses = array('Object'); it becomes global to the controller and it will load that model for all the actions of the controller despite of whether you require it or not. This will affect your performance.
If you use $this-LoadModel('ModelName'); in a particular function it will only load in that function not in all the actions.
You declare your controller and declare the $uses variable on it like this:
var $uses = array('Object');

Categories