Can't extend my class to Eloquent while it's already extended to BaseController - class

I have a ListingsController that extends BaseController which is fine, my app works.
But now I intend to create a new ContactController and create a relation between it and ListingController.
Each listing should have 1 contact and there's a contact_id field in listings table.
The problem is, to use that, I need to extend my class to Eloquent and it's already extended to BaseController and if I change that my app crashes down.
Is there a solution for this?
Thanks.

As SUB0DH said, relationships should be declared in the Model, not in the Controller, you'd want to have something like this in your Listing model:
public function contact()
{
return $this->hasOne('Contact');
}
and in your Contact model you can link the contact to a listing by using
public function user()
{
return $this->belongsTo('User');
}
Be sure to read http://laravel.com/docs/eloquent#one-to-one

Related

One to many polymorphic relationship

It's a common situation but I somehow couldn't manage to find a reasonable solution so far. Basically I need the following:
I have the model House which contains a couple of other models (e.g. Brick, 'Stick', 'Chair' etc.). Each one of them has a belongsTo relation to the House (so basically in the sticks, chairs and bricks table there is a house_id column). Each model contains a public function house() method which returns the house they're part of. Now comes the problem that I'd like to get all of a house's supplies by a method, let's say for example public function supplies(), which should return a collection of instances of the classes Stick, Chair and Brick. Is there any convenient way to achieve that? Could I for example unite those classes by a trait and somehow point to that trait in the house's method or maybe with a BaseClass, let's say Supply, that all the supplies should inherit? Any recommendances? Any help is greatly appreciated and thanks in advance!
There is no built-in support for this in Laravel.
You can define separate HasMany relationships and then merge them with an accessor:
class House extends Model {
public function bricks() {
return $this->hasMany(Brick::class);
}
public function chairs() {
return $this->hasMany(Chair::class);
}
public function sticks() {
return $this->hasMany(Stick::class);
}
public function getSuppliesAttribute() {
return $this->bricks->toBase()->merge($this->chairs)->merge($this->sticks);
}
}
$supplies = $house->supplies;
+++ UPDATE +++
I've created a package for merging relationships using views:
https://github.com/staudenmeir/laravel-merged-relations
First, create the merge view in a migration:
use Staudenmeir\LaravelMergedRelations\Facades\Schema;
Schema::createMergeView(
'supplies', [(new House)->bricks(), (new House)->chairs(), (new House)->sticks()]
);
Then define the relationship:
class House extends Model
{
use \Staudenmeir\LaravelMergedRelations\Eloquent\HasMergedRelationships;
public function supplies()
{
return $this->mergedRelation('supplies');
}
}
Use it like any other relationship:
House::find($id)->supplies;
House::find($id)->supplies()->paginate();
House::with('supplies')->get();

Laravel Eloquent Models __construct method to call relations

I want to have my model automatically call its relations when instantiated. As of now my model looks like this:
class AdminLog extends Model{
public function __construct(){
$this->belongsTo('App\User', 'admin_id');
}
}
but when i try to do dd(AdminLog::get()->first());, it doesnt show any relations.
Edit#1: tried adding parent::__construct(); inside the model's __construct method but it didn't work.
belongsTo() defines a relationship, it doesn't load it.
First you need to define the relationship, then you can load it at any point using the load method.
class AdminLog extends Model {
public function user() {
return $this->belongsTo(\App\User::class, 'admin_id');
}
}
$log = AdminLog::first();
$log->load('user');
It is possible to load inside the constructor, but I would highly recommend against that. If you have 20 AdminLog objects then it will query the database 20 times, once for each object. That's inefficient.
What you should do instead is use eager loading. This will query the users table just once for all 20 admin logs. There are many ways to do this, here is an example:
$logs = AdminLog::take(20)
->with('user')
->get();
dd($logs->toArray());

Get a list of multiple types using Entity Framework

