How to make my method working only 1 time? - php

I have a method in the model Users
public function getRating()
{
$id = \Yii::$app->request->get('id');
$rating = Yii::$app->db->createCommand(
"SELECT * FROM (
SELECT *, (#position:=#position+1) as rate FROM (
SELECT executor_id, SUM(rate) / COUNT(rate) as pts FROM user_replies, (SELECT #position:=0) as a
GROUP BY executor_id ORDER BY pts DESC
) AS subselect
) as general WHERE executor_id = $id"
)->queryOne();
return $rating;
}
and i output result in the view like that
<?php echo $singleUser->getRating()['rate']; ?>
but more qualified coder said me that my query will be executing 2 times. Is that possible to rewrite code so it executes only 1 time?

You seem to be calling $singleUser->getRating() twice.
You could try saving the result in a variable, that way you will not call the database twice.
i.e.
$rating = $singleUser->getRating();
Now it's possible to just use the value from that variable. Saving you a trip to the database.
!is_null($rating)
echo $rating['rate']

As mentioned by thordoor, you can save the value to a variable.
I would just like to add that you could use a private static variable inside the class.
private static $_rating;
And inside your Method you could look inside this variable.
public function getRating(){
if(static::$_rating===null){
// here goes your code
// and an asignment like
static::$_rating = $rating;
}
return static::$_rating;
}
With this way you can have multiple user objects and query the ratings for each of them.
Correct me if I am wrong.

Related

Making where clause dynamic in sql in CI

I want to display the content of page dynamically this following code is working fine but it only shows the content of specific id...how can i make that dynamic??
Model
public function getAllDepartment() {
$join = $this->db->query( "Select * from labreport_db inner join patient_db on labreport_db.P_ID=patient_db.id where labreport_db.P_ID=15");
return $join->result_array();
}
Controller
public function reportDisplay(){
$data['clubs'] = $this->labdoc_model->getAllDepartment();
$this->load->view('SystemAdminUser/labreport', $data);
}
There is simple work around for this using Query Builder class of CI.
So this is how your code will look like,
$id=15;
$this->db->select('*');
$this->db->from('labreport_db');
$this->db->join('patient_db', 'labreport_db.P_ID = patient_db.id');
$this->db->where('labreport_db.P_ID', $id);
$query = $this->db->get();
This is standard approach in CI to make database operation using query builder class in which you can perform dynamic WHERE condition.
For which just change the value of $id and the query will do the needful.
Reference: https://www.codeigniter.com/userguide3/database/query_builder.html#selecting-data
Hold the id in some variable like:
$pid = $_REQUEST['p_id'];
// $_REQUEST['p_id'] will contain the dynamic value in it
and put this variable in your query like:
where labreport_db.P_ID = $pid;
It will show the data for the value contained in $pid, and make sure it contains the dynamic value in it.
You can used this code for you solution.
Model.php
public function getAllDepartment($pId) {
$join = $this->db->query( "Select * from labreport_db inner join patient_db on labreport_db.P_ID=patient_db.id where labreport_db.P_ID=".$pId);
return $join->result_array();
}
Controller.php
public function reportDisplay(){
$pid = $_REQUEST['pid']; //OR $_GET['pid']; OR $_POST['pid']; You can pass your id for get content
$data['clubs'] = $this->labdoc_model->getAllDepartment($pid);
$this->load->view('SystemAdminUser/labreport', $data);
}
There are a couple of ways doing it. One of them is through CI routing ability.
Model
public function getAllDepartment($p_id = 0) {
$join = $this->db->query( "Select * from labreport_db inner join patient_db on labreport_db.P_ID=patient_db.id where labreport_db.P_ID={$p_id}");
return $join->result_array();
}
Comment: I added $p_id as a variable to fetch the ID dynamically.
Controller
public function reportDisplay($p_id = 0){
$data['clubs'] = $this->labdoc_model->getAllDepartment($p_id);
$this->load->view('SystemAdminUser/labreport', $data);
}
Comment: We also add a variable called $p_id in the reportDisplay function and pass it to your model's getAllDepartment()function.
How to fetch the report dynamically
I don't know your URL structure, but for example purposes let's say it's http://localhost/yourcontrollername/reportDisplay/
To access it dynamically, simply add an ID after the reportDisplay
For example:
http://localhost/yourcontrollername/reportDisplay/15
http://localhost/yourcontrollername/reportDisplay/10

