We have moved our forum to GitHub Discussions. For questions about Phalcon v3/v4/v5 you can visit here and for Phalcon v6 here.

Having problems with ORM getRelated records on 1.2.6

I've been struggling with this for a while and I'm at a loss.

I have 2 related classes Organization and Campaigns

class Organizations extends \Phalcon\Mvc\Model
{
    public $id;
    public function getSource()
    {
        return "bwg_entities";
    }

    public function initialize() {
         $this->hasMany("id", "Users", "entity_id" );
         $this->hasMany("campaign_id", "Campaigns", "id", array("foreignKey" =>true));
    }
    ....
}

class Campaigns extends \Phalcon\Mvc\Model
{

    public $id;
    public $entity_id;
    public function getSource()
    {
        return "bwg_campaigns";
    }

    public function initialize() {
         $this->belongsTo("entity_id", "Organizations", "id" );
         $this->hasMany("id", "CampaignDatafields", "campaign_id");

         $this->skipAttributesOnCreate(array('date_created'));
    }
....
}

In my controller, I retrieve organizations but I never get back the related campaigns.

$organization = Organizations::findFirst(array(
                "entity_code = :org_id: AND is_active = 1",
                "bind" => array('org_id' => $orgId)

                ));

        foreach($organization->campaigns as $c) {
             echo json_encode($c);
        }       
        exit;
} 

I've tried using getRelated() fail. i've tried above code with $organization->getCampaigns().. no error but no result.

Finally, from my mysql :

select e.*, c.entity_id, c.name from  bwg_entities e left join bwg_campaigns c on c.entity_id = e.id;

returns:

1000    HRC Human Rights Campaign   Steven Churchill    [email protected]    1   1000    HRC dev

so the data is there.

Try removing the public $id and public $entityid declarations. It's unnecessary (for the purposes of ORM) and I have a feeling that may be messing things up.

edited Mar '14

Thanks, I gave that a whirl and still get blanks in the logs.

i changed the controller code a bit and get this errror in my log:

        if($orgId == null) {
            $this->flash->error('Organization is invalid');
            $this->response->redirect("campaignmanager/index");
            return;
        }
        $organization = Organizations::findFirst(array(
                "entity_code = :org_id: AND is_active = 1",
                "bind" => array('org_id' => $orgId)

                ));
       // $this->logger->log($organization->campaigns->id);
        $this->logger->log($organization->campaigns[0]->id);
        foreach($organization->campaigns as $c) {
             $this->logger->log( json_encode($c));
        }

Phalcon\Mvc\Model\Exception[0]: The index does not exist in the cursor [Mon, 24 Mar 14 17:39:01 +0000][INFO] /Proj/BetterWorldGiving/hrc_server/webapp/app/controllers/CampaignmanagerController.php[22] [Mon, 24 Mar 14 17:39:01 +0000][DEBUG] Trace:

Can't help you with that - I've never seen that error before.

Do you have a query log turned on? Can you see the query that Phalcon is sending to MySQL?

I see in your controller code you're referencing entity_code. Is that supposed to be entity_id?

Could you post the structure of your entities & campaigns tables?

edited Mar '14

how do i turn the query log on ? I was googling for that but my google-fu was not good.

CREATE TABLE `bwg_entities` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `entity_code` varchar(10) NOT NULL,
  `entity_name` varchar(255) NOT NULL,
  `primary_contact_name` varchar(255) NOT NULL,
  `primary_contact_email` varchar(255) DEFAULT NULL,
  `is_active` tinyint(1) NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1001 DEFAULT CHARSET=utf8;

CREATE TABLE `bwg_campaigns` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT 'The internal Campaign ID',
  `name` varchar(250) NOT NULL DEFAULT '' COMMENT 'The common name of the campaign',
  `skin_location` varchar(250) DEFAULT NULL COMMENT 'The skin directory or id',
  `campaign_type` varchar(20) DEFAULT 'Donation' COMMENT 'Donation or Petition',
  `length` varchar(10) DEFAULT NULL COMMENT 'Long or short',
  `banner` varchar(255) NOT NULL DEFAULT '' COMMENT 'Path to the image file',
  `sugg_donation_amount` float DEFAULT NULL COMMENT 'suggested donation amount, changable on iPad',
  `description` text COMMENT 'About the campaign',
  `date_created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'Date it was created',
  `note` text,
  `internal_id` varchar(20) DEFAULT NULL,
  `internal_name` varchar(200) DEFAULT NULL,
  `entity_id` int(11) unsigned NOT NULL,
  `ROI_ID` varchar(40) NOT NULL DEFAULT 'UNSET',
  PRIMARY KEY (`id`),
  KEY `entity_id` (`entity_id`),
  CONSTRAINT `bwg_campaigns_ibfk_1` FOREIGN KEY (`entity_id`) REFERENCES `bwg_entities` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;

CREATE TABLE `bwg_users` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `first_name` varchar(80) NOT NULL DEFAULT '',
  `last_name` varchar(80) NOT NULL DEFAULT '',
  `address` varchar(255) DEFAULT '',
  `city` varchar(255) DEFAULT '',
  `state` varchar(20) DEFAULT NULL,
  `postal` varchar(10) DEFAULT NULL,
  `email_address` varchar(255) NOT NULL DEFAULT '',
  `hashedauth` varchar(255) NOT NULL DEFAULT '',
  `is_active` tinyint(1) NOT NULL DEFAULT '1',
  `second_factor_key` varchar(10) DEFAULT '000000',
  `token` varchar(10) DEFAULT '',
  `token_created` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  `entity_id` int(11) unsigned DEFAULT NULL,
  `bwg_super_admin_id` int(11) unsigned DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `emailkey` (`email_address`),
  KEY `entity_id` (`entity_id`),
  KEY `superadminfk` (`bwg_super_admin_id`),
  CONSTRAINT `bwg_users_ibfk_1` FOREIGN KEY (`entity_id`) REFERENCES `bwg_entities` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=10010 DEFAULT CHARSET=utf8;
edited Mar '14

2 commands should do it:

SET GLOBAL general_log = 'ON';
SET GLOBAL general_log_file = '/path/to/log/file'

Make sure the log file is writable by your mysql user. Tail the file with tail -f /path/to/log/file to see the queries get dumped in there in real time.

The only other thing I can suggest at this point is to remove the foreign key declaration. I have no reason for suggesting this other than the fact that I don't specify this, and I don't have this problem. Really just a stab in the dark though. I have great faith in the query log getting you what you need.

edited Mar '14

well, i see WHY the query is returning the wrong result, but I have no idea how to fix it. It's passing in Null.

  13 Query  SELECT IF(COUNT(*)>0, 1 , 0) FROM `INFORMATION_SCHEMA`.`TABLES` WHERE `TABLE_NAME`='bwg_entities'
           13 Query DESCRIBE `bwg_entities`
           13 Query SELECT `bwg_entities`.`id`, `bwg_entities`.`entity_code`, `bwg_entities`.`entity_name`, `bwg_entities`.`primary_contact_name`, `bwg_entities`.`primary_contact_email`, `bwg_entities`.`is_active` FROM `bwg_entities` WHERE `bwg_entities`.`entity_code` = 'HRC' AND `bwg_entities`.`is_active` = 1 LIMIT 1
           13 Query SELECT IF(COUNT(*)>0, 1 , 0) FROM `INFORMATION_SCHEMA`.`TABLES` WHERE `TABLE_NAME`='bwg_campaigns'
           13 Query DESCRIBE `bwg_campaigns`
           13 Query SELECT `bwg_campaigns`.`id`, `bwg_campaigns`.`name`, `bwg_campaigns`.`skin_location`, `bwg_campaigns`.`campaign_type`, `bwg_campaigns`.`length`, `bwg_campaigns`.`banner`, `bwg_campaigns`.`sugg_donation_amount`, `bwg_campaigns`.`description`, `bwg_campaigns`.`date_created`, `bwg_campaigns`.`note`, `bwg_campaigns`.`internal_id`, `bwg_campaigns`.`internal_name`, `bwg_campaigns`.`entity_id`, `bwg_campaigns`.`ROI_ID` FROM `bwg_campaigns` WHERE `bwg_campaigns`.`id` = NULL

Again here's the code:

 $this->organization = Organizations::findFirst(array(
                "entity_code = :org_id: AND is_active = 1",
                "bind" => array('org_id' => $orgId)       
));
$this->view->org=  $this->organization;
$this->view->campaigns = $this->organization->campaigns;
edited Oct '14

flipping the keys in the hasMany seemed to work.

i'm still not quite clear on the params on this function. is it supposed to map class organizations

public function initialize() {
$this->hasMany("id", "Campaigns", "entity_id");

The order of arguments is

  1. Name of local variable
  2. Name of class the current class is related to
  3. Name of variable in the related class that the named local variable maps to

So your relation can be read like this: "This class' $id should be the same as many Campaign objects' $entity_id"