tags:

views:

2398

answers:

9

OK, so I'm trying to teach myself the CakePHP framework, and I'm trying to knock up a simple demo app for myself.

I have the controllers, views and models all set up and working, but I want to do something slightly more than the basic online help shows.

I have a guitars_controller.php file as follows...

<?php
class GuitarsController extends AppController {
    var $name = 'Guitars';
    function index() {
     $this->set('Guitars', $this->Guitar->findAll());
     $this->pageTitle = "All Guitars";
    }
    function view($id = null) {
     $this->Guitar->id = $id;
     $this->set('guitar', $this->Guitar->read());
        // Want to set the title here.
    }
}
?>

The 'Guitar' object contains an attribute called 'Name', and I'd like to be able to set that as the pageTitle for the individual page views.

Can anyone point out how I'd do that, please?

NB: I know that there is general disagreement about where in the application to set this kind of data, but to me, it is data related.

A: 
$this->pageTitle = $this->Guitar->Name;

It should go in the View though, I don't PHP, or cakePHP, but thats something a view should do, not the controller.

FlySwat
It *can* also be set in the view.However, CakePHP exposes data as associative arrays and not Objects.$this->pageTitle = $guitar['Guitar']['name']
Cheekysoft
A: 
$this->pageTitle = $this->Guitar->Name;

That's what I thought too, but it doesn't work. It makes perfect sense in an object-oriented paradigm, but apparently not in CakePHP.

ZombieSheep
It is important to understand that unlike Rails, CakePHP does not produce model data as objects. The model classes in app/model are pretty much just DAOs. Data is always made available as assocative arrays.
Cheekysoft
A: 

It should go in the controller. See this

Gaurav
You can also set it in the view
Cheekysoft
+4  A: 

You can set this in the controller:

function view($id = null) {
    $guitar = $this->Guitar->read(null, $id);
    $this->set('guitar', $guitar);
    $this->pageTitle = $guitar['Guitar']['name'];
}

Or in the view:

<? $this->pageTitle = $guitar['Guitar']['name']; ?>

The value set in the view will override any value that may have already been set in the controller.

For security, you must ensure that your layout / view that displays the pageTitle html-encodes this arbitrary data to avoid injection attacks and broken html

<?php echo h( $title_for_layout ); ?>
Paolo Bergantino
A: 

"but I want to do something slightly more than the basic online help shows."

Isn't that always the rub? So much documentation is geared towards a bare minimum that it really does not help much. You can complete many of the tutorials available but as soon as you take 1 step off the reservation the confusion sets in. Well, it's either bare minimum or pro developer maximum but rarely hits that sweet spot of ease, clarity and depth.

I'm currently rewriting some Zend Framework documentation for my own use simply so I can smooth out the inconsistencies, clarify glossed over assumptions and get at the core, "best practice" way of understanding it. My mantra: Ease, clarity, depth. Ease, clarity, depth.

gaoshan88
A: 

Ah, the none-obvious answer is as follows...

$this->pageTitle = $this->viewVars['guitar']['Guitar']['Name'];

I found this by placing the following code in the controller (was a long shot that paid off, to be honest)

echo "<pre>"; print_r($this);echo "</pre>";

Thanks to all those that tried to help.

ZombieSheep
cake has an excellent function called debug() for this purpose.In your controller or view: debug( $variable, true ); The boolean htmlencodes the debug data.Also you shouldn't read from viewVars. Check Paulo's answer which is currently top-voted.
Cheekysoft
Thanks for that valuable info. I'll try to remember to use this next time. :)
ZombieSheep
+3  A: 

These actions are model agnostic so can be put in your app/app_controller.php file

<?php
class AppController extends Controller {
    function index() {
        $this->set(Inflector::variable($this->name), $this->{$this->modelClass}->findAll());
        $this->pageTitle = 'All '.Inflector::humanize($this->name);
    }
    function view($id = null) {
        $data = $this->{$this->modelClass}->findById($id);
        $this->set(Inflector::variable($this->modelClass), $data);
        $this->pageTitle = $data[$this->modelClass][$this->{$this->modelClass}->displayField];
    }
}
?>

Pointing your browser to /guitars will invoke your guitars controller index action, which doesn't exist so the one in AppController (which GuitarsController inherits from) will be run. Same for the view action. This will also work for your DrumsController, KeyboardsController etc etc.

neilcrookes
In imho, this isnt that useful, since in most realworld settings you need more things to happen than this. Also it answers the question, but also complicates it more than needed an as such obfuscates more than it aids. At least given the basic understanding that the OP has.
Alexander Morland
Anything extra that you need to have done should be done in a subclass of this. This is a great example of factoring out common code. The syntax is a little more complicated but that complexity is justified because of the duplicate code that is removed.
Antonio Haley
Whilst this works just fine, it may be a bit over-generic and confusing for a beginner.
Cheekysoft
A: 

In response to your own answer about oo paradigm. Its like this :

function view($id) {
    $this->Guitar->id = $id;
    $this->Guitar->read();
    $this->pageTitle = $this->Guitar->data['Guitar']['name'];
    $this->set('data', $this->Guitar->data);
}

By the way, you should check if id is set and valid etc, since this is url user input.

Alexander Morland
A: 
echo "<pre>"; print_r($this);echo "</pre>";

how about

pr( $this );