I'm trying to pass an array of database entries to a view using Eloquent. I'm new to MVC development. The code is as follows:
School.php (model)
class School extends Eloquent
{
protected $table = 'Schools';
public $timestamps = false;
protected $softDelete = false;
public function school()
{
return $this->hasOne('School');
}
}
SchoolController.php (controller)
class SchoolController extends BaseController
{
public $restful = true;
public function getIndex()
{
return View::make('schools')
->with('schools', School::all());
}
}
schools.blade.php (View)
#extends('layouts.schools')
#section('school-search')
<ul>
#foreach($schools as $school)
<li>{{ $school->name }}</li>
#endforeach
</ul>
#stop
However, I'm getting a white screen of death when I load the page. The view works fine when I comment out the "->with('schools', School::all())" part, so I think it has to do with Laravel failing to access the School object. I've googled/stackoverflowed a bit and can't find anyone with a similar problem.
Thanks!
edit: Some relevant info:
I have had this problem before, where it would whitescreen anything I routed to, however I corrected that by changing app/storage permissions. Changing permissions does not seem to help this whitescreen problem.
Laravel seems to be error reporting just fine. When there is something that doesn't make sense in my code, I get an error.
We are in development environment.
edit:
when I run php artisan serve, it gives an error "This php binary is not version 5.4 or greater" Could this be related?
edit:
I've updated to PHP 5.4. Still whitescreening. Here is the latest in my error log.
#0 /var/www/playground/vendor/laravel/framework/src/Illuminate/Foundation/Console/ServeCommand.php(29): Illuminate\Foundation\Console\ServeCommand->checkPhpVersion()
#1 /var/www/playground/vendor/laravel/framework/src/Illuminate/Console/Command.php(108): Illuminate\Foundation\Console\ServeCommand->fire()
#2 /var/www/playground/vendor/symfony/console/Symfony/Component/Console/Command/Command.php(241): Illuminate\Console\Command->execute(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#3 /var/www/playground/vendor/laravel/framework/src/Illuminate/Console/Command.php(96): Symfony\Component\Console\Command\Command->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#4 /var/www/playground/vendor/symfony/console/Symfony/Component/Console/Application.php(892): Illuminate\Console\Command->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#5 /var/www/playground/vendor/symfony/console/Symfony/Component/Console/Application.php(191): Symfony\Component\Console\Application->doRunCommand(Object(Illuminate\Foundation\Console\ServeCommand), Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#6 /var/www/playground/vendor/symfony/console/Symfony/Component/Console/Application.php(121): Symfony\Component\Console\Application->doRun(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#7 /var/www/playground/artisan(59): Symfony\Component\Console\Application->run()
#8 {main} [] []
The problem is with your School.php's relationship defination.
public function school()
{
return $this->hasOne('School');
}
By this you are telling laravel that this model has a one-to-one / one-to-many relationship with itself and this causes a recursive loop when School::all() is called. Once the loop exceeds the max allowed memory size as set in php.ini, it will return an empty response. Thats why you are getting a blank screen.
This relationship does not seem logical to me but if the schools are hierarchical, you should change the method name school() to something like parent() to avoid confusing laravel. Eg..
public function parent()
{
return $this->hasOne('School', 'parent_id');
}
class School extends Eloquent
{
protected $table = 'Schools';
public $timestamps = false;
protected $softDelete = false;
public function school()
{
return $this->hasOne('School');
}
}
You have a School object which has a one to one relationship with another school object? You also haven't defined the foreign key to the relationship
I think that laravel is just recursively loading school object after school object and then running out of memory before it can build an error. You can test this by commenting out the entire school() function and seeing what happens.
Another question can you access you apache error log?
Related
So I have this model, 'Ticket' that contains (among other things) a "category_id" column.
To simplify, here is how my datas look:
Tickets table
id
Title
category_id
1
Issue #1
2
2
Issue #2
4
3
Issue #3
1
Categories table
id
Title
1
Authentication
2
Account
3
Billing
In my Ticket model, I've done the following:
/**
* #return Category
*/
public function category(): Category
{
return Category::firstWhere($this->category_id);
// return $this->belongsTo('App\TicketCategory'); <-- how it was, can't eager load.
}
But I'm getting an undefined function addEagerConstraints().
Edit: here is my controller:
class TicketController extends Controller
{
public function index()
{
$tickets = Ticket::with('category')->all();
// dd($tickets);
return view('tickets.index', compact('tickets'));
}
}
I also tried with hasOne but this implies that "categories" needs a "ticket_id" column, which I want to avoid.
I'd like my models just to pick the category they are related to and nothing more.
What would be a solution here?
Thanks in advance
In your category model, have the following code:
public function tickets()
{
return $this->hasMany(Ticket::class);
}
And add this in the ticket model:
public function category()
{
return $this->belongsTo(Category::class);
}
Add in the PHP 8 stuff you have already, and it should work!
Edit:
I saw you added more about how to load this properly. The code you already have in your controller should work with this as well. You'll maybe need to change the model class names in the methods I provided, but that should do the trick!
For more information about this type of relationship (one to many) read this part of the documentation.
I am upgrading and refactoring my site to laravel 5.5, and this code is giving me a problem at the moment. I searched in the laravel github docs and didn't find any breaking changes that might affect this.
What I am trying to do is Related To section in my site, In every recipe page I want to display some more recipes that has the same category.
Here is my code:
public static function getRelatedRecipes($recipe){
$related_category_ids = $recipe->category()->pluck('categories.id');
return $relatedRecipes =
Recipe::whereHas('categories', function ($q)use($related_category_ids){
$q->whereIn('category_id', $related_category_ids);
})
->where('id', '<>', $recipe->id)
->take(4)
->inRandomOrder()
->get();
}
This is the recipe model:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Recipe extends Model
{
protected $guarded=[];
/**
* Get the route key name for Laravel.
*
* #return string
*/
public function getRouteKeyName()
{
return 'slug';
}
public function category()
{
return $this->belongsToMany('App\Category');
}
}
What could be the problem?
Thanks,
P.S
If any other code that you think is needed to resolve this, please tell me and I will post it here. :)
First of all make sure, Recipe you use in the method is the model, so instead of
Recipe::whereHas('categories', function ($q)use($related_category_ids){
use
\App\Recipe::whereHas('categories', function ($q)use($related_category_ids){
The other thing is this categories relationship. In model you don't have categories relationship, you have only category relationship
I'm new to Laravel.
I have two tables related to each other.
I want to set null to the related table record when the other related table record is soft deleted.
I know how to soft delete when the other related table record, but how can I set null instead of soft-delete?
Product Model (Edited)
class Product extends Model
{
use SoftDeletes;
protected $dates = ['deleted_at'];
public $table = "products";
public function projects()
{
return $this->hasMany("App\Model\Project");
}
public static function boot(){
parent::boot();
static::deleted(function($product)
{
//set null
$product->projects()->setNull();
});
}
}
Project Model(Edited)
<?php
class Project extends Model
{
use SoftDeletes;
protected $dates = ['deleted_at'];
public function product()
{
return $this->belongsTo("App\Model\Product");
}
public function setNull()
{
$this->product_id = NULL;
$this->save();
}
}
Table Schema
Schema::create('projects', function (Blueprint $table) {
$table->increments('id');
$table->string('project_name')->unique("project_name");
$table->integer('project_value')->unsigned();
$table->integer('product_id')->unsigned()->nullable();
$table->foreign('product_id')->references('id')->on('products')->onDelete("set null");
$table->timestamps();
$table->softDeletes();
$table->engine = 'InnoDB';
});
note
one project belongs to one product. It seems a bit weird but it's ok.
Error Message
When I delete a product record, I got the following error.
[2017-05-13 17:25:28] local.ERROR: BadMethodCallException: Call to undefined method Illuminate\Database\Query\Builder::setNull() in /vagrant/door/vendor/laravel/framework/src/Illuminate/Database/Query/Builder.php:2443
Stack trace:
#0 /vagrant/door/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php(1239): Illuminate\Database\Query\Builder->__call('setNull', Array)
#1 [internal function]: Illuminate\Database\Eloquent\Builder->__call('setNull', Array)
#2 /vagrant/door/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Relations/Relation.php(340): call_user_func_array(Array, Array)
#3 /vagrant/door/app/Model/Product.php(44): Illuminate\Database\Eloquent\Relations\Relation->__call('setNull', Array)
#4 /vagrant/door/vendor/laravel/framework/src/Illuminate/Events/Dispatcher.php(348): App\Model\Product::App\Model\{closure}(Object(App\Model\Product))
#5 /vagrant/door/vendor/laravel/framework/src/Illuminate/Events/Dispatcher.php(199): Illuminate\Events\Dispatcher->Illuminate\Events\{closure}('eloquent.delete...', Array)
#6 /vagrant/door/vendor/laravel/framework/src/Illuminate/Events/Dispatcher.php(172): Illuminate\Events\Dispatcher->dispatch('eloquent.delete...', Array, false)
#7 /vagrant/door/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Concerns/HasEvents.php(148): Illuminate\Events\Dispatcher->fire('eloquent.delete...', Object(App\Model\Product))
#8 /vagrant/door/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php(748): Illuminate\Database\Eloquent\Model->fireModelEvent('deleted', false)
#9 /vagrant/door/app/Http/Controllers/ProductController.php(80): Illuminate\Database\Eloquent\Model->delete()
#10 [internal function]: App\Http\Controllers\ProductController->destroy(Object(App\Http\Requests\ProductRequest), '1')
Check out dissociate() method, this will reset both the foreign key of the relation and the relation on the object.
Basically you want something like this:
static::deleted(function($product)
{
// remove relation
$product->projects()->each(function($project) {
$project->product()->dissociate();
$project->save();
});
});
In your project model define a custom method like,
public function setNull()
{
$this->field_names= NULL;
$this->save();
}
Then in the boot function you call this method like
$product->projects()->setNull();
P. S- sorry I'm on mobile
I followed this tutorial to get Laravel's Eloquent running inside an existing Codeigniter project and everything worked fine until I attemped to use Eloquent's relationships. Here's my offending code:
class Announcement_model extends Eloquent {
protected $table = 'announcements';
public function game() {
$this->load->model('game_model');
return $this->belongsTo('Game_model', 'game_id');
}
}
class Game_model extends Eloquent {
protected $table = 'games';
}
And the controller:
class Api_announcement extends REST_Controller {
...
public function index_get() {
$response = Announcement_model::with('game')->get();
$this->response(array('error'=> false, 'response' => $response), 200);
}
}
I'm running into this error:
<b>Fatal error</b>: Uncaught exception 'LogicException' with message 'Relationship method must return an object of type Illuminate\Database\Eloquent\Relations\Relation' in myproject\vendor\illuminate\database\Eloquent\Model.php:2695
Stack trace:
#0 myproject\vendor\illuminate\database\Eloquent\Model.php(2665): Illuminate\Database\Eloquent\Model->getRelationshipFromMethod('load')
#1 myproject\vendor\illuminate\database\Eloquent\Model.php(2607): Illuminate\Database\Eloquent\Model->getRelationValue('load')
#2 myproject\vendor\illuminate\database\Eloquent\Model.php(3325): Illuminate\Database\Eloquent\Model->getAttribute('load')
#3 myproject\application\models\announcement_model.php(11): Illuminate\Database\Eloquent\Model->__get('load')
#4 myproject\vendor\illuminate\database\Eloquent\Builder.php(477): Announcement_model->game()
#5 [internal function]: Illuminate\Database\Eloquent\Builder->Illuminate\Database\Eloquent\{closure}()
#6 in
<b>myproject\vendor\illuminate\database\Eloquent\Model.php</b> on line
<b>2695</b>
What am I doing wrong? I've looked up and down for a solution but nothing works.
return $this->belongsTo('Game_model', 'game_id')->select(array('name'));
Returns in array, but no Relation. You need this:
return $this->belongsTo('Game_model', 'game_id');
Just migrated to 4.1 to take advantage of this powerful feature.
everything seems to work correctly when retrieving individual 'morphedByXxxx' relations, however when trying to retrieve all models that a particular tag belongs to -- i get an error or no results.
$tag = Tag::find(45); //Tag model name = 'awesome'
//returns an Illuminate\Database\Eloquent\Collection of zero length
$tag->taggable;
//returns Illuminate\Database\Eloquent\Relations\MorphToMany Builder class
$tag->taggable();
//returns a populated Collection of Video models
$tag->videos()->get();
//returns a populated Collection of Post models
$tag->posts()->get();
My Tag Model class loooks like this:
class Tag extends Eloquent
{
protected $table = 'tags';
public $timestamps = true;
public function taggable()
{
//none of these seem to function as expected,
//both return an instance of MorphToMany
//return $this->morphedByMany('Tag', 'taggable');
return $this->morphToMany('Tag', 'taggable');
//this throws an error about missing argument 1
//return $this->morphToMany();
}
public function posts()
{
return $this->morphedByMany('Post', 'taggable');
}
public function videos()
{
return $this->morphedByMany('Video', 'taggable');
}
}
And the Post and Video models look like this:
class Post extends Eloquent
{
protected $table = 'posts';
public $timestamps = true;
public function tags()
{
return $this->morphToMany('Tag', 'taggable');
}
}
I am able to add/remove Tags to Posts and Videos as well as retrieve the related Posts, and Videos for any Tag -- however -- what is the proper way to retrieve all Models having the Tag name 'awesome'?
Was able to figure it out, would love to hear comments on this implementation.
in Tag.php
public function taggable()
{
return $this->morphToMany('Tag', 'taggable', 'taggables', 'tag_id')->orWhereRaw('taggables.taggable_type IS NOT NULL');
}
in calling code:
$allItemsHavingThisTag = $tag->taggable()
->with('videos')
->with('posts')
->get();
I just used this on Laravel 5.2 (not sure if it is a good strategy though):
Tag model:
public function related()
{
return $this->hasMany(Taggable::class, 'tag_id');
}
Taggable model:
public function model()
{
return $this->belongsTo( $this->taggable_type, 'taggable_id');
}
To retrieve all the inverse relations (all the entities attached to the requested tag):
#foreach ($tag->related as $related)
{{ $related->model }}
#endforeach
... sadly this technique doesn't offer eager load functionalities and feels like a hack. At least it makes it simple to check the related model class and show the desired model attributes without much fear to look for the right attributes on the right model.
I posted a similar question in this other thread as I am looking for relations not known in advance.