Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Default Model Instance on Empty Relation #1886

Closed
pavel-voronin opened this issue Dec 24, 2012 · 6 comments
Closed

Default Model Instance on Empty Relation #1886

pavel-voronin opened this issue Dec 24, 2012 · 6 comments

Comments

@pavel-voronin
Copy link
Contributor

I want to set new param (e.g. 'default', 'defaultCriteria', etc.) to CActiveRecord.relations() array, which say to CActiveFinder (or CActiveRecord?) to load default model instance (or set of instances in some relation types) in case when nothing is found in CActiveRecord.getRelated().

Use case:

// old
if ( $company->initiator ) // this block can appear multiple times in multiple variations per view
    echo $company->initiator->name;

// new
echo $company->initiator->name; // initiator populated with Default User Model if no one found
@samdark
Copy link
Member

samdark commented Dec 24, 2012

I don't think it will fit framework well. You can always use a method like $company->getInitiatorName().

@samdark samdark closed this as completed Dec 24, 2012
@pavel-voronin
Copy link
Contributor Author

No I can't if i have long relation chains like Yii::app()->user->model->favorites[0]->company->initiator->name and something happens (e.g. company status was set to 'delete' and company.defaultScope() deny this company to be fetched). Now I must check every chain element for existence.

@resurtm
Copy link
Contributor

resurtm commented Dec 24, 2012

Yii::app()->user->model->favorites[0]->company->initiator->name

  1. Yii::app()->user->model — i daresay you're performing SELECT * ... which is bad practice and evil. Select clause should be context-aware as much as possible.
  2. $model->favorites[0] — this could be shortened to getFirstFavorite() or getFavorite().
  3. $company->initiator->name — this could be shortened to getInitiatorName().

In summary:

<?php

// data definition, model
class User extends CActiveRecord
{
    public $id;
    public $first_name;

    public function relations()
    {
        return array(
            'favorites'=>array(self::HAS_MANY,'Favorite','user_id'),
            // neat way of getting single favorite related record
            'favorite'=>array(self::HAS_ONE,'Favorite','user_id'),
        );
    }
}

class Favorite extends CActiveRecord
{
    public $user_id;
    public $company_id;

    public function relations()
    {
        return array(
            'company'=>array(self::BELONGS_TO,'Company','company_id',
                'condition'=>'company.deleted=0'),
        );
    }
}

class Company extends CActiveRecord
{
    public $id;

    public function relations()
    {
        return array(
            'initiator'=>array(self::HAS_ONE,'Initiator','company_id'),
        );
    }

    public function getInitiatorName()
    {
        if($this->initiator)
        {
            return $this->initiator->name;
        }
    }
}

class Initiator extends CActiveRecord
{
    public $id;
    public $company_id;
    public $name;
}

// querying, controller
$criteria=new CDbCriteria();
$criteria->with=array(
    'favorite'=>array('select'=>false),
    'favorite.company'=>array('select'=>false),
    'favorite.company.initiator'=>array('select'=>'name'),
);
$criteria->select=array('t.id','t.first_name');
$criteria->addColumnCondition(array('t.id'=>Yii::app()->user->id));

$user=User::model()->find($criteria); // passed to the view
$favorite=$user->favorite; // passed to the view

// displaying, view
echo $user->first_name;
if($favorite!==null && $favorite->company!==null):
    echo $favorite->company->initiatorName;
endif;

Any situation could be simplified as i described above.

@pavel-voronin
Copy link
Contributor Author

You didn't understand me, sorry.

@resurtm
Copy link
Contributor

resurtm commented Dec 24, 2012

I did. You're using relations improperly. We can continue discussion in Skype or Jabber if you want.

@resurtm
Copy link
Contributor

resurtm commented Dec 24, 2012

Yii::app()->user->model->favorites[0]->company->initiator->name

http://www.soberit.hut.fi/mmantyla/badcodesmellstaxonomy.htm

The Feature Envy smell means a case where one method is too interested in other classes, and the Inappropriate Intimacy smell means that two classes are coupled tightly to each other. Message Chains is a smell where class A needs data from class D. To access this data, class A needs to retrieve object C from object B (A and B have a direct reference). When class A gets object C it then asks C to get object D. When class A finally has a reference to class D, A asks D for the data it needs. The problem here is that A becomes unnecessarily coupled to classes B, C, and D, when it only needs some piece of data from class D. The following example illustrates the message chain smell: A.getB().getC().getD().getTheNeededData()

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants