I've created a BaseModel class, which extends from Model. It seemed like everything was working fine, but now I've run into a problem when saving. I'm overriding the save() method in this BaseModel. I'd just like to add some attributes to the model before saving. So I do that, then call return parent::save($options);. The method signature is still the same: public function save(array $options = []).
It appears to be grabbing the name of the BaseModel class for the table name when performing the insert (it's using base_models as the table name), rather than the actual model that is being saved. Has anyone run into this before? What is the proper way of extending from the model class?
I originally created some traits to handle some extra functionality, but thought it would be a better idea to just create a base model and have my models extend from that instead.
In your model (the child one that extends the base model) add the table name explictly for example:
class SomeChildModel extends BaseModel {
// Manually set the table name
protected $table = 'table_name';
}
I realized that I previously had a static method that was creating an instance of itself using new self() and would set a few attributes, back when I was using the methods from a trait. It was fine before, but now since I moved the methods into the base model, that method was actually being called on the base model itself rather than the class that had the trait.
I was basically using the static method to instantiate the class, as I've read it's one way to avoid cluttering the constructor. But I just opted to do it in the constructor this time around since it made sense, so that was my solution.
Laravel will use snake case of the class name by default (the class where save method is called), if no $table instance variable is set. In your case it will use snake case of the BaseModel as a table name. You have two solutions:
Solution 1:
In classes which extends BaseModel add the $table instance variable as follow:
class User extends BaseModel {
protected $table = 'table_name'; // Your table name in the database;
}
Solution 2:
You can use Laravel Eloquent's Events, which allows you to hook into various points in the model's lifecycle.
You can hook into the save method as follow and make your changes. You can use these methods in your BaseClass, in traits, etc. For example in your BaseModel:
class BaseModel extends Model
{
/**
* Listen for save event
*/
protected static function boot()
{
parent::boot();
static::saving(function($model)
{
if ( ! $model->isValid()) {
return false;
}
});
}
}
The above will always call isValid before a model is saved into the storage. In this case it will return false and will not save the object.
For more info see the official docs here. Let me know if it isn't clear.
Related
I dont know how else to label the title. Anyone have ideas go ahead and make a suggested edit.
I have a series of Models for the database in my application.
I can currently add a global scope to the model and have the model automatically add a "where" clause on my queries to the database on a key:value pair. This is working great.
class Customers extends Model
{
protected $table = 'customers';
protected static function boot() {
parent::boot();
static::addGlobalScope('companyRecordID', function (Builder $builder) {
$builder->where('companyRecordID', Auth::guard('user')->user()->companyRecordID);
});
}
}
I am having troubles trying to identify if this can be done; Id like to be able to store the "companyRecordID" from the Auth::guard('user')->user()->companyRecordID automatically when a database record is created. Similar to created_at and updated_at are created automatically without requiring code from the controller to define.
Can someone direct me to what I should be looking for. Ive spent a few hours trying to google key word pairs to find an answer with no avail.
If you are using Models to create the records you can listen for the creating event for the Model and then add any additional fields you may need. You can create a listener for the creating event on Customers:
Customers::creating(function ($customer) {
if (auth('user')->user()) {
$customer->companyRecordID = auth('user')->user()->companyRecordID;
}
});
You can throw that in a Service Provider's boot method or your Model's boot method. If you throw it in the Model's boot method you may want to adjust to using static:: instead of Customers::.
I believe you got your answer but,
On your model please use protected $fillable
protected $fillable = ['','',''];
protected $table = 'customers';
also, you can use Relationships to optimize your codes.
Any simpler way to not depend on Laravel's sql table naming convention?
In your Model you can override the table it's going to use. Just add a protected property:
class Category extends Model {
protected $table = 'categories123123'; //For example =D
}
categories, it works it out using Doctrine's Inflector class!
I'm looking for a way to define a custom Eloquent method which only returns a calculation based on several columns in the according database table. I also tried setting it in the models attributes, but neither seem to work. Maybe I'm missing something, here's what I got so far:
<?php
use Illuminate\Database\Eloquent\Model;
class Team extends Model
{
public function difference() {
return $this->goals_f - $this->goals_a;
}
}
The error message I'm recieving is:
Relationship method must return an object of type Illuminate\Database\Eloquent\Relations\Relation
Your error makes it sound to me like you are trying to call your method like a property" $team->difference. You would instead need to call it like: $team->difference(). If you want to get the difference as if it was a property, then you would need to define an accessor:
public function getDifferenceAttribute(){
return $this->goals_f - $this->goals_a;
}
Then you could call it like $team->difference.
You could also define a protected $appends property to your model so that the difference property is subsequently visible in it's JSON representation:
protected $appends = ['difference'];
More information: https://laravel.com/docs/5.2/eloquent-mutators#accessors-and-mutators
Is there any function to get the all table or model names in cakePhp.
I want to update my table's field and for that I need to select all table dynamically so that in future when I'll add new table I do not have to make changes in function.
The new table automatically update the fields.
I don't quite understand the question - from what i gather you want to write abstract actions to account for multiple models? If this is the case you can add abstract actions into the AppController and use $this->modelClass. This will return the model name from were you are calling the abstract action from. For example if you calling the abstract action from 'UsersController' which by default uses the Model 'User' then the modelClass will return 'User'.
class AppController extends Controller {
public function abstractAdd() {
// Get the model in use
$this->{$this->modelClass}->create();
// Use the save method in that model
if ($this->{$this->modelClass}->save($data)) {
// do something
}
}
}
class UsersController extends AppController {
public function add() {
$this->abstractAdd();
}
}
Hope this helps
I too ran into the problem that FUSE won't work with CI and RBphp.
in APPPATH/application/core/ I have a base model called "MY_Model.php"
class MY_Model {}
class Base extends RedBean_SimpleModel {
// static methods
}
I have a derived class, like this, called "model_user.php" in APPPATH/application/models/:
class Model_User extends Base {
public function getData() {
return $this->bean->id;
}
}
And in the controller I load the model:
$this->load->model('Model_User');
The rb library is autoloaded via the autoload.php file.
After creating an object of the type Model_User with redbean, I still cannot access the getData() method.
I already read this question + answer asked here, but they didn't help me.
The problem was due to the naming convention. Whilst the table itself was called "users", the bean's name was "Model_User". So RedBean was looking for a "User" table in the database. Renaming the class to Model_Users, or renaming the table to "user" was the solution.