Sort alphabetically when multiple queries?

I am having difficulty sorting my data results alphabetically when matching them with the User that has placed the item in their "Locker".
I have two queries; the first one searches the database for all of the items that the user placed in their 'locker', and the second query pulls the details of the item and sorts them into a list by which brand the items are.
I feel like there is a better way to do this rather than forcing the page to run the query once for each item, but am not sure the proper way to write out the mySQL in the most efficient way that works.
I think the solution would be to pull all IDs as an array, then somehow search and sort all of their associated brands in the second query.
I currently have:
//$lockerid is pulled earlier in the code based on which locker number is associated with this user
// Pull all of the items and their ids that are in this users locker
$userlockerquery= mysql_query("SELECT DISTINCT item_id FROM lockers WHERE user_id = '$profile_userid' AND locker_id ='$lockerid' ");
while($lockeritems=mysql_fetch_array($userlockerquery)){
$indi_item=$lockeritems[item_id];
$lockeritemdetails = mysql_query("SELECT DISTINCT brand FROM inventory WHERE id = '$indi_item' ");
$brands=mysql_fetch_array($lockeritemdetails );
$brandname=$brands[brand];
echo '<div>'.$brandname.'</div>';
}
Although the results do show up with all of the brands, My problem seems to be that since the query is ran once for each items id, it cannot have the list results talk to each other, and thus cannot have them ordered by ASC alphabetically, since the query is ran once per each item.
Also because of this, the DISTINCT flag does not have any effect, since it is not matching against any other results.
As an example, my results would return in divs in order of ID instead of brand, and repeating:
Nike
Puma
Puma
Converse
Rather than
Converse
Nike
Puma
Adding the ORDER BY flag to the second query did not help, so I figured I would try to ask here for some ideas. Please let me know if any other details are needed!
Maybe try something like this class. See if it will work for your needs. It's hard to check it without trying the sql queries, but provided I've written it properly, it should work.
class MyLocker
{
// Protected means that you can't use this variable outside of the functions/class
// so you can not use $myLocker->_array; It will throw an error
protected $_array;
// Construct is basically used as an auto-function. It will execute automatically
// when you create a new instance of the class so as soon as you do this:
// $myLocker = new MyLocker($_locker); you initiate the __construct
// When you label as public, you allow it to be used outside of itself
public function __construct($_array)
{
// When you set this variable, it is now open to use in all
// other functions in this class.
$this->_array = $_array;
}
// This is the method that will do everything
public function LockerContents()
{
// Loop through query. Since the $_array was set in the __construct
// it is available in this function as $this->_array
while($lockeritems = mysql_fetch_array($this->_array)){
// $brand is something we want to use in other functions but not
// outside the class so it is set here for use in the Fetch() function
$this->brand = $lockeritems['item_id'];
// We ant to use our Fetch() function to return our brand
$_brand = $this->Fetch();
// If brand available, set it to an array
if(!empty($_brand))
$array[] = $_brand;
}
if(isset($array)) {
// Sort the array
asort($array);
// Finally, we use the Display() function for the final output
$this->Display($array);
}
else { ?>
<div>Locker is empty.</div><?php
}
}
// Establish this as an in-class variable
protected $brand;
// Establish this as a public function incase we want to use it by itself
// To do so you would write $myLocker->Fetch(); outside of the class.
// Since you need $brand for this function to work, you would need to turn
// $brand from "protected" to "public" and write $myLocker->brand = 'whatever';
// before you run the $myLocker->Fetch();
public function Fetch()
{
$query = mysql_query("SELECT DISTINCT brand FROM inventory WHERE id = '".$this->brand."'");
$brands = mysql_fetch_array($query);
// Return brand
return (isset($brands['brand']))? $brands['brand']:"";
}
protected function Display($array)
{
if(is_array($array)) {
foreach($array as $object) { ?>
<div><?php echo $object; ?></div><?php
}
}
}
}
// You should be using mysqli_ or PDO for your db connections/functions.
$_locker = mysql_query("SELECT DISTINCT item_id FROM lockers WHERE user_id = '$profile_userid' AND locker_id ='$lockerid' ");
// If there are more than 0 rows, create locker.
if(mysql_num_rows($_locker) > 0) {
// Create new instance of the locker app
$myLocker = new MyLocker($_locker);
// Display the results
$myLocker->LockerContents();
}

