I would like to set up a table prefix for all my models, since this is how it is designed in the database.
How can I achieve that?
You can override the getSource method to set the prefix:
class Users extends Phalcon\Mvc\Model
{
public function getSource()
{
return 'my_' . 'users';
}
}
Or, you can set a base model class to set the table prefix for all models:
class BaseModel extends Phalcon\Mvc\Model
{
public function getSource()
{
return 'my_' . strtolower(get_class($this));
}
}
and extend all models from that
class Users extends BaseModel
{
}
or in PHP 5.4 you can create a trait:
trait CustomPrefix
{
public function getSource()
{
return 'my_' . strtolower(get_class($this));
}
}
then in your model:
class Users extends Phalcon\Mvc\Model
{
use CustomPrefix;
}
Source
Also, if you have tables with underscores "_" you could write it like that:
public function getSource()
{
return 'my_'.strtolower(preg_replace('/([a-z])([A-Z])/', '$1_$2', get_class($this)));
}
you can also add all your settings to initialize function. If you have any connection between models like one-one many-many one-many you will define them also in initialize method.
class Robots extends \Phalcon\Mvc\Model
{
public function initialize()
{
$this->setSource("the_robots");
}
}
Related
I'm trying to make use of a base interface for all my other interfaces as follows:
Base interface
<?php
namespace App\Repositories\Data;
interface IDataRepository
{
public function getAll();
public function getById($id);
public function create($model);
public function update($model);
public function delete($id);
}
Implemented base interface
<?php namespace App\Repositories\Data;
use Illuminate\Database\Eloquent\Model;
class DataRepository implements IDataRepository
{
// model property on class instances
protected $model;
// Constructor to bind model to repo
public function __construct(Model $model)
{
$this->model = $model;
}
// Get all instances of model
public function getAll()
{
return $this->model->all();
}
// create a new record in the database
public function create($model)
{
return $this->model->create($model);
}
// update record in the database
public function update($model)
{
$record = $this->find($model.id);
return $record->update($model);
}
// remove record from the database
public function delete($id)
{
return $this->model->destroy($id);
}
// show the record with the given id
public function getById($id)
{
return $this->model-findOrFail($id);
}
}
The interface where i'm trying to make use of the base interface
<?php
namespace App\Repositories;
use App\Repositories\Data\IDataRepository;
interface ITestRepository extends IDataRepository
{
}
implementation
<?php namespace App\Repositories;
use App\Library\Classes\Test;
use Illuminate\Database\Eloquent\Model;
class TestRepository implements ITestRepository
{
}
In my controller i'm trying to just call test repository so i can use all the base repository functions:
class TestController extends Controller
{
protected $testRepository;
public function __construct(Test $test)
{
$this->testRepository = new TestRepository($test);
}
public function index()
{
$data['testData'] = $this->testRepository->getAll();
return view('test', $data);
}
}
But i get the following error:
Class App\Repositories\TestRepository contains 5 abstract methods and
must therefore be declared abstract or implement the remaining methods
My application works fine if i only make use of my base interface and pass through a model. What would be the correct way to share functions from my base interface across all my other interfaces, so as to prevent code duplication? I appreciate any help.
I think that a Trait which will contains all methods of your interface declaration is the best choice. Something like (not sure about logic):
namespace App\Repositories;
trait TDataRepository
{
// model property on class instances
protected $model;
// Constructor to bind model to repo
public function __construct(Model $model)
{
$this->model = $model;
}
// Get all instances of model
public function getAll()
{
return $this->model->all();
}
// create a new record in the database
public function create($model)
{
return $this->model->create($model);
}
// update record in the database
public function update($model)
{
$record = $this->find($model.id);
return $record->update($model);
}
// remove record from the database
public function delete($id)
{
return $this->model->destroy($id);
}
// show the record with the given id
public function getById($id)
{
return $this->model-findOrFail($id);
}
}
And then just use it for classes with base interface:
namespace App\Repositories;
use App\Library\Classes\Test;
use Illuminate\Database\Eloquent\Model;
class TestRepository implements ITestRepository
{
use TDataRepository;
}
Also there are some other options:
abstract class with methods for base interface but it not so flexible like trait,
composition but you should change base idea and create a new entity for composition.
<?php
namespace App\Repositories;
use App\Interfaces\ITestRepository;
class TestRepository implements ITestRepository
{
public function getAll()
{
// TODO: Implement getAll() method.
}
public function getById($id)
{
// TODO: Implement getById() method.
}
public function create($model)
{
// TODO: Implement create() method.
}
public function update($model)
{
// TODO: Implement update() method.
}
public function delete($id)
{
// TODO: Implement delete() method.
}
}
Class must be declared abstract or implement methods 'getAll', 'getById', 'update', 'create', 'delete'
So All the method is by default abstract method in interface and you have to define all method in this class.
The class TestRepository should not implement any interface, but extend DataRepository:
<?php namespace App\Repositories;
use App\Repositories\Data\DataRepository;
class TestRepository extends DataRepository
{
}
DataRepository contains already the implementation of the interface IDataRepository. When you create a class implementing ITestRepository you will have to define the implementation of all the methods in the interface (which are the same as the base interface, in your case).
Suppose I got a model with a few relations:
class Author extends Model
{
public function shortStories()
{
return $this->hasMany(ShortStory::class);
}
public function essays()
{
return $this->hasMany(Essay::class);
}
public function books()
{
return $this->hasMany(Book::class);
}
}
Now suppose I got two more models that want to eager load this model with its relations:
class Publisher extends Model
{
public function scopeWithAuthor($query)
{
$query->with('author.shortStories', 'author.essays', 'author.books');
}
}
class Reviewer extends Model
{
public function scopeWithAuthor($query)
{
$query->with('author.shortStories', 'author.essays', 'author.books');
}
}
Problem - if the relations of author change I now need to reflect this in multiple locations.
My question - how do I achieve this in DRY style?
I know that I could add a protected $with to the Author class but then it would always load the relation, not just when required.
With that in mind, one solution I have come up with is to extend the Author model like so:
class AuthorWithRelations extends Author
{
protected $with = ['shortStories', 'essays', 'books'];
}
This then allows me to refactor the scopes of the other models like so:
class Publisher extends Model
{
public function scopeWithAuthor($query)
{
$query->with('authorWithRelations');
}
}
class Reviewer extends Model
{
public function scopeWithAuthor($query)
{
$query->with('authorWithRelations');
}
}
This works well enough but really I was wondering if Laravel provides a better / inbuilt approach to this?
Hello I´m writing an API and I want to display more information about the related model.
Routes.php
Route::resource('makes', 'MakesController');
MakesController.php
class MakesController extends Controller
{
public function index()
{
$data = Make::all();
return response()->json($data);
}
}
This returns only information about the makes (id, name)
but how can I display also how many models has each make?
I have defined these two models
class Make extends Model
{
public function models()
{
return $this->hasMany('App\CarModel');
}
}
class CarModel extends Model
{
public function make()
{
return $this->belongsTo('App\Make');
}
}
You can define $visible field in the Make model's class like this:
protected $visible = ['models'];
This will automatically appends the related model's array to array/json.
You can also use an optional way with makeVisible method:
class MakesController extends Controller
{
public function index()
{
$data = Make::all();
return response()->makeVisible('models')->json($data);
}
}
I am struggling with working with relationships right now and would like some help as for how to make this relationship work. I am using Laravel.
Lets say you have a staff model that looks like so:
Staff.php
class Staff extends \Eloquent {
protected $fillable = [];
public function status()
{
return $this->belongsTo('Staff_status');
}
}
The database table for the staff is as follows:
Table Name: staff
Fields: id, staffer_name, status_id
You also have a staff status model represented below:
Staff_statuses.php
class Staff_status extends Eloquent {
public function staff()
{
return $this->hasMany('Staff');
}
}
You also have a staff database table like so:
Table Name: staff_statuses
Fields: id, status_name
However when I try and load the staff controller index method it says class Staff_status is not found.
Any idea why?
You have used Staff_statuses.php as the name of your model but you are using Staff_status in the class name and thus you are calling it using Staff_status from your controller as well. This is the problem.
Change the file name to match the class name. For example, use something like this:
// StaffStatus.php
class StaffStatus extends Eloquent{
protected $table = 'staff_statuses';
public function staff()
{
return $this->hasMany('Staff');
}
}
// Staff.php
class Staff extends Eloquent {
protected $table = 'staff';
protected $fillable = [];
public function status()
{
return $this->belongsTo('StaffStatus');
}
}
In the controller you may use something like this:
$staffStatus = StaffStatus::all();
$staff = Staff::all();
namespace App;
use Illuminate\Database\Eloquent\Model;
class Photo extends Model
{
public function imageable()
{
return $this->morphTo();
}
}
class Staff extends Model
{
public function photos()
{
return $this->morphMany('App\Photo', 'imageable');
}
}
class Product extends Model
{
public function photos()
{
return $this->morphMany('App\Photo', 'imageable');
}
}
Currently i have all my models extending a base class called "Base"
Base extends Eloquent
the problem is i use Sentry 2 for user authentication and groups thus my two of my models User and Group extend their respective Sentry base model SentryUserModel and SentryGroupModel.
I cannot figure out a way to have these two models: User, Group extend my Base model
You could make your User and Group models extend SentryUserModel and SentryGroupModel respectively then extend Base model using a magic function.
Code:
class User extends SentryUserModel
{
private $base;
function __construct()
{
$this->base = new Base();
}
// fake "extends Base" using magic function
public function __call($method, $args)
{
$this->base->$method($args[0]);
}
}
class Group extends SentryGroupModel
{
private $base;
function __construct()
{
$this->base = new Base();
}
// fake "extends Base" using magic function
public function __call($method, $args)
{
$this->base->$method($args[0]);
}
}