Laravel cursor usage dilemma - php

get works while cursor returns blank
$excep[] = DB::table('table')->where('user_id', $user)->select('data')->get();
return $excep; // returns some sql data
But with cursor:
$excep[] = DB::table('table')->where('user_id', $user)->select('data')->cursor();
return $excep; // returns [{}]
Information isn't enough to understand: https://laravel.com/docs/5.5/eloquent#chunking-results

cursor only can be used on iterations, if you need all data at once, you must use get.
// All users will be loaded on memory first on collection and then, iterate.
// You can return all users as return UserModel::get();
foreach (UserModel::get() as $user) {
$this->sendWellcomeMail($user);
}
// Only one user on memory on each iteration.
// You can NOT return all users with return UserModel::cursor();
foreach (UserModel::cursor() as $user) {
$this->sendWellcomeMail($user);
}

Related

Count empty mysql columns in PHP

I'm trying to create a method that counts the empty mysql columns.
My code is as follows:
public function countCompletion() {
$userData = $this->find(Session::get('user'));
$userData = $this->_data;
$completion = 0;
foreach($userData as $item) {
if(empty($item)) {
$completion++;
}
}
die($completion);
}
The problem is, when I die $completion it just shows nothing, while it should show 2.
According to the documentation, when die (or exit) is called with an integer argument the argument is not printed but is instead passed back to the operating system as an exit code. To get the value to display you will need to return it, then print it from the calling routine.
first check with "echo" inside "foreach" to display column content then you can do a loop to incremente number of empty column
foreach($userData as $item) {
echo 'data: '.$item.'<br>';
if(empty($item)) {
$completion++;
}
}
bacause you have to verify that your function is executing successfully
you can use "var_dump()" also to test what variable contains
var_dump($completion);
die();

PDO mutliple fetch_assoc from one query [duplicate]

I'm trying to write an iterator for results from a PDO statement but I can't find any way of rewinding to the first row. I would like to avoid the overhead of calling fetchAll and storing all the result data.
// first loop works fine
foreach($statement as $result) {
// do something with result
}
// but subsequent loops don't
foreach($statement as $result) {
// never called
}
Is there some way of reseting the statement or seeking the first row?
I'm pretty sure this is database dependent. Because of that, it is something you should try to avoid. However, I think you can achieve what you want by enabling buffered queries. If that doesn't work, you can always pull the result into an array with fetchAll. Both solutions have implications for your applications performance, so think twice about it, if the resultsets are large.
This little class I wrote wraps a PDOStatement. It only stores the data that is fetched. If this doesn't work, you could move the cache to read and write to a file.
// Wrap a PDOStatement to iterate through all result rows. Uses a
// local cache to allow rewinding.
class PDOStatementIterator implements Iterator
{
public
$stmt,
$cache,
$next;
public function __construct($stmt)
{
$this->cache = array();
$this->stmt = $stmt;
}
public function rewind()
{
reset($this->cache);
$this->next();
}
public function valid()
{
return (FALSE !== $this->next);
}
public function current()
{
return $this->next[1];
}
public function key()
{
return $this->next[0];
}
public function next()
{
// Try to get the next element in our data cache.
$this->next = each($this->cache);
// Past the end of the data cache
if (FALSE === $this->next)
{
// Fetch the next row of data
$row = $this->stmt->fetch(PDO::FETCH_ASSOC);
// Fetch successful
if ($row)
{
// Add row to data cache
$this->cache[] = $row;
}
$this->next = each($this->cache);
}
}
}
see slide 31 from this presentation, you can do a $statement->rewind() if it applies to a buffered query. If you use mysql, you can emulate buffered queries by using PDO_MYSQL_ATTR_USE_BUFFERED_QUERY:
$pdo->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, 1);
#NoahGoodrich pointed you to spl. Here is an example that always works:
$it = new ArrayIterator($stmt->fetchAll());
Asked a long time ago but currently there's another solution.
The method PDOStatement::fetch() may receives a second parameter, the cursor orientation, with one of PDO::FETCH_ORI_* constants. These parameter are only valid if the PDOStatement are created with the atribute PDO::ATTR_CURSOR as PDO::CURSOR_SCROLL.
This way you can navigate as follows.
$sql = "Select * From Tabela";
$statement = $db->prepare($sql, array(
PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL,
));
$statement->execute();
$statement->fetch(PDO::FETCH_BOTH, PDO::FETCH_ORI_NEXT); // return next
$statement->fetch(PDO::FETCH_BOTH, PDO::FETCH_ORI_PRIOR); // return previous
$statement->fetch(PDO::FETCH_BOTH, PDO::FETCH_ORI_FIRST); // return first
$statement->fetch(PDO::FETCH_BOTH, PDO::FETCH_ORI_LAST); // return last
$statement->fetch(PDO::FETCH_BOTH, PDO::FETCH_ORI_ABS, $n); // return to $n position
$statement->fetch(PDO::FETCH_BOTH, PDO::FETCH_ORI_REL, $n); // return to $n position relative to current
More info in docs and PDO predefined constants.
Note: used PDO::FETCH_BOTH because is the default, just customize it for your project.
You'll probably want to take a look at some of the PHP SPL classes that can be extended to provide array-like access to objects.
Standard PHP Library (SPL) I would specifically
recommend that you look at the
ArrayIterator, ArrayObject, and
perhaps the Iterator interface.
Simple
Tutorial
Another
Quick Tutorial

How to check MySQL results to determine if field is empty across results

I have some fairly complex MySQL queries that return about 30 fields.
I am doing some conditional formatting for a report and need to determine if any of those fields are empty across all of the results.
I know how to check on a per row basis, but I need to determine if an entire "column" is empty after returning the results.
I'm using PHP 5.2 and simple HTML to generate the reports.
Something like this?
$results = mysql_fetch_array($resource);
$columnEmpty = checkEmptyColumn($results, "column_name"); // returns true if empty
function checkEmptyColumn($array, $columnName){
foreach ($array as $arr){
if(!empty($arr[$columnName])) return false;
}
return true;
}

How to call a function inside itself?

I have a function that generates a key of 4 characters that has to be unique for each time. In order to do that, the function first generates a key, and then checks a database table to see if it's in use by someone else.
If it's not in use, it returns the key, else, it calls itself again, but this causes the function to do an infinite loop, which is a no-no. Here's the whole function:
function key_generator($length = 4)
{
// I've subsequently left out the generating code,
// which is not necesarry in this case
$key = 'xxxx';
if ($this->user_model->valid_key($key) == true)
{
return $key;
}
else
{
$this->key_generator(4);
}
}
What is the correct way to call the function again?
By the way, I'm using CodeIgniter, hence $this.
I would not use recursive functions for retry-scenarios (since you don't reuse the result of the function, it's pointless to use recursion)... It adds a lot of unnecessary overhead. Do something like this:
do {
$key = ...; // Generate your key here...
} while (!$this->user_model->valid_key($key));
return $key;
If you're near the maximum number of keys, this will result in very long loop times, so you might want to put some kind of max limit.
Oh, and if this is occurring on multiple threads simultaneously and you're checking a database, you should implement table write locking so that the same key can't be inserted twice. Preferably the function that checks whether a key is available should lock, check, and if available write in the same transaction to avoid any collisions.
You need to return the result of the self-call, otherwise the valid key won't get returned once it recurses.
return $this->key_generator($length);
but this causes the function to do an infinite loop,
If you absolutely want to keep your recursive strategy you have to define an end case. For example you may define a counter, like this:
function key_generator($length = 4, $limit=5)
{
if($limit === 0) {
throw new YourException();
}
// I've subsequently left out the generating code,
// which is not necesarry in this case
$key = 'xxxx';
if ($this->user_model->valid_key($key) == true)
{
return $key;
}
else
{
return $this->key_generator(4, ($limit-1));
}
}
It is however also possible to do your code iteratively...
If you include enough uniqueness in your key generation routine, you might be able to avoid this situation in the first place. E.g. have the routine take into account the current timestamp and the local hostname and/or PID.
Looping in such a non-deterministic fashion is generally proof of some part being too naive. That's not good. :-)
Anyhow, it would at least be good practice to catch it and log some sort of error as opposed to hanging the request and finally timing out:
function key_generator($length = 4)
{
/* The $attempts_left clearly depends on how much trust
you give your key generation code combined with the key space size. */
$attempts_left = pow(16, $length) * 2;
/* ... just guessing, in case your key base is 16, i.e. [0-9a-z] for example */
do {
// ... key generation goes here ...
$key = 'xxxx';
} while ( $this->user_model->valid_key($key) == false && $attempts_left-- > 0 );
if( $attempts_left < 1 )
return false;
else
return $key;
}
Why don't you just scan the key value space for the first unused key? Needs the key to fulfill additional constraints on top of being four characters long and unique?
You could remember the last returned key to resume scanning from there on subsequent calls.
If you want subsequent calls not to return similar keys, you could shuffle your key database first. This would mean that you need to hold a 456976, 1679616, 7311616, or 14776336 element array somewhere (depending on whether the alphabet used are single- or double-cased characters, with or without digits).
You could put your code into a loop and determine the key iteratively instead of
recursively.
Example:
function key_generator($length = 4)
{
do {
$key = 'xxxx'; //TODO
if (timeOutReached()) return InvalidKey;
} while (!$this->user_model->valid_key($key))
return $key;
}
The loop itself does not prevent an infinte loop, but unlike a function call, this doesn't eat up stack space, so you don't risk a stack overflow.
Also it simplifies things a little bit. Depending on the type of the key you can also adapt the key generation method, for example with numbered keys you can increase exponentially with each iteration.
Remarks: If it is possible, use a database's auto-increment feature instead of rolling your own key generation feature.
Also make sure you protect your code against concurrent access. What if two instances of this function try to generate a key and they both determine the same? Use critical sections or transactions to make sure nothing bad happens.
Using a function inside itself
function test($val) {
/*initialize return value by using the conditions*/
if($val>=5){
/*do something with return statement*/
return $val+10;
} else {
/*set the return default value for avoid the error throwing*/
return "default value";
}
/*return the function used for check the condition*/
return test($val);
}
echo test(4); // output "default value";
echo test(6); //output 16

