Related
I'm new to CakePHP and PHPUnit and I want to test one of my controllers. So far I have this method I like to test:
public function getAlternatives($id = null){
// ID parameter given or is NaN?
if (!$id || !is_numeric($id)) {
throw new BadRequestException();
}
// Error if object not found
if (!$this->Designitem->exists($id)) {
throw new NotFoundException();
}
$alternatives = $this->Designitem->getItemsWithFunritures($id);
$this->set(array(
'alternatives' => $alternatives,
'_serialize' => array('alternatives'),
'_jsonp' => true));
}
Now I want to test whether the getItemsWithFurnitures is called on my model Designitem. To test this I implemented this test:
public function testGetAlternativesWithValidID() {
$id = 1;
$url = array('controller' => 'Designitems', 'action' => 'getAlternatives', $id . '.json');
$expected = array(
'Designitem' =>
array(
'id' => 1,
'design_id' => 1,
'furniture_id' => 1,
'template_id' => 1,
),
);
$designitems = $this->generate('Designitems', array(
'methods' => array(
'getAlternatives',
),
'models' => array(
'Designitem' => array('getItemsWithFunritures'),
),
));
$designitems->Designitem
->expects($this->once())
->method('getItemsWithFunritures')
->will($this->returnValue($expected));
$result = $this->testAction($url);
$this->assertEquals(json_encode($expected), $result);
}
EDIT: My Designitems Fixture contains one stubbed entry. It looks like this:
class DesignitemFixture extends CakeTestFixture {
public $fields = array(
'id' => array('type' => 'integer', 'null' => false, 'default' => null, 'unsigned' => false, 'key' => 'primary'),
'design_id' => array('type' => 'integer', 'null' => false, 'default' => null, 'unsigned' => false),
'furniture_id' => array('type' => 'integer', 'null' => false, 'default' => null, 'unsigned' => false),
'template_id' => array('type' => 'integer', 'null' => true, 'default' => null, 'unsigned' => false),
'templateitem_id' => array('type' => 'integer', 'null' => true, 'default' => null, 'unsigned' => false),
'amount' => array('type' => 'integer', 'null' => false, 'default' => null, 'length' => 5, 'unsigned' => false),
'feedback' => array('type' => 'string', 'null' => true, 'default' => null, 'length' => 20, 'collate' => 'utf8_general_ci', 'charset' => 'utf8'),
'clicks' => array('type' => 'integer', 'null' => true, 'default' => '0', 'unsigned' => false),
'ilike' => array('type' => 'boolean', 'null' => false, 'default' => null),
'dislike' => array('type' => 'boolean', 'null' => false, 'default' => null),
'dislike_reason' => array('type' => 'string', 'null' => false, 'default' => null, 'length' => 100, 'collate' => 'utf8_general_ci', 'charset' => 'utf8'),
'dislike_comment' => array('type' => 'string', 'null' => false, 'default' => null, 'length' => 2000, 'collate' => 'utf8_general_ci', 'charset' => 'utf8'),
'parent_id' => array('type' => 'integer', 'null' => true, 'default' => null, 'unsigned' => false),
'has_alternatives' => array('type' => 'boolean', 'null' => true, 'default' => null),
'is_selected' => array('type' => 'boolean', 'null' => true, 'default' => null),
'is_recommendation' => array('type' => 'boolean', 'null' => true, 'default' => null),
'deleted' => array('type' => 'integer', 'null' => false, 'default' => null, 'length' => 4, 'unsigned' => false),
'deleted_date' => array('type' => 'datetime', 'null' => true, 'default' => null),
'created' => array('type' => 'datetime', 'null' => true, 'default' => null),
'modified' => array('type' => 'datetime', 'null' => true, 'default' => null),
'indexes' => array(
'PRIMARY' => array('column' => 'id', 'unique' => 1)
),
'tableParameters' => array('charset' => 'utf8', 'collate' => 'utf8_general_ci', 'engine' => 'InnoDB')
);
public $records = array(
array(
'id' => 1,
'design_id' => 1,
'furniture_id' => 1,
'template_id' => 1,
'templateitem_id' => 1,
'amount' => 1,
'feedback' => 'Lorem ipsum dolor ',
'clicks' => 1,
'ilike' => 1,
'dislike' => 1,
'dislike_reason' => 'Lorem ipsum dolor sit amet',
'dislike_comment' => 'Lorem ipsum dolor sit amet',
'parent_id' => 1,
'has_alternatives' => 1,
'is_selected' => 1,
'is_recommendation' => 1,
'deleted' => 0,
'deleted_date' => '2016-07-14 12:05:39',
'created' => '2016-07-14 12:05:39',
'modified' => '2016-07-14 12:05:39'
),
);
}
When I run the test, I get an error that the getItemsWithFurnitures returned null:
Test result
Can anyone tell me what I'm doing wrong? Thank you!
I found a solution to the problem. My problem was that not the getItemsWithFurnitures returned null but the tested method getAlternatives isn't returning any value (-> null). So I have to check if the set value $this->set(...); is the same as the expected array. To achieve this I have to change the return method of the testAction(...) by passing array('return' => 'contents'). It will then return the produced content instead of the methods return value. The working test looks like this:
public function testGetAlternativesWithValidID() {
$id = 1;
$url = array('controller' => 'Designitems', 'action' => 'getAlternatives', $id . '.json');
$this->_generateMockWithAuthUserId('Designitems', 1);
$expected = array(
'Designitem' =>
array(
'id' => 1,
'design_id' => 1,
'furniture_id' => 1,
'template_id' => 1,
),
);
$data = $this->getMockForModel('Designitem', array('getItemsWithFunritures'));
$data->expects($this->once())
->method('getItemsWithFunritures')
->will($this->returnValue($expected));
$result = $this->testAction($url, array('return' => 'contents'));
// Delete all whitespaces from the result.
$result = preg_replace('/\s+/', '', $result);
// Add the surrounding alternatives array to the expected and convert to json-format.
$expected = json_encode(array('alternatives' => $expected));
$this->assertEquals($expected, $result);
}
Because I add these items into another array 'alternatives' while setting it to the view, I have to place the expected array in this 'alternatives'-array. I also had to replace all whitespaces because the json encoding methods used are different. In order to compare them they have to be exactly the same so I removed the whitespaces and the test passes.
I hope someone can use this info.
I need to access the array elements, from the below array structure.Here i need to access the NewsFeedComment array.I am trying to do this, but it's giving me the error Undefined index: comments
How can i access the elements in the NewsFeedComment array
In Controller:
$this->set('newsfeed',$this->paginate('NewsFeed',$newsfeed));
In view:
<?php foreach ($newsfeeds $newsfeed): ?>
<div class="news_reply_display">
<?php echo $newsfeed['NewsFeedComment'][0]['comments'] ?>
</div>
<?php endforeach; ?>
array(
(int) 0 => array(
'NewsFeed' => array(
'id' => '2',
'title' => 'Best Restaurant',
'group_id' => '1',
'posted_message' => 'message.',
'user_id' => '11',
'created' => '2013-12-03 09:35:02',
'status' => 'A'
),
'Group' => array(
'id' => '1',
'group_name' => 'My group',
'created_user' => '1',
'created_date' => '2013-04-24 15:31:09',
'privacy' => '0',
'membership' => '0',
'description' => 'desc'
),
'NewsFeedComment' => array(
(int) 0 => array(
'id' => '1',
'news_feed_id' => '2',
'comments' => 'comment1',
'status' => 'A'
),
(int) 1 => array(
'id' => '2',
'news_feed_id' => '2',
'comments' => 'comment2',
'status' => 'A'
),
(int) 2 => array(
'id' => '3',
'news_feed_id' => '2',
'comments' => 'comment3',
'status' => 'A'
)
)
),
(int) 1 => array(
'NewsFeed' => array(
'id' => '1',
'title' => 'Test Subject',
'group_id' => '1',
'posted_message' => 'description.',
'user_id' => '1',
'created' => '2013-12-03 08:25:12',
'status' => 'A'
),
'Group' => array(
'id' => '1',
'group_name' => 'secondgroup',
'title' => 'Second Grouups',
'group_slug' => 'secgroup',
'created_user' => '1',
'created_date' => '2013-04-24 15:31:09',
'privacy' => '0',
'membership' => '0',
'description' => 'desc'
),
'NewsFeedComment' => array()
)
)
That index doesn't exist. In that particular case you must use $newsfeed[0]['NewsFeedComment']['comments'].
Now, if you would like to extract all "NewsFeedComent" arrays from $newsfeed then you can use Hash::extract
$newsFeedComments = Hash::extract($users, '{n}.NewsFeedComment');
debug($newsFeedComments);
foreach($newsfeeds as $newsfeed){
foreach($newsfeed['NewsFeedComment'] as $NewsFeedCommentData){
echo $NewsFeedCommentData['comments'];
}
}
Using the above code you will get comments corresponding to each index of array $newsfeeds
I want to display the commentairs on the page of the article, my comments are submitted by users.
Currently I am able to display the comments but not the users associated with comments.
SQL:
posts
CREATE TABLE `posts` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(255) CHARACTER SET utf8 NOT NULL DEFAULT '',
`slug` varchar(255) CHARACTER SET utf8 NOT NULL DEFAULT '',
`content` longtext CHARACTER SET utf8 NOT NULL,
`created` datetime NOT NULL,
`active` tinyint(1) DEFAULT '0',
`picture` tinyint(1) DEFAULT NULL,
`type` enum('Article','News','Page') CHARACTER SET utf8 DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=15 DEFAULT CHARSET=utf8;
post_comments
CREATE TABLE `post_comments` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`post_id` int(11) DEFAULT NULL,
`user_id` int(11) NOT NULL,
`title` varchar(255) NOT NULL DEFAULT '',
`content` text NOT NULL,
`created` datetime NOT NULL,
`status` tinyint(1) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
--
$post = $this->Post->find('first', array(
'conditions' => array('Post.slug' => $slug, 'Post.active' => '1'),
'contain' => array('PostComment')
));
--
debug($post);
array(
'Post' => array(
'id' => '2',
'name' => 'azeaeaez',
'slug' => 'azeaeaez1',
'content' => 'aeaeaeaze',
'created' => '2013-10-21 12:33:30',
'active' => true,
'picture' => null,
'type' => 'News',
'user_id' => null
),
'PostComment' => array(
(int) 0 => array(
'id' => '4',
'post_id' => '2',
'user_id' => '6',
'title' => 'Super comme article',
'content' => 'Merci c'est cool j'en prend note !',
'created' => '2013-10-29 08:58:07',
'status' => false
),
(int) 1 => array(
'id' => '3',
'post_id' => '2',
'user_id' => '31',
'title' => 'Super cool',
'content' => 'merci les loulous',
'created' => '2013-10-26 17:09:21',
'status' => false
)
)
)
the desired result
array(
'Post' => array(
'id' => '2',
'name' => 'azeaeaez',
'slug' => 'azeaeaez1',
'content' => 'aeaeaeaze',
'created' => '2013-10-21 12:33:30',
'active' => true,
'picture' => null,
'type' => 'News',
'user_id' => null
),
'PostComment' => array(
(int) 0 => array(
'id' => '4',
'post_id' => '2',
'user' => array(
'user_name' => 'toto',
'email' => tot#email.com,
...
),
'title' => 'Super comme article',
'content' => 'Merci c'est cool j'en prend note !',
'created' => '2013-10-29 08:58:07',
'status' => false
),
(int) 1 => array(
'id' => '3',
'post_id' => '2',
'user' => array(
'user_name' => 'toto',
'email' => tot#email.com,
...
),
'title' => 'Super cool',
'content' => 'merci les loulous',
'created' => '2013-10-26 17:09:21',
'status' => false
)
)
)
try
'contain' => array('PostComment', 'PostComment.User')
(I assume that you have set the relationship between PostComment and User)
You'll need
$post = $this->Post->find('first', array(
'conditions' => array('Post.slug' => $slug, 'Post.active' => '1'),
'contain' => array('PostComment' => 'User')
));
And you need to set up the proper association between the User and PostComment models.
Hi i wrote contain on my model it effects only on first record and the rest of them
contains all the unnecessary records.
My Controller logic :
$findFiles['conditions']['Content.created_by'] = $curUser;
$findFiles['conditions']['KmpContent.is_approved'] = false;
$findFiles['conditions']['KmpContent.is_file'] = true;
$findFiles['contain'] = array('Parent' => array('SectionApprover' => array('Approver')));
$findFiles['recursive'] = 3;
$findFiles['fields'] = array('id', 'file_path', 'url_path', 'is_approved', 'name', 'created', 'approved_by','parent_id','display_text','is_active');
$fileData = $this->KmpContent->find('all', $findFiles);
The array Details are as follows
0 =>
array (
'KmpContent' =>
array (
'id' => '881',
'file_path' => '/uploads/test_file_for_multiple_approvers_backend_validations.docx',
'url_path' => '/uploads/test_file_for_multiple_approvers_backend_validations.docx',
'is_approved' => '0',
'name' => 'file_test_file_for_multiple_approvers_backend_validations.docx',
'created' => '2013-08-20 11:49:58',
'approved_by' => NULL,
'parent_id' => '143',
'display_text' => 'test file for multiple approvers',
'is_active' => '1',
),
'Parent' =>
array (
'id' => '143',
'name' => 'sct_Services.html',
'display_text' => 'Services',
'Parent' =>
array (
),
'Uploader' =>
array (
),
'SectionApprover' =>
array (
0 =>
array (
'id' => '104',
'kmp_content_id' => '143',
'approver_id' => '882',
'Approver' =>
array (
'id' => '882',
'first_name' => 'Prakasha',
'last_name' => 'Matte',
),
),
1 =>
array (
'id' => '256',
'kmp_content_id' => '143',
'approver_id' => '1168',
'Approver' =>
array (
'id' => '1168',
'first_name' => 'Rima Roy',
'last_name' => 'Chowdhury',
),
),
2 =>
array (
'id' => '257',
'kmp_content_id' => '143',
'approver_id' => '1171',
'Approver' =>
array (
'id' => '1171',
'first_name' => 'Durga Venkatesh',
'last_name' => 'Sambhani',
),
),
3 =>
array (
'id' => '258',
'kmp_content_id' => '143',
'approver_id' => '1172',
'Approver' =>
array (
'id' => '1172',
'first_name' => 'Gowtham Babu',
'last_name' => 'Tummala',
),
),
4 =>
array (
'id' => '259',
'kmp_content_id' => '143',
'approver_id' => '889',
'Approver' =>
array (
'id' => '889',
'first_name' => 'Sandeep',
'last_name' => 'Pathuri',
),
),
),
),
'SectionApprover' =>
array (
),
),
1 =>
array (
'KmpContent' =>
array (
'id' => '882',
'file_path' => '/uploads/test_file_for_ma_contentcontroller_save.txt',
'url_path' => '/uploads/test_file_for_ma_contentcontroller_save.txt',
'is_approved' => '0',
'name' => 'file_test_file_for_ma_contentcontroller_save.txt',
'created' => '2013-08-20 11:54:15',
'approved_by' => NULL,
'parent_id' => '28',
'display_text' => 'test file for MA',
'is_active' => '1',
),
'Parent' =>
array (
'id' => '28',
'name' => 'sct_domain.html',
'display_text' => 'Domains',
'Parent' =>
array (
),
'Uploader' =>
array (
),
'SectionApprover' =>
array (
0 =>
array (
'id' => '26',
'kmp_content_id' => '28',
'approver_id' => '467',
'KmpContent' =>
array (
'id' => '28',
'name' => 'sct_domain.html',
'description' => NULL,
'page_title' => 'IVV Knowledge Portal :: mckesson :: domain',
'display_logo_path' => '../images/domains.png',
'display_text' => 'Domains',
'top_logo_path' => '/mckesson_ban.jpg',
'top_logo_url' => 'http://www.mckesson.com/en_us/McKesson.com/',
'header_text' => 'Domains',
'header_desc' => NULL,
'header_logo_path' => '',
'is_section' => '1',
'url_path' => '/university/mckesson/domains.html',
'can_upload_files' => '1',
'is_file' => '0',
'file_path' => NULL,
'display_order' => '1',
'aco_path' => '',
'menu_name' => 'mckesson',
'view_path' => 'download_files',
'is_approved' => '1',
'parent_id' => '11',
'is_active' => '1',
'created' => '2013-06-22 21:18:27',
'created_by' => NULL,
'modified' => '2013-06-22 21:21:01',
'approved_by' => NULL,
),
'Approver' =>
array (
'id' => '467',
'first_name' => 'Nageswara Rao',
'last_name' => 'Menda',
),
),
),
),
'SectionApprover' =>
array (
),
),
I dont want the kmpContent in with in the sectionapprovers for all the records
What if you formatted the statement like
$fileData = $this->KmpContent->find('all', array(
'conditions' => array(
'KmpContent.created_by' => $curUser,
'KmpContent.is_approved' => false,
'KmpContent.is_file' => true,
),
'contain' => array(
'Parent' => array(
'SectionApprover' => array(
'Approver'
)
)
),
'recursive' => 3, // though you don't need to set recursive with contain
'fields' => array('id', 'file_path', 'url_path', 'is_approved', 'name', 'created', 'approved_by','parent_id','display_text','is_active')
));
I have a question regarding model association. Consider the following application: each month a new question is asked to the users. These have the ability to give a tip on this question and other users have the ability to react on this tip. My model-setup is like this:
Users hasMany Tips, Reactions
Tips belongsTo User
Tips hasMany Reactions
Reactions belongsTo User, Tip
Now I want to get all the tips on that question from all users. I do a simple find all on the tips-table which return me all tips joined with their user and reactions. The reactions however do not contain the user, which is very important, obviously.
Cake automatically converts my find all to two queries: one on the tips-table joining the user and one on the reactions table, but there is no join on the users-table, which is what i need.
So my question is: why is the users-table not joined with the reactions and how can i solve this?
Code:
User-model:
public $hasMany = array('Tip', 'Reaction');
Tip-model:
public $hasMany = array('Reaction' => array(
'foreignKey' => 'tip_id'
));
public $hasOne = array('User' => array(
'fields' => array(
'User.id, User.first_name, User.last_name'
),
'foreignKey' => 'id'
));
Reaction-model:
public $belongsTo = array('Tip', 'ReactionUser' => array(
'className' => 'User',
'foreignKey' => 'id'
));
Controller:
$tips = $this->Tip->find('all');
OUTPUT:
array(
(int) 0 => array(
'Tip' => array(
'id' => '1',
'user_id' => '1',
'question_id' => '1',
'tip' => 'Testing da new datavbase',
'votes' => '0',
'approved' => '1',
'pic' => '',
'created' => '2012-05-18 09:22:56'
),
'User' => array(
'id' => '1',
'first_name' => 'Bart',
'last_name' => 'De Bock'
),
'Reaction' => array(
(int) 0 => array(
'id' => '1',
'tip_id' => '1',
'user_id' => '1',
'reaction' => 'lorem ipsum',
'votes' => '0',
'approved' => '1',
'pic' => '',
'created' => '0000-00-00 00:00:00'
)
)
),
(int) 1 => array(
'Tip' => array(
'id' => '2',
'user_id' => '2',
'question_id' => '1',
'tip' => 'Test',
'votes' => '0',
'approved' => '1',
'pic' => '',
'created' => '2012-05-18 10:22:51'
),
'User' => array(
'id' => '2',
'first_name' => 'Deborah',
'last_name' => 'Rochtus'
),
'Reaction' => array(
(int) 0 => array(
'id' => '2',
'tip_id' => '2',
'user_id' => '3',
'reaction' => 'Say whaat?',
'votes' => '2',
'approved' => '1',
'pic' => '',
'created' => '2012-05-18 10:33:32'
),
(int) 1 => array(
'id' => '3',
'tip_id' => '2',
'user_id' => '4',
'reaction' => 'Hmmm..',
'votes' => '0',
'approved' => '1',
'pic' => '',
'created' => '2012-05-18 10:33:44'
)
)
)
)
As you can see, these reactions do not contain the associated user...
Thanks for your help!
Use Containable:
In AppModel:
public $uses = array('Containable');
Change your find call to:
$this->Tip->find('all', array('contain' => array('User', 'Reaction' => array('User'))));
Please try this
$tips = $this->Tip->find('all'
array(
'recursive'=>'2'
)
);
recursive value maybe 1, 2, 3, 4 etc as you need.