Cakephp Articles

RSS Feed - Tag Cakephp

Emailing through Google Apps / Gmail on CakePHP

Category: PHP & CakePHP Tags: Email, PHP, CakePHP | Written on Jun 07, 2009

When launching new websites and web applications, it is difficult to get on trusted email lists of Hotmail, Yahoo and Etc. Aside from having proper SPF records, a great way to avoid this sysadmin problem is to use Gmail / Google Apps to offload your domain's email to their servers. By doing this, your domain gets an instant trust factor with receiving mail servers that a new server simply cannot do in a short period of time.

To email with Google Apps / Gmail with CakePHP, I've had recent success using the SwiftMailer CakePHP component. It is easy to use and leverages the PHP SwiftMailer library.

Configuring SwiftMailer CakePHP Component with Gmail

This is pulled off the component article's example, but I posted it here as well for your reference.

PHP:
  1. $this->SwiftMailer->smtpType = 'tls';
  2. $this->SwiftMailer->smtpHost = 'smtp.gmail.com';
  3. $this->SwiftMailer->smtpPort = 465;
  4. $this->SwiftMailer->smtpUsername = 'name@domain.com';
  5. $this->SwiftMailer->smtpPassword = 'your_password';
  6.  
  7. $this->SwiftMailer->sendAs = 'both';
  8. $this->SwiftMailer->from = 'name@domain.com';
  9. $this->SwiftMailer->fromName = 'Full Name';
  10. $this->SwiftMailer->to = 'to_name@domain.com';
  11. $this->SwiftMailer->template = 'your_action';
  12. $this->SwiftMailer->subject = 'your_subject'

I added two custom attributes here, template and subject because I find I like to set that as a variable instead of putting it in the send function (in the next step).

Emailing with SwiftMailer CakePHP Component

The send function has 3 parameters, but we are only concerned with the first two since we've already configured our settings in the step above. The first is the template found in /views/elements/email, the second is the subject.

PHP:
  1. try {
  2.     if(!$this->SwiftMailer->send($this->SwiftMailer->template, $this->SwiftMailer->subject)){
  3.         $this->log("Error sending email");
  4.     }
  5. } catch(Exception $e) {
  6.     $this->log("Failed to send email: ".$e->getMessage());
  7. }

You will also notice here that we are wrapping the send function in a try/catch block. This allows us to output whatever caused the function to fail through an exception (and fail silently), rather having the component either kill the client to output the message, or simply return false with no explanation like a lot of things in CakePHP-land. Try/catch blocks work great in non-mission critical things like sending an email, conturary to the core library which should simply fail and exit the application.

I had one error on my local computer with TLS not being installed into PHP. So I added the following line to my PHP compile to add TLS support:

Bash:
  1. --with-openssl

My entire PHP compile looks like this...

Bash:
  1. sudo make clean && sudo ./configure --prefix=/usr/local/php5  --with-pear --enable-sockets --with-iodbc=/usr --with-curl=/usr --with-mysql=/usr/local/mysql --without-iconv --with-apxs2=/opt/local/apache2/bin/apxs --with-zlib-dir=../zlib-1.2.3/ --with-jpeg-dir=../jpeg-6b --with-openssl --with-gd --with-freetype2=/Developer/SDKs/MacOSX10.5.sdk/usr/X11/include/freetype2/freetype && sudo make && sudo make install

As an alternative to SwiftMailer, I was pointed to joshua's solution on the mailing list to use the built-in CakePHP email component with Gmail. Apparently he got it to work, but I couldn't for whatever reason.

Enjoy having mail go through to your users without fail!

Getting Projects Done in 2008

Category: Marc Grabanski's Work Tags: Business, CakePHP | Written on Nov 02, 2008

I have decided to pour all of my resources and energy into getting four rather demanding projects done before the end of the year. This big end-of-year push has had a lot of thought behind it, which I wanted to share with you and document here on my blog.

Push Forward

The Projects

Of the four projects I am focusing on getting done, two are consulting jobs and two are my own start-up companies.  With the start-ups, I have partnered with businesses to help define the products and they will sell them when the products are released to the public.

