How to extend cactiverecord - yii

I want add aditional methods in CActiveRecord, but if class Project_Model extends CActiveRecord {} get error
The table "Project_ActiveRecord" for active record class "Project_ActiveRecord" cannot be found in the database.
I want create simple structure: CActiveRecord->Project_ActiveRecord (only extend methods)->Table (real table).
How can do this?

The error is clear: You don't have a table named Project_ActiveRecord in your DB!
If Project_Model is going to be the base model for your others active record models then you should do something like:
//A base classe example that has a behavior shared by all the inherited class
abstract class Project_Model extends CActiveRecord
{
public function behaviors(){
return array(
'CTimestampBehavior' => array(
'class' => 'zii.behaviors.CTimestampBehavior',
'setUpdateOnCreate' => true
),
);
}
}
And then you can declare the other class that will have a table in the db:
class YourClass extends Project_Model
{
/**
* Returns the static model of the specified AR class.
* #param string $className active record class name.
* #return Token the static model class
*/
public static function model($className=__CLASS__)
{
return parent::model($className);
}
/**
* #return string the associated database table name
*/
public function tableName()
{
return 'YourClassTable';
}
...
}
Then you shoudl never call the class Project_Model (this is why I put the keyword abstract) in your code, you have to call the inherited classes that have an existing table in the db!

Related

Laravel 5.2 Eloquent Relationships with Irregular Names

I'm building out my first project in Laravel and have run into a bit of a snag with a one to many relationship between two tables.
Historically, I would have done something like this in SQL to achieve my end goal:
SELECT tag_key.key
FROM tag
LEFT JOIN tag_key
ON tag.tag_key_id = tag_key.id;
With Laravel, I'm trying to do things the ORM way and am getting hung up, probably on a naming thing somewhere down the pipe. Here's the code:
Part 1: Migrations:
"tag_keys" table
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateTagKeysTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('tag_keys', function (Blueprint $table) {
$table->increments('id');
$table->string('key', 128);
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::drop('tag_keys');
}
}
"tags" table
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateTagsTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('tags', function (Blueprint $table) {
$table->increments('id');
$table->string('value', 128);
$table->integer('tag_key_id')->unsigned()->index();
$table->foreign('tag_key_id')->references('id')->on('tag_keys')->onDelete('cascade');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::drop('tags');
}
}
Part 2: Models:
"TagKey" model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class TagKey extends Model
{
protected $fillable = [
'key'
];
protected $dates = [];
protected $table = 'tag_keys';
/**
* Tag Keys have many Tags
*/
public function values()
{
return $this->hasMany('App\Tag');
}
}
"Tag" model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Tag extends Model
{
protected $fillable = [
'value',
'tag_key_id'
];
protected $dates = [];
/**
* Tag values belong to Tag Keys
*/
public function key()
{
return $this->belongsTo('App\TagKey');
}
}
Independently, they both work just fine. However, when I jump into tinker and try this (given there is a valid row in both the "tag" and "tag_key" tables and given that id 1 in the "tag" has the value of 1 in the "tag_key" table under the "tag_key_id" column):
$tag = App\Tag::first();
$tag->key;
=> null
What am I missing here? How do I build this association?
When the foreign key name doesn't follow Eloquent conventions ("snake case" name of the owning model and suffix it with _id), you should specify it in the relationship:
TagKey object:
return $this->hasMany('App\Tag', 'tag_key_id');
Key object:
return $this->belongsTo('App\TagKey', 'tag_key_id');
More info in the documentation

Calling a parent from an instantiated child fails strict standards

