Laravel database Insert error - php

I trying to insert data to database using laravel 4 eloquent model. But throws the error:
"Call to undefined method Illuminate\Support\Facades\Request::save() "
I am new to laravel don't know where I Have gone wrong.
my UsersController.php code
public function postRequest() {
$request = new Request;
$request->vms = Input::get('vms');
$request->location = Input::get('location');
$request->descr = Input::get('descr');
$request->status = Input::get('status');
$request->save();
}
My Request.php Model
<?php
class Request extends Eloquent {
protected $table = 'requests';
protected $fillable = array('vms', 'location', 'descr', 'status');
public function ruser() {
return $this->hasOne('Ruser'); // this matches the Eloquent model
}
}

The problem is that your Request model name conflicts with Laravel Request class. You have two options:
1) Namespace your model:
<?php namespace App;
class Request extends Eloquent {
...
}
Then use it as:
$request = new App\Request;
2) Rename your model.

Seems like your hitting the laravel "Request" facade, instead of your Request model.
Could you try to prefix your new class call with the correct namespaces?
$request = new yourname\yourpackage\Request();
Or, best of all, call it something else?

Related

Returning null instead of "Call to undefined relationship" error for Laravel relationships

When I use ModelName::with('somerelation')->get() with Laravel Eloquent, if the model doesn't have this relationship I get Call to undefined relationship [somerelation] on model [App\SomeModel] error.
But for polymorphic relations, I get collection of all related models and I would like to use with('somerelation') and get null if relationship is not defined. Is there any way to avoid error and return null from with() or any way to use with conditionally?
What I do on all my Laravel projects is creating a Model class that extends Eloquent Model and all my models will extend my Model class, so I can override some methods from Eloquent Model using my rules.
So you can create a new class (I call it Model) and override the method with with a try/catch block retuning null in the case this exception is thrown by eloquent model.
Example:
namespace App;
use Illuminate\Database\Eloquent\Model as EloquentModel;
use Illuminate\Database\Eloquent\RelationNotFoundException;
abstract class Model extends EloquentModel
{
public static function with($relations)
{
try {
return parent::with($relations);
} catch (RelationNotFoundException $e) {
return null;
}
}
}
Previous answer by #Leonardo Oberle doesn't work for me.
I was struggling by finding a way how to validate the integrity of a relationship string passed to the with() method, so it will load relation only upon it exists, and will not throw errors if something is missing.
So, I ended up creating a abstract Model class which extends from EloquentModel and overwrites the with() method as in Leonardo Oberle's response.
The only thing is that the method's code should look like :
namespace App;
use Illuminate\Database\Eloquent\Model as EloquentModel;
use Illuminate\Database\Eloquent\RelationNotFoundException;
abstract class Model extends EloquentModel
{
public static function with($relations)
{
$filteredRelations = $this->relationExistsUntil($relations);
parent::with($filteredRelations);
}
}
/**
* #param string $with
* #return string
*/
protected function relationExistsUntil(string $with): string
{
$model = $this;
$result = '';
$relationParts = explode('.', $with);
foreach ($relationParts as $relationPart) {
$isValidRelation = method_exists($model, $relationPart) && $model->{$relationPart}() instanceof Relation;
if (!$isValidRelation) {
break;
}
$result .= empty($result) ? $relationPart : ".$relationPart";
$model = ($model->{$relationPart}()->getRelated());
}
return $result;
}
So, with that, if you will try smth like
`$user->with('relation1.relation2.relation3');`
where `relation2` doesn't exist, it will load only `relation1` and the rest will be skipped, and no exceptions/errors would be thrown.
Just don't forget to make all models then extend from that new abstract class.

eloquent: How to load and set model variables, inside the model itself?

Laravel documentation suggests the following way to set up an eloquent model:
$user = user::with($conditions)->first();
What if I want to set up my eloquent model inside the model itself:
$user = new user();
$user->setup($conditions);
// class definition
class user extends Eloquent{
public function setup($conditions){
// load current object with table data
// something like
$this->where($conditions)->first();
// previous line output is dangling, is ok to assign it to $this variable?
}
}
If you're extending from Eloquent model, you may try the following approach. I assume you have a unique id column.
public function setup($conditions)
{
$model = self::with($conditions)->first();
if (! is_null($model)) {
$this->exists = true;
$this->forceFill(self::find($model->id)->toArray());
}
return $this;
}
Hope this solve your issue.

Calling a class method of an associated eloquent model

I'm having trouble figuring out how to call a class function, in this case File->saveFile() through the parent class Article
class Article extends Model {
public $table = 'pl_gen_article';
public function background_image () {
return $this->morphOne('App\Ubercms\File', 'fileable');
}
}
class File extends Model {
public $table = 'ubercms_file';
public function saveFile (UploadedFile $file) {}
}
$articleId = \Route::input('id');
$article = Article::findOrFail($articleId);
$file = $request->file('image');
// ----------------------
// Attempts
// 1.
$article->background_image->saveFile($file)
// 2.
$image = new $article->background_image();
$image->saveFile($file);
How do I create a File model instance from Article model?
Through the Laravel Api Docs traced the response of $article->background_image() which as MorphOne instance, where I can call firstOrNew which returns an File instance and I'm able to call saveFile afterwards.
$model = $article->background_image()->firstOrNew([]);
$model->saveFile($file);

How to replace the Laravel Builder class

I want to replace the Laravels builder class with my own that's extending from it. I thought it would be as simple as matter of App::bind but it seems that does not work. Where should I place the binding and what is the proper way to do that in Laravel?
This is what I have tried:
my Builder:
use Illuminate\Database\Eloquent\Builder as BaseBuilder;
class Builder extends BaseBuilder
{
/**
* Find a model by its primary key.
*
* #param mixed $id
* #param array $columns
* #return \Illuminate\Database\Eloquent\Model|static|null
*/
public function find($id, $columns = array('*'))
{
Event::fire('before.find', array($this));
$result = parent::find($id, $columns);
Event::fire('after.find', array($this));
return $result;
}
}
And next I tried to register the binding in bootstrap/start.php file like this :
$app->bind('Illuminate\\Database\\Eloquent\\Builder', 'MyNameSpace\\Database\\Eloquent\\Builder');
return $app;
Illuminate\Database\Eloquent\Builder class is an internal class and as such it is not dependency injected into the Illuminate\Database\Eloquent\Model class, but kind of hard coded there.
To do what you want to do, I would extend the Illuminate\Database\Eloquent\Model to MyNamespace\Database\Eloquent\Model class and override newEloquentBuilder function.
public function newEloquentBuilder($query)
{
return new MyNamespace\Database\Eloquent\Builder($query);
}
Then alias MyNamespace\Database\Eloquent\Model to Eloquent at the aliases in app/config/app.php
Both of the answers are correct in some way. You have to decide what your goal is.
Change Eloquent Builder
For example, if you want to add a new method only for eloquent models (eg. something like scopes, but maybe a little more advanced so it’s not possible in a scope)
Create a new Class extending the Eloquent Builder, for Example CustomEloquentBuilder.
use Illuminate\Database\Eloquent\Builder;
class CustomEloquentBuilder extends Builder
{
public function myMethod()
{
// some method things
}
}
Create a Custom Model and overwrite the method newEloquentBuilder
use Namespace\Of\CustomEloquentBuilder;
use Illuminate\Database\Eloquent\Model;
class CustomModel extends Model
{
public function newEloquentBuilder($query)
{
return new CustomEloquentBuilder($query);
}
}
Change Database Query Builder
For example to modify the where-clause for all database accesses
Create a new Class extending the Database Builder, for Example CustomQueryBuilder.
use Illuminate\Database\Query\Builder;
class CustomQueryBuilder extends Builder
{
public function myMethod()
{
// some method things
}
}
Create a Custom Model and overwrite the method newBaseQueryBuilder
use Namespace\Of\CustomQueryBuilder;
use Illuminate\Database\Eloquent\Model;
class CustomModel extends Model
{
protected function newBaseQueryBuilder()
{
$connection = $this->getConnection();
return new CustomQueryBuilder(
$connection, $connection->getQueryGrammar(), $connection->getPostProcessor()
);
}
}
Laravel Version: 5.5 / this code is untestet
The answer above doesn't exactly work for laravel > 5 so I done some digging and I found this!
https://github.com/laravel/framework/blob/5.2/src/Illuminate/Database/Eloquent/Model.php#L1868
use this instead!
protected function newBaseQueryBuilder()
{
$conn = $this->getConnection();
$grammar = $conn->getQueryGrammar();
return new QueryBuilder($conn, $grammar, $conn->getPostProcessor());
}

Get array of Eloquent model's relations

