Overhead of using Yii::app()->db multiple times? - yii

if I have to do multiple queries in a row, is it better to do this:
$connection = Yii::app()->db;
once... and then keep using $connection, or is there an overhead if I have multiple functions like this:
function mainFunction() {
$dbResult1 = dbresult1();
$dbResult2 = dbresult2();
$dbResult2 = dbresult3();
}
function dbresult1() {
$connection = Yii::app()->db;
// do stuff
return $result;
}
function dbresult2() {
$connection = Yii::app()->db;
// do stuff
return $result;
}
function dbresult3() {
$connection = Yii::app()->db;
// do stuff
return $result;
}
Would it be better to do this:
function mainFunction() {
$connection = Yii::app()->db;
// do stuff with $connection for $dbResult1
// do stuff with $connection for $dbResult2
// do stuff with $connection for $dbResult3
}
?

You can trace the source code to see what happens when you call Yii::app()->db:
Yii::app() returns the static app property of YiiBase. You can see the source code here.
public static function app()
{
return self::$_app;
}
Yii::app()->db here it gets more interesting, because something gets looked up. You can see the source code here.
public function getDb()
{
return $this->getComponent('db');
}
getComponent() is a method of CModule you find the source code here.
public function getComponent($id,$createIfNull=true)
{
if(isset($this->_components[$id]))
return $this->_components[$id];
elseif(isset($this->_componentConfig[$id]) && $createIfNull)
{
$config=$this->_componentConfig[$id];
if(!isset($config['enabled']) || $config['enabled'])
{
Yii::trace("Loading \"$id\" application component",'system.CModule');
unset($config['enabled']);
$component=Yii::createComponent($config);
$component->init();
return $this->_components[$id]=$component;
}
}
}
As you see Yii::app()->db results in a few method calls and an array lookup. If performance is highly critical you might should cache the db instance. Else I would target on writing clean and readable code and won't care about such little tweaks.

Related

How to extend Illuminate\Database\Query\Builder

