How do I use a Laravel dynamic relationship? - laravel

I am a newbe in Laravel. The docs show how to use relationships like this:
One To Many (Inverse) / Belongs To
Now that we can access all of a post's comments, let's define a relationship to allow a comment to access its parent post. To define the inverse of a hasMany relationship, define a relationship method on the child model which calls the belongsTo method:
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Comment extends Model
{
/**
* Get the post that owns the comment.
*/
public function post()
{
return $this->belongsTo(Post::class);
}
}
Once the relationship has been defined, we can retrieve a comment's parent post by accessing the post "dynamic relationship property":
use App\Models\Comment;
$comment = Comment::find(1);
return $comment->post->title;
My question is: Where is this code? In a controller or in a view?

If you use MVC structure, you should understand that
Model is layer where you store your data
View is layer where you should only display your data
and Controller is layer where you can keep your logic.
If you have a lot of difficult logic or big application, you should better to use Services, as layer between Controllers And Models.
Receiving Comments from model and prepeare them should be in controller level. In view level you just define how to show them to user.
I hope it will help you to understand difference between logic layers.

you can access this relationship in controller or view like this-
suppose you want to make relation between product model and brand model:-
in product model:-
public function brand(){
return $this->belongsTo('App\Model\Brand','brand_id','id');
}
now you are able to see which product belongs to which brand without any query or using loop.
just do in controller:-
$product=Product::with('brand')->get();
here you get all the data...
and when you use it on **view **just do it:
{{$product->brand->brand_name}}
//brand name should the column name
I hope you understood...
Happy Learning!

Related

Laravel Relationships, don't know how to display

I have two models. Business and City.
Business:
id
title
-some columns--
city_id
City:
id
name
How to display the city name, when I get business data to view
I was able to display cities using the laravel voyager lessons
When I want to get it like $business->city_id
If you are using models, you can create a relationship by adding hasOne or hasMany to your model codes.
When you call it from your controller, you can call the relationship you wrote in your model with the 'with' query.
Model
public function city()
{
return $this->hasOne(City::class,'id','cityid');
}
Controller
$business=Business::with('city')->first();
$cityname=$business->city->name;
If you don't use model, you can connect with 'join'
You have 2 options. First, you can get city details on the controller:
Business::with('city')...;
On the blade
$business->city->name;
Other option fetching it on the blade directly. I don't recommend this because of extra database queries.
$business->city()->name;

Laravel restrict content based on customer/user/tenant

I'm in a dilemma to find some sort of logic to restrict user access to content within the same model.
For example, a supplier only can see products that they supply and the customer only can see a product which they buying. (note: Each product can have multiple supplier or customers. We call id a product node)
Now, I have the relationship set to a product belongs to many suppliers and a product belongs to multiple customers.
Currently I have the spatie roles and permissions in my site, which works great for 1 tenant (mainly our office(50-150 users)). It is not a problem if our office user can see details of multiple customers or products, but the problem starts when the customer logs in. I only want to show the product pricing or data that belonging to them. It is a big no no to see any other customer or supplier data.
I looked multi tenancy implementation, but I believe this wouldn't cover my need.
I apologise if I've overlooked something, but I try to keep the data as secured as possible.
Could you please shed some light on this dilemma and direct me to the correct path?
Many thanks for your input!
I'm assuming that all of the models you want to restrict have a relationship directly to the customer, so you can actually add a global scope that adds a default parameter to the query.
Take the following scope:
<?php
namespace App\Scopes;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Scope;
use Illuminate\Support\Facades\Auth;
class CustomerOwnedScope implements Scope {
public function apply(Builder $builder, Model $model) {
if (Auth::guard('customer')->check()) {
$builder->where('customer_id', '=', Auth::guard('customer')->id);
}
}
public function extend(Builder $builder) {
$this->addWithoutCustomer($builder);
}
protected function addWithoutCustomer(Builder $builder) {
$builder->macro('withoutCustomer', function (Builder $builder) {
return $builder->withoutGlobalScope($this);
});
}
}
Any model that has this scope will automatically add the clause WHERE customer_id = ? where ? is the id of the currently authenticated customer, if one is authenticated. Assuming that you're using Laravel auth this would prevent you from having to do anything specific to achieve your goal.
It also adds the scope withoutCustomer() that would prevent the where clause from being added.
The simplest way to add this to a model that belongs to a customer would be to create yourself a trait (concern) like so:
<?php
namespace App\Concerns;
use App\Scopes\CustomerOwnedScope;
trait OwnedByCustomer {
public static function bootOwnedByCustomer() {
static::addGlobalScope(new CustomerOwnedScope);
}
public function customer() {
$this->belongsTo(Customer::class, 'customer_id');
}
}
This would add the customer relationship as well as add the scope to automatically query based on the current customer.
You can obviously modify this further to include other relationships, or you can add some more conditions to only apply for customers with a certain flag set, or not set (for internal users, etc).
This whole approach does assume that your internal admin users and your external customer users are using different auth guards (which would be the ideal approach in this situation).
I should add that the code above is taken from an article I wrote on the subject of multi-tenancy, specifically the part about dealing with tenants in a single database. If you would like, you can read it here: https://ollieread.com/articles/laravel-multi-tenancy-avoiding-over-engineering#single-database

