Inizio  >  Docs  >  Programming  >  PHP  >  CakePHP  
CakePHPCakePHP

displayField different than 'name'

http://book.cakephp.org/view/438/displayField

The <code>displayField</code> attribute specifies which database field should be used as a label for the record. The label is used in scaffolding and in <code>find('list')</code> calls. The model will use <code>name</code> or <code>title</code>, by default.

For example, to use the <code>username</code> field:

Plain Text View

class User extends AppModel {
var $displayField = 'username';
}
  1. <code>class User extends AppModel {</code>
  2. <code> var $displayField = 'username';</code>
  3. <code>}</code>

To top

Installing Prototype/Scriptaculous into your CakePHP App

http://www.liquidbass.de/?p=88

 

Installing Prototype/Scriptaculous into your CakePHP App

I wanted to install the prototype framework with the scriptaculous effects to my cakePHP Application, but after uploading the prototype files into the webroot/js folder and linking them in the layout, i got a failure message like “Undefined variable: javascript”.

This variable has to be defined in the Applications Helper, so you can put this line of code in your AppHelper class. If you dont know what to do: create a file named “app_helper.php” in your /app folder and insert these lines of code.

class AppHelper extends Helper {
    var $helpers = array('Html','Javascript','Ajax');
}

The $javascript variable is now available and you can insert your javascript files (the prototype framework in my excample) like this in the head of your layout.

echo $javascript->link('scriptaculous/lib/prototype');
echo $javascript->link('scriptaculous/src/scriptaculous');

 

To top

cake bake Call to undefined function mysql_connect()

On this situation:

htdocs/cake/cake/console$ ./cake bake -app /var/www/localhost/htdocs/nikoz/ProdNG2/

Welcome to CakePHP v1.2.4.8284 Console
---------------------------------------------------------------
App : ProdNG2
Path: /var/www/localhost/htdocs/nikoz/ProdNG2
---------------------------------------------------------------
Interactive Bake Shell
---------------------------------------------------------------
[D]atabase Configuration
[M]odel
[V]iew
[C]ontroller
[P]roject
[Q]uit
What would you like to Bake? (D/M/V/C/P/Q)
> m
---------------------------------------------------------------
Bake Model
Path: /var/www/localhost/htdocs/nikoz/ProdNG2/models/
---------------------------------------------------------------

Fatal error: Call to undefined function mysql_connect() in /var/www/localhost/htdocs/cake_1.2.5/cake/libs/model/datasources/dbo/dbo_mysql.php on line 374

 

to solve do:

sudo ./cake bake -app /var/www/localhost/htdocs/nikoz/ProdNG2/

 

To top

Multilanguage apps

http://teknoid.wordpress.com/2008/11/28/cakephp-url-based-language-switching-for-i18n-and-l10n-internationalization-and-localization/#

 

 

nuts and bolts of cakephp

CakePHP URL-based language switching for i18n and l10n (internationalization and localization)

Posted in CakePHP by teknoid on November 28, 2008

I should preface this post by saying that it does not cover the basics of i18n and l10n so, please, first take a look at the manual on how to get the basics going.

To better understand the goal and why some things were done the way they were, I’ll summarize the requirements:

  1. The app has to support two languages or more (in this case English and Russian)
  2. Default language is English
  3. The language switching is based on a URL param
  4. The URL format should be: example.com/eng/controller/action
  5. Language choice should persist in the session and a cookie

Just a note here… there are other ways to determine the language requested by the user, for example it could come from a domain name like eng.example.com or rus.example.com. Hopefully the approach outlined here will also be helpful if other methods of language switching are used in your app…

Also, worth while to mention, that having language name in the URL (as opposed to just reading it from the session or cookie) helps with SEO… I won’t bore you here with details, but basically it helps to ensure that a variation of each page, based on the language param in the URL, is properly indexed by the search engines. Thus, each indexed page can be found later in the native language of the user.

Last, but not least, CakePHP uses three letter language name abbreviation, based on this, so I figure, should be fine to use the same in the URL’s.

Alright, so looking at the URL format, instantly raises a question… how do we tack on the language name to the “front” of each URL?

Thankfully the Router accomplishes that pretty easily (in app/config/routes.php):

  1. Router::connect('/:language/:controller/:action/*',  
  2.                        array(),  
  3.                        array('language' => '[a-z]{3}'));  

It takes a ‘language’ parameter and throws it to the front of the URL, just as we need it.

Now, we need to specify a default language to use, I just add this to my app/config/core.php

<code>
Configure::write('Config.language', 'eng');
</code>

So, when someone comes to the example.com/users/home, the site is displayed in English by default. Then we usually see a link somewhere (with a little flag next to it :)), to switch to another language.

In cake we can make those language-switching links like this:

<code>
$html->link('Русский', array('language'=>'rus'));
</code>

Notice that we set the language param, which we’ll rely on to do our switching. Providing no other params, will simply reload the current page (in the new language) with the param tacked to the front of the URL (more about this later).

Side note, it’s not a good idea to use the __() translation function on language-switching links… If I get to the site and it’s displayed in the language I can’t understand even remotely, the only savior would be a link in my native language, which indicates that i can switch to it (and well, a little flag would help too :))

So now we actually need the code to switch the language, when a user clicks on the link, like above.

It’s best done in the App Controller, kinda like here:

  1. var $components = array('Session', 'Cookie');   
  2.   
  3. function beforeFilter() {  
  4.     $this->_setLanguage();  
  5. }   
  6.   
  7. function _setLanguage() {  
  8.   
  9.     if ($this->Cookie->read('lang') && !$this->Session->check('Config.language')) {  
  10.         $this->Session->write('Config.language', $this->Cookie->read('lang'));  
  11.     }  
  12.     else if (isset($this->params['language']) && ($this->params['language']  
  13.              !=  $this->Session->read('Config.language'))) {       
  14.   
  15.         $this->Session->write('Config.language', $this->params['language']);  
  16.         $this->Cookie->write('lang', $this->params['language'], null, '20 days');  
  17.     }  
  18. }   

Let’s take a look at the code quickly and consider some scenarios…

I created a separate method <code>_setLanguage();</code>, the reason I like doing this is that it keeps the beforeFilter() cleaner, which already has enough crap in there usually.
Secondly, it can be overridden in the child controllers, if required.

So let’s consider some user-case scenarios:

  1. The user comes to the site for the very first time

    In this case the default language is read from the core.php file, so the site is set to English

  2. The user starts clicking around the site for the very first time in his native English

    Nothing really needs to be done, so we can happily skip that part

  3. The user comes to the site and has to switch the language to Russian

    Thankfully he sees a link to do so, and clicks on it. Now we check our <code>else if</code>, since no cookie or session with configured language exist yet. We see that the link has a /rus/ param in the URL and it is not yet stored in the session, therefore we write the new value of the default language to the session and the cookie.

  4. The above user browses around the site, leaves, and then comes back

    The session value is still present and therefore the site is automagically translated to Russian. This is good if the user forgot or doesn’t care to use links like example.com/rus/controller/action, because even plain links like example.com/controller/action will display the site in the right language because of the session value.

  5. The above user closes the browser, goes out hunting for wild boars, and comes to the site on some other day

    Now we rely on our previously stored cookie to read in the language and ensure we don’t override anything that might be in the session already. (the first <code> if </code>)

  6. Now if the user decides to read the site in English

    We pretty much follow through the same steps as above.

Now the last thing we need to do is to ensure that a URL param gets automatically added to all the links on the site, if a given language is chosen. Remember, that this is important to have such links for SEO as well.

Well, we’re sure as hell not going to supply the ‘language’ param manually to each link, so let’s override the cake’s default url() method to ensure the language param is now added to all links.

We create app_helper.php in /app/ (same place for app_controller.php and app_model.php), something like this:

  1. class AppHelper extends Helper {  
  2.   
  3.    function url($url = null, $full = false) {  
  4.         if(!isset($url['language']) && isset($this->params['language'])) {  
  5.           $url['language'] = $this->params['language'];  
  6.         }       
  7.   
  8.         return parent::url($url, $full);  
  9.    }  
  10.   
  11. }  

Basically we check if ‘language’ param is already in the URL if it is, we don’t need to worry about it.
If not, and <code>$this->params['language']</code> is available we pre-pend the required language to the URL.
The rest of the site, and all standard links will now include that ‘language’ param at the front of the URL (again, good for SEO).

And that’s pretty much it, even though the post was a bit long-winded (and beer to you, if you’ve made through the whole thing) it is quite nice to be able to do i18n & l10n in just about 15 lines of code.

A little disclaimer: even though the code seems to work fine, it is still experimental… so if you find some problems I haven’t yet encountered, please be sure to let me know.

P.S. Here’s a sampe test view, from which you can generate your .po files (easily done with cake i18n console command, but this is a topic for another tutorial and there are plenty of them “out there”).

  1. <?php  
  2.     __('This is only a test message');  
  3. ?>  
  4.   
  5. <p>  
  6.     <?php echo $html->link(__('Regular link', true), array('action'=>'test')); ?>  
  7. </p>  
  8.   
  9. <p>  
  10.     <?php echo $html->link(__('Regular link two', true), array('controller'=>'users''action'=>'test5''some stuff')); ?>  
  11. </p>  
  12.   
  13. <p>  
  14.     <?php echo $html->link('English'array('language'=>'eng')); ?>  
  15. </p>  
  16.   
  17. <p>  
  18.     <?php echo $html->link('Русский'array('language'=>'rus')); ?>  
  19. </p>  

You’d probably want to switch your language, if you are not so good with Russian ;)

58 Responses

