I'm trying to create an additional attribute method in a model which appends a ratings label column to an existing rating model. I have the exact same code working for another model which adds click data. I'm getting an Undefined index: rating_label error - can't figure out why? Any help much appreciated.
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Rating extends Model
{
protected $table = 'rating';
protected $primaryKey = 'rating_id';
protected $appends = array('rating_label');
/**
* Define a 1-many inverse relationship in eloquent
*/
public function Article()
{
return $this->belongsTo(Article::class, 'article_id');// (Model, primary_key)
}
/**
* Add additional column to Rating model for use in ClassifyingService class
*/
public function getRatingLabelAttribute()//accessor getter/setter
{
return $this->attributes['rating_label'];
}
}
Related
I'm currently trying to create a eloquent relationship between two models in my database, one in sql and on in mongodb:
<?php
namespace App\Models\Trend;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Jenssegers\Mongodb\Eloquent\HybridRelations;
class Location extends Model
{
use HasFactory, HybridRelations;
protected $table = 'trends';
protected $fillable = [
'woeid',
'name',
];
/**
* #return \Illuminate\Database\Eloquent\Relations\HasMany|\Jenssegers\Mongodb\Relations\HasMany
*/
public function trends()
{
return $this->hasMany(Trend::class);
}
}
<?php
namespace App\Models\Trend;
use App\Models\Scopes\AscendingOrderScope;
use App\Models\Team;
use App\Models\User;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Jenssegers\Mongodb\Eloquent\Model;
class Trend extends Model
{
use HasFactory;
protected $connection = 'mongodb';
protected $collection = 'trends';
protected $fillable = ['trends'];
/**
* #return void
*/
protected static function booted()
{
static::addGlobalScope(new AscendingOrderScope);
}
/**
* #return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function location()
{
return $this->belongsTo(Location::class);
}
}
Once i try to call the ->location relationship on the Trend model I only get the following error:
PHP Error: Call to a member function prepare() on null in /home/fmk/Code/socmint/vendor/laravel/framework/src/Illuminate/Database/Connection.php on line 413
In the database the location_id field is corretly set with an id of an existing Location model.
Since it is a hybrid relation I also added the HybridRelation trait as described in the packages example (I'm nearly doing the exact stuff as in the example).
The other way around (calling location->trends is working without a problem)...
What am I missing?
Thanks for your help,
FMK
Found the solution after debugging through the callstack.
Laravel seems to does not know which connection to use on the relationship model so it defaults back to the one of the model with the relationship defined.
In my case the trend was using the mongodb connection and laravel tried to search for the location in this connection aswell.
Solution was was to define the connection on the SQL Trend model aswell:
protected $connection = 'mysql';
I'm on Laravel 8 with Livewire, currently have 3 models, Category, SubCategory and MenuItem for 3 tables. All the above models have separate livewire controllers and have the code for the CRUD operations respectively. I have separate views and routes to edit the above tables and they all have a eloquent relationship between each other. Now what I need to do here to is, I need to display all the three tables in a single view to carry out the CRUD operations.
I tried to achieve this by using the sub-view function, to pass the view and make the variables available to the specific view, but it didn't work out and I think it isn't the way to do it, was just trying to figure a workaround. I'm mentioning my models down below for referencing. Please help me with this. Thanks a lot for your time!
App\Models\Category
class Category extends Model
{
use HasFactory;
protected $table = "categories";
protected $fillable = ['sub_category_name'];
public function SubCategories() {
return $this->hasMany(SubCategory::class, 'category_id');
}
public function MenuItems() {
return $this->hasManyThrough(
'MenuItem::class',
'SubCategory::class',
'sub_category_id',
'category_id'
);
}
}
App\Models\SubCategory
class SubCategory extends Model
{
use HasFactory;
protected $table = "sub_categories";
protected $fillable = ['category_id', 'sub_category_name'];
public function Categories() {
return $this->belongsTo(Category::class, 'category_id');
}
public function MenuItems() {
return $this->hasMany(MenuItem::class, 'sub_category_id');
}
}
App\Models\MenuItem
class MenuItem extends Model
{
use HasFactory;
protected $table = "menu_items";
protected $fillable = ['sub_category_id', 'item_name', 'item_description'];
public function SubCategories() {
return $this->belongsTo(SubCategory::class, 'sub_category_id');
}
}
This is what I tried to achieve the said result. As I needed to include the view with the sub category table to the menu items table view. I made the variables available to that specific view.
Resources\Views\Livewire\Menu-Item
<div>
#include('livewire.sub-category')
</div>
App\Providers\AppServiceProvider
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\View;
use App\Models\SubCategory;
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*
* #return void
*/
public function register()
{
//
}
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
View::composer('livewire.menu-item', function ($view) {
$view::with('sub_category_name', SubCategory::orderBy('sub_category_name')->get());
});
}
}
I managed to solve the above problem, using livewire's component feature. Created 3 separate component for 3 separate tables, and finally used all the three components in the master-menu.blade.php file. Working with livewire and laravel is a treat.
I'm trying to create a many to many relationship using Laravel, but I am stuck.
Here's my current table model:
album
album_id
name
created_at
user_image
user_image_id
value
albumxuser_image (junction table)
albumxuser_image_id (primary key & auto increment)
album_id (FK from album)
user_image_id (FK from user_image)
I want to be able to get the album name from albumxuser_image table.
Here's what I've done so far.
Album.php model
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Album extends Model {
/**
* The database table used by the model.
*
* #var string
*/
protected $table = 'album';
protected $primaryKey = 'album_id';
public function AlbumxUserImage() {
return $this->belongsToMany('AlbumxUserImage', 'albumxuser_image','album_id','user_image_id');
}
}
routes.php (I didn't use view since I'm making a practice)
Route::get('all', function() {
$albumxuserimage = AlbumxUserImage::all();
foreach ($albumxuserimage->AlbumxUserImage as $getthem) {
echo $getthem->pivot->name; // I want to get the name column of the album table.
}
});
AlbumxUserImage.php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class AlbumxUserImage extends Model {
protected $table = 'albumxuser_image';
protected $primaryKey = 'albumxuser_image_id';
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = ['album_id', 'user_image_id'];
}
Here's the error I get
Call to undefined method Illuminate\Database\Eloquent\Collection::AlbumxUserImage()
You're trying to call AlbumxUserImage() on a Collection of models instead of on each individual model.
AlbumxUserImage::all() is returning a Collection of models, which you can think of as an array. You need to iterate over the collection and call AlbumxUserImage() on each model in the collection.
That may solve your problem for now, but you seem to not understand how many-to-many relationships work in Laravel.
How you should be doing Many-To-Many
I don't know why you have a model for your pivot table. That is not how Laravel normally handles models with many-to-many relationships. A typical many-to-many relationship with your tables would look like this:
Models:
class Album extends Model {
protected $table = 'album';
protected $primaryKey = 'album_id';
public function images() {
return $this->belongsToMany('App\UserImage', 'albumxuser_image','album_id','user_image_id');
}
}
class UserImage extends Model {
protected $table = 'user_image';
protected $primaryKey = 'user_image_id';
public function albums() {
return $this->belongsToMany('App\Album', 'albumxuser_image','user_image_id','album_id');
}
}
Usage:
// Get all album names through UserImage
$userImages = UserImage::all();
foreach ($userImages as $userImage) {
foreach ($userImage->albums as $album) {
echo $album->name;
}
}
// Get all images through Album
$albums = Album::all();
foreach ($albums as $album) {
foreach ($album->images as $image) {
echo $image->value;
}
}
I'm trying to make a CRUD application in Laravel 5 to better understand how a php platform work ( first time using one ), but I keep getting the "Method [all] does not exist." error and I can't understand what i'm doing wrong. I have a table named 'products' in Mysql and what I'm trying to do, is to list all the entry's from within the table. I also have an index.blade.php that I will post if needed.
ProductsController.php
class ProductsController extends Controller {
/**
* Display a listing of the resource.
*
* #return Response
*/
public function index()
{
$products = ProductsController::all();
return View::make('products.index')->with('products', $products);
}
Products.php
class Products extends Eloquent
{
}
routes.php
Route::resource('/', 'ProductsController#index');
Eloquent will assume the User model stores records in the users table. You may specify a custom table by defining a $table property on your model. [Ref]
So, you should rename your Products.php to Product.php (or define the $table property on your model).
Then you can retrieve all products:
$products = Product::all();
Product.php
<?php namespace App;
use Illuminate\Database\Eloquent\Model;
class Product extends Model {
//
}
ProductsController.php
<?php namespace App\Http\Controllers;
use App\Product;
class ProductsController extends Controller {
public function index()
{
$products = Product::all();
return View::make('products.index')->with('products', $products);
}
}
Why you write ProductsController to access all() function. To access all() function you must call Product model.
ProductsController::all();
Example
Product Model
class Product extends Model
{
/**
* The database table used by the model.
*
* #var string
*/
protected $table = 'products';
}
Product Controller
class ProductController extends Controller {
/**
* Display a listing of the resource.
*
* #return Response
*/
public function index()
{
$products = Product::all();
return View::make('products.index')->with('products', $products);
}
Sometimes you may wish to limit the attributes that are included in your model's array or JSON form, such as passwords. To do so, add a hidden property definition to your model:
class User extends Model {
protected $hidden = ['password'];
}
This is model specific.
Is there any method to hide globally?
ie,I want to hide deleted_at and created_by from all model json result.
The easiest way to do that is by creating a base model. Like this:
class BaseModel extends Model {
protected $hidden = ['deleted_at', 'created_by'];
}
And then all your models extend from that:
class User extends BaseModel {
}
Note that this way if you wanted to add some hidden fields for a specific model you would have to as well specify those two global hidden attributes:
class User extends BaseModel {
protected $hidden = ['deleted_at', 'created_by', 'password'];
}
If that bothers you, you could merge the global attributes in from the contructor:
class BaseModel extends Model {
private $globalHidden = ['deleted_at', 'created_by'];
public function __construct(array $attributes = array()){
$this->hidden = array_merge($this->globalHidden, $this->hidden);
parent::__construct($attributes);
}
}