Note that there are some explanatory texts on larger screens.

plurals
  1. POImproving quality of code in CakePHP
    text
    copied!<p>I have been using CakePHP for a few weeks now and its been an great experience. I've managed to port a site surprisingly quickly and I've even added a bunch of new features which I had planned but never got around to implementing.</p> <p>Take a look at the following two controllers, they allow a user to add premium status to one of the sites linked to their account. They don't feel very 'cakey', could they be improved in any way?</p> <p>The PremiumSites controller handles the signup process and will eventually have other related things such as history.</p> <p><code></p> <pre><code>class PremiumSitesController extends AppController { var $name = 'PremiumSites'; function index() { $cost = 5; //TODO: Add no site check if (!empty($this-&gt;data)) { if($this-&gt;data['PremiumSite']['type'] == "1") { $length = (int) $this-&gt;data['PremiumSite']['length']; $length++; $this-&gt;data['PremiumSite']['upfront_weeks'] = $length; $this-&gt;data['PremiumSite']['upfront_expiration'] = date('Y-m-d H:i:s', strtotime(sprintf('+%s weeks', $length))); $this-&gt;data['PremiumSite']['cost'] = $cost * $length; } else { $this-&gt;data['PremiumSite']['cost'] = $cost; } $this-&gt;PremiumSite-&gt;create(); if ($this-&gt;PremiumSite-&gt;save($this-&gt;data)) { $this-&gt;redirect(array('controller' =&gt; 'paypal_notifications', 'action' =&gt; 'send', $this-&gt;PremiumSite-&gt;getLastInsertID())); } else { $this-&gt;Session-&gt;setFlash('Please fix the problems below', true, array('class' =&gt; 'error')); } } $this-&gt;set('sites',$this-&gt;PremiumSite-&gt;Site-&gt;find('list',array('conditions' =&gt; array('User.id' =&gt; $this-&gt;Auth-&gt;user('id'), 'Site.is_deleted' =&gt; 0), 'recursive' =&gt; 0))); } } </code></pre> <p></code></p> <p>PaypalNotifications controller handles the interaction with Paypal.</p> <p><code></p> <pre><code>class PaypalNotificationsController extends AppController { var $name = 'PaypalNotifications'; function beforeFilter() { parent::beforeFilter(); $this-&gt;Auth-&gt;allow('process'); } /** * Compiles premium info and send the user to Paypal * * @param integer $premiumID an id from PremiumSite * @return null */ function send($premiumID) { if(empty($premiumID)) { $this-&gt;Session-&gt;setFlash('There was a problem, please try again.', true, array('class' =&gt; 'error')); $this-&gt;redirect(array('controller' =&gt; 'premium_sites', 'action' =&gt; 'index')); } $data = $this-&gt;PaypalNotification-&gt;PremiumSite-&gt;find('first', array('conditions' =&gt; array('PremiumSite.id' =&gt; $premiumID), 'recursive' =&gt; 0)); if($data['PremiumSite']['type'] == '0') { //Subscription $paypalData = array( 'cmd' =&gt; '_xclick-subscriptions', 'business'=&gt; '', 'notify_url' =&gt; '', 'return' =&gt; '', 'cancel_return' =&gt; '', 'item_name' =&gt; '', 'item_number' =&gt; $premiumID, 'currency_code' =&gt; 'USD', 'no_note' =&gt; '1', 'no_shipping' =&gt; '1', 'a3' =&gt; $data['PremiumSite']['cost'], 'p3' =&gt; '1', 't3' =&gt; 'W', 'src' =&gt; '1', 'sra' =&gt; '1' ); if($data['Site']['is_premium_used'] == '0') { //Apply two week trial if unused $trialData = array( 'a1' =&gt; '0', 'p1' =&gt; '2', 't1' =&gt; 'W', ); $paypalData = array_merge($paypalData, $trialData); } } else { //Upfront payment $paypalData = array( 'cmd' =&gt; '_xclick', 'business'=&gt; '', 'notify_url' =&gt; '', 'return' =&gt; '', 'cancel_return' =&gt; '', 'item_name' =&gt; '', 'item_number' =&gt; $premiumID, 'currency_code' =&gt; 'USD', 'no_note' =&gt; '1', 'no_shipping' =&gt; '1', 'amount' =&gt; $data['PremiumSite']['cost'], ); } $this-&gt;layout = null; $this-&gt;set('data', $paypalData); } /** * IPN Callback from Paypal. Validates data, inserts it * into the db and triggers __processTransaction() * * @return null */ function process() { //Original code from http://www.studiocanaria.com/articles/paypal_ipn_controller_for_cakephp //Have we been sent an IPN here... if (!empty($_POST)) { //...we have so add 'cmd' 'notify-validate' to a transaction variable $transaction = 'cmd=_notify-validate'; //and add everything paypal has sent to the transaction foreach ($_POST as $key =&gt; $value) { $value = urlencode(stripslashes($value)); $transaction .= "&amp;$key=$value"; } //create headers for post back $header = "POST /cgi-bin/webscr HTTP/1.0\r\n"; $header .= "Content-Type: application/x-www-form-urlencoded\r\n"; $header .= "Content-Length: " . strlen($transaction) . "\r\n\r\n"; //If this is a sandbox transaction then 'test_ipn' will be set to '1' if (isset($_POST['test_ipn'])) { $server = 'www.sandbox.paypal.com'; } else { $server = 'www.paypal.com'; } //and post the transaction back for validation $fp = fsockopen('ssl://' . $server, 443, $errno, $errstr, 30); //Check we got a connection and response... if (!$fp) { //...didn't get a response so log error in error logs $this-&gt;log('HTTP Error in PaypalNotifications::process while posting back to PayPal: Transaction=' . $transaction); } else { //...got a response, so we'll through the response looking for VERIFIED or INVALID fputs($fp, $header . $transaction); while (!feof($fp)) { $response = fgets($fp, 1024); if (strcmp($response, "VERIFIED") == 0) { //The response is VERIFIED so format the $_POST for processing $notification = array(); //Minor change to use item_id as premium_site_id $notification['PaypalNotification'] = array_merge($_POST, array('premium_site_id' =&gt; $_POST['item_number'])); $this-&gt;PaypalNotification-&gt;save($notification); $this-&gt;__processTransaction($this-&gt;PaypalNotification-&gt;id); } else if (strcmp($response, "INVALID") == 0) { //The response is INVALID so log it for investigation $this-&gt;log('Found Invalid:' . $transaction); } } fclose($fp); } } //Redirect $this-&gt;redirect('/'); } /** * Enables premium site after payment * * @param integer $id uses id from PaypalNotification * @return null */ function __processTransaction($id) { $transaction = $this-&gt;PaypalNotification-&gt;find('first', array('conditions' =&gt; array('PaypalNotification.id' =&gt; $id), 'recursive' =&gt; 0)); $txn_type = $transaction['PaypalNotification']['txn_type']; if($txn_type == 'subscr_signup' || $transaction['PaypalNotification']['payment_status'] == 'Completed') { //New subscription or payment $data = array( 'PremiumSite' =&gt; array( 'id' =&gt; $transaction['PremiumSite']['id'], 'is_active' =&gt; '1', 'is_paid' =&gt; '1' ), 'Site' =&gt; array( 'id' =&gt; $transaction['PremiumSite']['site_id'], 'is_premium' =&gt; '1' ) ); //Mark trial used only on subscriptions if($txn_type == 'subscr_signup') $data['Site']['is_premium_used'] = '1'; $this-&gt;PaypalNotification-&gt;PremiumSite-&gt;saveAll($data); } elseif($txn_type == 'subscr-cancel' || $txn_type == 'subscr-eot') { //Subscription cancellation or other problem $data = array( 'PremiumSite' =&gt; array( 'id' =&gt; $transaction['PremiumSite']['id'], 'is_active' =&gt; '0', ), 'Site' =&gt; array( 'id' =&gt; $transaction['PremiumSite']['site_id'], 'is_premium' =&gt; '0' ) ); $this-&gt;PaypalNotification-&gt;PremiumSite-&gt;saveAll($data); } } /** * Used for testing * * @return null */ function index() { $this-&gt;__processTransaction('3'); } } </code></pre> <p></code></p> <p>/views/paypal_notifications/send.ctp</p> <p>Sends the user to Paypal along with all the necessary data</p> <p><code></p> <pre><code>echo "&lt;html&gt;\n"; echo "&lt;head&gt;&lt;title&gt;Processing Payment...&lt;/title&gt;&lt;/head&gt;\n"; echo "&lt;body onLoad=\"document.form.submit();\"&gt;\n"; echo "&lt;center&gt;&lt;h3&gt;Redirecting to paypal, please wait...&lt;/h3&gt;&lt;/center&gt;\n"; echo $form-&gt;create(null, array('url' =&gt; 'https://www.sandbox.paypal.com/cgi-bin/webscr', 'type' =&gt; 'post', 'name' =&gt; 'form')); foreach ($data as $field =&gt; $value) { //Using $form-&gt;hidden sends in the cake style, data[PremiumSite][whatever] echo "&lt;input type=\"hidden\" name=\"$field\" value=\"$value\"&gt;"; } echo $form-&gt;end(); echo "&lt;/form&gt;\n"; echo "&lt;/body&gt;&lt;/html&gt;\n"; </code></pre> <p></code></p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload