How can I extend an existing facade in Laravel? - php

Given the below, stock standard user model (with one small addition), how can I add the following name_list function so it is available through the normal Model facade?
I would like to use it such as:
User::name_list()
Note: I understand I could actually just flag the method as static, but I'm not looking to access a static method, but a normal method exposed through the ioc container.
class User extends Eloquent {
protected $hidden = array('password');
protected $guarded = array();
public function name_list()
{
return User::lists("name");
}
}

Try Eloquent scopes instead. Using scopes, you can chain multiple methods.
public function scopeName_list($query)
{
return $query->get()->lists('name');
}
// and then call...
User::name_list();
// or
User::whereActive(true)->name_list();

Related

Laravel 6 Eloquent model serialization ignoring Accessors

I'm using Laravel 6 with a SQL Server 2017 database backend. In the database I have a table called PersonPhoto, with a Photo column and a Thumbnail column where the photos and thumbnails are stored as VARBINARY.
I have defined the following Eloquent model, with two Accessors to convert the images to base64 encoding:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class PersonPhoto extends Model
{
protected $connection = 'mydb';
protected $table = 'PersonPhoto';
protected $primaryKey ='PersonID';
public function person(){
return $this->belongsTo('App\Person', 'PersonID');
}
public function getPhotoAttribute($value){
return base64_encode($value);
}
public function getThumbnailAttribute($value){
return base64_encode($value);
}
}
This works fine in Blade templates, however when I try to serialize to JSON or an Array I get a "Malformed UTF-8 characters, possibly incorrectly encoded" error, as if the Accessors are being ignored and the raw data is being serialized. To workaround this, I have altered the model:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class PersonPhoto extends Model
{
protected $connection = 'mydb';
protected $table = 'PersonPhoto';
protected $primaryKey ='PersonID';
//Added to hide from and add fields to serializer
protected $hidden = ['Photo', 'Thumbnail'];
protected $appends = ['encoded_photo', 'encoded_thumbnail'];
public function person(){
return $this->belongsTo('App\Person', 'PersonID');
}
public function getPhotoAttribute($value){
return base64_encode($value);
}
public function getThumbnailAttribute($value){
return base64_encode($value);
}
//Added these new accessors
public function getEncodedPhotoAttribute(){
return base64_encode($this->Photo);
}
public function getEncodedThumbnailAttribute(){
return base64_encode($this->Thumbnail);
}
}
This hides the original Photo and Thumbnail fields from the serializer and includes the two new accessors. This appears to work and solves my issue.
Questions:
1) Is Laravel's serializer ignoring my Accessors as I suspect, and is this by design?
2) Although my workaround works, is this a reasonable approach or am I likely to run into problems? Is there a better way of doing it?
Thanks
I think you have two issues:
First, Laravel serialization requires that you append any accessors you want included — even if an attribute of the same name already exists. You did not explicitly append the desired values in the first example.
https://laravel.com/docs/5.8/eloquent-serialization#appending-values-to-json
Second, Laravel doesn't always like capitalized attribute names. It happily expects everything to be lowercase (snake_case) and based on some quick testing, seems to have some trouble associating a proper $value to pass to an accessor when case is involved.
However, you can modify your accessor to call the attribute directly instead of relying on Laravel to figure out what you are asking for and achieve the desired results.
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class PersonPhoto extends Model
{
protected $connection = 'mydb';
protected $table = 'PersonPhoto';
protected $primaryKey = 'PersonID';
// add the desired appends for serialization
protected $appends = ['Photo','Thumbnail'];
public function person()
{
return $this->belongsTo('App\Person', 'PersonID');
}
public function getPhotoAttribute()
{
// access the attribute directly
return base64_encode($this->attributes['Photo']);
}
public function getThumbnailAttribute()
{
// access the attribute directly
return base64_encode($this->attributes['Thumbnail']);
}
}
EDIT: I actually see that you did something similar in your second example with $this->Thumbnail and $this->Photo. My example is of the same concept, but without relying on magic methods.
__get/__set/__call performance questions with PHP

LARAVEL how to change $fillable in Model from trait?

I have in model:
use seoTrait;
protected $fillable = [
'name', 'title', 'description'
];
I created trait "seoTrait" which need "seoMeta" in $fillable.
Now I add :
protected $fillable = [
'name', 'title', 'description', 'seoMeta'
];
But is it possible in trait "seoTrait" add something to $fillable ?
For anyone that came here looking for an answer; I believe that there is a better way than constructor overloading.
Others have pointed out that Laravel supports bootable model traits, using the boot<TraitName> method you can set up the trait for usage. However, the boot<TraitName> method has to be static, so you cannot alter any non-static properties of the model.
However, I found out that there is a non-static equivalent to the boot<TraitName> method; the initialize<TraitName> method.
Internally, when Eloquent boots up a model, it also registers all initialize methods for the model, based on the methods found in the traits that the model uses. Then upon instantiating that model, the initialize methods are fired.
An example of usage, based on the problem stated in this question:
trait SEOTrait
{
/**
* This method is called upon instantiation of the Eloquent Model.
* It adds the "seoMeta" field to the "$fillable" array of the model.
*
* #return void
*/
public function initializeSEOTrait()
{
$this->fillable[] = 'seoMeta';
}
}
Sadly there isn't any information in the official documentation about either bootable or initializable traits. However, I still find it really cool that both functionalities exist.
I had the same requirement. However, I didn't want to declare a constructor in my trait, as this leads to very unexpected behaviour - what if another trait also declares a constructor?
As pointed out by PeterPan666, we can't use the static trait boot() method to directly set the non-static fillable property - but we can utilise Laravel Model Events, which receive an instance of the model.
For example:
public static function bootSeoTrait() : void
{
static::retrieved(function($model) {
$model->fillable = array_merge($model->fillable, ['seoMeta']);
});
}
Update
Although the $fillable property is protected, the GuardsAttributes trait - which the Illuminate\Database\Eloquent\Model uses - contains the following setter:
/**
* Set the fillable attributes for the model.
*
* #param array $fillable
* #return $this
*/
public function fillable(array $fillable)
{
$this->fillable = $fillable;
return $this;
}
So, we can set the $fillable protected property from our model instance in the retrieved event.
Since Laravel 5.7, you can initialize a model trait with a magic initializeTraitName method on the trait which allow access to the model instance.
trait SeoTrait
{
public function initializeSeoTrait()
{
$this->fillable[] = 'seoMeta';
}
}
You can use constructor inside your trait, but it is important to send fillable attributes to parent constructor Illuminate\Database\Eloquent\Modal
parent::__construct($attributes);
Here is example code:
public function __construct(array $attributes = []) {
parent::__construct($attributes);
$this->fillable[] = 'seoMeta';
}
As #DokiCRO said, you could implement a constructor within your trait. You must then consider that there won't be any other trait that will be able to overwrite the construct.
For anything else, I would suggest to go with the static bootTraitClassName(). But in this specific case we need to overwrite a non-static protected property, which can't be achievable within a static context.
So this justifies the constructor overload. Maybe use one trait that is responsible for overloading $fillable arrays for all your models, which will make your life easier in the long run.
Just make sure to include your code before the parent construct gets called though.
public function __construct(array $attributes = []) {
$this->fillable[] = 'seoMeta';
parent::__construct($attributes);
}

Traits with PHP and Laravel