Is it possible to rewind a PDO result?

I'm trying to write an iterator for results from a PDO statement but I can't find any way of rewinding to the first row. I would like to avoid the overhead of calling fetchAll and storing all the result data.
// first loop works fine
foreach($statement as $result) {
// do something with result
}
// but subsequent loops don't
foreach($statement as $result) {
// never called
}
Is there some way of reseting the statement or seeking the first row?
I'm pretty sure this is database dependent. Because of that, it is something you should try to avoid. However, I think you can achieve what you want by enabling buffered queries. If that doesn't work, you can always pull the result into an array with fetchAll. Both solutions have implications for your applications performance, so think twice about it, if the resultsets are large.
This little class I wrote wraps a PDOStatement. It only stores the data that is fetched. If this doesn't work, you could move the cache to read and write to a file.
// Wrap a PDOStatement to iterate through all result rows. Uses a
// local cache to allow rewinding.
class PDOStatementIterator implements Iterator
{
public
$stmt,
$cache,
$next;
public function __construct($stmt)
{
$this->cache = array();
$this->stmt = $stmt;
}
public function rewind()
{
reset($this->cache);
$this->next();
}
public function valid()
{
return (FALSE !== $this->next);
}
public function current()
{
return $this->next[1];
}
public function key()
{
return $this->next[0];
}
public function next()
{
// Try to get the next element in our data cache.
$this->next = each($this->cache);
// Past the end of the data cache
if (FALSE === $this->next)
{
// Fetch the next row of data
$row = $this->stmt->fetch(PDO::FETCH_ASSOC);
// Fetch successful
if ($row)
{
// Add row to data cache
$this->cache[] = $row;
}
$this->next = each($this->cache);
}
}
}
see slide 31 from this presentation, you can do a $statement->rewind() if it applies to a buffered query. If you use mysql, you can emulate buffered queries by using PDO_MYSQL_ATTR_USE_BUFFERED_QUERY:
$pdo->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, 1);
#NoahGoodrich pointed you to spl. Here is an example that always works:
$it = new ArrayIterator($stmt->fetchAll());
Asked a long time ago but currently there's another solution.
The method PDOStatement::fetch() may receives a second parameter, the cursor orientation, with one of PDO::FETCH_ORI_* constants. These parameter are only valid if the PDOStatement are created with the atribute PDO::ATTR_CURSOR as PDO::CURSOR_SCROLL.
This way you can navigate as follows.
$sql = "Select * From Tabela";
$statement = $db->prepare($sql, array(
PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL,
));
$statement->execute();
$statement->fetch(PDO::FETCH_BOTH, PDO::FETCH_ORI_NEXT); // return next
$statement->fetch(PDO::FETCH_BOTH, PDO::FETCH_ORI_PRIOR); // return previous
$statement->fetch(PDO::FETCH_BOTH, PDO::FETCH_ORI_FIRST); // return first
$statement->fetch(PDO::FETCH_BOTH, PDO::FETCH_ORI_LAST); // return last
$statement->fetch(PDO::FETCH_BOTH, PDO::FETCH_ORI_ABS, $n); // return to $n position
$statement->fetch(PDO::FETCH_BOTH, PDO::FETCH_ORI_REL, $n); // return to $n position relative to current
More info in docs and PDO predefined constants.
Note: used PDO::FETCH_BOTH because is the default, just customize it for your project.
You'll probably want to take a look at some of the PHP SPL classes that can be extended to provide array-like access to objects.
Standard PHP Library (SPL) I would specifically
recommend that you look at the
ArrayIterator, ArrayObject, and
perhaps the Iterator interface.
Simple
Tutorial
Another
Quick Tutorial

Categories