Laravel Method [hasMany] does not exist

I have 2 controllers and models:
User Controller & Model
Hero Controller & Model
Each user can have unlimited heroes - it means that the relationship between them is one to many.
In my UserController I created the following method:
/**
* Get the heroes of the user.
*/
public function heroes()
{
return $this->hasMany(Hero::Class);
}
while in my HeroController I created this method:
/**
* Get the user that owns the hero.
*/
public function user()
{
return $this->belongsTo(User::class)
}
Added this to my routes file:
Route::get('userHeroes', 'UserController#heroes');
and it returns this error:
{"error":{"message":"Method [hasMany] does not exist.","status_code":500}}
What could have gone wrong.. ?
The controller is just a delegate between the request and the return data - you tell it that you want something, it figures out what you want, and then it calls the appropriate places to get something to return.
The hasMany() and belongsTo() methods, on the other hand, are logic specifically related to the Hero and User models, on the other hand.
What you need is to move the heroes() method to your User model, because a user can have many heroes. Also need the user() method to your Hero model, because a hero belongs to a user.
Then you put an action call in a controller. Let's say, for instance, that you have a UserController which has an getHeroes() method. That might look like this:
public function getHeroes() {
$user = auth()->user();
$heroes = $user->heroes;
return $heroes;
}
And that will format it to JSON. Just an example.
But you might want to read a tutorial or two about this, since it's fairly basic stuff and it's good to get a good handle on early on. Please don't take that the wrong way - we're happy to help if you run into problems, I just think you might need a stronger foundation. The screencasts at Laracasts are highly recommended for this purpose.
it must be declared in models, not in controllers, hasMany() is a method in eloquent models.
hasMany and belongsTo methods are eloquent class methods.
And we inherit eloquent in our model so that we can use the eloquent methods functionality.
In order to use the relation, you have to define the relation method in respective model class and then you can call from controller.
Please refer the documentation Eloquent relationship documentation
Hope i have cleared your doubt.
Thanks

what to do with an inverted polymorphic relation?