Subscribe to comments with RSS.

  1. Nasko said, on November 28, 2008 at 7:09 pm

    Now, ain’t this a perspective that most I18N/L10N tutorials are completely lacking on? I’ve read numerous articles about gettext in general, and i18n in the CakePHP context, but was completely lost as to how exactly I could automate the generation of links w/ corresponding language parameters. As a result I now have 2 projects, deployed with static /controller/action links, relying on the Config/Cookie setting for the language selection and with no SEO happiness at all…

    This couldn’t have come at a more convenient time. Thanks for this article, tekno! :-)

  2. andreas said, on November 28, 2008 at 7:18 pm

    I did something similar in one of my cakePHP-apps.
    The reason I switchted to URLs like en.domain.com instead of domain.com/en/ is:
    You don’t have to mess araound with AppHelper::url().
    (On the other hand you have to take special care of your cookies: set them for *.domain.com not just en.domain.com….)

  3. Kim Biesbjerg said, on November 28, 2008 at 7:48 pm

    Hi,

    A couple of things:

    You should also override Controller::redirect in your AppController in the same fashion you override Helper::url in AppHelper. This way redirects work transparently too.

    About SEO.. In your example you will be able to reach the same page on at least two urls:
    1. domain.com/controller/action
    2. 1. domain.com/eng/controller/action

    This is not good for SEO as you might get penalized for duplicate content. What you should do is you should check in beforeFilter if supplied url language param equals the default language set in core.php, and if it does do a 301 (permanent) redirect to domain.com/controller/action (See, the language param has been removed)

    Of course, I also have an opinion on using flags for language representatives: Don’t do it! ;-)

    Flags represents countries; Not languages!

    In Canada spoken languages include French and English – What flag are you going to use? Someone will feel insulted / less comfortable whatever you choose.

  4. teknoid said, on November 28, 2008 at 8:22 pm

    @Kim Biesbjerg
    I’m not quite sure about any penalties for duplicate content… I don’t have any concrete support that it’s going to have any impact on page ranking. Not having a param in the URL by default, ensures simplicity for the user, which, IMO is quite more important. Either way it’s a simple change and is really up to the requirements.

    Flags… that’s up to the user, hence, as you’ve noticed, I was more or less kidding about it :)

    @andreas
    That approach is just fine as well, but may not be available to some users. Secondly I’m not sure how well that plays with SEO.

    @Nasko
    That’s exactly why I wrote this one up, I saw lots of other tutorials that deals with the basics (some better than others), but nothing that actually showed and explained the functional aspect of this in your app.
    Well, either way… glad to hear it was helpful ;)

  5. powtac said, on November 29, 2008 at 7:22 am

    Great post! Thank you, I was already looking for something like this.

  6. leo said, on November 29, 2008 at 8:57 am

    Thank’s for the article teknoid! :)
    Here’s another great one about choosing an url-style for multilingual websites: h3h.net/2007/01/designing-urls-for-multilingual-web-sites/

  7. teknoid said, on November 29, 2008 at 2:44 pm

    @powtac
    Cool, you’re welcome :)

    @leo
    That was an interesting read, thanks.
    It to me it seems that we are lucky to have such an easy alternative in cake, the similar approach on his list required possibly modified dir structure on the server, which would be horrible to maintain.
    Regarding the semantics and simplicity (or as he says aesthetics), having a language URL param seems quite reasonable and clean to me. That being said, my second choice would be language specific domains, as eng.example.com, as IMO, it is quite a nice and simple option, but unfortunately not always available for simple hosts or those who don’t wish to get into DNS management.

  8. snowdog said, on November 29, 2008 at 2:57 pm

    I have a very similar approach, but to avoid the problem mentioned by Kim Biesbjerg and to make url shorter for some readers I set one primary language for my app and then use urls without language param for the main language.

    For example, if my site is in English, Russian and French i will have urls like:

    - domain.com/controller/action for English
    - domain.com/fr/controller/action for French
    - domain.com/ru/controller/action for Russian

    BTW, I prefer using 2-letters code as more intuitive for most users.

  9. holooli said, on November 29, 2008 at 3:28 pm

    thanks! great post.

    as Kim said, it’s better to use sub-domains url based translation:
    1- less code
    2- better for SEO, Search engines don’t like duplication.

  10. teknoid said, on November 29, 2008 at 9:35 pm

    @holooli

    Unfortunately some users cannot control the domain name to that extend (which was the case for this client). Secondly I’m not positive that it’s better for SEO, and in in all honestly it is good and consistent marketing that wins the SE rankings, SEO from the developer’s perspective can only take you so far.

  11. teknoid said, on November 29, 2008 at 9:32 pm

    @snowdog

    It pretty much works the same one this site… I’m gonna put my trust in ISO :)

  12. Martin said, on November 30, 2008 at 7:04 am

    Nice article. Definitely an under-documented aspect of language management.

    Just a small note on language codes:
    Just as using a Canadian flag might offend a large part of the population, Using “English” is likely to offend a lot of people. That’s because English is not a language. English is not A language. There is en_gb and en_us for example with differences in spelling like colour vs. color.

    Cake supports these types of language names as well as the simpler eng and en. Using eng or en will select a default version of English if your app does not require the more detailed nuances of the language. Cake recognizes these versions of English (as an example): English (Australian), English (Belize), English (Canadian), English (British), English (Ireland), English (Jamaica), English (New Zealand), English (Trinidad), English (United States), English (South Africa)

    The same setup is of-course available for French and any other language spoken in more than one country. I guess the more slang you want to use the more pronounced the differences are likely to be.

    I just thought it was an aspect worth mentioning in this context since quite a few languages have these kinds of variations.

  13. teknoid said, on November 30, 2008 at 2:31 pm

    @Martin
    Thanks for your insight. You are absolutely right about that, but taking a more simplistic approach, let’s consider some other scenarios… For example if I have a Russian flag and a US flag, it accomplishes two things. One is the availability of another language is indicated by a static icon, which could be a good thing if somehow the actual link text did not display properly (due to encoding, etc, etc,). Secondly, the US flag shows further that we are dealing with information for US-based content (rather than British or Irish) and thus, it plays a powerful, yet a simple UI distinction. So again, depending on the context and the application itself, it could be a positive design move or a completely wrong one.

  14. primeminister said, on December 1, 2008 at 5:37 am

    He Teknoid! Very good and complete article. The way you determine which language to serve to the client is pretty much like I do in a couple of projects: www.cake-toppings.com/2008/08/29/language-detection-and-appropriate-redirects/

    I agree that language flag in domain (fra.domain.com, nl.domain.com) is better for SEO IF (and only if) you place that domain on a server in that country (France or Netherlands) and get content from that server. Then it will count as really language specific and get some extra points in find-ability.

  15. Oscar said, on December 1, 2008 at 8:21 am

    Excellent post, thanks!

    I’m considering going with the sub-domain approach though, anyone got tips how to do that?

    Also, couldn’t HTTP Accept-Language be used to do the initial selection automatically as well? I think I read somewhere this could be done directly via Routes, but never found any more info on how to do it.

  16. teknoid said, on December 1, 2008 at 12:14 pm

    @Oscar

    Thank you.

    As far as different types of language switching approaches, they are quite nicely outlined in the link posted by leo… please see above.

  17. teknoid said, on December 1, 2008 at 1:49 pm

    @primeminister

    Sounds good.
    I do feel that domain named based switching is easier, but this was a better exercise and at some point we might switch to another approach for this client. That, however, becomes much simpler once the foundation is laid out.

  18. Oscar said, on December 2, 2008 at 5:05 pm

    Ran into some problems today, when trying to combine this method with pretty urls, done like this: debuggable.com/posts/new-router-goodies:480f4dd6-4d40-4405-908d-4cd7cbdd56cb

    Does anyone have a nice solution? The url method (i renamed it to prettyUrl since it causes problems with the url rule validation) calls Router directly and the Model doesn’t seem to have a clue about languages.. Meeh. :/

  19. Oscar said, on December 4, 2008 at 5:49 am

    Right, figured out a pretty nice solution. prettyUrl() now returns an array with parameters fit for Router::url instead of passing them to Router::url itself. So, instead of returning a string with the url, an array is built and returned which then should be passed to Router::url, easiest via HtmlHelper::link for example. This will then automatically go through our custom url() method which will add the language parameters.

  20. teknoid said, on December 4, 2008 at 10:07 am

    @Oscar

    Well done. Thanks for sharing. ;)

  21. Oscar said, on December 4, 2008 at 10:46 am

    Awh crap, teknoid, please edit my comment and change “not returns” to “now returns” :)

  22. teknoid said, on December 4, 2008 at 11:59 am

    @Oscar

    Done

  23. Glad Bee said, on December 6, 2008 at 4:50 pm

    Great,thanks!

  24. dagod said, on January 16, 2009 at 6:46 am

    Hi, I’m trying to localize the Pages controller, but I’ve a little problem when I create $html->link(’English’, array(’language’=>’eng’)); and I’m on example.com/pages/home it points to example.com/pages/display. It seems that passed params get lost… is it right or I’ve to change something in routes? For the moment I fixed the problem manually adding the pass params: $html->link(’English’, array(’language’=>’eng’,join(’/',$this->params['pass'])))
    Is there a better solution? thank yuo

  25. visskiss said, on February 17, 2009 at 7:59 am

    Hey teknoid,

    I set this up as you suggested and it seems to work well with a couple of caveats. I changed the regex for languageto just be a list of acceptable three letter languages (otherwise, the add action was being interpreted as a language. I also added a route for the index page of each other language (like /fre/ for example).

    However, I’m having trouble with the html::link helper, specifically

    $html->link(’Français’,array(’language’=>’fre’))

    This works unless there’s a paramater in the current url, so /posts/view/5 should link to ‘/fre/posts/view/5′ but it actually just links to ‘/fre/posts/view’ which in turn redirects.

    Theories? Solutions?

    Thanks again.

  26. visskiss said, on February 18, 2009 at 2:55 am

    Well, it’s provisionally fixed. Instead of

    $html->link(’Français’,array(’language’=>’fre’))

    I use

    $html->link(’English’,array(’language’=>”)+$this->params['pass'])

    which adds the unnamed paramaters located in params->pass (typically [0] => 3 etc) to the link. I also used

    function _setLanguage() {
    if (isset($this->params['language'])) {
    $this->Session->write(’Config.language’, $this->params['language']);
    } else if (isset($this->params['named']['language'])) {
    $this->params['language']=$this->params['named']['language'];
    $this->Session->write(’Config.language’, $this->params['language']);
    } else {
    $this->Session->write(’Config.language’, ‘eng’);
    }
    $this->set(’language’,$this->Session->read(’Config.language’));
    }

    as my set language function so I can use $language in my views if necessary (I use it to suffix sql field names where tables have multiple languages)

  27. teknoid said, on February 20, 2009 at 10:13 am

    @visskiss

    Thanks for sharing. Just curious, why do you need the table suffix in the view?

  28. bberg said, on February 22, 2009 at 4:32 am

    @visskiss
    i’m with you. keeping parameter in the url while changing languages is nice. thx for sharing the code.

    @teknoid
    i use $language in the view as a css id for the flags. this way i can modify the current one so the user knows it is already “clicked”. but i don’t see why one would need it for tables suffix there too…
    btw. thanks for the article.

  29. bberg said, on February 22, 2009 at 5:09 am

    i must say that the 3-letter language name abbreviation based on the standard iso 639-2 is no good:
    pick brazil. it is commonly abbreviated as “bra”.
    the standard points “bra” to the braj country.
    the 2-letter iso 639-1? no good either:
    in brazil one speaks portuguese. in portugal too. but that’s 2 different languages. this standard points it to “pt” – for portugal only.
    using “pt_br” like “en_us” or “en_gb” would be the solution imho, although it is not always possible.

  30. teknoid said, on February 23, 2009 at 11:58 am

    @bberg

    I’m glad you’ve found the article helpful.
    Also, you are definitely right that the given ISO abbreviation may not be applicable in some cases (for me it worked fine, so I figured to use it)… but hopefully the post shows how to use any type of URL-based language switching to base upon for your specific need.

  31. kooms said, on February 27, 2009 at 11:28 pm

    Thanks blog owner to write this article!

  32. teknoid said, on February 28, 2009 at 2:43 pm

    @kooms

    You’re welcome, glad you’ve found it helpful.

  33. Josenivaldo Benito Junior said, on March 18, 2009 at 9:21 pm

    Hi,

    For redirect method I overloaded it in the App_controller.php file like this:

    function redirect( $url, $status = NULL, $exit = true ) {
    if (!isset($url['language']) && $this->Session->check(’Config.language’)) {
    $url['language'] = $this->Session->read(’Config.language’);
    }
    parent::redirect($url,$status,$exit);
    }

    Although after saving session information any URL (with or without language) will work this make sure that things like $this->redirect(array(…)); will not result in a URL without language. This could annoy the user since his URL will have or not the language set after some action. To prevent this is better to have it since first time user set and not change until he sets another language.

    Regards,
    Benito.

  34. teknoid said, on March 19, 2009 at 1:56 pm

    @Josenivaldo Benito Junior

    Thanks for sharing.

  35. Josenivaldo Benito Junior said, on March 25, 2009 at 7:50 pm

    @teknoid

    I still have a doubt I could not solve yet. Is not necessary to use L10n component like cookbook suggests? What would be expected??

    Regards,
    Benito

  36. teknoid said, on March 25, 2009 at 8:10 pm

    @Josenivaldo Benito Junior

    No, not for this case.
    It works perfectly well for me, without the use of the component.

  37. Josenivaldo Benito Junior said, on March 25, 2009 at 9:09 pm

    @teknoid

    Yes, yes, for me it works perfectly well too!

    I am just curious because virtually all I18n articles for CakePHP (and even CookBook) mention the need of L10n component but just set the session “Config.lang” or configure “Config.language ” do the job with no pain. I am wondering what is the difference between use or not the L10n since, as per my understand, the unique function it has is to get locale messages for a given valid locale (what, per my understand, is happening with your simple, few lines, solution).

    Regards,

  38. teknoid said, on March 26, 2009 at 8:21 am

    @Josenivaldo Benito Junior

    L10n will let you to set locale manually amongst other things, but I don’t see any need to use it, when (as you’ve mentioned) the setting can be obtained from Config and Session.

  39. ivan said, on March 31, 2009 at 10:41 am

    thanks for this post teknoid, I found t to be very helpful.

    I just had a problem with the login form not working anymore with the Auth component, but I fixed it adding the language param to loginAction.

    $this->Auth->loginAction = array( ‘controller’=>’users’,
    ‘action’=>’login’,
    ‘language’=>$this->Session->read(’Config.language’));

    I also overloaded the flash function in app_controller so I can keep the language param (the same Josenivaldo did with the redirect function)

    function flash($message, $url, $pause = 1) {
    if (!isset($url['language']) && $this->Session->check(’Config.language’)) {
    $url['language'] = $this->Session->read(’Config.language’);
    }
    parent::flash($message,$url,$pause);
    }

    Thanks again for this wonderful post.

  40. teknoid said, on March 31, 2009 at 11:25 am

    @ivan

    Great tips, thanks for sharing.
    I’m glad you’ve found it helpful to get started.

  41. Phally said, on April 3, 2009 at 10:21 am

    Isn’t it easier to get the language always out the url instead of Cookies/Sessions? If no language was found, redirect to the same page, but with the language in the url. It is not that hard to do, I’ve done it myself. Takes care of duplicate content too.

  42. teknoid said, on April 3, 2009 at 11:15 am

    @Phally

    If I went to www.example.com, switched to my native language, it is best to store my preference in the cookie. Because when I come back the next day to www.example.com, there is no language param in the URL to extract the language setting from.
    The thing is the language parm may not always be available, so using session/cookie is a perfect fall-back and improves usability as well as SEO.

  43. Robin said, on April 11, 2009 at 6:28 am

    Hi teknoid,

    thanks for this pretty code.
    it works great with my “normal” pages.

    Im trying to combine this language switching with multiple pagination (debuggable.com/posts/how-to-have-multiple-paginated-widgets-on-the-same-page-with-cakephp:48ad241e-b018-4532-a748-0ec74834cda3) but i go in circle…

    i always get the problem that my paginator links look like this:
    /controller/action/params/page:2/language:deu/model:Project

    and not like desired:
    /deu/controller/action/params/page:2/model:Project

    I think this depends on some function that needs to be overridden in the app_controler, possibly right? But i think the paginate function would get its url from $this->params …i am helpless :/

    hopefully,

    Robin

  44. teknoid said, on April 14, 2009 at 4:46 pm

    @Robin

    Have you tried asking at the google group or IRC? I see where the problem is, but don’t have a solution off top of my head.
    I am actually using AJAX-based pagination for this project and do not seem to have a similar issue.

  45. لوگوس said, on April 26, 2009 at 9:50 am

    A truly great article. All comments are also very insightful. Perhaps I should combine all these into a tutorial and post it on my blog in my native language (Persian) or even put an English translation out there for others to use. Are you OK with that ?

  46. teknoid said, on April 27, 2009 at 8:28 am

    @لوگوس

    Absolutely, no problem.

    And I’m glad you’ve enjoyed it.

  47. kettle said, on May 1, 2009 at 4:57 pm

    Hey Teknoid:

    Once again you’ve come thru in a huge way!

    Running into a small issue with the routing though. Seems like I lose url parameters when I try using $html->link(’eng’, array(’language’ => ‘eng’))

    So if I’m on this page:
    /rus/posts/view/3

    I end up on
    /eng/posts/view

    after clicking the link above. Would be great to be able to just drop this in my default layout and not have to worry about passing those params.

    Either way, thanks again for this super clear and helpful tutorial I wish I found months ago!

    • kettle said, on May 1, 2009 at 5:13 pm

      Argh, sorry, see others have already posted that question (thought I checked thoroughly)! Disregard my post.

      Thanks!

  48. teknoid said, on May 1, 2009 at 5:42 pm

    @kettle

    Thanks. Glad you got it figured out.

  49. David said, on May 19, 2009 at 6:45 pm

    Thanks for the tips, you just resolved me a big trouble :D

  50. teknoid said, on May 20, 2009 at 8:22 am

    @David.

    Good to hear ;)

  51. kicaj said, on May 29, 2009 at 9:48 am

    Maybe You know, why when use admin routing cake switch me to default language, and i can’t switch to other languages?

  52. teknoid said, on May 29, 2009 at 1:29 pm

    @kicaj

    I do use this approach with admin routing. Not sure what the problem is exactly.

  53. kicaj said, on May 30, 2009 at 12:47 pm

    Hmm, now I use [named][language] and work perfect

  54. teknoid said, on May 30, 2009 at 2:22 pm

    @kicaj

    Good… good… ;)

  55. Oscar said, on July 15, 2009 at 10:27 am

    Great tutorial!
    As many other people I was having a hard time understanding the whole multilanguage thing!
    Thanks to you I finally achieved a working multilingual site.
    great work!

  56. teknoid said, on July 15, 2009 at 10:41 am

    @Oscar

    Thanks. Glad to hear it was helpful.


Leave a Reply

<form action="http://teknoid.wordpress.com/wp-comments-post.php" method="post" id="commentform">

<input class="comment" name="author" id="author" size="22" tabindex="1" type="text" /> <label><small>Name (required)</small></label>

<input class="comment" name="email" id="email" size="22" tabindex="2" type="text" /> <label><small>Mail (will not be published) (required)</small></label>

<input class="comment" name="url" id="url" size="22" tabindex="3" type="text" /> <label><small>Website</small></label>

<textarea name="comment" id="comment" cols="100" rows="10" tabindex="4"></textarea>

<input class="subcom" name="submit" id="submit" tabindex="5" value="Submit Comment" title="Please review your comment before submitting" type="submit" /> <input name="comment_post_ID" value="391" id="comment_post_ID" type="hidden" /> <input name="comment_parent" id="comment_parent" value="0" type="hidden" />

<input name="genseq" value="1248073436" type="hidden" />

<input name="subscribe" id="subscribe" value="subscribe" style="width: auto;" type="checkbox" /> <label id="subscribe-label">Notify me of follow-up comments via email.</label>

</form>

<noscript><p><img src="http://pixel.quantserve.com/pixel/p-18-mFEk4J448M.gif?labels=adt.0%2Clanguage.en%2Cposttag.cakephp%2Cposttag.cakephp-12%2Cposttag.cakephp-i18n%2Cposttag.cakephp-internalization%2Cposttag.cakephp-l10n%2Cposttag.cakephp-localization%2Cposttag.i18n%2Cposttag.internationalization%2Cposttag.l10n%2Cposttag.localization" style="display: none" height="1" width="1" alt="" /></p></noscript>

To top

Creating PDF files with CakePHP and TCPDF

http://bakery.cakephp.org/articles/view/creating-pdf-files-with-cakephp-and-tcpdf

By Kalileo (kalileo)

With CakePHP 1.2 creating PDFs with CakePHP has just gotten a lot easier. This tutorial shows how to combine CakePHP and the powerful TCPDF for easy PDF file creation.

TCPDF is an Open Source PHP class for generating PDF documents. It continues where FPDF stopped, and contains all its goodies plus support of UTF-8 Unicode and Right-To-Left languages! Especially the missing UTF-8 Unicode support in FPDF is a problem for everyone living outside the English language only countries.

Step 1: Download and install TCPDF

  1. Go to http://www.tcpdf.org and download the latest version of TCPDF.
  2. Extract to one of your vendors folders, such as app/vendors. It will create a directory tcpdf there with tcpdf.php and more in it. You need at least the folders tcpdf/config and tcpdf/fonts in your application.
  3. Configure TCPDF, see its documentation. You want at least to have a look at tcpdf/config/tcpdf_config.php.


Step 2: Extend TCPDF to customize your header and footer

There is a default header and footer in TCPDF, defined in a header() and a footer() method, which is supposed to be overwritten by you, if needed. This can be done by extending TCPDF and then calling this extended TCPDF class from your application.

In app/vendors create the file xtcpdf.php with this content:

<?php
App::import('Vendor','tcpdf/tcpdf');

class XTCPDF  extends TCPDF
{

    var $xheadertext  = 'PDF created using CakePHP and TCPDF';
    var $xheadercolor = array(0,0,200);
    var $xfootertext  = 'Copyright © %d XXXXXXXXXXX. All rights reserved.';
    var $xfooterfont  = PDF_FONT_NAME_MAIN ;
    var $xfooterfontsize = 8 ;


    /**
    * Overwrites the default header
    * set the text in the view using
    *    $fpdf->xheadertext = 'YOUR ORGANIZATION';
    * set the fill color in the view using
    *    $fpdf->xheadercolor = array(0,0,100); (r, g, b)
    * set the font in the view using
    *    $fpdf->setHeaderFont(array('YourFont','',fontsize));
    */
    function Header()
    {

        list($r, $b, $g) = $this->xheadercolor;
        $this->setY(10); // shouldn't be needed due to page margin, but helas, otherwise it's at the page top
        $this->SetFillColor($r, $b, $g);
        $this->SetTextColor(0 , 0, 0);
        $this->Cell(0,20, '', 0,1,'C', 1);
        $this->Text(15,26,$this->xheadertext );
    }

    /**
    * Overwrites the default footer
    * set the text in the view using
    * $fpdf->xfootertext = 'Copyright © %d YOUR ORGANIZATION. All rights reserved.';
    */
    function Footer()
    {
        $year = date('Y');
        $footertext = sprintf($this->xfootertext, $year);
        $this->SetY(-20);
        $this->SetTextColor(0, 0, 0);
        $this->SetFont($this->xfooterfont,'',$this->xfooterfontsize);
        $this->Cell(0,8, $footertext,'T',1,'C');
    }
}
?>

Of course, customize this to show your organization's name etc., and modify the code as you like. See the TCPDF documentation for details.

Step 3: Create your layout for PDF

You cannot use your default layout, as it would wrap the PDF file in your HTML page code. You need a layout such as this one, save it as app/views/layouts/pdf.ctp :

<?php
header("Content-type: application/pdf");
echo $content_for_layout;
?>

Step 4: For your Controller

In your controller you will have a method which will output the PDF. This here is the code as it is used in one of my real world applications to print a nice PDF page with data and pictures about a property:

function viewPdf($id = null)
    {
        if (!$id)
        {
            $this->Session->setFlash('Sorry, there was no property ID submitted.');
            $this->redirect(array('action'=>'index'), null, true);
        }
        Configure::write('debug',0); // Otherwise we cannot use this method while developing

        $id = intval($id);

        $property = $this->__view($id); // here the data is pulled from the database and set for the view

        if (empty($property))
        {
            $this->Session->setFlash('Sorry, there is no property with the submitted ID.');
            $this->redirect(array('action'=>'index'), null, true);
        }

        $this->layout = 'pdf'; //this will use the pdf.ctp layout
        $this->render();
    }

Adapt to your needs. The critical part is just to select the PDF layout before rendering.

$this->layout = 'pdf'; //this will use the pdf.ctp layout
        $this->render();

Step 5: For your View

Here is where the magic happens. Because with CakePHP we can load the vendor directly in the view we do not need to wrap it in a helper. So the big TCPDF library with currently 9600 lines of code in the main class tcpdf.php alone will only get loaded when we really need it, that is when we actually create the PDF file. The vendor is now used here like an external helper. Note: I do not know if that was intended or not, but the more I think about it the more I like it, it's so elegant and efficient, and demonstrates the power and flexibility of CakePHP.

But enough said, here's the code for the view:

View Template:

<?php
App::import('Vendor','xtcpdf');
$tcpdf = new XTCPDF();
$textfont = 'freesans'; // looks better, finer, and more condensed than 'dejavusans'

$tcpdf->SetAuthor("KBS Homes & Properties at kbs-properties.com");
$tcpdf->SetAutoPageBreak( false );
$tcpdf->setHeaderFont(array($textfont,'',40));
$tcpdf->xheadercolor = array(150,0,0);
$tcpdf->xheadertext = 'KBS Homes & Properties';
$tcpdf->xfootertext = 'Copyright © %d KBS Homes & Properties. All rights reserved.';



// Now you position and print your page content
// example:
$tcpdf->SetTextColor(0, 0, 0);
$tcpdf->SetFont($textfont,'B',20);
$tcpdf->Cell(0,14, "Hello World", 0,1,'L');
// ...
// etc.
// see the TCPDF examples

echo $tcpdf->Output('filename.pdf', 'D');

?>

That was easy! Yes, that's all.

The Questions and Answers below are only of interest for users of the FPDF helper.

Why not FPDF?

For me the main reason is that there is no Unicode support. You can add a limited unicode support to it, as described on the Dievolution blog, by hacking the Cell method of FPDF, but then, why not go for TCPDF right away. No hack needed, and the TCPDF author, Nicola Asuni, is very active, releasing a new update almost every week.

How about the FPDF helper, as shown here in the bakery?

I used this helper quite a lot, it worked fine with CakePHP 1.1. Somewhere between the 1.2 beta and 1.2 RC it stopped working though. The reason IMHO is that it is not implemented correctly.

It extends the FPDF class directly, but a Helper should extend a Helper, such as the AppHelper class.

This is what the FPDF helper does, <del>works</del> worked with CakePHP 1.1, but wrong:

class FpdfHelper extends FPDF

This would be correct but it does not work:

class FpdfHelper  extends AppHelper

Somewhere in the CakePHP 1.2 development a change happened which was that helpers receive an array as first argument when they are initialized. A Helper which extends AppHelper expects that and handles it correctly, but FPDF does not know what to do with that array, as it expects as first argument the page orientation.

Can the FPDF Helper be hacked to continue working with CakePHP 1.2?

Yes, it can, but this should be not the solution, as it is not needed (as shown above). Simply add this line in the FPDF code (the one in your vendors directory, not the helper), as first line of the FPDF method, which is in my FPDF version at line 78:

<code>if (is_array($orientation)) return;</code>

 

it will then be:

 

<code>function FPDF($orientation='P',$unit='mm',$format='A4')
{
    if (is_array($orientation)) return;
    ... </code>

This will make it ignore the Helper initialization, but let it run fine when it is called later, via

<code>$this->FPDF($orientation, $unit, $format);</code>

in the FPDF helper's setup() method.

Why is this FPDF hack not needed in CakePHP 1.2?

FPDF and TCPDF are external libraries, which you can integrate in CakePHP under Vendors. Now CakePHP 1.2 changed the way Vendors are included from

<code>vendor("fpdf/fpdf") </code> 

to

App::import('Vendor','fpdf/fpdf'); - or for TCPDF: -  App::import('Vendor','tcpdf/tcpdf');

This alone does not change too much though. Still, you would need a helper to wrap the TCPDF calls to use them in your view, similar to:

Helper Class:

<code> <?php
App::import('Vendor','xtcpdf');

class TcpdfHelper extends AppHelper {
    var $pdf;
    function setup() {
        $this->pdf = new XTCPDF();
    }
}

?></code>

Fortunately this is not needed, because in CakePHP 1.2 RC2 you can now use App::import directly in the view. As shown above :)

Comments 

CakePHP Team Comments Author Comments

 

 

Comment

 

1 TCPDF path configuration

Hi,
maybe you should spent a little more on how you set tcpdf paths in configuration file.
I tried to make it run bur I always got "TCPDF error: Could not include font definition file".
Nice post, really interesting.
Bye!!

Posted Aug 28, 2008 by Giovanni Casano

 

 

Comment

 

2 Error: Fatal error: Class 'XTCPDF' not found in C:\xampp\htdocs\cake12\CakePHP\app\views\books\view_pdf.ctp on line 3

Hi;

I followed the tutorial but having some problem:
Following is the error...

<q> Fatal error: Class 'XTCPDF' not found in C:\xampp\htdocs\cake12\CakePHP\app\views\books\view_pdf.ctp on line 3</q>



Posted Oct 23, 2008 by Muhammad Mohsin Ali

 

 

Question

 

3 Always get an empty page

I tried your tutorial to create PDFs with my cakrPHP application. The first try I use your code as you discribe above to create a simple PDF. But if i call the view, i get an empty page instead of the PDF. The only thing i changed is the classname for my own extended TCPDF class. Any hint? Has anyone else the same problem? If needed i can post the relevant code here.
Any help would be appreciated.

draikin

Posted Oct 29, 2008 by Thomas Heinrich

 

 

Comment

 

4 Reverse in Persian problem

when i use tcpdf directly ( samples in example folder ) i see the result right, but when i use it as helper in cake or vendor all of persian characters are reverse! can anyone help me?

Posted Oct 30, 2008 by Vahid Alimohammadi

 

 

Comment

 

5 I only get a blank page

First, thank you for this great tutorial. Unfortunatly it dosn't work for me. I tried your example code but only get an empty page. The only thing i changed was the class name for the extended vendor class. I don't if I miss anything. Has anyone a similar problem with the above code?

Posted Nov 2, 2008 by Thomas Heinrich

 

 

Comment

 

6 permissions

Hi Kalileo thanks for providing this - it seems cool.

I had a problem getting it to work at the beginning until I gave the whole tcpdf dir a 755 permission. the instructions are not clear on the TCPDF site about how to set the permissions and it would not work for me easily until I did this. I use XAMPP

Posted Nov 5, 2008 by Luke Barker

 

 

Comment

 

7 Only get an empty page

If i try the above example in my cakePHP application, the result is an empty page. No content, no download. Has anyone got a PDF page with the above code? Did i miss something? Any hints?

draikin

Posted Nov 13, 2008 by Thomas Heinrich

 

 

Comment

 

8 Hints to troubleshoot problems

If it doesn't work (ie. blank page instead of pdf) you may try checking these:
* www-data (or whatever user your webserver is running as) has read access to tcpfg/ -R
* increase memory limit in php.ini
* remove "echo" before "$tcpdf->Output"

Posted Nov 20, 2008 by Voro Experior

 

 

Bug

 

9 No 'Hello, world' until I added AddPath()...

THANKS HEAPS!!!! This got my App PDFing within a couple days.

Example worked OK, but didn't see "Hello, world." until I added <code> $tcpdf->AddPath(); </code> in the view in front of the SetTextColor() bit.

Also, it showed up inside the header, until I repositioned it from Cell(0,14, ...); to Cell(75,75, ...); May just need $tcpdf->lastPath(); ahead of the AddPath();

Using writeHTML() for now to keep it 'easy' making invoices and POs, but when I learn about headers and footers, I'll figure out why "Hello, world" was inside the header...

regards,
oh4real

Posted Dec 24, 2008 by ohforreal

 

 

Comment

 

10 Great article

Followed this through and got PDFs generating from my model data in no time. There are lots of easy examples on the tcpdf website. Well Done!!!

Posted Jan 7, 2009 by Paul Rhodes

 

 

Comment

 

11 Great article

I need this indeed. Great article. Thanks!

Posted Feb 13, 2009 by KANG Ghee Keong

 

 

Question

 

12 How to print table data?

Thanks, this is a very interesting article about howto integrate things like fpdf or tcpdf into cake infrastructure, I am really glad, that you wrote this, as it is not possible to understand from the manuals or any book out there how this could be achieved. Thanks!
However, it would be very nice to go one step further and show how to use this thing in a more productive way - say how would you print your models to pdf? How would you print tabe data?

Posted Mar 2, 2009 by Johnny Cake

 

 

Comment

 

13 Why not as a component? Help fight climate warming!

There is one important idea in this tutorial: generate the pdf only when needed. So why do you want to generate the pdf over and over again for every request? On a site with many visitors this will take your server down, especially if you are using the bloated tcpdf lib and not fpdf. You will especially have much fun if a spider follows all your "generate pdf"-links. You NOT have to generate the pdf on every request, but only when the content you want to output has changed. A lot of cpu cycles could be saved that way and climate will stay cool.
Of course this depends on your content, but if you have an article or a newsitem or a tutorial like this page and the content will not change very fast or maybe never - it would be much better design to generate the pdf after inserting or updating and keep the generated pdf downloadable and link to it.
I do not understand cake very well right now, but I think a component would be the right place for this kind of thing... I will check that out later.

Posted Mar 4, 2009 by Johnny Cake

 

 

Comment

 

14 Don't forget AddPage()

Thank you for the great article. I had some trouble getting this to work in that the header and footer were there, but no text I added. This was until I found that adding:

$tcpdf->AddPage();

in the view right before:

$tcpdf->SetTextColor(0, 0, 0);

in the view fixed it.

Posted Apr 2, 2009 by Al Scheuring

 

 

Comment

 

15 Apology

I have to apologize to all commenters here, it took me until now to see that I have to click on view comments in the my account page to see (and publish) your comments. Sorry Bakers!

Posted Apr 26, 2009 by Kalileo

 

 

Comment

 

16 @Muhammad Mohsin Ali:

you need to call in your view

View Template:

<code>
App::import('Vendor','xtcpdf');
</code> before you call

View Template:

<code>
$tcpdf = new XTCPDF(); 
</code> If xtcpdf.php with the Class XTCPDF is in app/vendors, and no typos etc, then it will be found.

Posted Apr 26, 2009 by Kalileo

 

 

Comment

 

17 Problems with some TCPDF versions

@Thomas Heinrich:
A few moths ago I needed to move a site with this code running from one server to another, and used the opportunity to update cake and tcpdf. All fine on the development server, but not on the production server.

Similar problems as you saw, it just didn't work, something with the fonts was messed up. It printed lines, borders, but no fonts. Which is kinda stupid :(

The solution was to rollback TCPDF to the old version. And again, working like a charm :) for an example see http://kbs-properties.com/properties/view/46 - click on the PDF icon at the top right above the content.

The working version was TCPDF 4.0.017 with release date 2008-08-05, the problematic one TCPDF 4.5.023 with release date: 2009-03-06.

Posted Apr 26, 2009 by Kalileo

 

 

Comment

 

18 clearing header area

@ohforreal: Yes, keeping the header and footer area clear is tricky, IIRC this code, before starting to print something on the page, helped:

View Template:

<code>
$pdf->SetAutoPageBreak( true, 25 );
$pdf->SetTopMargin(34);
</code>

Posted Apr 26, 2009 by Kalileo

 

 

Comment

 

19 How to print table data?

@Johnny Cake: you can treat such a PDF view the same way you treat a regular view, so you use the same logic and procedure to get your data ready to show. Then you pack it either in the TCPDF cell/multicell/write methods or you pack it into html code and print that using the TCDPF methods for printing HTML. There are examples in the TCPDF code / on the TCPDF website.

Posted Apr 26, 2009 by Kalileo

 

 

Comment

 

20 Saving CPU cycles

@Johnny Cake: with the App::import('Vendor','xtcpdf'); in the view TCPDF will only get loaded when you use it. I don't see how that can get reduced ;) except you could additionally wrap it in code to cache it, Cake makes that easy.

However, as you say, such code should only be used for dynamic data, such as vouchers, or price lists with limited validity. If you have static data, then offer a static PDF file for download.

FPDF has a problem with unicode, it cannot mix e.g. English and Thai. A big thank to Nicola Asuni to have bloated ;) TCPDF to fix that..