I'm trying to get an array of all of my model's associations. I have the following model:
class Article extends Eloquent
{
protected $guarded = array();
public static $rules = array();
public function author()
{
return $this->belongsTo('Author');
}
public function category()
{
return $this->belongsTo('Category');
}
}
From this model, I'm trying to get the following array of its relations:
array(
'author',
'category'
)
I'm looking for a way to pull this array out from the model automatically.
I've found this definition of a relationsToArray method on an Eloquent model, which appears to return an array of the model's relations. It seems to use the $this->relations attribute of the Eloquent model. However, this method returns an empty array, and the relations attribute is an empty array, despite having my relations set up correctly.
What is $this->relations used for if not to store model relations? Is there any way that I can get an array of my model's relations automatically?
It's not possible because relationships are loaded only when requested either by using with (for eager loading) or using relationship public method defined in the model, for example, if a Author model is created with following relationship
public function articles() {
return $this->hasMany('Article');
}
When you call this method like:
$author = Author::find(1);
$author->articles; // <-- this will load related article models as a collection
Also, as I said with, when you use something like this:
$article = Article::with('author')->get(1);
In this case, the first article (with id 1) will be loaded with it's related model Author and you can use
$article->author->name; // to access the name field from related/loaded author model
So, it's not possible to get the relations magically without using appropriate method for loading of relationships but once you load the relationship (related models) then you may use something like this to get the relations:
$article = Article::with(['category', 'author'])->first();
$article->getRelations(); // get all the related models
$article->getRelation('author'); // to get only related author model
To convert them to an array you may use toArray() method like:
dd($article->getRelations()->toArray()); // dump and die as array
The relationsToArray() method works on a model which is loaded with it's related models. This method converts related models to array form where toArray() method converts all the data of a model (with relationship) to array, here is the source code:
public function toArray()
{
$attributes = $this->attributesToArray();
return array_merge($attributes, $this->relationsToArray());
}
It merges model attributes and it's related model's attributes after converting to array then returns it.
use this:
class Article extends Eloquent
{
protected $guarded = array();
public static $rules = array();
public $relationships = array('Author', 'Category');
public function author() {
return $this->belongsTo('Author');
}
public function category() {
return $this->belongsTo('Category');
}
}
So outside the class you can do something like this:
public function articleWithAllRelationships()
{
$article = new Article;
$relationships = $article->relationships;
$article = $article->with($relationships)->first();
}
GruBhub, thank you very much for your comments. I have corrected the typo that you mentioned.
You are right, it is dangerous to run unknown methods, hence I added a rollback after such execution.
Many thanks also to phildawson from laracasts, https://laracasts.com/discuss/channels/eloquent/get-all-model-relationships
You can use the following trait:
<?php
namespace App\Traits;
use Illuminate\Database\Eloquent\Relations\Relation;
trait EloquentRelationshipTrait
{
/**
* Get eloquent relationships
*
* #return array
*/
public static function getRelationships()
{
$instance = new static;
// Get public methods declared without parameters and non inherited
$class = get_class($instance);
$allMethods = (new \ReflectionClass($class))->getMethods(\ReflectionMethod::IS_PUBLIC);
$methods = array_filter(
$allMethods,
function ($method) use ($class) {
return $method->class === $class
&& !$method->getParameters() // relationships have no parameters
&& $method->getName() !== 'getRelationships'; // prevent infinite recursion
}
);
\DB::beginTransaction();
$relations = [];
foreach ($methods as $method) {
try {
$methodName = $method->getName();
$methodReturn = $instance->$methodName();
if (!$methodReturn instanceof Relation) {
continue;
}
} catch (\Throwable $th) {
continue;
}
$type = (new \ReflectionClass($methodReturn))->getShortName();
$model = get_class($methodReturn->getRelated());
$relations[$methodName] = [$type, $model];
}
\DB::rollBack();
return $relations;
}
}
Then you can implement it in any model.
<?php
namespace App;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Passport\HasApiTokens;
use App\Traits\EloquentRelationshipTrait;
class User extends Authenticatable
{
use Notifiable, HasApiTokens, EloquentRelationshipTrait;
Finally with (new User)->getRelationships() or User::getRelationships() you will get:
[
"notifications" => [
"MorphMany",
"Illuminate\Notifications\DatabaseNotification",
],
"readNotifications" => [
"MorphMany",
"Illuminate\Notifications\DatabaseNotification",
],
"unreadNotifications" => [
"MorphMany",
"Illuminate\Notifications\DatabaseNotification",
],
"clients" => [
"HasMany",
"Laravel\Passport\Client",
],
"tokens" => [
"HasMany",
"Laravel\Passport\Token",
],
]
I have published a package in order to get all eloquent relationships from a model. Such package contains the helper "rel" to do so.
Just run (Composer 2.x is required!):
require pablo-merener/eloquent-relationships
If you are on laravel 9, you are able to run artisan command model:show

Categories