Note that there are some explanatory texts on larger screens.

plurals
  1. POAm I Using A Factory To Promote Polymorphism?
    text
    copied!<p>My first question is basically asking for a code-review. Does the code I'm about to provide use a Factory to promote Polymorphism? Its written in PHP. Here are the basic requirements:</p> <ul> <li>Pass a long url to a library and return a shortened url. Along with the long url, pass user properties to attempt to locate the users specific shortener service and API key.</li> <li>Allow users to set API keys for specific URL shorteners. My code assumes this is already set in the database and Bitly is the only service supported.</li> <li>If a user doesn't have an API key and service set, use the default API key and service. Again, my code assumes the default is set to Bitly in the database.</li> <li>If the url shortener service fails, log the failure, but don't throw an exception. The library should silently fail. Instead of using the short url, we'll use the long url.</li> </ul> <p>Here is an example of calling the code:</p> <pre><code>&lt;?php $long_url = 'http://www.news.com/story/1'; $account_id = 1; $use_this_url = $long_url; $meta = array( 'account_id' =&gt; $account_id, // OPTIONS // 'service_id' =&gt; $service_id, // 'account_id' =&gt; $account_id, ); $shortener = new Shortener_Factory($long_url, $meta); if ($shortener-&gt;shorten_long_url() AND $shortener-&gt;save_short_url()) { $use_this_url = $shortener-&gt;short_url; } echo $use_this_url; </code></pre> <p>Here are the classes:</p> <pre><code>&lt;?php interface ShortenerServiceInterface { public function save_short_url(); public function shorten_long_url(); } abstract class ShortenerServiceAbstract implements ShortenerServiceInterface { // Url to be shortened public $long_url = ''; // Long url unique id public $url_id = 0; // Service unique id public $shorturlservice_id = 0; // Service account unique id public $shorturlserviceaccount_id = 0; // Short url service unique API login public $api_login = ''; // Short url service unique API key public $api_key = ''; // Short url service unique hash which maps to original url value public $hash = ''; // Shortened url string public $short_url = ''; // Attempt to call shortner service three times before failing public $attempts = 3; // Shorten long url with specific service API/logic public function shorten_long_url() { // Can't save a short url when one doesn't exist if (!$this-&gt;long_url OR !$this-&gt;api_login OR !$this-&gt;api_key) { log('error', 'ShortenerServiceAbstract::shorten_long_url - no long url to shorten - '.var_export($this, TRUE)); return FALSE; } } // Save short url and related meta-data to shorturls table public function save_short_url() { // Can't save a short url when one doesn't exist if (!$this-&gt;url_id OR !$this-&gt;hash OR !$this-&gt;shorturlservice_id OR !$this-&gt;shorturlserviceaccount_id) { log('error', 'ShortenerServiceAbstract::save_short_url - no short url to save - '.var_export($this, TRUE)); return FALSE; } // Insert a new short url, or update an existing record $saved = Shorturl_Model::insert_on_dup_key_update($this-&gt;url_id, $this-&gt;hash, $this-&gt;shorturlservice_id, $this-&gt;shorturlserviceaccount_id); if (!$saved) { log('error', 'ShortenerServiceAbstract::save_short_url - short url record can not be saved - '.var_export($this, TRUE)); return FALSE; } else { return TRUE; } } } // Bitly, a simple url shortener // @link http://code.google.com/p/bitly-api/wiki/ApiDocumentation class ShortenerServiceBitly extends ShortenerServiceAbstract { public function shorten_long_url() { // Make sure we have required members set parent::shorten_long_url(); $urlencoded = urlencode($this-&gt;long_url); $bitlyurl = 'http://api.bit.ly/shorten?version=2.0.1&amp;longUrl='.$urlencoded.'&amp;login='.$this-&gt;api_login.'&amp;apiKey='.$this-&gt;api_key.'&amp;history=1'; $attempts = 1; while ($attempts &lt;= 3) { $json_result = file_get_contents($bitlyurl); if ($json_result) { // Return an assoc array $json_decode = json_decode($json_result, TRUE); if (is_array($json_decode) AND isset($json_decode['errorCode']) AND $json_decode['errorCode'] == 0) { // Don't compare sent URL with returned URL // Bitly removes invalid poritions of URLs // The camparison might fail even though the URLs are the "same" $shortened = current($json_decode['results']); break; } else { log('error', 'ShortenerServiceBitly::shorten_long_url - bit.ly json decoded - '.var_export($json_decode, TRUE)); } } else { log('error', 'ShortenerServiceBitly::shorten_long_url - bit.ly http response - '.var_export($json_result, TRUE)); } $attempts++; } if (isset($shortened)) { $this-&gt;short_url = $shortened['shortUrl']; $this-&gt;hash = $shortened['userHash']; return TRUE; } else { return FALSE; } } } // Shortener Factory class Shortener_Factory { // Shortener service account parameter object // @param object shortener account properties private $_account; // Shortener service object created by factory //@param object shorterner service functions private $_service; // Url to be shortened private $_long_url; // Set url members, service parameter object and finally the service itself public function __construct($long_url, $meta=array()) { $this-&gt;_long_url = $long_url; $this-&gt;_set_account($meta); $this-&gt;_set_service(); } // Set shortener service account parameter object // @param $meta array determine parameters for the current service object private function _set_account($meta=array()) { $s = FALSE; // Get shorturl service account if (isset($meta['account_id'])) { $s = Shorturlserviceaccount_Model::get_by_account_id($meta['account_id']); } elseif (isset($meta['service_id'])) { $s = Shorturlserviceaccount_Model::get_by_service_id($meta['service_id']); } // Account not found, lets use default if (!$s) { $s = Shorturlserviceaccount_Model::get_default(); } // Must have a service to use if ($s === FALSE) { log('error', 'Shortener_Core::_set_account - _account not found - '.var_export($this, TRUE)); return FALSE; } else { $this-&gt;_account = $s; } } // Use shortener service account parameter object to set shortener service object private function _set_service() { switch ($this-&gt;_account-&gt;name) { case 'bitly': $this-&gt;_service = new ShortenerServiceBitly; break; default: log('error', 'Shortener_Core::_set_service - _account not set - '.var_export($this, TRUE)); return FALSE; } $this-&gt;_service-&gt;long_url = $this-&gt;_long_url; $this-&gt;_service-&gt;shorturlserviceaccount_id = $this-&gt;_account-&gt;id; $this-&gt;_service-&gt;shorturlservice_id = $this-&gt;_account-&gt;shorturlservice_id; $this-&gt;_service-&gt;api_login = $this-&gt;_account-&gt;api_login; $this-&gt;_service-&gt;api_key = $this-&gt;_account-&gt;api_key; } // Public API for shortener service object methods public function __call($name, $arguments) { if (!$this-&gt;_service) { log('error', 'Shortener_Core::__call - _service not set - '.var_export($this, TRUE)); return FALSE; } return $this-&gt;_service-&gt;$name(); } // Public API for shortener service object members public function __get($name) { return ($this-&gt;_service-&gt;$name) ? $this-&gt;_service-&gt;$name : NULL; } } </code></pre>
 

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