Posted Apr 26, 2009 by Kalileo

 

 

Comment

 

21 AddPage()

@Al Scheuring: yes, thanks for mentioning that! In the meantime also my code has $pdf->AddPage(); exactly at the place you specify, however when I wrote the article it was not there, so it seems to have worked without.

As mentioned earlier, TCPDF is seeing a lot of development, so that might be just one visible result.

The code in the view, as I use it now, has changed to:

View Template:

<code>
App::import('Vendor','xtcpdf');
$pdf = new XTCPDF();
$textfont      = 'freesans'; // looks better, finer, and more condensed than 'dejavusans'

$footerHeight = 25;

$tcpdf->SetAuthor("KBS Homes & Properties at http://kbs-properties.com ");
$tcpdf->SetAutoPageBreak( true, $footerHeight );
$tcpdf->SetTopMargin(34);
$tcpdf->setHeaderFont(array($textfont,'',40));
$tcpdf->xheadercolor = array(150,0,0);
$tcpdf->xheadertext = 'KBS Homes & Properties';
$tcpdf->xfootertext = 'Copyright © %d KBS Homes & Properties. All rights reserved.';

// Now you position and print your page content
// example: 
$tcpdf->AddPage();
$tcpdf->SetTextColor(0, 0, 0);
$tcpdf->SetFont($textfont,'B',20);
$tcpdf->Cell(0,14, "Hello World", 0,1,'L');
// ...
// etc.
// see the TCPDF examples 

echo $tcpdf->Output('filename.pdf', 'D');
?>
</code>

Posted Apr 26, 2009 by Kalileo

 

 

Question

 

22 Download error

Great tutorial. Thanks.
Using the code as is in this tutorial, I see only this error message:
"  TCPDF ERROR: Some data has already been output, can't send PDF file". Only when I change the output type 'D' to 'S', in the Output method of the $tcpdf method, can I see the PDF file in the browser.
I have reviewed the files of PHP controllers, models and helpers, and I've removed all the spaces that were before " What can be wrong?

Posted May 11, 2009 by Claudio Juan Böhm

 

 

Comment

 

23 < >

.

The comment above was posted May 11, 2009 by Claudio Juan Böhm but it is not displayed completely because he uses < > in it and the bakery comment validation lets it through without sanitation. Konqueror gets a big hiccup, Firefox not so much. Anyway, see the missing part in the quote in the next comment, which is my reply to it.

Posted May 12, 2009 by Kalileo

 

 

Comment

 

24 @Claudio Juan Böhm

<q>Great tutorial. Thanks.
</q> :)
<q>Using the code as is in this tutorial, I see only this error message:
"  TCPDF ERROR: Some data has already been output, can't send PDF file". Only when I change the output type 'D' to 'S', in the Output method of the $tcpdf method, can I see the PDF file in the browser.
I have reviewed the files of PHP controllers, models and helpers, and I've removed all the spaces that were before <code> <? Php  </code>, but I do not get a direct download of the PDF file.
What can be wrong?
</q>
You mention that you checked "controllers, models and helpers", but how about view and layout? See the pdf.ctp in app/views/layouts/pdf.ctp which should look as described above, and then set in the controller with $this->layout = 'pdf'; before calling $this->render();
oh yes, and check also for spaces after the PHP closing tag, not just before the PHP opening tag

Posted May 12, 2009 by Kalileo

 

 

Comment

 

25 about __view() and AddPath()

In my tests, first I had the so-called blank screen. The first procedure to find the problem is re-enabling the debug:

<code> // Configure::write('debug',0) </code>
The first problem was caused by this line:

<code> $property = $this->__view($id); // here the data is pulled from the database and set for the view </code>
This '$this->__view()' function is an author function, not Cake native, as I'd supposed it was. This is the error:

<q>Fatal error: Call to undefined method CidadesController::__view() in ...app\controllers\my_controller.php on line ### </q>
The second detail is about using the AddPath() in the view:

<code> $tcpdf->AddPath(); </code>
Because it generates this error:

<q>Fatal error: Call to undefined method XTCPDF::AddPath() in ...\app\views\my_views\view_pdf.ctp on line 17</q>
This can resolve the problem of the blank screen.

I hope this comment could be useful to save time. These little details make programmers lose hours or even days to find the solution.

Sorry for the mediocre english :P

Posted May 13, 2009 by Leonel Sanches

 

 

Comment

 

26 $this->__view($id);

@Leonel Sanches

<q> The first problem was caused by this line:

<code> $property = $this->__view($id); // here the data is pulled from the database and set for the view </code>
This '$this->__view()' function is an author function, not Cake native, as I'd supposed it was.
</q>
Of course it is! Please have a look at whats written right above that sample code:

<q> In your controller you will have a method which will output the PDF. This here is the code as it is used in one of my real world applications to print a nice PDF page with data and pictures about a property
</q>
So in your controller you need to do whatever is needed to pull any data you might want to publish from your database and set it.

In my application the "view" and the "viewPdf" share the same data, and while the "view" optimizes it for screen display, "viewPdf" optimizes for PDF display. They share the same code to pull and set the data, which I have combined in $this->__view($id); as said there:

<q> // here the data is pulled from the database and set for the view
</q>

So adapt that to your data and your needs please.

<q> The second detail is about using the AddPath() in the view:
<code> $tcpdf->AddPath(); </code> Because it generates this error:
<q>Fatal error: Call to undefined method XTCPDF::AddPath() in ...\app\views\my_views\view_pdf.ctp on line 17</q> </q>
As you might have seen, my sample code above does not contain $tcpdf->AddPath() so I don't know where and why you have added it.

There are many different versions of TCPDF out there, and many different server environments. Some seem to need it (see comment 9 from Dec 24, 2008 by ohforreal), others not.

In any case, if you get a blank screen, your approach to re-enable debug output by commenting the line

<code>
Configure::write('debug',0)
</code>
is a good and fast way to see any error messages.

Posted May 19, 2009 by Kalileo

 

 

Comment

 

27 View to pdf

how can we conver view to pdf?

Posted May 22, 2009 by umit celik

 

 

Comment

 

28 @umit celik

Umit, that's what this article is all about, and the view part is described above in step 5.

If you explain where you're stuck I can try to answer more specific.

Posted May 23, 2009 by Kalileo

 

 

Comment

 

29 TCPDF 4.6.013 needs PHP set to more than 16 MB

The code as shown in this article works with the current TCPDF version, TCPDF 4.6.013 without any change.

However if you want to use one of the best features, Unicode support, and the included font which supports it best, freeserif, you might run into internal server errors, resulting in nice white pages. The reason is that freeserif has been doubling its size, probably supporting more and more, but with the side effect of using more memory. if your server is configured to allow PHP 16 MB RAM, then that is not enough.

Even without using freeserif, but freesans, after half a page of content the same error seems to be happening.

Either adjust the value in your php.ini on your server, or add the line

<code>
php_value memory_limit 36M
</code>
to your .htaccess and all is fine, the error is gone and the pages are not so white anymore.

Posted May 31, 2009 by Kalileo

 

 

Comment

 

30 Output files don't seem to be recognized by adobe

Everything seems to be working OK Cake-wise, except the resulting files can not be opened by Adobe reader. Do you think this is something wrong with TCPDF? Any clues?

The first few lines of the pdf file when I open it up in a text editor look like:
<code>
  %PDF-1.7
3 0 obj
<</Type /Page
/Parent 1 0 R
/MediaBox [0 0 595.28 841.89]
/Resources 2 0 R
/Contents 4 0 R>>
endobj
4 0 obj
<</Filter /FlateDecode /Length 245>>
stream
</code>

Posted Jun 14, 2009 by killian tobin

 

 

Comment

 

31 scratch my last comment

Thanks for the great article!

my version of Adobe Reader was the problem.

Posted Jun 14, 2009 by killian tobin

 

 

Question

 

32 Merging PDFS?

I've looked through the methods but didn't see anything for merging an external pdf with a pdf you're creating - i just want to append an external pdf to the end. The closest I could find was to create an annotation. Does anyone know a way to merge pdfs with tcpdf?

Posted Jul 7, 2009 by clive

 

 

Comment

 

33 Check for spaces in all the files included in the controller

<q><q>Great tutorial. Thanks.
</q> :)
<q>Using the code as is in this tutorial, I see only this error message:
"  TCPDF ERROR: Some data has already been output, can't send PDF file". Only when I change the output type 'D' to 'S', in the Output method of the $tcpdf method, can I see the PDF file in the browser.
I have reviewed the files of PHP controllers, models and helpers, and I've removed all the spaces that were before <code> <? Php  </code>, but I do not get a direct download of the PDF file.
What can be wrong?
</q>
You mention that you checked "controllers, models and helpers", but how about view and layout? See the pdf.ctp in app/views/layouts/pdf.ctp which should look as described above, and then set in the controller with $this->layout = 'pdf'; before calling $this->render();
oh yes, and check also for spaces after the PHP closing tag, not just before the PHP opening tag
</q>
I had the same problem, but I found spaces after the closing ?> tag in one of the models included in the controller that uses the tcpdf and the vendor class xtcpdf.php file.

So take the time and check all the included views, controllers and models. Do not forget to check the app_controller.php and the app_model.php as well.

Just thought this might help someone that get the same error.

Posted Jul 8, 2009 by Fanie Smith

 

 

Comment

 

34 Problem forcing save on pdf

I am trying to create a pdf, then save it to disk, without ever outputting it to the screen.

<code> $tcpdf->Output('filename.pdf', 'F'); </code>
Using the F parameter in the output function to force the save to disk, creates the pdf, and saves it to disk properly, however, i am still left with a popup error everytime from Adode Reader..."File does not begin with '%PDF-'" ...almost like it is still trying to display the pdf to the screen as well. Does anyone know how i can just save it to disk, for future use, without ever outputting anything to the screen?

Posted Jul 31, 2009 by Robert

 

 

Comment

 

35 @Robert, saving pdf to disk instead of download

<q>I am trying to create a pdf, then save it to disk, without ever outputting it to the screen.

<code> $tcpdf->Output('filename.pdf', 'F'); </code>
Using the F parameter in the output function to force the save to disk, creates the pdf, and saves it to disk properly, however, i am still left with a popup error everytime from Adode Reader..."File does not begin with '%PDF-'" ...almost like it is still trying to display the pdf to the screen as well. </q>
Robert, you probably still send the layout as shown in the article to the browser, with
<code> header("Content-type: application/pdf");  </code> This will make your browser start your PDF viewer, and then you send nothing, because you save to disk only. Thus the error message of your PDF viewer.

In your case you need neither the layout as shown in this article, nor the call for it in the controller as shown in this article.
<code> $this->layout = 'pdf'; //this will use the pdf.ctp layout  </code> Just take it off.

The easiest way to get what you want is probably to add in the view, after your
<code> $tcpdf->Output('filename.pdf', 'F'); </code> a regular cake view code, such as for a confirmation page saying that the pdf file was saved, or whatever else you want to display after you saved that pdf.

Posted Aug 1, 2009 by Kalileo

 

 

Comment

 

36 how to create the pdf form using tcpdf

I want to create form using tcpdf which shows the details on combo box onChange event.

I have installed the tcpdf and watch the examples of that but the example number 14 is not working. please help me ..to get pdf form..
Thank you..

Posted Aug 17, 2009 by lubna

 

 

Comment

 

37 The view will not open as pdf file

I have the same problem as killian tobin had. I just want to know how it is managed and what version of pdf should be used.
I just have a simple view with lots of characters not adobe.

Posted Aug 18, 2009 by Azita

 

 

Comment

 

38 what version od Adobe did you use?

<q>Thanks for the great article!

my version of Adobe Reader was the problem.</q>

Posted Aug 18, 2009 by Azita

 

 

Comment

 

39 Every (more or less recent) PDF Reader should work

<q>Thanks for the great article!

