I have 4 models held together by 4 pivot tables:
User, Company, Phone, Address
The User and Company are both tied together to Phone with the pivot tables user_phone and company_phone.
User has a method: addDefaultPhone( Request $request ). It grabs $request->input() and creates a phone number and attaches it to the User.
The same exact method can be used in the Company class. How can I include addDefaultAddress to both classes (without copying and pasting of course)?
You may use inheritance or trait. Choose whatever you want.
Inheritance
Create a base class:
namespace App;
use Illuminate\Database\Eloquent\Model;
class ThingWithAPhone extends Model {
public function addDefaultPhone() {
/* Whatever you want... */
}
}
Then both User and Company could extend this class:
// In the user file
class User extends ThingWithAPhone { /* ... */ }
// In the company file
class Company extends ThingWithAPhone { /* ... */ }
Trait
Create a trait:
namespace App;
class Phonable {
public function addDefaultPhone() {
/* Whatever you want... */
}
}
Use this trait:
// In the user file
class User extends Model {
use Phonable;
/* ... */
}
// In the company file
class Company extends Model {
use Phonable;
/* ... */
} }
With trait you can create class which have X traits, and one other class with Y traits and some of these traits may be common to both classes.
The Best i can think of is to create a trait and share among the classes.
Related
I'm trying to cast a model to another one that extends the same model.
Is there a build in way in Laravel this achieve this?
Example
In the code below I would like to cast User to ExtendedUser
class User extends Model
{
...
}
class ExtendedUser extends User
{
...
}
I am developing an app that has two name spaced differentiated folders.
Lets say
App/Http/Users/ and
App/Http/Drivers/
I have two api routes setup api.php and dapi.php.
The routes are also prefixed by localhost/api/foo and localhost/dapi/bar respectively.
Everything works ok but the issue is that there are some methods that I need to call for both. Such as save address info or call. Right now I have to make same controllers for both and duplicate a lot of code. What would be the best approach for this kind of project?
you should use traits
Traits are a mechanism for code reuse in single inheritance languages
such as PHP. A Trait is intended to reduce some limitations of single
inheritance by enabling a developer to reuse sets of methods freely in
several independent classes living in different class hierarchies. The
semantics of the combination of Traits and classes is defined in a way
which reduces complexity, and avoids the typical problems associated
with multiple inheritance and Mixins.
for example:
in your traite:
trait SameMethods {
function call() { /*1*/ }
function saveAddress() { /*2*/ }
}
.
namespace App\Http\Drivers;
class Foo extends Controller{
use SameMethods ;
/* ... */
}
.
namespace App\Http\Users;
class Bar extends Controller{
use SameMethods ;
/* ... */
}
Now you have these methods on your controllers.
another way is you have an another class for example ParentController extended from Controller that it contains same methods and foo and bar extends from this class
ParentController extends Controller {
function call() { /*1*/ }
function saveAddress() { /*2*/ }
}
.
namespace App\Http\Drivers;
class Foo extends ParentController {
/* ... */
}
.
namespace App\Http\Users;
class Bar extends ParentController {
/* ... */
}
I have a number of tables / models setup that have 'locked_at' and 'locked_by' columns, in essence what I would like to do is call something like:
$model->lock();
This method would check that row is not already locked, set the both cells and then save the model.
I can create the lock method inside each of my models, but that doesn't seem like the best idea. I would prefer to create the method once and have it accessible to all models.
Is there a way of doing this in laravel?
Just like ceejayoz suggested, you could achieve it by using a Trait.
Step 1
Create a folder called Traits and inside that create trait class like the following
<?php
namespace App\Traits;
trait Lockable {
public function lock() {
$this->lock = 1;
$this->save();
}
}
Step 2:
Now import the trait on your model class like the following
<?php
namespace App;
use Illuminate\Foundation\Auth\User as Authenticatable;
use App\Traits\Lockable;
class User extends Authenticatable
{
use Lockable;
}
Thats it! Now you could call the function like
$user = \App\User::find(1);
$user->lock();
You can create BaseModel class that extends Model and make all your models that using lock() method extend BaseModel class instead of theModel. Then just define lock() method in the BaseModel class.
I have a project made with the command phalcon project simple --type=simple.
I haven't changed the structure at all.
The part where I'm stumped, is that I have two databases I look at.
I want to access the Account model for both databases A and B, with out doing something like $account = AAccount::find(); and $account = BAccount::find();.
I currently have this code:
model/AAccount.php
class AAccount extends Phalcon\Mvc\Model {
// use DB A
}
model/BAccount.php
class BAccount extends Phalcon\Mvc\Model {
// use DB B
}
What is the most optimum way of doing so? Namespaces? I cannot change the table name Account for both.
I don't know if I understand your question: you have two tables with the same name, but they are in two different schemas (databases)? If yes, I had the same problem and I solve it with the follow structure (you can see part of this code in my bauhaus project) (see this reference too: point to other schema (Phalcon - Working with Model)):
(1) Base model class located at models/:
namespace MyApp\Model;
class Base extends \Phalcon\Mvc\Model
{
// code for your model base class
}
(2) Base class for schema A located at models/schema-a/:
namespace MyApp\Model\SchemaA;
class Base extends MyApp\Model\Base
{
// ...
// returns the name of the schema A
public function getSchema()
{
return `schema_a_name`;
}
// ...
}
(3) Base class for schema B located at models/schema-b/:
namespace MyApp\Model\SchemaB;
class Base extends MyApp\Model\Base
{
// ...
// returns the name of the schema B
public function getSchema()
{
return `schema_b_name`;
}
// ...
}
(4) Account Model in the schema A located at models/schema-a/:
namespace MyApp\Model\SchemaA;
class Account extends Base
{
// ...
}
(5) Account Model in the schema B located at models/schema-b/:
namespace MyApp\Model\SchemaB;
class Account extends Base
{
// ...
}
This solution works good when you have a fixed number of schemas, but If you have no-fixed number of schemas, I think a better solution would be to create an logic in the getSchema function of the model base. Something like:
public function getSchema()
{
// this is just a suggest
return $this->getDI()->scope->currentSchema;
}
I hope this can help you.
Note: you will have to be careful to create relationships between models with namespace.
Let's assume that we have module called 'UsersModule' with the following model in it:
class User extends CActiveRecord
{
// Some code here
}
We use this module in different applications and some time we want to extend User model to add some custom methods or properties to it. More over, often we want to change tables in database to store this new properties in it. But we don't want to change code in the UsersModule itself because it comes from the master repository (GitHub for ex.) and when we fix some bugs in it we want to simply update this module from repository in all our projects. At the same time we want to save custom changes made for the projects. So we have the following idea:
In UsersModule.php we do the following:
class UsersModule extends CWebModule
{
public $usersBaseClass = 'UsersBase';
}
In Users.php:
$extendClass = Yii::app()->getModule('users')->usersBaseClass;
$version = '1.0';
$usersFile = Yii::getPathOfAlias('application.runtime').'/Users_extends_'.$extendClass.'_v'.$version.'.php';
if(!file_exists($usersFile)) {
$code =<<<PHP
<?php
/**
* This is the model class for table "{{users}}".
*/
class Users extends {$extendClass}
{
/**
* Returns the static model of the specified AR class.
* #param string \$className active record class name.
* #return Users the static model class
*/
public static function model(\$className=__CLASS__)
{
return parent::model(\$className);
}
}
PHP;
file_put_contents($usersFile, $code);
}
if(!class_exists('Users', flase))
require_once($usersFile);
Also we introduce UsersBase.php:
class UsersBase extends CActiveRecord
{
// All base Users model logic is here
}
So when we use Users class somewhere in our application our code in Users.php generates real Users class that extends desired base class. In each project when we want to extend our Users model we can do the following:
In configs/main.php of the project:
'modules' =>
'users => array(
'usersBaseClass' => 'MyUsers'
)
And also we add MyUsers.php some where in our application:
class MyUsers extends UsersBase
{
// All the custom logic goes here
}
So my question is:
Is it a good idea to generate classes automatically in runtime or not?
Genrating php code during runtime could work, but not the best solution imho. You should use some kind of table inheritance.
More info:
http://www.yiiframework.com/wiki/198/single-table-inheritance/
http://learnyii.blogspot.hu/2012/04/yii-table-inheritance-single-active.html