Using MVC4 with Entoty Framework CodeFirst I am having problems with the following scenario:
public class Survey
{
public QuestionCollection Questions {get;set;}
}
public class QuestionCollection : List<IQuestion> //Just for MVC
{ }
public class QuestionType1 : IQuestion { ... }
public class QuestionType2 : IQuestion { ... }
Seems straightforward. Now in my controller I want to get the Survey so i have:
DataContext context = new DataContext ();
var survey = context.Surveys.Include(s => s.Questions).SingleOrDefault(s => s.Id == id);
It does compile but runtime it gives me the error:
A specified Include path is not valid. The EntityType 'Survey' does not declare a navigation property with the name 'Questions'.
What am I doing wrong here?
Is there any good tutorial on this topic?
Entity Framework Code First requires that navigation collections be declared as an ICollection<T>. Also, to enable lazy loading of the associations, it should be virtual. This is because, unless otherwise specified, EF will return a proxy object wrapping your declared class. Since your original QuestionCollection property is a concrete implementation, it can't override that in the proxy and enable the navigation. Questions has to be declared as the interface.
Your concerns and requirements in EF are different than in MVC, and they aren't always compatible. If you really, really wanted QuestionCollection, you'll have to map that.
Your Surveys entity should look like this:
public class Survey
{
public virtual ICollection<Question> Questions { get; set; }
}
Also, EF can't implement entity types declared as an interface. This won't work: public virtual ICollection<IQuestion> - your individual question types must all inheirit from a common abstract or concrete instance. They can still implement the interface, but your entity type properties cannot be declared that way.
I would highly recommend going through this series of blog posts on inheritance structures in
EF.
The way you would set up your questions entities would look like this:
// You can still keep the IQuestion interface around for MVC
public abstract class Question : IQuestion
{
// ... properties ...
}
public class QuestionType1 : Question
{
// ... properties ...
}
public class QuestionType2 : Question
{
// ... properties ...
}
public class Survey
{
// Note, collection of Question, not the interface.
public virtual ICollection<Question> Questions { get; set; }
}
Depending on how exactly you want your table structure to look, the base Question class may or may not be abstract. Refer to the above blog posts to see the various options - Table per Type, Table per Hierarchy, Table per Concrete.
Have a look at this link,I think you need to set some auto policies http://forums.asp.net/t/1816051.aspx/1

how to parametrize an import in a View?

I am looking for some help and I hope that some good soul out there will be able to give me a hint :)
I am building a new application by using MVVM Light. In this application, when a View is created, it instantiates the corresponding ViewModel by using the MEF import.
Here is some code:
public partial class ContractEditorView : Window
{
public ContractEditorView ()
{
InitializeComponent();
CompositionInitializer.SatisfyImports(this);
}
[Import(ViewModelTypes.ContractEditorViewModel)]
public object ViewModel
{
set
{
DataContext = value;
}
}
}
And here is the export for the ViewModel:
[PartCreationPolicy(CreationPolicy.NonShared)]
[Export(ViewModelTypes.ContractEditorViewModel)]
public class ContractEditorViewModel: ViewModelBase
{
public ContractEditorViewModel()
{
_contract = new Models.Contract();
}
}
Now, this works if I want to open a new window in order to create a new contract... or in other words, it is perfect if I don't need to pass the ID of an existing contract.
However let's suppose I want to use the same View in order to edit an existing contract. In this case I would add a new constructor to the same View, which accepts either a model ID or a model object.
"Unfortunately" the ViewModel is created always in the same way:
[Import(ViewModelTypes.ContractEditorViewModel)]
public object ViewModel
{
set
{
DataContext = value;
}
}
As far as I know, this invokes the standard/no-parameters constructor of the corresponding ViewModel at composition-time.
So what I would like to know is how to differentiate this behavior? How can I call a specific constructor during composition time? Or how can I pass some parameters during the Import?
I really apologize if this question sounds silly, but I have only recently started to use MEF!
Thanks in advance,
Cheers,
Gianluca.
You CAN do this. Check out the Messenger implementation in MVVM-Light. You can pass a NotificationMessage(Of Integer) to send the right ID to the view model. The view model has to register for that type of message, and load it when a message is sent.
MEF Imports by default only have a parameterless constructor.

How to automatically set and attribute to controller

Maybe the question is not self-explanatory, so I will explain it through.
The deal is: I got the variable $conn in the bootstrap class file. I'd like to make it global for every controller so that I just have to call $this->conn in the controller action scope in order to access the data inside. How would I do it?
Thx
One fairly straightforward way is to create your own base class form which your controller's inherit:
<?PHP
class My_Controller_Action extends Zend_Controller_Action {
public $conn;
public function init(){
//set $this->conn
}
}
class Some_Real_Controller extends My_Controller_Action {
//$this->conn exists!
}
class Some_Other_Real_Controller extends My_Controller_Action {
//$this->conn exists here too!
}
Matthew Weier O'Phinney posted a blog entry recently with some examples of how to use action helpers to do this, see:
http://weierophinney.net/matthew/archives/235-A-Simple-Resource-Injector-for-ZF-Action-Controllers.html
this will achieve the same thing without having to use a base controller class.