I have been trying to get my head around these polymorphic relationships all day. I might be over complicating/thinking it but. Can Laravel handle inverse polymorphic relationships? I have a registration flow that can have two types of field Models- normal field and customField.
When I loop through all the fields available it could pull the attributes from either NormalField or CustomField.
<?php
foreach($registrationFlow->fields->get() as $field)
{
echo $field->name; // could be custom field or could be normal field
}
?>
My difficulty is that, the example given in the docs works if you want to assign a photo to either staff or orders, but i want to assign either a customField or a normalField to a registrationFlow
*Edit
If you follow the example for the polymorphic many to many relationship, The tag class contains posts and videos- while i would want just a simple fields() method that relates to customField or normalField dependent on the type
First of all, you should take a look at the updated docs for Laravel 5.1: https://laravel.com/docs/5.1/eloquent-relationships#polymorphic-relations.
I think the difficulty with the example they provide is that the relationship between Photo and Staff/Product are "has-a" relationships, whereas you are trying to model an "is-a" relationship. However, you can model "is-a" essentially the same way. Take a look at this article: http://richardbagshaw.co.uk/laravel-user-types-and-polymorphic-relationships/.
Basically, the strategy is to define a generic model (and a generic table), perhaps in your case Field, that relates to your RegistrationFlow. You then have two subtype models, NormalField and CustomField, that have one-to-one relationships with Field. (there's your "is-a"). Thus, RegistrationFlow is indirectly related to your field subtypes.
Polymorphism comes in when you want to access the specific subtypes:
class Field extends Model {
public function fieldable()
{
return $this->morphTo();
}
}
Your base field table should have fieldable_id and fieldable_type columns defined (see the Eloquent docs).
You can then add methods to NormalField and CustomField that let you access the base model (your "inverse relationship"):
class NormalField {
public function field()
{
return $this->morphOne('Field', 'fieldable');
}
}
class CustomField {
public function field()
{
return $this->morphOne('Field', 'fieldable');
}
}
Usage:
$field = Field::find(1);
// Gets the specific subtype
$fieldable = $field->fieldable;

Laravel 4 Use the same Model and Controller for 12 lists for selects

I have to meke models, controllers and views for 12 tables. They have all the same structure id, name, order.
I was thinking and maybe using:
Controller
index($model)
$model::all()
return View::make(all_tables,compact('model'))
edit($model,$id)... and so on.
But and don't know if there's a way for using only one model.
Did anybody do anything like this?
Any idea?
Thanks
Although each model has the same table structure, what you're trying to achieve would not be advisable as you'd lose a lot of the fluent capabilities of Laravel's Eloquent ORM.
Regarding the controller, this would work:
<?php
namespace App\Http\Controllers;
use App\Http\Requests;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
class GenericModelController extends Controller
{
public function loadModelById($model, $id)
{
$instance = \App::make('App\\' . ucfirst($model));
return $instance->find($id);
}
}
You'll need the following route:
Route::get('show/{model}/{id}', 'GenericModelController#loadModelById');
Example, to load a user with an id of 1:
http://www.yourdomain.com/show/user/1
Edit: I just saw that you're using Laravel 4, so the syntax for defining a route will be a little different I believe but the general concept will still work. Testing in Laravel 5 and works perfectly.
You should get get some idea from here.Please use the link below.
https://scotch.io/tutorials/a-guide-to-using-eloquent-orm-in-laravel
// app/models/Bear.php
class Bear extends Eloquent {
// MASS ASSIGNMENT -------------------------------------------------------
// define which attributes are mass assignable (for security)
// we only want these 3 attributes able to be filled
protected $fillable = array('name', 'type', 'danger_level');
// DEFINE RELATIONSHIPS --------------------------------------------------
// each bear HAS one fish to eat
public function fish() {
return $this->hasOne('Fish'); // this matches the Eloquent model
}
// each bear climbs many trees
public function trees() {
return $this->hasMany('Tree');
}
// each bear BELONGS to many picnic
// define our pivot table also
public function picnics() {
return $this->belongsToMany('Picnic', 'bears_picnics', 'bear_id', 'picnic_id');
}
}
I find a simple way.
Only one model, one controller and one view(index,edit, etc) too.
A single table with
id, name of list, value (name to appears in the list)
Yo pass can pass to de view all the values per list, and for any list in the table you can create de select if it's no empty.

Resources