I am using Laravel 5.1 and would like to access an array on the Model from the Trait when the Model before the model uses the appends array.
I would like to add certain items to the appends array if it exists from my trait. I don't want to edit the model in order to achieve this. Are traits actually usable in this scenario or should I use inheritance?
array_push($this->appends, 'saucedByCurrentUser');
Here is how my current setup works.
Trait
<?php namespace App;
trait AwesomeSauceTrait {
/**
* Collection of the sauce on this record
*/
public function awesomeSauced()
{
return $this->morphMany('App\AwesomeSauce', 'sauceable')->latest();
}
public function getSaucedByCurrentUserAttribute()
{
if(\Auth::guest()){
return false;
}
$i = $this->awesomeSauced()->whereUserId(\Auth::user()->id)->count();
if ($i > 0){
return true;
}
return false;
}
}
Model
<?php namespace App;
use App\AwesomeSauceTrait;
use Illuminate\Database\Eloquent\Model;
class FairlyBlandModel extends Model {
use AwesomeSauceTrait;
protected $appends = array('age','saucedByCurrentUser');
}
What I would like to do is something to achieve the same effect as extending a class. I have a few similar traits, so using inheritance gets somewhat ugly.
trait AwesomeSauceTrait {
function __construct() {
parent::__construct();
array_push($this->appends, 'saucedByCurrentUser');
}
}
I have seen some workarounds for this, but none of them seem better/cleaner than just adding the item to the array manually. Any ideas are appreciated.
Update
I discovered this way of accomplishing what I need for one trait, but it only works for one trait and I don't see an advantage of using this over inheritance.
trait
protected $awesomeSauceAppends = ['sauced_by_current_user'];
protected function getArrayableAppends()
{
array_merge($this->appends, $this->awesomeSauceAppends);
parent::getArrayableAppends();
}
How I am currently handling my Model, for what it is worth.
model
public function __construct()
{
array_merge($this->appends, $this->awesomeSauceAppends);
}
Traits are sometimes described as "compiler-assisted copy-and-paste"; the result of using a Trait can always be written out as a valid class in its own right. There is therefore no notion of parent in a Trait, because once the Trait has been applied, its methods are indistinguishable from those defined in the class itself, or imported from other Traits at the same time.
Similarly, as the PHP docs say:
If two Traits insert a method with the same name, a fatal error is produced, if the conflict is not explicitly resolved.
As such, they are not very suitable for situations where you want to mix in multiple variants of the same piece of behaviour, because there is no way for base functionality and mixed in functionality to talk to each other in a generic way.
In my understanding the problem you're actually trying to solve is this:
add custom Accessors and Mutators to an Eloquent model class
add additional items to the protected $appends array matching these methods
One approach would be to continue to use Traits, and use Reflection to dynamically discover which methods have been added. However, beware that Reflection has a reputation for being rather slow.
To do this, we first implement a constructor with a loop which we can hook into just by naming a method in a particular way. This can be placed into a Trait of its own (alternatively, you could sub-class the Eloquent Model class with your own enhanced version):
trait AppendingGlue {
public function __construct() {
// parent refers not to the class being mixed into, but its parent
parent::__construct();
// Find and execute all methods beginning 'extraConstruct'
$mirror = new ReflectionClass($this);
foreach ( $mirror->getMethods() as $method ) {
if ( strpos($method->getName(), 'extraConstruct') === 0 ) {
$method->invoke($this);
}
}
}
}
Then any number of Traits implementing differently named extraConstruct methods:
trait AwesomeSauce {
public function extraConstructAwesomeSauce() {
$this->appends[] = 'awesome_sauce';
}
public function doAwesomeSauceStuff() {
}
}
trait ChocolateSprinkles {
public function extraConstructChocolateSprinkles() {
$this->appends[] = 'chocolate_sprinkles';
}
public function doChocolateSprinklesStuff() {
}
}
Finally, we mix in all the traits into a plain model, and check the result:
class BaseModel {
protected $appends = array('base');
public function __construct() {
echo "Base constructor run OK.\n";
}
public function getAppends() {
return $this->appends;
}
}
class DecoratedModel extends BaseModel {
use AppendingGlue, AwesomeSauce, ChocolateSprinkles;
}
$dm = new DecoratedModel;
print_r($dm->getAppends());
We can set the initial content of $appends inside the decorated model itself, and it will replace the BaseModel definition, but not interrupt the other Traits:
class ReDecoratedModel extends BaseModel {
use AppendingGlue, AwesomeSauce, ChocolateSprinkles;
protected $appends = ['switched_base'];
}
However, if you over-ride the constructor at the same time as mixing in the AppendingGlue, you do need to do a bit of extra work, as discussed in this previous answer. It's similar to calling parent::__construct in an inheritance situation, but you have to alias the trait's constructor in order to access it:
class ReConstructedModel extends BaseModel {
use AppendingGlue { __construct as private appendingGlueConstructor; }
use AwesomeSauce, ChocolateSprinkles;
public function __construct() {
// Call the mixed-in constructor explicitly, like you would the parent
// Note that it will call the real parent as well, as though it was a grand-parent
$this->appendingGlueConstructor();
echo "New constructor executed!\n";
}
}
This can be avoided by inheriting from a class which either exists instead of the AppendingGlue trait, or already uses it:
class GluedModel extends BaseModel {
use AppendingGlue;
}
class ReConstructedGluedModel extends GluedModel {
use AwesomeSauce, ChocolateSprinkles;
public function __construct() {
// Standard call to the parent constructor
parent::__construct();
echo "New constructor executed!\n";
}
}
Here's a live demo of all of that put together.
I thought I'd add an update for 2019 since this was one of the first discussions that popped up when trying to do a similar thing. I'm using Laravel 5.7 and nowadays Laravel will do the reflection that IMSoP mentioned.
After the trait has been booted, Laravel will then call initializeTraitName() on the constructed object (where TraitName is the full name of the trait).
To add extra items to $appends from a trait, you could simply do this...
trait AwesomeSauceTrait {
public function initializeAwesomeSauceTrait()
{
$this->appends[] = 'sauced_by_current_user';
}
public function getSaucedByCurrentUserAttribute()
{
return 'whatever';
}
}
KISS:
I don't see any reason why you should use trait when your are simply appending attributes.
I would only recommend using trait without a constructor like you were doing, only if you model is getting pretty bulky and you wish to slim down things.
Please also note this not the correct way of appending attribute
protected $appends = array('age','saucedByCurrentUser');
You could do this:
protected $appends = array('age','sauced_by_current_user');
Appends attribute names should the snake_case of its method Name
Edited:
The idea behind appends is to dynamically add fields that doesn't exist in your database table to your model so after you can do like:
$model = FairlyBlandModel ::find(1);
dd($model->sauced_by_current_user);

Load all relationships for a model

Usually to eager load a relationship I would do something like this:
Model::with('foo', 'bar', 'baz')...
A solution might be to set $with = ['foo','bar','baz'] however that will always load these three relations whenever I call Model
Is it possible to do something like this: Model::with('*')?
No it's not, at least not without some additional work, because your model doesn't know which relations it supports until they are actually loaded.
I had this problem in one of my own Laravel packages. There is no way to get a list of the relations of a model with Laravel. It's pretty obvious though if you look at how they are defined. Simple functions which return a Relation object. You can't even get the return type of a function with php's reflection classes, so there is no way to distinguish between a relation function and any other function.
What you can do to make it easier is defining a function that adds all the relationships.
To do this you can use eloquents query scopes (Thanks to Jarek Tkaczyk for mentioning it in the comments).
public function scopeWithAll($query)
{
$query->with('foo', 'bar', 'baz');
}
Using scopes instead of static functions allows you to not only use your function directly on the model but for example also when chaining query builder methods like where in any order:
Model::where('something', 'Lorem ipsum dolor')->withAll()->where('somethingelse', '>', 10)->get();
Alternatives to get supported relations
Although Laravel does not support something like that out of the box you can allways add it yourself.
Annotations
I used annotations to determine if a function is a relation or not in my package mentioned above. Annotations are not officially part of php but a lot of people use doc blocks to simulate them.
Laravel 5 is going to use annotations in its route definitions too so I figuered it not to be bad practice in this case. The advantage is, that you don't need to maintain a seperate list of supported relations.
Add an annotation to each of your relations:
/**
* #Relation
*/
public function foo()
{
return $this->belongsTo('Foo');
}
And write a function that parses the doc blocks of all methods in the model and returns the name. You can do this in a model or in a parent class:
public static function getSupportedRelations()
{
$relations = [];
$reflextionClass = new ReflectionClass(get_called_class());
foreach($reflextionClass->getMethods() as $method)
{
$doc = $method->getDocComment();
if($doc && strpos($doc, '#Relation') !== false)
{
$relations[] = $method->getName();
}
}
return $relations;
}
And then just use them in your withAll function:
public function scopeWithAll($query)
{
$query->with($this->getSupportedRelations());
}
Some like annotations in php and some don't. I like it for this simple use case.
Array of supported relations
You can also maintain an array of all the supported relations. This however needs you to always sync it with the available relations which, especially if there are multiple developers involved, is not allways that easy.
protected $supportedRelations = ['foo','bar', 'baz'];
And then just use them in your withAll function:
public function scopeWithAll($query)
{
return $query->with($this->supportedRelations);
}
You can of course also override with like lukasgeiter mentioned in his answer. This seems cleaner than using withAll. If you use annotations or a config array however is a matter of opinion.
There's no way to know what all the relations are without specifying them yourself. How the other answers posted are good, but I wanted to add a few things.
Base Model
I kind of have the feeling that you want to do this in multiple models, so at first I'd create a BaseModel if you haven't already.
class BaseModel extends Eloquent {
public $allRelations = array();
}
"Config" array
Instead of hard coding the relationships into a method I suggest you use a member variable. As you can see above I already added $allRelations. Be aware that you can't name it $relations since Laravel already uses that internally.
Override with()
Since you wanted with(*) you can do that too. Add this to the BaseModel
public static function with($relations){
$instance = new static;
if($relations == '*'){
$relations = $instance->allRelations;
}
else if(is_string($relations)){
$relations = func_get_args();
}
return $instance->newQuery()->with($relations);
}
(By the way, some parts of this function come from the original Model class)
Usage
class MyModel extends BaseModel {
public $allRelations = array('foo', 'bar');
}
MyModel::with('*')->get();
I wouldn't use static methods like suggested since... it's Eloquent ;)
Just leverage what it already offers - a scope.
Of course it won't do it for you (the main question), however this is definitely the way to go:
// SomeModel
public function scopeWithAll($query)
{
$query->with([ ... all relations here ... ]);
// or store them in protected variable - whatever you prefer
// the latter would be the way if you want to have the method
// in your BaseModel. Then simply define it as [] there and use:
// $query->with($this->allRelations);
}
This way you're free to use this as you like:
// static-like
SomeModel::withAll()->get();
// dynamically on the eloquent Builder
SomeModel::query()->withAll()->get();
SomeModel::where('something', 'some value')->withAll()->get();
Also, in fact you can let Eloquent do it for you, just like Doctrine does - using doctrine/annotations and DocBlocks. You could do something like this:
// SomeModel
/**
* #Eloquent\Relation
*/
public function someRelation()
{
return $this->hasMany(..);
}
It's a bit too long story to include it here, so learn how it works: http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/annotations-reference.html
Since i've met with a similar problem, and found a good solution that isn't described here and doesn't require filling some custom arrays or whatever, i'll post it for the future.
What i do, is first create a trait, called RelationsManager:
trait RelationsManager
{
protected static $relationsList = [];
protected static $relationsInitialized = false;
protected static $relationClasses = [
HasOne::class,
HasMany::class,
BelongsTo::class,
BelongsToMany::class
];
public static function getAllRelations($type = null) : array
{
if (!self::$relationsInitialized) {
self::initAllRelations();
}
return $type ? (self::$relationsList[$type] ?? []) : self::$relationsList;
}
protected static function initAllRelations()
{
self::$relationsInitialized = true;
$reflect = new ReflectionClass(static::class);
foreach($reflect->getMethods(ReflectionMethod::IS_PUBLIC) as $method) {
/** #var ReflectionMethod $method */
if ($method->hasReturnType() && in_array((string)$method->getReturnType(), self::$relationClasses)) {
self::$relationsList[(string)$method->getReturnType()][] = $method->getName();
}
}
}
public static function withAll() : Builder
{
$relations = array_flatten(static::getAllRelations());
return $relations ? self::with($relations) : self::query();
}
}
Now you can use it with any class, like -
class Project extends Model
{
use RelationsManager;
//... some relations
}
and then when you need to fetch them from the database:
$projects = Project::withAll()->get();
Some notes - my example relation classes list doesn't include morph relations, so if you want to get them as well - you need to add them to $relationClasses variable. Also, this solution only works with PHP 7.
You could attempt to detect the methods specific to your model using reflection, such as:
$base_methods = get_class_methods('Illuminate\Database\Eloquent\Model');
$model_methods = get_class_methods(get_class($entry));
$maybe_relations = array_diff($model_methods, $base_methods);
dd($maybe_relations);
Then attempt to load each in a well-controlled try/catch. The Model class of Laravel has a load and a loadMissing methods for eager loading.
See the api reference.
You can create method in your Model
public static function withAllRelations() {
return static::with('foo', 'bar', 'baz');
}
And call Model::withAllRelations()
Or
$instance->withAllRelations()->first(); // or ->get()
You can't have a dynamic loading of relationships for a certain model. you need to tell the model which relations to support.
composer require adideas/laravel-get-relationship-eloquent-model
https://packagist.org/packages/adideas/laravel-get-relationship-eloquent-model
Laravel get relationship all eloquent models!
You don't need to know the names of the methods in the model to do this. Having one or many Eloquent models, thanks to this package, you can get all of its relationships and their type at runtime
The Best Solution
first create a trait, called RelationsManager:
<?php
namespace App\Traits;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasManyThrough;
use Illuminate\Database\Eloquent\Relations\HasOne;
use Illuminate\Database\Eloquent\Relations\HasOneThrough;
use Illuminate\Database\Eloquent\Relations\MorphMany;
use Illuminate\Database\Eloquent\Relations\MorphOne;
use Illuminate\Database\Eloquent\Relations\MorphTo;
use Illuminate\Database\Eloquent\Relations\MorphToMany;
use ReflectionClass;
use ReflectionMethod;
trait RelationsManager
{
protected static $relationsList = [];
protected static $relationsInitialized = false;
protected static $relationClasses = [
HasOne::class,
HasMany::class,
BelongsTo::class,
BelongsToMany::class,
HasOneThrough::class,
HasManyThrough::class,
MorphTo::class,
MorphOne::class,
MorphMany::class,
MorphToMany::class,
];
public static function getAllRelations($type = null): array
{
if (!self::$relationsInitialized) {
self::initAllRelations();
}
return $type ? (self::$relationsList[$type] ?? []) : self::$relationsList;
}
protected static function initAllRelations()
{
self::$relationsInitialized = true;
$reflect = new ReflectionClass(static::class);
foreach ($reflect->getMethods(ReflectionMethod::IS_PUBLIC) as $method) {
/** #var ReflectionMethod $method */
if ($method->hasReturnType() && in_array((string) $method->getReturnType(), self::$relationClasses)) {
self::$relationsList[(string) $method->getReturnType()][] = $method->getName();
}
}
}
public static function withAll(): Builder
{
$relations = array_flatten(static::getAllRelations());
return $relations ? self::with($relations) : self::query();
}
}
Now you can use it with any class, like -
class Company extends Model
{
use RelationsManager;
//... some relations
}
and then when you need to fetch them from the database:
$companies = Company::withAll()->get();
this solution only works with PHP 7 Or Higher.
Done