I am trying to call a parent method from its child which has the same method name. Doing so results in a strict standards error. There's an easy solution of renaming the child method. However, is there a way to keep the names of the two methods identical without a standards warning? Thanks.
Strict standards: Declaration of Child::getContentFromDb() should be compatible with Parent::getContentFromDb($id) in /foo/Child.class.php on line xxx
Pseudo-code example:
class Parent {
protected function getInfoFromDb($id) {
return $infoFromDb;
}
}
class Child extends Parent {
public static $id = xx;
public $info = array();
public function __construct() {
$this->info = $this->getInfoFromDb();
}
public function getInfoFromDb() {
// the line below causes the problem
return parent::getInfoFromDb(self::$id);
}
}
Your method override should take the same parameter list as the one you are overriding.
e.g.
class ParentClass {
protected function getInfoFromDb($id) {
return "INFO FROM DB:" . $id;
}
}
class Child extends ParentClass {
public static $id = "xx";
public $info = array();
public function __construct() {
$this->info = $this->getInfoFromDb();
}
/**
* #param specific ID, or do not set for default action.
* #return string
*/
public function getInfoFromDb($id = false) {
return parent::getInfoFromDb(self::$id);
}
}

Please explain the foreign_key and local_key in Laravel ORM relationships

I'm effectively trying to define the relationships between users (sender and recipient) and messages.
My Messages migration is:
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateMessagesTable extends Migration {
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
//
Schema::create('messages', function($t){
$t->increments('id');
$t->integer('sender_user_id')->unsigned();
$t->integer('recipient_user_id')->unsigned();
$t->string('subject');
$t->text('content');
$t->timestamps();
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
//
Schema::dropIfExists('messages');
}
}
My Message model was straightforward:
<?php
class Message extends Eloquent{
// link to sender user id
public function from(){
return $this->hasOne('User', 'sender_user_id');
}
// link to recipient user id
public function to(){
return $this->hasOne('User', 'recipient_user_id');
}
}
But I'm unsure in defining the hasMany relationships in my User model.
The docs (http://laravel.com/docs/eloquent#relationships) shows the following:
return $this->hasMany('Comment', 'foreign_key');
return $this->hasMany('Comment', 'foreign_key', 'local_key');
Now, I'm confused which key is which in the latter hasMany relationship. Which is correct for my User model?
public function sentMessages(){
return $this->hasMany('Messages', 'id', 'sender_user_id');
}
public function sentMessages(){
return $this->hasMany('Messages', 'sender_user_id', 'id');
}
You have to set your relation like this:
public function sentMessages()
{
return $this->hasMany('Messages', 'sender_user_id');
}
public function receivedMessages()
{
return $this->hasMany('Messages', 'recipient_user_id');
}

How to create a laravel model that implements an API?

When I create a Model, it initially looks something like this:
class User extends Eloquent implements UserInterface, RemindableInterface {
/**
* The database table used by the model.
*
* #var string
*/
protected $table = 'users';
....
.. etc
The problem is, it connect to a DB. I want a way that it skips the fact that I want it to connect to a DB, but rather allow me to overwrite the functions like this:
function find($id) {
//insert curl api call to get user id
}
How does one do that?
You can just override them all:
class User extends Eloquent implements UserInterface, RemindableInterface {
protected $table = 'users';
public static function find($id, $columns = array('*')) {
//insert curl api call to get user id
return $model;
}
}

which is the correct PHPdoc for methods of objects which are properties in phpstorm?

I'm new to PHPStorm and I imported an existing project in this IDE. Now I receive many warnings like
Method 'query' not found in class
I read about using PHPDoc-blocks in order to declare the origin of variables which are not defined in the current class, but I cannot get out how I should do it for this situation:
class loginModel extends Model{
public function checkLogin(){
[...]
if($this->db->query($sql)){[...]} //Warning as stated above
[...]
}
}
$this->db itself is inheritated from class Model:
class Model{
protected $db;
private function connect(){
$this->db = new PGSQL();
}
}
and therefore can access the public PGSQL method named query.Maybe not that well designed, but how could I solve these messages without downgrading their severity?
class Model{
/**
* #var PGSQL
*/
protected $db;
private function connect(){
$this->db = new PGSQL();
}
}
Docblocks work on properties too