CakePHP call to member function on non-object - cakephp

I have the following Model and Controller files, and when i visit this url, http://....../pois/index i get this error:
Notice (8): Undefined property: PoisController::$Poi [APP/controllers/pois_controller.php, line 5]
Fatal error: Call to a member function find() on a non-object in /home/joecoyle/public_html/app/controllers/pois_controller.php on line 5
The Model is this, called poi.php:
<?php
class Poi extends AppModel {
}
?>
And the controller is this, named pois_controller.php
<?php
class PoisController extends AppController {
function index(){
$this->set('pois',$this->Poi->find('all'));
}
}
?>
As i am new to CakePHP i am not sure what is causing this error, as everything seems to be named, right, and i am following the tutorial on the CakePHP site...
Thanks

You need add var $name = "Poi"; to initialize your class in the controller.
And I've tested that in PHP5.It seems that this is necessary.
Edit:
controller file name:pois_controller.php,code:
<?php
class PoisController extends AppController
{
var $name = "Poi";
function index()
{
debug($this->Poi);
exit;
}
}
?>
database name:pois.Structure:id ,name
And using /pois/ will got:
Poi Object
(
[name] => Poi
[useDbConfig] => default
[useTable] => pois
[displayField] => name
[id] =>
[data] => Array
(
)
[table] => pois
[primaryKey] => id
[_schema] => Array
(
[id] => Array
(
[type] => integer
[null] =>
[default] =>
[length] => 11
[key] => primary
)
[name] => Array
(
[type] => integer
[null] =>
[default] =>
[length] => 11
)
...etc

If SpawnCxy's solution doesn't do the job (my own controllers set the name property to the pluralized version rather than the singular variation that the model takes), take a look at the inflection. "Poi" isn't a "common" word and a quick test tells me that CakePHP 1.2.6 doesn't handle this word the way you're thinking it will:
echo '<p>' . Inflector::singularize( 'Pois' ) . '</p>'; # prints "Pois"
echo '<p>' . Inflector::pluralize( 'Poi' ) . '</p>'; # prints "Pois"
The point of this, of course, is that Cake may not be making the correct association between the PoisController (plural) and the Poi model (singular) the way it does for most common English names.

An alternative to adapting your code to Cake's pluralising/singularising rules is the converse: adapting Cake's rules to your code:
In app/config/inflections.php, find the $irregularPlural line, and change it to:
$irregularPlural = array('poi'=>'pois');
This will instruct Cake to treat the singular of "Pois" as "Poi."
This is a good choice when changing the inflection rules creates better readability/comprehensibility of the rest of your code. For example, by default, Cake treats the singular of "News" as "New". However, it made more sense to find news items with $this->News->find than $this->New->find, so I tweaked the inflection rules.

It's a problem because $this->Poi has not been initialized as an object. I'm not familiar with CakePHP, but in your init function in the PoisController or in contructor you should call $this->Poi = new Poi(); so in the index action when you try to call find(), the method will be called on an instance of Poi model.

Related

CakePHP Not Saving BelongsTo Key

I'm trying to save a record that belongs to another model. Yet, I get an error that the foreign key is missing. The CakePHP docs show examples of this working but I can't get it to work.
Here is the Form:
echo $this->Form->create('Message', array('action'=>'add'));
echo $this->Form->hidden('Ticket.id');
echo $this->Form->input('Message.message');
echo $this->Form->submit('Save Message');
echo $this->Form->end();
Here is what is returned to the controller upon submit:
Array(
[Ticket] => Array
(
[id] => 2
)
[Message] => Array
(
[message] => Message text
)
)
Here is my Message model:
class Message extends AppModel {
public $belongsTo = array('Ticket');
}
Here is my Ticket model:
class Ticket extends AppModel {
public $hasMany = 'Message';
}
Here is my controller logic:
$this->Message->save($this->request->data);
Here is the error message I receive:
Error: SQLSTATE[HY000]: General error: 1364 Field 'ticket_id' doesn't have a default value
The CakePHP documents are pretty clear that Cake will grab the id from the Ticket array. The only way I can get this to work is if I manually assign the ticket id to the message array.
$this->request->data['Message']['ticket_id'] = $this->request->data['Ticket']['id']
I shouldn't have to do that. Where's the magic? I've read at least 20 similar posts but none exactly like this (probably because this is so basic that nobody has this problem because it works for them).
I'm using version 2.4.2
Thanks for any help.
Don't use Model::save() in this case, the reason is that you also want to save associated data, in order for you save data for the main model along with its associated models you need to use Model::saveAssociated().
Your controller should be looking like this
$this->Message->saveAssociated($this->request->data);

CakePHP virtualField find all not null

I have a database table "transactions" which has a field "account". I want to retrieve a subset of all not-null account rows from the current set of data and have it as a virtualField I can access down the line in my view.
class Transaction extends AppModel {
public $virtualFields = array(
"Accounts" => $this->Transaction->find("all", array("conditions" => array("not" => array("Transaction.account" => null))))
);
}
So that I get an array of all transactions with non-null account fields named "Accounts".
This doesn't work - gives me "unexpected T_VARIABLE" error (doesn't like $this). I was trying to follow the guide here. I'm a moderate level PHP developer and this is my first real Cake project, so I may be going about this completely wrong.
When you're inside the model that you're querying, you don't specify the model name, just:
$this->find('all'); // when you're inside transaction model
...so try this:
"Accounts" => $this->find("all", array("conditions" => array("not" => array("Transaction.account" => null))))

cakephp saving data for a related model's related model (not typo)

I've run into a bit of a problem saving data in cake php.
here are the models/relationships.
District hasMany Departments
Department hasMany Groups
I am in a view for creating new district, in which I've allowed the user to create multiple new departments. while creating each department, the user may create multiple groups for that dept. Now the trouble is I'm unsure of how to save the group data.
for each department that is created on the fly, im using the multiple index method for the inputs (i.e. "Department.0.name", Department.0.type) so this will be a cinch to save using the saveAll method. However, for each group that is created, i will need a department_id, and since none of the District's departments have yet been saved, they don't have an id. how can i save this new district's data, saving the new departments, and their associated new created groups? is there a way that i can address the name attribute of the group inputs that will create the proper association, something like "Department.0.Group.0.name", for instance?
Thanks in advance!!! if anything is unclear, please don't hesitate to say so, I'll be glad to rephrase.
What does your POST data array look like?
<?php
debug($this->data);
?>
If it is not in the correct format, the associated models won't get saved.. Cake knows to grab the "lastInsertId()" of the models which haven't been saved yet, so you don't have to worry about those... What i'm not sure about, and the docs don't really go into, is how deep the save goes. The example provided is as follows:
$this->data =
Array
(
[Article] => Array
(
[title] => My first article
)
[Comment] => Array
(
[0] => Array
(
[comment] => Comment 1
[user_id] => 1
)
[1] => Array
(
[comment] => Comment 2
[user_id] => 2
)
)
)
$this->Article->saveAll($this->data);
This is the correct structure (cakephp 1.3) for saving associated models of a 'hasMany' relationship, but i'm not sure if it goes any deeper than one child.
One thing that comes to my mind is to build the array according to the format above, but leave the parent model out. Then manually save the parent model data, grab the ::getLastInsertId(); then do a saveAll on departments and groups.
[UPDATE]
I just tested your theory and it will work the way you intend.
<?php
echo $this->Form->input('Department.0.Group.0.name');
?>
Will produce:
<input name="data[Department][0][Group][0][name]" type="text" id="Department0Group0name">
[UPDATE 2]
I did some exploring in lib/Cake/Model/Model.php and found this:
<?php
...
public function saveAssociated($data = null, $options = array()) {
...
... // code omitted.
...
if ($options['deep']) { // This will recurse infinitely through all associations
$saved = $this->{$association}->saveAssociated($values, array_merge($options, array('atomic' => false)));
}
...
...
... // code omitted.
...
?>

How to pass database record from Controller to View in CakePHP

I've started a project in CakePHP. I have no experience of it, most of my experience is with Symfony2.
Right now, I have built a view file, a controller, and a model for use with this project and it's database. In one controller I want to pass one record from the database to the view for use on the homepage. However, I'm unable to pass the record as I get this error:
Notice (8): Undefined variable: content [APP\View\Contents\home.ctp,
line 42]
Here is my controller code:
function home() {
$content = $this->Content->query("SELECT title, content FROM content WHERE id = 1;");
$this->set('pagecontent',$content);
}
And here is the code I'm using to display the data in the view file:
<?php $content['content']; ?>
What have I missed?
EDIT:
I have changed the <?php $content['content']; ?> to <?php echo $pagecontent['Content']['content']; ?> inline with the changes outlined in the answer from Ross. However, there is now this error:
Notice (8): Undefined index: Content [APP\View\Contents\home.ctp, line
43]
I have used the <?php echo debug($this->viewVars); ?> and this is the output from that:
app\View\Contents\home.ctp (line 42) Array (
[pagecontent] => Array
(
[0] => Array
(
[content] => Array
(
[title] => <h1>This is a title</h1>
[content] => <p>this is some test text</p>
)
)
)
)
$this->set('pagecontent',$content); - this is where you are setting view variables.
You are trying to access a variable called $content, when in fact it is stored as $pagecontent.
Also based on Cake conventions, the key content should actually be Content, so your output should probably be:
<h1><?php echo $pagecontent['Content']['title']; ?></h1>
<div class="page-content">
<?php echo $pagecontent['Content']['content']; ?>
</div>
You can always do debug($this->viewVars); to see exactly what you have access to.
Seeing the output helps; the error is due to how cake is returning the data.
This is likely due to you using query() rather than find() or read(). (also explains why your content key is lowercase - query() uses the table name, rather than the model name.
Try:
$content = $this->Content->find('first',
array('fields' => array('title', 'content'),
'conditions' => array('Content.id' => 1)
)
);
$this->set('pagecontent', $content);
// view
echo $pagecontent['Content']['title'];
echo $pagecontent['Content']['content'];
should now work.
The alternative is to just access the data through the array index:
echo $pagecontent[0]['content']['title']
which isn't as "cake" like.
to expand = query() returns data in a different structure than using find or read. There's other ways you can do this too.
$this->Content->id = 1;
$this->set('pagecontent', $this->Content->read(array('title', 'content')));
should also be valid.

How do I get data from associated models in CakePHP?

I create a simple blog with cakephp where i have some posts and some comments.
After i bake an application it create a comments folder with the index.ctp and a posts folder with the index.ctp
What i want to do is display them as fallow:
Post1
comment1
comment2
Post2
comment1
comment2
If i place the comments inside the posts/index.ctp i get an error telling me that the $comments is not defined.
How can i do this?
Thanks
edit:
alright, im sorry for the comeback, but it's still a bit unclear. I do have the $hasMany relationship setup, in fact on the page that displays the posts i have a link that points me to the comments. The only thing that i want them to be displayed in the same page as the posts.
i should be able to say <?php echo $comment['Comment']['content']; ?>
Check your controllers.
If you want to display Comment information in a Posts view, you need to be sure that the Posts controller can load the data.
The "CakePHP" way is to define relationships between models. Check your baked models and see if there is something like this:
class Post extends AppModel{
var $hasMany = array( 'Comment' );
}
When the models are associated with each other, your Posts controller will automatically find Post objects and their associated Comment objects.
For instance, this line:
$this->Post->findById( $id );
Will produce something like this:
Array
(
[Post] => Array
(
[id] => 42
[text] => Post1
)
[Comment] => Array
(
[0] => Array
(
[id] => 1
[post_id] => 42
[text] => Comment1
)
[1] => Array
(
[id] => 2
[post_id] => 42
[text] => Comment2
)
)
)
Good documentation at http://book.cakephp.org/
Model Associations
Retreiving Data
EDIT: Adding more info after your comment
As long as the models have the association, CakePHP will pull the data appropriately (unless you set Recursive => false or are using Containable which I assume you aren't).
Check your PostsController controller and see how it's loading the data. I'm guessing it is doing something like the following:
$post = $this->Post->findById( $id );
$this->set( compact( 'post' ) );
or
$this->data = $this->Post->findById( $id );
Check which way it is storing the retrieved data, and then access that variable from the view.
For example, if it is storing the data in a variable named "$post", you would put something like this in your view:
// output the 'text' field of the 'post' object
echo $post[ 'post' ][ 'text' ];
// loop through associated comments
foreach ( $post[ 'comment' ] as $comment ){
//output the 'text' field of a 'comment' object
echo $comment[ 'text' ];
}
By default CakePHP stashes tons of detail in arrays after retrieving data. The trick is to know the hierarchy of the data and fetch it from the array accordingly.

Resources