I'm planning to have a function that will store the sql statement on the Cache using the given second parameter on remember() as the key and whenever the sql statement changes it will run against the database again and overwrite the stored sql, also the cached result, and if not it will take the default cached result by the remember() function.
So I am planning to have something like this on Illuminate\Database\Query\Builder
/**
* Execute the query based on the cached query
*
* #param array $columns
* #return array|static[]
*/
public function getCacheByQuery($columns = array('*'))
{
if ( ! is_null($this->cacheMinutes))
{
list($key, $minutes) = $this->getCacheInfo();
// if the stored sql is the same with the new one then get the cached
// if not, remove the cached query before calling the getCached
$oldSql = self::flag($key);
$newSql = $this->toSql().implode(',', $this->bindings);
if ($newSql!==$oldSql)
{
// remove the cache
\Cache::forget($key);
// update the stored sql
self::updateFlag($key, $newSql);
}
return $this->getCached($columns);
}
return $this->getFresh($columns);
}
public static function updateFlag($flag, $value)
{
$flags = \Cache::get(t().'databaseFlags', []);
$flags[$flag] = $value;
\Cache::put(t().'databaseFlags', $flags, USER_SESSION_EXPIRATION);
}
public static function flag($flag)
{
$flags = \Cache::get(t().'databaseFlags', []);
return #$flags[$flag] ?: false;
}
But the thing is, I don't want to put this directly on Illuminate\Database\Query\Builder since it is just my need for the current application I am working. I'm trying to extend Illuminate\Database\Query\Builder, but the problem is it does not detect the my extension class.
Call to undefined method Illuminate\Database\Query\Builder::getCachedByQuery()
My Extension Class
<?php namespace Lukaserat\Traits;
class QueryBuilder extends \Illuminate\Database\Query\Builder {
/**
* Execute the query based on the caced query
*
* #param array $columns
* #return array|static[]
*/
public function getCachedByQuery($columns = array('*'))
{
if ( ! is_null($this->cacheMinutes))
{
list($key, $minutes) = $this->getCacheInfo();
// if the stored sql is the same with the new one then get the cached
// if not, remove the cached query before calling the getCached
$oldSql = self::flag($key);
$newSql = $this->toSql().implode(',', $this->bindings);
if ($newSql!==$oldSql)
{
// remove the cache
\Cache::forget($key);
// update the stored sql
self::updateFlag($key, $newSql);
}
return $this->getCached($columns);
}
return $this->getFresh($columns);
}
public static function updateFlag($flag, $value)
{
$flags = \Cache::get(t().'databaseFlags', []);
$flags[$flag] = $value;
\Cache::put(t().'databaseFlags', $flags, USER_SESSION_EXPIRATION);
}
public static function flag($flag)
{
$flags = \Cache::get(t().'databaseFlags', []);
return #$flags[$flag] ?: false;
}
}
Implementing on..
<?php
use LaravelBook\Ardent\Ardent;
use Lukaserat\Traits\DataTable;
use Lukaserat\Traits\QueryBuilder as QueryBuilder;
use Illuminate\Support\MessageBag as MessageBag;
class ArdentBase extends Ardent implements InterfaceArdentBase{
use DataTable;
Am I missing something?
Is it correct that I overwrite the get() method on the Illuminate\Database\Query\Builder by renaming the function I made in my extension class from getCachedByQuery to get since I just extending the routine of the get.
I changed
public function getCachedByQuery($columns = array('*'))
to
public function get()
on my Lukaserat\Traits\QueryBuilder
and it is now working as I expected..

what is the correct way to extract two sets of data from a method class

I am new to OOP and still a bit confused by the concepts
I created a class` method that will extract two sets of data from a Zend_Session_Namespace. my problem now is that I don't know how to extract these data when its pulled into another method.
It might be best if I show you what I mean:
Public function rememberLastProductSearched()
{
$session = new Zend_Session_Namespace(searchedproducts);
if ($this->getRequest()->getParam('product-searched')) {
$session->ProductSearched = $this->getRequest()->getParam('product-searched');
return " $session->ProductSearched";
} else {
if ($session->ProductSearched) {
return " $session->ProductSearched ";
}
}
if ($this->getRequest()->getParam('search-term')) {
$session->SearchTerm = $this->getRequest()->getParam('search-term');
return " $session->SearchTerm";
} else {
if ($session->SearchTerm) {
return " $session->SearchTerm ";
}
}
This method should obtain two sets of data i.e the
$session->SearchTerm
$session->ProductSearched
my confusion is this; how do I now extract both sets of data in another method call (that is within the same class).i.e
Above is my attempt to extract the information- but it did not work.
Alternatively, should I have placed the information into an array- if so, can somebody please tell me how I could have done this.
It looks like what you're trying to do is use the product-searched and search-terms from params and store them in the session if they're set, otherwise access previously saved values. It would help a bit to see how you're calling this method, but I would probably modify your code slightly to return the session namespace object instead, since that then contains the two values, regardless of whether they came from params or were there already:
public function rememberLastProductSearched()
{
$searchedProducts = new Zend_Session_Namespace('searchedproducts');
if ($this->getRequest()->getParam('product-searched')) {
$searchedProducts->ProductSearched = $this->getRequest()->getParam('product-searched');
}
if ($this->getRequest()->getParam('search-term')) {
$searchedProducts->SearchTerm = $this->getRequest()->getParam('search-term');
}
return $searchedProducts;
}
I'm assuming you have this method in a controller class, so you'd call it like this:
public function searchAction()
{
$searchedProducts = $this->rememberLastProductSearched();
// do something with the values here
}
you'll then have the two values in $searchedProducts->ProductSearched and $searchedProducts->SearchTerm.
The line "return $something;" will stop the code execution and return the value. If you want to return more than one value, you will need to either return an array or use two separate functions to return the values. If you want to return an array, you could do it this way:
public function rememberLastProductSearched() {
$returnArray = array();
$session = new Zend_Session_Namespace(searchedproducts);
if ($this->getRequest()->getParam('product-searched')) {
$session->ProductSearched = $this->getRequest()->getParam('product-searched');
$returnArray['productSearched'] = $session->ProductSearched;
} else {
if ($session->ProductSearched) {
$returnArray['productSearched'] = $session->ProductSearched;
}
}
if ($this->getRequest()->getParam('search-term')) {
$session->SearchTerm = $this->getRequest()->getParam('search-term');
$returnArray['searchTerm'] = $session->SearchTerm;
} else {
if ($session->SearchTerm) {
$returnArray['searchTerm'] = $session->SearchTerm;
}
}
return $returnArray;
}
In your controller or wherever you wanted to check for those values:
$lastSearch = $this->rememberLastProductSearched();
echo $lastSearch['productSearched']; // Product Searched
echo $lastSearch['searchTerm']; // Search terms
But it might be cleaner to use two function
public function getLastProductSearched() {
$session = new Zend_Session_Namespace(searchedproducts);
if ($this->getRequest()->getParam('product-searched')) {
$session->ProductSearched = $this->getRequest()->getParam('product-searched');
$returnValue = $session->ProductSearched;
} else {
if ($session->ProductSearched) {
$returnValue = $session->ProductSearched;
}
}
return $returnValue;
}
public function getLastSearchTerms() {
$session = new Zend_Session_Namespace(searchedproducts);
if ($this->getRequest()->getParam('search-term')) {
$session->SearchTerm= $this->getRequest()->getParam('search-term');
$returnValue = $session->SearchTerm;
} else {
if ($session->SearchTerm) {
$returnValue = $session->SearchTerm;
}
}
return $returnValue;
}
And you could use them like this:
echo $this->getLastProductSearched(); // Product Searched
echo $this->getLastSearchTerms(); // Search terms
It will make your code easier to read and debug later on. A few more notes on your code. You could avoid using nested ifs by using ||.
if ($this->getRequest()->getParam('product-searched') || $session->ProductSearched) {
$returnValue = $this->getRequest()->getParam('product-searched') || $session->ProductSearched;
}
will achieve the same thing as :
if ($this->getRequest()->getParam('product-searched')) {
$session->ProductSearched = $this->getRequest()->getParam('product-searched');
$returnArray['productSearched'] = $session->ProductSearched;
} else {
if ($session->ProductSearched) {
$returnArray['productSearched'] = $session->ProductSearched;
}
}
Hope this helps !

PHP Memcached extension OOP instantiation

Background:
I have installed the PHP Memcached extension on my live server.
Despite various efforts, I can't seem to install Memcached within my XAMPP development box, so I am relying on the following code to only instantiate Memcached only on the Live server:
My connect file which is included in every page:
// MySQL connection here
// Memcached
if($_SERVER['HTTP_HOST'] != 'test.mytestserver') {
$memcache = new Memcached();
$memcache->addServer('localhost', 11211);
}
At the moment I am instantiating each method, and I can't help thinking that that there is a better way to acheive my objective and wonder if anyone has any ideas?
My class file:
class instrument_info {
// Mysqli connection
function __construct($link) {
$this->link = $link;
}
function execute_query($query, $server) {
$memcache = new Memcached();
$memcache->addServer('localhost', 11211);
$result = mysqli_query($this->link, $query) or die(mysqli_error($link));
$row = mysqli_fetch_array($result);
if($server == 'live')
$memcache->set($key, $row, 86400);
} // Close function
function check_something() {
$memcache = new Memcached();
$memcache->addServer('localhost', 11211);
$query = "SELECT something from somewhere";
if($_SERVER['HTTP_HOST'] != 'test.mytestserver') { // Live server
$key = md5($query);
$get_result = $memcache->get($key);
if($get_result) {
$row = $memcache->get($key);
} else {
$this->execute_query($query, 'live');
}
} else { // Test Server
$this->execute_query($query, 'prod');
}
} // Close function
} // Close Class
I would suggest that you read up on interface-based programming and dependency injection. Here's some example code that might give you an idea about how you should go about it.
interface CacheInterface {
function set($name, $val, $ttl);
function get($name);
}
class MemCacheImpl implements CacheInterface {
/* todo: implement interface */
}
class OtherCacheImpl implements CacheInterface {
/* todo: implement interface */
}
class InstrumentInfo {
private $cache;
private $link;
function __construct($link, $cache) {
$this->link = $link;
$this->cache = $cache;
}
function someFunc() {
$content = $this->cache->get('some-id');
if( !$content ) {
// collect content somehow
$this->cache->set('some-id', $content, 3600);
}
return $content
}
}
define('IS_PRODUCTION_ENV', $_SERVER['HTTP_HOST'] == 'www.my-real-website.com');
if( IS_PRODUCTION_ENV ) {
$cache = new MemCacheImpl();
} else {
$cache = new OtherCacheImpl();
}
$instrumentInfo = new InstrumentInfo($link, $cache);
BTW. You actually have the same problem when it comes to mysqli_query, your'e making your code dependent on a Mysql database and the mysqli extension. All calls to mysqli_query should also be moved out to its own class, representing the database layer.

yii cdbdatareader and readObject function

I am trying to construct an object from a stored procedure will yii.
http://www.yiiframework.com/doc/api/1.1/CDbDataReader
I am unsure how to use the function $dataReader->readObject('image', $image);
to construct an object- anyone any ideas if this is the correct way or if this is very slow way of constructing objects
function __construct($image) {
print "In BaseClass constructor\n";
}
public static function getImageFromAliasTitle($alias_title)
{
// $alias_title =Utils::checkEnteredData($alias_title);
$connection = Yii::app()->db;
$command = $connection->createCommand("CALL get_associated_image_detail(:in_image_alias_title, :in_image_visible, :in_image_approved, :in_album_visible, :in_album_approved)");
$command->bindParam(":in_image_alias_title",$alias_title,PDO::PARAM_STR);
$command->bindValue(":in_image_visible",'1',PDO::PARAM_STR);
$command->bindValue(":in_image_approved",'Yes',PDO::PARAM_STR);
$command->bindValue(":in_album_visible",'1',PDO::PARAM_STR);
$command->bindValue(":in_album_approved",'Yes',PDO::PARAM_STR);
try{
$dataReader = $command->query();
if($dataReader->count() >0)
{
$image = $dataReader->read();
}
$dataReader->readObject('image', $image);
// $image = $dataReader->read();
$dataReader->nextResult();
$album = $dataReader->readAll();
$dataReader->nextResult();
$tag = $dataReader->readAll();
$dataReader->nextResult();
$user_image = $dataReader->readAll();
$dataReader->close();
}
catch(Exception $e){
Yii::log('', CLogger::LEVEL_ERROR, 'Message Here...');
}
return $image;
}
What about this:
foreach($row as $dataReader->readAll()){
echo $row["image"];
}
if It does not help then try to print:
print_r($dataReader->readAll());

General internet "scraping" question

I just started studying programming about 6 months ago and I have really been diving deep into Objective-C. Unfortunately, I don't know any programmers IRL to bounce general questions off of.
What languages are being used when people write programs that will search a website for information and then send it back? For example, if I wanted to write a program that would search weather.com for the daily temperature of the last 30 days in a given location and then send it back as say...an NSArray or NSDictionary, how would i do that? Can I do that in Objective C or is that super-advanced scripting language stuff? If I CAN do it in Objective-C, can someone link to a tutorial or place that may get me started learning that type of stuff? (I don't really know the term for this type of programming so my google searches have been unfruitful.)
I most commonly use PHP and MySQL with CURL
http://en.wikipedia.org/wiki/CURL
You can do some fun things like Search Engine Results Page queries, etc.
Here is the source from a crawler I use. I've cut out some parts for anonymity's sake, but it's a good almost-working example. I can help you get it running if need be.
<?php
class Crawler {
protected $markup = '';
protected $uri = '';
protected $db_location = "localhost";
protected $db_username = "***";
protected $db_password = "***";
protected $db_name = "***";
public function __construct() {
ini_set('memory_limit', -1);
}
public function getMarkup() {
$markup = "";
$markup = #file_get_contents($this->uri);
return $markup;
}
public function get($type) {
$method = "_get_{$type}";
if (method_exists($this, $method)){
return call_user_method($method, $this);
}
}
protected function db_query($query) {
$connection = mysql_connect($this->db_location,$this->db_username,$this->db_password) or die(mysql_error());
mysql_select_db($this->db_name,$connection) or die(mysql_error()." >> ".$query);
//echo $query."<br/>"; //for debugging
$result = mysql_query($query,$connection) or die (mysql_error()." >> ".$query);
$i = 0;
if($result != 1)
{
while ($data_array = mysql_fetch_array($result))
{
foreach($data_array as $key => $value)
{
$tableArray[$i][$key] = stripslashes($data_array[$key]);
}
$i++;
}
return $tableArray;
}
}
protected function db_insert($table,$array) {
$tableArray = $this->db_query("show columns from ".$table);
$inputString = "";
foreach($tableArray as $key => $value)
{
if (array_key_exists($value[0], $array) && $value[0]) {
$inputString .= "'".addslashes($array[$value[0]])."', ";
} else {
$inputString .= "'', ";
}
}
$inputString = substr($inputString, 0, -2);
$this->db_query("insert into $table values(".$inputString.")");
return mysql_insert_id();
}
protected function _get_data() {
//$scrape['id'] = $this->get('id');
$scrape['name'] = $this->get('name');
$scrape['tags'] = $this->get('tags');
$scrape['stat_keys'] = $this->get('stat_keys');
$scrape['stat_values'] = $this->get('stat_values');
foreach($scrape['stat_values'] as $key => $value) {
$scrape['stat_values'][$key] = trim($scrape['stat_values'][$key]);
if(strpos($value,"<h5>Featured Product</h5>")) {
unset($scrape['stat_values'][$key]);
}
if(strpos($value,"<h5>Featured Company</h5>")) {
unset($scrape['stat_values'][$key]);
}
if(strpos($value,"<h5>Featured Type</h5>")) {
unset($scrape['stat_values'][$key]);
}
if(strpos($value,"sign in")) {
unset($scrape['stat_values'][$key]);
}
if(strpos($value,"/100")) {
unset($scrape['stat_values'][$key]);
}
}
if(sizeof($scrape['tags']) > 0 && is_array($scrape['tags'])) {
foreach($scrape['tags'] as $tag) {
$tag_array[$tag] = $tag_array[$tag] + 1;
}
$scrape['tags'] = $tag_array;
foreach($scrape['tags'] as $key => $tag_count) {
$scrape['tags'][$key] = $tag_count - 1;
}
}
$scrape['stat_values'] = array_merge(array(),$scrape['stat_values']);
return $scrape;
}
protected function _get_images() {
if (!empty($this->markup)){
preg_match_all('/<img([^>]+)\/>/i', $this->markup, $images);
return !empty($images[1]) ? $images[1] : FALSE;
}
}
protected function _get_links() {
if (!empty($this->markup)){
preg_match_all('/<a([^>]+)\>(.*?)\<\/a\>/i', $this->markup, $links);
return !empty($links[1]) ? $links[1] : FALSE;
}
}
protected function _get_id() {
if (!empty($this->markup)){
preg_match_all('/\/wine\/view\/([^`]*?)-/', $this->markup, $links);
return !empty($links[1]) ? $links[1] : FALSE;
}
}
protected function _get_grape() {
if (!empty($this->markup)){
preg_match_all('/ class="linked" style="font-size: 14px;">([^`]*?)<\/a>/', $this->markup, $links);
return !empty($links[1]) ? $links[1] : FALSE;
}
}
}
if($_GET['pass'] == "go") {
$crawl = new Crawler();
$crawl->go();
}
?>
So, you want to know how to write server-side code? Well, in theory you can write that in whatever you want. I also assure you it isn't "super-advanced".
You might find it easiest to get started with PHP. W3schools.com has a fine tutorial.
What you are describing is a crawler (e.g. Google).
Any language that has the ability to send HTTP requests and receive responses can do this (which is most languages).
If you don't care to code this thing from scratch, try downloading an open source crawler framework that will allow for custom plugins to parse the resulting HTML.
For your example, you would tell the crawler what site you want it to crawl (i.e. your weather site), add URI constraints if necessary, and create a custom plugin to parse the weather data out of the HTML it responds with. You can then save that data however you see fit.