my version of Adobe Reader was the problem.
</q>
Azita, TCPDF produces PDF code, which should be readable with every PDF reader. I have testet several Adobe PDF reader versions on various OS', such as Linux, Mac, Windows Vista and XP, and other PDF readers such as KPDF (Linux's KDE 3.x) and Okular (Linux's KDE 4.x). I have neither encountered this problem, nor has a customer using one of my real life applications using TCPDF reported it.

I have not tested it with very old versions of Adobe reader though.

Azita, which version did you use which showed this problem?

Posted Aug 19, 2009 by Kalileo

 

 

Comment

 

40 basic questions

I am trying to get this working without having much familiarity with CakePHP besides a couple tutorials, so forgive me for asking questions that are probably obvious to everyone else.

Questions:
1 - what should the controller class name be? (class name XtcpdfsController? file name xtcpdfs_controller.php?)
2 - does the controller class need to import XTCPDF?
3 - what should the view directory be named? (xtcpdfs? pdfs?)
4 - what should the view file name be? (view.ctp?)
5 - Any chance you could post a working barebones version of the whole thing?

Thanks!

Posted Aug 20, 2009 by Nate Tanner

 

 

Comment

 

41 Re: basic questions

@Nate Tanner

<q>I am trying to get this working without having much familiarity with CakePHP besides a couple tutorials, so forgive me for asking questions that are probably obvious to everyone else.

Questions:
1 - what should the controller class name be? (class name XtcpdfsController? file name xtcpdfs_controller.php?)
</q>
This really depends on your application. It has nothing to do with XTCPDF.

In my real life applications it is for example BookingsController / bookings_controller.php or PropertiesController / properties_controller.php. If you follow one of the blog tutorials it could be PostsController / posts_controller.php.

<q> 2 - does the controller class need to import XTCPDF?
</q>
No, why would it?

There is nothing in the controller which uses TCPDF or XTCPDF, it only gets the data you will use in the view from the Model, and selects the PDF layout.

We only load the TCPDF stuff when we need it, in the PDF view, thanks to App::import('Vendor','xtcpdf'); there.

<q> 3 - what should the view directory be named? (xtcpdfs? pdfs?)
</q>
Same answer as to your question 1. This really depends on your application. It has nothing to do with XTCPDF.

Again, if you follow a blog tutorial it could be "/app/views/posts"

<q> 4 - what should the view file name be? (view.ctp?)
</q>
Follow cakePHP conventions. You might have noticed that the view in cakePHP is having the name depending on the function in the controller which renders that view.

You could name it in the controller "function view()" and then use as view "view.ctp". In my tutorial I use "function viewPDF()" and consequently the view is "view_pdf.ctp". I would not use "view" here because that usually displays the record on screen (in your browser) and now we show a different view (of the same data), a view in PDF format.

<q> 5 - Any chance you could post a working barebones version of the whole thing?
</q>
Considering the answers above, do you really still need it?

If yes, and if you follow a tutorial published somewhere, point me to it, and I see if I can find the time to add it to that.

<q> Thanks!
</q>
You're welcome :)

Posted Aug 20, 2009 by Kalileo

 

 

Comment

 

42 Re: basic questions

<q>@Nate Tanner
<q>I am trying to get this working

Thanks, that was very helpful!</q></q>

Posted Aug 23, 2009 by Nate Tanner

 

 

Comment

 

43 using a pdf as the background of the new pdf

Using this library, is it possible to insert a previously created PDF as the background, and then insert text and/or images on top of the background PDF? I went through the examples but didn't see one that did this...

Thanks!

Posted Aug 23, 2009 by Nate Tanner

 

 

Question

 

44 blank page problem

All I see is a blank page, not even PDF.
Do I actually have to set anything in the 'tcpdf_config.php'?

I red all the comments here, but nothing helped out. I don't find any older version of TCPDF, as you suggested in comment #17.

What can I do?

Posted Sep 4, 2009 by Christian Niklas

 

 

Comment

 

45 Call to undefined method XTCPDF::AddPath()

Well, meanwhile I disabled the Configure::write('debug', 0); line, but now I receive the following error message:

Call to undefined method XTCPDF::AddPath()

Posted Sep 5, 2009 by Christian Niklas

 

 

Comment

 

46 was all my fault

Sorry guys, now it works just fine. I wrote AddPath(); into my view instead of AddPage();

Posted Sep 5, 2009 by Christian Niklas

 

 

Comment

 

47 Happy to see that you got it working

<q>Sorry guys, now it works just fine. I wrote AddPath(); into my view instead of AddPage();
</q>
I'm happy to see that you got it working.

In hindsight I think the older version of TCPDF versus new version issue was just a memory issue, see my comment 33 TCPDF 4.6.013 needs PHP set to more than 16 MB Some fonts covering a lot of the unicode chars got quite big, and the fonts used by the older versions have less unicode chars, thus they are smaller and need less memory when used.

Posted Sep 6, 2009 by Kalileo

 

 

Comment

 

48 Same ID

hello, I got the following in the controller:
<code>
function card($id = null) {
    $this->set('n', $this->Patient->field('name', $id));
    $this->layout = 'pdf'; 
    $this->render(); 
}
</code> And this is used in the view like so: $tcpdf->Cell(50,5,$n, 0, 0);
The links that point to this function are:
/cake/patients/card/1
/cake/patients/card/2
when follow either one of these link, I get the same ID 1, meaning when generating the pdf, it contains the ID 1 in both cases.
WHat could i be doing wrong ?

Posted Sep 18, 2009 by noregret

 

 

Comment

 

49 @noregret: id or name?

<q> WHat could i be doing wrong ?
</q>
@noregret: I don't really know what you try to do, because you talk about the ID, but you read the field "name".

However I guess that you want this:

<code>
function card($id = null) {
    // sanitize $id
    $this->Patient->id = $id;
    $this->set('n', $this->Patient->field('name'));
    $this->layout = 'pdf'; 
    $this->render(); 
}
</code>
And keep in mind that that should give you the name, not the ID.

Posted Sep 18, 2009 by Kalileo

To top

To top

appunti

Application layout:

css files, images, javascript

app/webroot/css/
app/webroot/img/
app/webroot/js

Dafault layout :
app/views/layouts/default.ctp

default route:

app/config/routes.php:

Router::connect('/', array('controller' => 'pages', 'action' => 'display', 'home'));

 

convenzioni file in app:

index.php

config:
acl.ini.php
bootstrap.php
core.php
#configurazione dell'accesso al DB (hostname, driver, username, password, etc)
database.php
inflections.php
routes.php
sql

#i nomi dei controllers sono il plurale dei nomi dei modelli seguiti da _controller.php
controllers:
components
labels_controller.php
###############################################
class LabelsController extends AppController {

        var $name = 'Labels';
        var $scaffold;
        
        public function sindex() {
###############################################
panels_controller.php
###############################################
class PanelsController extends AppController {

        var $name = 'Panels';
        var $scaffold;
        
        public function sindex() {
###############################################

locale:
eng

#i nomi dei modelli sono al singolare (relativi alle tabelle del DB plurali)
models:
behaviors
datasources
label.php
###############################################
class Label extends AppModel {

        var $name = 'Label';
###############################################
panel.php
###############################################
class Panel extends AppModel {

        var $name = 'Panel';
###############################################
plugins:
empty

tests:
cases
fixtures
groups

tmp:
cache
logs
sessions
tests

vendors:
shells

views:
elements
errors
helpers
layouts
pages
scaffolds

webroot:
css
css.php
favicon.ico
files
img
index.php
js
test.php

To top

cake bake (example)

cd /srv/www/htdocs/
tar xfvj cake_1.2.0.7296-rc2.tar.bz2
mv cake_1.2.0.7296-rc2 cake
cp -Rv cake/app/ patch_panels
vim
patch_panels/webroot/index.php

insert in the begin of the file:

define('CAKE_CORE_INCLUDE_PATH', '/path to/cake');

chmod -R ugo+rw patch_panels/tmp/
cd cake/cake/console/

on mac osx with MAMP:

sudo ln -sf /Applications/MAMP/tmp/mysql /var/

with leopard and MAMP 1.8.4:
sudo ln -sf  /Applications/MAMP/tmp/mysql/mysql.sock /tmp

 

cake bake -app /path to/patch_panel/
####################### DB CONFIGURATION ######################


Welcome to CakePHP v1.2.0.7296 RC2 Console
---------------------------------------------------------------
App : app
Path: /srv/www/htdocs/patch_panels/app
---------------------------------------------------------------
Your database configuration was not found. Take a moment to create one.
---------------------------------------------------------------
Database Configuration:
---------------------------------------------------------------
Name:  
[default] >
Driver: (db2/firebird/mssql/mysql/mysqli/odbc/oracle/postgres/sqlite/sybase)
[mysql] >
Persistent Connection? (y/n)
[n] >
Database Host:  
[localhost] >
Port?  
[n] >
User:  
[root] > patch_panel
Password:  
> patch_panel
Database Name:  
[cake] > patch_panel
Table Prefix?  
[n] >
Table encoding?  
[n] >

---------------------------------------------------------------
The following database configuration will be created:
---------------------------------------------------------------
Name:         default
Driver:       mysql
Persistent:   false
Host:         localhost
User:         patch_panel
Pass:         ***********
Database:     patch_panel
---------------------------------------------------------------
Look okay? (y/n)
[y] > y
Do you wish to add another database configuration?  
[n] > n

Creating file /srv/www/htdocs/patch_panels/app/config/database.php
Wrote /srv/www/htdocs/patch_panels/app/config/database.php

################# MODELS CONFIGURATION ####################
cake bake

Welcome to CakePHP v1.2.0.7296 RC2 Console
---------------------------------------------------------------
App : app
Path: /srv/www/htdocs/patch_panels/app
---------------------------------------------------------------
Interactive Bake Shell
---------------------------------------------------------------
[D]atabase Configuration
[M]odel
[V]iew
[C]ontroller
[P]roject
[Q]uit
What would you like to Bake? (D/M/V/C/P/Q)
> m
---------------------------------------------------------------
Bake Model
Path: /srv/www/htdocs/patch_panels/app/models/
---------------------------------------------------------------
Possible Models based on your current database:
1. Label
2. Panel
Enter a number from the list above, type in the name of another model, or 'q' to exit  
[q] > 1
Would you like to supply validation criteria for the fields in your model? (y/n)
[y] > n
Would you like to define model associations (hasMany, hasOne, belongsTo, etc.)? (y/n)
[y] > y
One moment while the associations are detected.
---------------------------------------------------------------
Please confirm the following associations:
---------------------------------------------------------------
Label hasOne Panel? (y/n)
[y] > n
Label hasMany Panel? (y/n)
[y] > y
Would you like to define some additional model associations? (y/n)
[n] > n

---------------------------------------------------------------
The following Model will be created:
---------------------------------------------------------------
Name:       Label
Associations:
            Label hasMany    Panel
---------------------------------------------------------------
Look okay? (y/n)
[y] > y

Baking model class for Label...

Creating file /srv/www/htdocs/patch_panels/app/models/label.php
Wrote /srv/www/htdocs/patch_panels/app/models/label.php
Cake test suite not installed.  Do you want to bake unit test files anyway? (y/n)
[y] > n
---------------------------------------------------------------
Interactive Bake Shell
---------------------------------------------------------------
[D]atabase Configuration
[M]odel
[V]iew
[C]ontroller
[P]roject
[Q]uit
What would you like to Bake? (D/M/V/C/P/Q)
> m
---------------------------------------------------------------
Bake Model
Path: /srv/www/htdocs/patch_panels/app/models/
---------------------------------------------------------------
Possible Models based on your current database:
1. Label
2. Panel
Enter a number from the list above, type in the name of another model, or 'q' to exit  
[q] > 2
Would you like to supply validation criteria for the fields in your model? (y/n)
[y] > n
Would you like to define model associations (hasMany, hasOne, belongsTo, etc.)? (y/n)
[y] > y
One moment while the associations are detected.
---------------------------------------------------------------
Please confirm the following associations:
---------------------------------------------------------------
Panel belongsTo Label? (y/n)
[y] > y
Would you like to define some additional model associations? (y/n)
[n] > n

---------------------------------------------------------------
The following Model will be created:
---------------------------------------------------------------
Name:       Panel
Associations:
            Panel belongsTo Label
---------------------------------------------------------------
Look okay? (y/n)
[y] > y

Baking model class for Panel...

Creating file /srv/www/htdocs/patch_panels/app/models/panel.php
Wrote /srv/www/htdocs/patch_panels/app/models/panel.php
Cake test suite not installed.  Do you want to bake unit test files anyway? (y/n)
[y] > n
---------------------------------------------------------------
Interactive Bake Shell
---------------------------------------------------------------
[D]atabase Configuration
[M]odel
[V]iew
[C]ontroller
[P]roject
[Q]uit
What would you like to Bake? (D/M/V/C/P/Q)
> q


################# CONTROLLERS CONFIGURATION ####################
cake bake

Welcome to CakePHP v1.2.0.7296 RC2 Console
---------------------------------------------------------------
App : app
Path: /srv/www/htdocs/patch_panels/app
---------------------------------------------------------------
Interactive Bake Shell
---------------------------------------------------------------
[D]atabase Configuration
[M]odel
[V]iew
[C]ontroller
[P]roject
[Q]uit
What would you like to Bake? (D/M/V/C/P/Q)
> c
---------------------------------------------------------------
Bake Controller
Path: /srv/www/htdocs/patch_panels/app/controllers/
---------------------------------------------------------------
Possible Controllers based on your current database:
1. Labels
2. Panels
Enter a number from the list above, type in the name of another controller, or 'q' to exit  
[q] > 1
---------------------------------------------------------------
Baking LabelsController
---------------------------------------------------------------
Would you like to build your controller interactively? (y/n)
[y] > y
Would you like to use scaffolding? (y/n)
[n] > y

---------------------------------------------------------------
The following controller will be created:
---------------------------------------------------------------
Controller Name:  Labels
                   var $scaffold;
---------------------------------------------------------------
Look okay? (y/n)
[y] > y

Creating file /srv/www/htdocs/patch_panels/app/controllers/labels_controller.php
Wrote /srv/www/htdocs/patch_panels/app/controllers/labels_controller.php
Cake test suite not installed.  Do you want to bake unit test files anyway? (y/n)
[y] > n
---------------------------------------------------------------
Interactive Bake Shell
---------------------------------------------------------------
[D]atabase Configuration
[M]odel
[V]iew
[C]ontroller
[P]roject
[Q]uit
What would you like to Bake? (D/M/V/C/P/Q)
> c
---------------------------------------------------------------
Bake Controller
Path: /srv/www/htdocs/patch_panels/app/controllers/
---------------------------------------------------------------
Possible Controllers based on your current database:
1. Labels
2. Panels
Enter a number from the list above, type in the name of another controller, or 'q' to exit  
[q] > 2
---------------------------------------------------------------
Baking PanelsController
---------------------------------------------------------------
Would you like to build your controller interactively? (y/n)
[y] > y
Would you like to use scaffolding? (y/n)
[n] > y

---------------------------------------------------------------

The following controller will be created:
---------------------------------------------------------------
Controller Name:  Panels
           var $scaffold;
---------------------------------------------------------------
Look okay? (y/n)
[y] > y

Creating file /srv/www/htdocs/patch_panels/app/controllers/panels_controller.php
Wrote /srv/www/htdocs/patch_panels/app/controllers/panels_controller.php
Cake test suite not installed.  Do you want to bake unit test files anyway? (y/n)
[y] > n
---------------------------------------------------------------
Interactive Bake Shell
---------------------------------------------------------------
[D]atabase Configuration
[M]odel
[V]iew
[C]ontroller
[P]roject
[Q]uit
What would you like to Bake? (D/M/V/C/P/Q)
> q

To top

ACL

create your ACL database tables

../cake/cake/console/cake schema run create DbAcl -app ../test

Welcome to CakePHP v1.2.0.7692 RC3 Console
---------------------------------------------------------------
App : testPath: /srv/www/htdocs/cake_1.2.0.7692-rc3/../test
---------------------------------------------------------------
Cake Schema Shell
---------------------------------------------------------------
The following table(s) will be dropped.
acos
aros
aros_acos

Are you sure you want to drop the table(s)?
(y/n) [n] > y
Dropping table(s).
acos updated.
aros updated.
aros_acos updated.
The following table(s) will be created.
acos
aros
aros_acos

Are you sure you want to create the table(s)?
(y/n) [y] > y
Creating table(s).
acos updated.
aros updated.
aros_acos updated.
End create.

To create the aro groups

 ../cake/cake/console/cake  acl create aro 0 Users -app ../test
 New Aro 'Users' created.

../cake/cake/console/cake  acl view aro -app ../test

Aro tree:
---------------------------------------------------------------
  [1]Users
---------------------------------------------------------------

in users controller (users_controler.php) add:

<?php
class UsersController extends AppController

 var $components = array('Acl');

function register()
    {
        if(!empty($this->data)){
            if($this->User->save($this->data)){
                $this->Session->setFlash('registration OK');
                $this->Session->write('user', $this->data['User']['username']);
                $parent = $this->Acl->Aro->findByAlias('Users');
                $this->Acl->Aro->create(array(
                        'alias' => $this->data['User']['username'],
                        'model' => 'User',

                        'foreign_key' => $this->User->id,
                        'parent_id' => $parent['Aro']['id'])
                );
                $this->Acl->Aro->save();
            } else {
                $this->data['User']['password'] = '';
                $this->Session->setFlash('There was a problem saving
                                   this information');
            }
            $this->redirect(array('action'=>'index'),null,true);
        }
    }

 

 to check aro:

 ../cake/cake/console/cake  acl view aro -app ../test

Aro tree:
---------------------------------------------------------------
  [1]Users

    [3]pillolo

  [2]Dealers

---------------------------------------------------------------

to add an already created user:

../cake/cake/console/cake  acl create aro Users nikoz -app ../test

Aro tree:
---------------------------------------------------------------
  [1]Users

    [3]pillolo

    [4]nikoz

  [2]Dealers

---------------------------------------------------------------

 

To top

21 things on Cakephp

http://www.avatarfinancial.com/pages/cake/

 

What's Cake?

Cake is a rapid development framework for PHP which uses commonly known design patterns like ActiveRecord, Association Data Mapping, Front Controller and MVC. CakePHP is basically the PHP equivalent of Ruby on Rails.

What should I read first?

If you are new to CakePHP, I highly recommend reading through the CakePHP manual and the 15 minute blog tutorial in addition to the items listed here. There are a ton of tutorials in the wiki, too.

Why the list?

CakePHP is very new, so documentation beyond the basics is a bit sparse in areas. I built this website entirely using CakePHP and took notes along the way to share with others. While some of these items can be found in obvious places like the manual, others required a bit of elbow grease to figure out. My name is Matt Inman and your feedback is welcome, feel free to email me with questions or comments.

 

About this Article

This document was last modified on September 14, 2006 and was written by Matt Inman
Avatar Financial Group is a hard money lender based in Seattle, WA.

 

To top

Multiple Display Field

 

http://bakery.cakephp.org/articles/view/multiple-display-field-3

 

Multiple Display Field

Behaviors Oct 22, 2008

By Daniel Albert (resshin)

The behavior allows us to use multiple display field (such as "first_name" and "last_name") as a display field for generating list from a model.

This is really one of common issues: using multiple fields as display field when using the find('list') function.

Strangely enough, there's only little hint out there about how to do it "elegantly" in CakePHP. tclineks already make a great article in http://bin.cakephp.org/saved/19252#modify, but the code just won't works. I think it's happened because CakePHP now handles find function differently than the previous versions.

So then I wrote the code below to help anyone who need to use multiple fields in their display field.
Note: The afterFind function is taken without any change from tclineks' bin.

Using it is as simple as this:

  1. In your model, define that the model is acting as MultipleDisplayFieldBehavior. For example, see Figure 1.
  2. To generate a list, simply use the find('list') function. For example, see Figure 2.


Note: you must define the "displayField" property. This field (which can be a virtual/non-existent field) will then holds the concatenation of display fields that you defined.

Download code<code>
class User extends AppModel {
    var $name = "User";
    var $displayField = "full_name";
    var $actsAs = array('MultipleDisplayFields' => array(
        'fields' => array('first_name', 'last_name'),
        'pattern' => '%s %s'
    ));
}
</code> Figure 1

Download code<code>
$userList = $this->User->find("list");
</code> Figure 2

The MultipleDisplayFieldsBehavior class is defined as below:

Model Class:

Download code<code> <?php 
class MultipleDisplayFieldsBehavior extends ModelBehavior {
    var 
$config = array();
    
    function 
setup(&$model$config = array()) {
        
$default = array(
            
'fields' => array($model->name.'.first_name'$model->name.'.last_name'),
            
'pattern' => '%s %s'
        
); 
        
$this->config[$model->name] = $default;
        
        if(isset(
$config['fields'])) {
            
$this->config[$model->name]['fields'] = $config['fields'];
        }
        if(isset(
$config['pattern'])) {
            
$this->config[$model->name]['pattern'] = $config['pattern'];
        }
    }
    
    function 
afterFind(&$model$results) {
        
// if displayFields is set, attempt to populate
        
foreach ($results as $key => $val) {
            
$displayFieldValues = array();

            if (isset(
$val[$model->name])) {
                
// ensure all fields are present
                
$fields_present true;
                foreach (
$this->config[$model->name]['fields'] as $field) {
                    if (
array_key_exists($field,$val[$model->name])) {
                        
$fields_present $fields_present && true;
                        
$displayFieldValues[] = $val[$model->name][$field]; // capture field values
                    
} else {
                        
$fields_present false;
                        break;
                    }
                }

                
// if all fields are present then set displayField based on $displayFieldValues and displayFieldPattern
                
if ($fields_present) {
                    
$params array_merge(array($this->config[$model->name]['pattern']), $displayFieldValues);
                    
$results[$key][$model->name][$model->displayField] = call_user_func_array('sprintf'$params );
                }
            }
        }
        return 
$results;
    }


    function 
beforeFind(&$model, &$queryData) {
        if(isset(
$queryData["list"])) {
            
$queryData['fields'] = array();
            
            
//substr is used to get rid of "{n}" fields' prefix...
            
array_push($queryData['fields'], substr($queryData['list']['keyPath'], 4));
            foreach(
$this->config[$model->name]['fields'] as $field) {
                
array_push($queryData['fields'], $model->name.".".$field);
            }
        }
        
$model->varDump($queryData);
        return 
$queryData;
    }
}
?>
</code>
Hope it helps you... :)

To top

Boolean fileds (es. hide)

http://teknoid.wordpress.com/page/2/

CakePHP + MySQL + Tinyint(1) = Confusion

Just a quick note to point out that CakePHP fakes a BOOLEAN field in MySQL by using tinyint(1). MySQL doesn’t have a native support for BOOLEAN.

Therefore if you attempt to save some value other than 0 or 1, CakePHP will not allow you to do that (instead it will just save 1). The easiest way to get around this is to make your field tinyint(2), as one option.

To top