The Plan

My focus in November will be on consulting. Consulting is a great way to get temporary cash flow, through which I will be using to hire people to work on my startup companies. I will have a total of 4 contractors working for me in November.

The Logistics

UI skills are the most important for my consulting work, and CakePHP skills are most important for the startups. In case you are wondering who is working with me, here is a list of them and brief description of each:

  1. A developer that is a highly seasoned professional and core developer of CakePHP, he will be working on a startup in CakePHP.
  2. A developer that is a master of databases and does a lot of work with CakePHP, he will be working on a startup in CakePHP and on documentation
  3. A developer that is great at UI and CakePHP, however he will be consulting with me focusing on UI (jQuery/JavaScript/HTML/CSS) with me and has been for quite some time.
  4. A developer/designer who is good at a diverse amount of things, working with UI, straight PHP and some CakePHP. He will be working with me on UI consulting projects.

Though the above isn't 100% finalized, I am confident they will be joining me in these last two important months of the year - all of the projects fun to work on. 

The Goal

It is my goal to have a company with products, partnerships and consulting. So far it has been working out brilliant and I only expect the great work to continue.

This will be a wild two months that I'm hoping to propel those working with me into a great 2009.

Top Commenters Page

Category: Marc Grabanski's Work Tags: My Work, jQuery, CakePHP, MySQL | Written on Aug 19, 2008

An addition to my website is the top commenters page.  Even though the page doesn't look that complex, there is still a bit going on behind the scenes.

To get the top commenter count I have to thank Ryan Peterson in helping me write this custom MySQL query.  I used Group By to lump the results together based on the commenter's email address.  Then use count(*) to count the number of records in the group. Also used the NOT function in MySQL to filter my email address.

Mysql:
  1. SELECT `Comment`.`author`, `Comment`.`id`, `Comment`.`url`, count(*) AS `count` FROM `cake_comments` AS `Comment` WHERE 1 = 1 AND NOT(`Comment`.`email`=\'m@marcgrabanski.com\') GROUP BY `Comment`.`email` ORDER BY `count` DESC LIMIT 0, 10

Since I didn't want to load all of the related comments at once, I decied to use a little jQuery and Ajax to show comments that they have made.

First, I put a span tag around the comment count, because without JavaScript you won't see this functionality. On page load I swapped the spans into links with $(this).replaceWith('<a>' + $(this).html() + '</a>');

Instead adding behavior later after append, I used a jQuery object inside replaceWith  so I can attach behavior to the link and I like how the code looks.

JavaScript:
  1. $(this).replaceWith(
  2.     $('<a>' + $(this).html() + '</a>').click(function(){
  3.         //code here
  4.     })
  5. );

Using CakePHP's JavaScript object generator, $javascript->object($data); it was easy to send JSON back to the client and parse with jQuery. Here is the full source of the JavaScript file.

JavaScript:
  1. $(document).ready(function(){
  2.     $('.get_comments').each(function(){
  3.         $(this).replaceWith(
  4.             $('<a>'+$(this).html()+'</a>').click(function(){
  5.                 link = $(this);
  6.                 $.post('comments/get/comments', {
  7.                     'data[Comment][id]': $(this).siblings('.author').attr('id')
  8.                 }, function(data){
  9.                     out = '';
  10.                     for (i in data) {
  11.                         prefix = data[i].Article.type ? 'article/' : 'answers/';
  12.                         out += '<li><a href="' + prefix + data[i].Article.slug + '#c' + data[i].Comment.id + '">' + data[i].Article.title + '</a>' +
  13.                             data[i].Comment.created + '</li>';
  14.                     }
  15.                     $('<ol>' + out + '</ol>').hide().appendTo(link.parents('li:first')).slideDown();
  16.                     $(link).replaceWith( $(link).html() );
  17.                 }, 'json');
  18.             })
  19.         );
  20.     });
  21. });

 

Update: I think I'll post the CakePHP code just in case someone is interested. Here is the controller, I use the RequestHandler component var $components = array('RequestHandler'); and the Time helper var $helpers = array('Time'); in the top of the controller.

PHP:
  1. function get($type = null)
  2. {
  3.     if ($this->RequestHandler->isAjax()) {
  4.         Configure::write('debug', 0);
  5.         if ($type == 'comments') {
  6.             $comment = $this->Comment->read(array('Comment.email'), $this->data['Comment']['id']);
  7.             $results = $this->Comment->find('all', array(
  8.                 'conditions' => array('email' => $comment['Comment']['email']),
  9.                 'fields' => 'Article.title, Article.slug, Article.type, Comment.id, Comment.created'
  10.             ));
  11.             $this->set(compact('results'));
  12.         }
  13.     }
  14. }

I also turn debug off with Configure::write('debug', 0);. Also, I only use $type  so that I can setup my code to get types of data if I want later - more of a design pattern I typically follow.

Then in my view I use the time helper and output a JSON object.

PHP:
  1. <?php
  2. if ($result):
  3.         if (isset($result['Comment']['created'])):
  4.             $results[$key]['Comment']['created'] =
  5.                 $time->timeAgoInWords($result['Comment']['created']);
  6.         endif;
  7.     endforeach;
  8.     echo  $javascript->object($results);
  9. ?>

 

To see in action, click the comments count next to someone's name on the top commenters page.

Yahoo! Search BOSS Integration with CakePHP

Category: PHP & CakePHP Tags: CakePHP, Yahoo, API | Written on Jul 17, 2008

CakePHP Logo Yahoo Search Boss Description

Note on March 21st, 2008: Neil Crookes made a nice Yahoo! Boss CakePHP Plugin that I would recommend over my code. Neil's fits much better into the CakePHP environment.

Tutorial - CakePHP Ajax "Quick Save" with jQuery

Category: PHP & CakePHP Tags: CakePHP, jQuery | Written on Jul 15, 2008

When you are in an administration panel, sometimes you want a "quick save" feature that allows you to save without leaving the page.  Here is how to accomplish this with CakePHP and jQuery.

To start, download jQuery and the jQuery Form Plugin JavaScript.  Include them in your view with the JavaScript helper:

PHP:
  1. $javascript->link(array('jquery', 'form'), false);

Include the RequestHandler in your controller detect an Ajax save attempt.  Also include the JavaScript helper if you haven't already.

PHP:
  1. var $helpers = array('Javascript');
  2. var $components = array('RequestHandler');

Next we want to override our save function with the ajax quick save.  Put this right before your $this->Model->save($this->data) in your save action.

PHP:
  1. if ($this->RequestHandler->isAjax()) {
  2.     if ($this->Article->save($this->data)) {
  3.         echo 'success';
  4.     }
  5.     Configure::write('debug', 0);
  6.     $this->autoRender = false;
  7.     exit();
  8. }

This detects if the request is ajax, then saves the data.  Then it sends back a simple, "success" message to let you know things went fine.  It also writes debug to 0 and doesn't render anything, then exits.

Lastly, lets create and include a JavaScript file that performs the quick save.

JavaScript:
  1. jQuery(function($){
  2.     $('<input type="button" value="Quick Save" />')
  3.         .click(function(){
  4.             $(this).parents("form:first").ajaxSubmit({
  5.                 success: function(responseText, responseCode) {
  6.                     $('#ajax-save-message').hide().html(responseText).fadeIn();
  7.                     setTimeout(function(){
  8.                         $('#ajax-save-message').fadeOut();
  9.                     }, 5000);
  10.                 }
  11.             });
  12.             return false;
  13.         })
  14.         .appendTo('form div.submit');
  15. });

This adds a button called, "Quick Save" to each form on the page where a div with class="submit" exists (you may want to switch this to the id of the form you want to add quick save to). Then It also attaches a click event to the button that submits the form via the jQuery Form Plugin.

In a few simple steps, we've created a quick save feature that saves your data whenever you want without leaving the page.

Version 2 of MarcGrabanski.com Launched!

Category: Marc Grabanski's Work Tags: My Work, CakePHP, jQuery | Written on Jun 25, 2008

CakePHP Logo  jQuery Logo 

Note on June 27th: The website is now usable on IE6 and IE7.

Rebuilt from scratch on top of CakePHP and jQuery, version 2 of MarcGrabanski.com has been launched!

The first version was on top of PHP and HTML, which turned into a mess to maintain. This time I really thought long and hard on how to code the website from the ground-up. It is a psuedo CMS, blog and takes advantage of much of CakePHP's strengths.  The code is 100% hand written in a text editor, as well as the design was done in illustrator. I purchased the computer/face, then heavily modified it and illustrated all of the items around the monitor and keyboard. I enjoy illustrating but don't get to do it very often (too much coding). 

Finally I feel like I have a website to be pleased about - despite the compliments on the old website by far and wide audiences, I was never too happy with it.  But, this one I enjoy and am pleased with.  Which is ultimately what matters.  With this website I will be able to post more (hopefully) and definately have a much easier time maintaining.

Enjoy the new website, I know I will!

P.S. Please report any bugs you find in the new site to m@marcgrabanski.com

CakePHP on Media Temple (dv) 3.5

Category: Linux & Server Admin Tags: CakePHP, PHP, Linux, Media Temple | Written on Jun 18, 2008

A good thing to do when deploying CakePHP websites is to load one copy of the CakePHP core files onto your server, and point all of your domains to that core directory. 

Media Temple's Plesk default configuration does not let PHP access files outside the website httpdocs. So we need to configure the domain's settings to have access to the root /cake folder, or wherever you happened to put the CakePHP root files.

First, let's make a new config file in our domain. Make sure you replace domain.com with your domain.

Bash:
  1. cd /var/www/vhosts/domain.com/conf/
  2. vi vhost.conf

Then basically we are over riding the default settings of Plesk with our own. Setting open_basedir to allow the /cake path.

Apache:
  1. <Directory /var/www/vhosts/domain.com/subdomains/tools/httpdocs>
  2.         <IfModule sapi_apache2.c>
  3.                 php_admin_flag engine on
  4.                 php_admin_flag safe_mode off
  5.                 php_admin_value open_basedir "/cake:/var/www/vhosts/domain.com/subdomains/tools/httpdocs:/tmp"
  6.         </IfModule>
  7.         <IfModule mod_php5.c>
  8.                 php_admin_flag engine on
  9.                 php_admin_flag safe_mode off
  10.                 php_admin_value open_basedir "/cake:/var/www/vhosts/domain.com/subdomains/tools/httpdocs:/tmp"
  11.         </IfModule>
  12. </Directory>

Now we need to reload the vhost to include that loads our new config file.

Bash:
  1. /usr/local/psa/admin/sbin/websrvmng --reconfigure-vhost --vhost-name=domain.com
  2. service httpd graceful

Great! Now we can have a central set of cake files and use it for each domain.

CakePHP Email Encoding

Category: PHP & CakePHP Tags: CakePHP | Written on Feb 12, 2008

My email was not getting sent using the email component in CakePHP. I debugged inside the core and found out that my subject was getting changed to something like, "=?UTF-8?B?V2VsY29tZ...".

In talking to Larry (core CakePHP team), he educated me that this allows for characters other than the English language to be sent via email (UTF-8 encoding). Even though it apparently was correct, it was still not being received at my personal email or a Yahoo account. Gmail got it, the others didn't.

The Alternate Email Encoding (English only)

Larry showed me the alternative way to encode that works just fine for English characters. If you are having trouble with receiving these UTF-8 encoded emails, try sending with iso-8859-15 (only English characters). You can try the English encoding using this line of code:

PHP:
  1. $this->Email->charset = 'iso-8859-15';

This works for English-only applications, but if anyone can offer up a solution as to why Yahoo and Media Temple email accounts are not getting the UTF-8 emails please let me know. It is strange to me that gmail gets it just fine. Until then, I am only planning on sending English emails anyway so there is no issue until I build a multi-lingual application.

CakePHP Asset Mapper

Category: PHP & CakePHP Tags: CakePHP, PHP | Written on Dec 26, 2007

Released my CakePHP Asset Mapper. I've always wanted an easier way to control my JavaScript and CSS includes and this is the solution I came up with. Controls the entire web application's includes in one file!

Here is an example of a mapping rule:

PHP:
  1. $this->AssetRule->create();
  2. $this->AssetRule->compact->css = array('site','global');
  3. $this->AssetRule->compact->scripts = array('jquery', 'ui.datepicker');
  4. $this->AssetRule->runRule();

Accross the entire site, this would compact the site.css and global.css files together and run them through CSS Tidy. jQuery.js and ui.datepicker.js would be compacted together and then ran through JSMin.

Great, this simplifies a complex process of compacting and minimizing - while still giving you the freedom to include scripts normally. Compacting lowers the amount of http requests you website makes, increasing website performance. JSMin and CSS Tidy strip comments and whitespace leaving your files much smaller in size.

You can create a rule to include files in a specific controller and/or action with AssetRule->map and AssetRule->controller:

PHP:
  1. $this->AssetRule->create();
  2. $this->AssetRule->map->controller = 'posts';
  3. $this->AssetRule->map->action = 'admin_add';
  4. $this->AssetRule->compact->css = array('user');
  5. $this->AssetRule->runRule();

This would only include your 'user.css' file in the, 'posts' controller - with the action, 'admin_add'. The css file would be compacted with the others.

Some scripts like TinyMCE, include other files (so it can't be compacted with the others) and requires a codeblock to be initialized. This configuration satisfies TinyMCE:

PHP:
  1. $this->AssetRule->create();
  2. $this->AssetRule->map->action = 'admin_edit';
  3. $this->AssetRule->scripts = array('tiny_mce/tiny_mce');
  4. $this->AssetRule->codeblock = 'tinyMCE.init({
  5.    mode : "textareas",
  6.    theme : "advanced",
  7.    plugins : "media",
  8.    media_external_list_url : "media/list.js",
  9.    theme_advanced_buttons1 : "bold,italic,underline,separator,strikethrough,justifyleft,justifycenter,justifyright, justifyfull,bullist,numlist,undo,outdent,indent,redo,link,unlink",
  10.    theme_advanced_buttons2 : "",
  11.    theme_advanced_buttons3 : "",
  12.    theme_advanced_resizing : true,
  13.    theme_advanced_toolbar_location : "top",
  14.    theme_advanced_toolbar_align : "left",
  15.    theme_advanced_statusbar_location : "bottom",
  16.    extended_valid_elements : "a[name|href|target|title|onclick],img[class|src|border=0|alt|title|hspace|vspace|width|height|align|onmouseover|onmouseout|name],hr[class|width|size|noshade],font[face|size|color|style],span[class|align|style]"
  17. });';
  18. $this->AssetRule->runRule();

Coming from a heavy UI developer background, I can afford to be incredibly anal when managing my CSS and JavaScript files. I hope this saves you time, frustration and makes your developer-life better.

Edit CakePHP's THML / CTP files with Dreamweaver

Category: PHP & CakePHP Tags: CakePHP | Written before Dec, 2007

Note on July 15th, 2008: I haven't used dreamweaver for a long time, this article was written back in cake 1.1 days.  I suggest Text Mate for Mac OS X, and E Text Editor for Windows.

Dreamweaver Add THTML

I needed Dreamweaver to recognize a new file extension called, "thtml" for CakePHP. Here is how I got Dreamweaver to recognize new code extensions and highlight them correctly:

  1. Edit your Extensions.txt file: C:\\Documents and Settings\\User\\Application Data\\Macromedia\\Dreamweaver 8\\Configuration
  2. Add in the new file extension into its type: HTM,HTML,HTA,HTC,XHTML,THTML:HTML Documents
  3. Now Dreamweaver recognizes the new file types but to get code highlighting you need to edit your MMDocumentTypes.xml file: C:\\Program Files\\Macromedia\\Dreamweaver 8\\Configuration\\DocumentTypes
  4. Add in the new file extension to HTML winfileextension.

Here is the full article by Adobe: Adobe: Changing and adding file extensions recognized by Dreamweaver

Other Reading - Categories