Illuminate/Eloquent: how to use belongsTo in constructor - constructor

i would like to provide data from the "foreign key table" in the current model.
I am currently achieving this by a function (getBrand).
But now I would like to have this accessable as a property. So I added a property ($brand) and wanted to fill it by calling the function (getBrand) in the constructor of the model.
class Car extends Eloquent {
public $brand;
public function __construct() {
parent::__construct();
$this->brand = getBrand();
}
public function getBrand() {
return $this->belongsTo('App\Brand', 'FK_BrandId')->first()->Brandname;
}
}
But this creates an error during the execution of the constructor:
Trying to get property of non-object
Any ideas how to solve this? Thanks!

You could change your getBrand function a little to the following to define the relationship between a Car and a Brand:
public function brand() {
return $this->belongsTo('App\Brand', 'FK_BrandId');
}
The brand model can then be accessed from an instance of Car with, e.g. $car->brand. To access the brand name you can then use $car->brand->Brandname.
If you'd like to access the brand name directly, you could define an "accessor" on the Car model like this:
public function getBrandNameAttribute()
{
return $this->brand->BrandName;
}
You would then be able to access the brand name with $car->brand_name.

Related

How to get data from table reference in Laravel

I have table relation like this:
Is it possible to get the data of the project from the cash mutation table?
In example in cash mutation table with id '4' I wanna call agency name from projects table.
I've done it with with (eager loading in Laravel) but it returns null like:
$cash_mutations = CashMutation::where('id', 4)->with('project')->get();
This is my CashMutation Model:
class CashMutation extends Model
{
use HasFactory;
protected $guarded = ['id'];
public function category(){
return $this->belongsTo(Category::class);
}
public function balanceType(){
return $this->belongsTo(BalanceType::class);
}
public function project(){
return $this->belongsTo(Project::class, 'cash_mutation_id', 'id');
}
public function deposit(){
return $this->hasMany(Deposit::class);
}
}
and this is my Project Model:
class Project extends Model
{
use HasFactory;
protected $guarded = ['id'];
public function cashMutation(){
return $this->belongsTo(CashMutation::class);
}
public function projectFunding(){
return $this->hasMany(ProjectFunding::class);
}
public function SharingProfit(){
return $this->hasMany(SharingProfit::class);
}
}
Is it possible to do that in Laravel? If it possible anyone want to tell me about it? Thanks
Yes. It is definitely possible.
You don’t get an error message so the basic configuration should be fine.
I suspect that the data in the database is not correct. What’s the project_id for the CashMutation with the id 4? Is it maybe null?

Laravel Eloquent Getting children of children via model relqtionships

I'm trying to directly edit my Kodi MySQL DB and build a tool to fix some scraping errors that have always been not quite right.
the relationship of tables is
tvshow -> episode -> file
So I'm able to so far (after creating models for these tables)
List all shows
view specific show and list all episodes
show file entry for that episode.
What I'm trying to do is list all files that belong to the show, via a dropdown. ( as I need to change them )
So I need to use the TVShow model to get all epiodoes that have an idShow entry.. AND then get all the files based on the episode table. I know that Eloquent can handle this typically, but I've only ever used my own table structure, never one like this.. so I think my issue is over riding key names etc...
the key column names are:
idShow
idEpisode
idFile
(Where that SAME name is used as the primary key on the parent table AND the mapping ID in the child table)
Anyhoo, here's my models..
Any ideas?
TVShow
<?php
namespace App\Models;
use Eloquent as Model;
class TvShow extends Model
{
public $table = 'tvshow';
protected $primaryKey = 'idShow';
public function episodes()
{
return $this->hasMany(Episode::class, 'idShow');
}
}
Episode
<?php
namespace App\Models;
use Eloquent as Model;
class Episode extends Model
{
public $table = 'episode';
protected $primaryKey = 'idEpisode';
public function tvshow()
{
return $this->belongsTo(TvShow::class, 'idShow', 'idShow');
}
public function season()
{
return $this->hasOne(Season::class, 'idShow', 'idShow')->where('season', '>=', 0)->where('idSeason', $this->idSeason);
}
public function file()
{
return $this->hasOne(File::class, 'idFile', 'idFile');
}
public function files()
{
return $this->hasMany(File::class, 'idFile', 'idShow');
}
}
File
<?php
namespace App\Models;
use Eloquent as Model;
class File extends Model
{
public $table = 'files';
protected $primaryKey = 'idFile';
public function episode()
{
return $this->belongsTo(Episode::class, 'idFile', 'idFile');
}
}
I'm calling this in my Controller...
TvShow::with('episodes.files')->get();
I'm getting ALL shows as a list..?
A hasManyThrough relationship will work. Add this to your TvShow model.
public function files()
{
return $this->hasManyThrough(Episode::class, File::class);
}
See https://laravel.com/docs/7.x/eloquent-relationships#has-many-through

How to define an object in actionscript 3 using a custom class