Codeigniter: how do I select count when `$query->num_rows()` doesn't work for me?

I have a query which is returning a sum, so naturally it returns one row.
I need to count the number of records in the DB which made that sum.
Here's a sample of the type of query I am talking about (MySQL):
SELECT
i.id,
i.vendor_quote_id,
i.product_id_requested,
SUM(i.quantity_on_hand) AS qty,
COUNT(i.quantity_on_hand) AS count
FROM vendor_quote_item AS i
JOIN vendor_quote_container AS c
ON i.vendor_quote_id = c.id
LEFT JOIN company_types ON company_types.company_id = c.company_id
WHERE company_types.company_type = 'f'
AND i.product_id_requested = 12345678
I have found and am now using the select_min(), select_max(), and select_sum() functions, but my COUNT() is still hard-coded in.
The main problem is that I am having to specify the table name in a tightly coupled manner with something like $this->$db->select( 'COUNT(myDbPrefix_vendor_quote_item.quantity_on_hand) AS count' ) which kills portability and makes switching environments a PIA.
How can/should I get my the count values I am after with CI in an uncoupled way??
If you want a completely decoupled way of dealing with this, just run the query to get all the rows you'd add with SUM() and then add them together in PHP.
$sum = 0;
foreach($query->result() as $row)
{
$sum += $row->quantity_on_hand;
}
Or something like that.
What about defining your table in a var or const and then doing the query like so:
define('VENDOR_QUOTE_ITEM', 'vendor_quote_item');
$this->$db->select( 'COUNT(' . VENDOR_QUOTE_ITEM . '.quantity_on_hand) AS count' );
This should be faster than $query->num_rows() as that would retrieve results and have PHP count them. The above code cuts to the chase and just asks the DB for the count without returning anything else (because it uses mysql's COUNT())
As for why $query->num_rows(); isn't working.. Make sure that var you call num_rows on a CI query result object. You should have something like this:
$your_query = $this->db->query("YOUR QUERY");
$your_query->num_rows()
if you would like to use any MySQL function inside $this->db->select() function pass the second parameter as FALSE.
So it should be $this->$db->select( 'COUNT(myDbPrefix_vendor_quote_item.quantity_on_hand) AS count' , FALSE)
Well ... while it's a different direction than I initially envisioned, I ended up simply extending CI via the directions found HERE.
I added a select_count() method to match the existing select_min(), select_max(), and select_sum() methods.
This addition only applies to MySQL at this time, but it's a solid solution.
In case someone encounters a similar problem in the future, here's what I did:
I dropped Simons "MY_Loader" directly into my "application/core"
directory (didn't need to change a thing).
Then I created a "MY_DB_mysql_driver" in the "application/core" directory,
as per his instructions ... and made it looke like this: (sans comments for brevity)
.
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class My_DB_mysql_driver extends CI_DB_mysql_driver {
final public function __construct($params) {
parent::__construct($params);
log_message('debug', 'Extended DB driver class instantiated!');
} /* method: __CONSTRUCT */
final public function select_count($select = '', $alias = ''){
if ( !is_string($select) OR $select == ''){
$this->display_error('db_invalid_query');
}
if ($alias == ''){
$alias = $this->_create_alias_from_table(trim($select));
}
$sql = 'COUNT('.$this->_protect_identifiers(trim($select)).') AS '.$alias;
$this->ar_select[] = $sql;
if ($this->ar_caching === TRUE){
$this->ar_cache_select[] = $sql;
$this->ar_cache_exists[] = 'select';
}
return $this;
} /* method: SELECT_COUNT */
}
Hope it helps.

Why does ? not work in the LIMIT for Zend_Db

I have the following:
public function getAll($limit = 100)
{
//if ($thread != 0) { $threadq = "WHERE threadId=$threadId"; }
$query = <<<EOF
SELECT
x.*
FROM x
ORDER BY dater DESC
LIMIT ?
EOF;
return self::$db->fetchAll($query, $limit);
}
It seems it turns the LIMIT x into LIMIT 'x' and so the MySQL query parser goes wrong and complains.
However doing LIMIT $limit works fine
Why does this not work? and is there another method of doing this?
The replacement parameters must be inside array even if only single:
return self::$db->fetchAll($query, array($limit));
And for limit part of query you don't need to use ? replacement wildcard!
I'm going to go crazy and suggest you keep it easy and use Zend_Db_Select. This appears to be a simple query.
This demonstration uses a default ZF DbTable as the the adapter (I could just as easily use Zend_Db_Table::getDefaultAdapter();), however it can be adapted to almost any type of query:
<?php
class Application_Model_DbTable_User extends Zend_Db_Table_Abstract
{
protected $_name = 'user';
protected $_primary = 'id';
public function getAll($limit = 100)
{
$select = $this->select();//This is the adapter for this table and implies SELECT * FROM user
$select->order('name', 'DESC') //can also pass an array of columns
->limit($limit);//limit has a second arg for offset
return $this->fetchAll($select);//returns a rowset object, if an array is required append ->toArray to the fetchall().
}
}

Simple OOP and PHP not working... can anyone help? :)

My first foray into OOP with PHP - I am trying to build a query builder object that generates a query based on inputs to the object. I would imagine this is as simple as simple gets.
I expected that the line under the buildQuery function definition $active_value=$this->getActive; would assign 1 to the object's active attribute per the __construct() method... to no avail... what am i doing wrong to achieve the desired result i.e. buildQuery to return
select * from mytable where active=1
TIA!
class queryBuilder {
function __construct(){
$this->active=1;
}
public function active () {
$this->active=1;
}
public function inactive () {
$this->active=0;
}
public function getActive(){
return $this->active;
}
public function setActive($value){
$this->active->$value;
}
public function buildQuery() {
$active_value=$this->getActive();
$query="select * from mytable where active=$active_value";
return $query;
}
}
$init=new queryBuilder();
echo $init->buildQuery();
Response to edit of question
When I run this in a browser, I get select * from mytable where active=1. I assume that is what you need based on your question. If you want active to be quoted (which might be a typo in your original question), then you'll need to replace $query="select * from mytable where active=$active_value"; with:
$query="select * from mytable where active='$active_value'";
// this will output select * from mytable where active='1'
If you want this to be a Boolean in MySQL, then use of 1 vs. 0 should be sufficient, but you can cast:
$query="select * from mytable where active=CAST($active_value as BOOL)";
// this will output select * from mytable where active=CAST(1 as BOOL)
Original text
Well, first you need to use -> instead of =, second you need to call the function:
// not: $active_value=$this=getActive;
$active_value=$this->getActive();
Couple of comments:
As a general rule in OOP, methods are generally broken down to do, get, and set. The names are often different, but they should always be verbs. inactive and active aren't really intuitive.
If you have methods getActive and setActive it is often a good idea to use them to modify the state of the object itself. There are exceptions for performance reasons and the like, but generally it is a good idea and it re-enforces that those methods are there. inactive therefore, should be function inactive(){ $this->setActive(1);}
You should almost never assign a new variable to a pre-defined class. Always declare variables up front when you can (add private $active; at line 1 of the class)
Because $this->active is a boolean, then it should probably be TRUE or FALSE until it is actually added to the query: $active_value = $this->getActive()? 1: 0;

Categories