In my view, why does Laravel overwrite variables I declare in my controller with those from my model?

Am I understanding the MVC design pattern incorrectly? Why does Laravel seemingly overwrite variables I declare in my controller and pass to my view with those from my model? Say I'm passing the variable $journey from my controller to my view like so:
class JourneyController extends BaseController {
public function journey($id) {
$journey = Journey::find($id);
// I overwrite one of the attributes from the database here.
$journey->name = "Overwritten by the Controller";
return View::make('journey', array(
'journey' => $journey,
'bodyClass' => 'article'
));
}
}
But, I'm using an accessor to also modify the $journey->name attribute in my Journey model:
class Journey extends Eloquent {
protected $table = 'journeys';
protected $primaryKey = 'id';
public $timestamps = false;
public function getNameAttribute($value) {
return 'Overwritten by the Model';
}
}
So when my view is created, and I display $journey->name like so:
{{ $journey->name }}
I'm left with:
"Overwritten by the Model";
Why does this occur? Doesn't the controller handle a request, fetch information from my model, manipulate it, and then pass it to the view where it can be outputted? If this is the case, why, and also how, is the model seemingly 'jumping' in between to overwrite my controller-written variable with its own?
I know this is old, but I just found a solution on Laravel 4.2 today.
class Journey extends Eloquent {
protected $table = 'journeys';
protected $primaryKey = 'id';
public $timestamps = false;
public function getNameAttribute($value = null) {
if($value)
return $value;
return 'Overwritten by the Model';
}
}
You should update your getNameAttribute function as above to return the set value (if there is one) instead of always returning the string. Previously, calling this value would always run the function and ignore the set value, but now the function takes checks first for the value that you have set.
Hopefully 2 years isn't too late to still help some people!
Have a look at using Presenters, Take Jeffery Way's Presenter Package. Install it normally and then you can add the $presenter variable to your model.
For instance:
use Laracasts\Presenter\PresentableTrait;
class Journey extends Eloquent {
use PresentableTrait;
protected $presenter = "JourneyPresenter";
}
Then you can create your JourneyPresenter Class:
class JourneyPresenter {
public function journeyName()
{
return "Some Presentation Name";
}
}
In your view you can call this, like so:
<h1>Hello, {{ $journey->present()->journeyName }}</h1>
It really helps keep this sort of "presentation" logic out of your view and controller. You should try hard to keep your controller solely for its intended purpose, handling routes and basic guards and keep your views logic-less.
As for your problem, you may just be experiencing the natural order of Laravel operations.

Categories