Hi my problem is i have to be able to reference certain fields inside my Customer object.]
I am studying AS3 at the moment and being taught custom classes, but we are taught to use the toString method of returning a value i guess you could call it, what i need is to be able to call one field to identify the object i.e. name field from the object in the array, here's my code
package valueObjects
{
public class Person
{
//instance variables
protected var name:String;
protected var address:String;
protected var phoneNo:String;
public function Person(n:String,a:String,p:String)
{
name=n;
address=a;
phoneNo=p;
}
public function toString():String
{
//returns string
return name+":"+address+":"+phoneNo;
}
}
}
some reason it will not put that whole block of code together like THIS IS
So now how do i define it not toString but in object form ??
I think what you are trying to do is access the name, address and phoneNo vars from a different class?
If so, you have to declare them as public vars instead of private vars.
public var name:String; //now this can be accessed from other classes: thisClassInstance.name
If you want to have them read-only from other classes, you have to use a getter method:
protected var name_:String; //local var name for full access;
public function get name():String {
return name_; //this can be access by doing thisClassInstance.name
}

Looking to initialise every view with a List no matter the entry point of the site

I have a Shopping Basket which holds selected items by the user and is stored in a session variable. I'd like this to show various values on every view about the basket state i.e. basket:1, but I can only see how to pass this to a view at a single entry point. How would I initialise every view with this List?
You could render a child action in your Layout. The idea of a child action is that it could execute some logic in parallel to the main action.
For example you could have the following controller:
public class ShoppingBasketInfoController: Controller
{
[ChildActionOnly]
public ActionResult Index()
{
var model = Session["info"] as ShoppingInfoViewModel;
return PartialView(model);
}
}
and then you will have a corresponding partial view (~/Views/ShoppingBasketInfo/Index.cshtml):
#model ShoppingInfoViewModel
<div>
You have #Html.DisplayFor(x => x.NbProducts) in your basket
</div>
and then you could find an appropriate place in your Layout to render this action:
#Html.Action("Index", "ShoppingBasketInfo")
Now all your views will have this information shown at the specified location without worrying about where this information is coming from, how is it stored or what view model it uses. The main actions are completely independent.
I have decorated the child action with the [ChildActionOnly] attribute to ensure that this action will never be accessible through a normal HTTP request from the client using for example /ShoppingBasketInfo/Index. It could only be used within the context of the main executing action.
Your best bet is probably a combination of Base Controller, Base View Model, Interface and Action Filter.
// Interface. To be implemented by model and controller.
public interface IHoldABasket
{
Basket Basket { get; set; };
}
// Base view model. Has a basket as public property.
public BaseBasketViewModel : IHoldABasket
{
public Basket Basket { get; set; }
}
// Base controller model. Also has a basket.
public BaseController : Controller, IHoldABasket
{
public Basket Basket { get; set; }
public BaseController()
{
AttemptBasketLoad();
}
private void AttemptBasketLoad()
{
// Replace the SomeMethodToLoadBasket with whatever method you use
// to retrieve a basket.
Basket = SomeMethodToLoadBasket();
}
}
// Action Filter
public class BasketAwareAttribute : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
// If controller can hold basket AND model can hold basket
if (filterContext.Controller is IHoldABasket
&& filterContext.Controller.ViewData.Model is IHoldABasket)
{
// Copy basket from controller into model.
// Will now be accessible through Basket property on model.
((IHoldABasket)filterContext.Controller.ViewData.Model)
.LoggedInUser
= ((IHoldABasket)filterContext.Controller).LoggedInUser;
}
base.OnActionExecuted(filterContext);
}
}
So that's the infrastructure sorted. Let's look at a practical example. You probably have a ProductListViewModel. That should inherit from the base view model class.
First, make sure your ProductListViewModel inherits from BaseBasketViewModel.
public class ProductListViewModel : BaseBasketViewModel
{
}
Because of the inheritance, your view model contains a basket object and implements the IHoldABasket interface.
Your controllers will inherit from BaseController.
public class ProductController : BaseController
{
}
A controller method looks like this.
[BasketAware]
public ViewResult Products(int page = 1)
{
// Load VM that implements IHoldABasket
// Really contrived, I know... :P
var vm = new ProductListViewModel() { Results = productServices.Search() };
return View(vm);
}
That should be it. What's happening under the hood is
Base controller attempts to load a basket, storing it if it finds one
Controller and Model inherit a common interface, making the automated copy from controller to model easier to achieve.
Action filter loads at the last minute. If both controller and model can hold a basket (e.g. both implement IHoldABasket), the basket is copied from controller to model.
All view models that derive from BaseBasketViewModel will have a public property called Basket.

AS3 - References to argument, is that bad?

I read a question on stackoverflow (couldn't find it now) about how variables in a method can be only accessed in that method, but the code still works with the answer being an analogy of a hotel room. In AS3, I believe everything that's not primitive gets passed as a reference. So, the following code would be the same as that question and isn't guaranteed to work?
public class Testy {
private var foo:Array;
public function Testy(input:Array) {
// Allow the whole class to access it
foo = input;
}
public function traceFoo(){
trace(foo);
}
}
Now, foo would be a reference to the input argument in the class' constructor. Is this safe code/good practice? Thanks!
Yes this is safe/good code practice as long as you don't want to manipulate the original Array. If you want to manipulate the original array, allow public access to the array by making it a public var or using a public getter/setter.
What you've described is a property, and is inline with encapsulation of object oriented programming.
This would expose a getter and setter:
package
{
import flash.display.Sprite;
public class Testy extends Sprite
{
private var _foo:Array;
public function get foo():Array
{
return _foo;
}
public function set foo(value:Array):void
{
_foo = value;
}
public function Testy()
{
super();
}
}
}
Also it's better to return _foo.concat() in getter not to break encapsulation.