Invalid parameter number in eloquent - php

I've got this query :
use Illuminate\Database\Capsule\Manager as DB;
$arr = [/* Array values here */];
$in = str_repeat('?,', count($arr) - 1) . '?';
$str = "SELECT ... FROM ... WHERE ... AND ... IN ($in)";
$select_categories = DB::select($str, $arr);
Now I'm getting the error Uncaught PDOException: SQLSTATE[HY093]: Invalid parameter number, this is the stack trace :
/var/www/vendor/illuminate/database/Connection.php:330 Stack trace: #0 /var/www/vendor/illuminate/database/Connection.php(330): PDOStatement->execute() #1 /var/www/vendor/illuminate/database/Connection.php(657): Illuminate\Database\Connection->Illuminate\Database{closure}('SELECT categori...', Array) #2 /var/www/vendor/illuminate/database/Connection.php(624): Illuminate\Database\Connection->runQueryCallback('SELECT categori...', Array, Object(Closure)) #3 /var/www/vendor/illuminate/database/Connection.php(333): Illuminate\Database\Connection->run('SELECT name...', Array, Object(Closure)) #4 /var/www/vendor/illuminate/database/Capsule/Manager.php(199): Illuminate\Database\Connection->select('SELECT name...', Array) #5 /var/www/categ.class.php(81): Illuminate\Database\Capsule\Manager::__callStatic('select', Array) #6 /var/www/categ.class.php(123): Site\Naviga in /var/www/vendor/illuminate/database/Connection.php on line 664
I don't get why this is happening. I'm trying to echo the variables $str and $arr to try and see if the number of ? matches the count of the array and indeed it does. So I can't see why is that error being generated. Any idea?
In the stack there are 3 arguments run('SELECT name...', Array, Object(Closure)), maybe this is causing the issue as it thinks there is a third parametre which there isn't? Or something like that?
EDIT :
$str contains : "?,?,?,?,?,?"
$arr contains : [94, 91, 97, 92, 96, 90]
Result of dd($str, $arr); :
"SELECT ... FROM ... WHERE ... IN (?,?,?,?,?,?,?,?,?,?,?,?,?,?) ORDER BY pro.sort_order"
array:14 [
0 => "56"
1 => "163"
4 => "64"
6 => "53"
7 => "52"
10 => "55"
12 => "59"
13 => "57"
28 => "157"
43 => "60"
49 => "133"
68 => "287"
101 => "54"
109 => "278"
]

The solution is to use array_values($arr) instead of $arr in the select() method:
$select_categories = DB::select($str, array_values($arr));
$in has 14 ? and $arr has 14 elements. The reason why it does not work is because indexes of $arr are not from 0 to 13 but from 0 to 109. Since indexes are integer and not string, all of them from 0 to 109 exist even if some are null, so the size of $arr is 110.
The effect of using array_values() on $arr:
array:14 [
0 => "56"
1 => "163"
2 => "64"
3 => "53"
4 => "52"
5 => "55"
6 => "59"
7 => "57"
8 => "157"
9 => "60"
10 => "133"
11 => "287"
12 => "54"
13 => "278"
]

Related

Laravel whereNotIn plus whereIn doesn't equal total count

How is it possible that whereNotIn() plus whereIn() doesn't equal total count?
Running this:
$updatedBreeds = [
86,
113,
// etc ....
];
DB::enableQueryLog();
dump(Breed::count());
dump(Breed::whereIn('id', $updatedBreeds)->count());
dump(Breed::whereNotIn('id', $updatedBreeds)->count());
dd(DB::getQueryLog());
Returns this:
159
39
0
Am I missing something here? The whereNotIn() call should return 120 results.
Apparently, one of the values in the array was null. Which strangely enough led to this behavior.
Here is a dump on $updatedBreeds:
[
0 => 86
1 => 113
- 2 => null // When I removed this value, the whereNotIn() worked
2 => 44
3 => 8
4 => 54
5 => 54
// ...
]

PHP sort seems to malfunction

### Result of sort
sort($keys_arranged, SORT_NUMERIC);
var_dump($keys_arranged);
{ ...
[51]=> float(11.903327742296)
[52]=> int(5)
[53]=> float(13.165002546636)
[54]=> float(14.478273306964)
[55]=> float(4.6264742674547)
[56]=> float(13.290508819344)
[57]=> float(15.686809055276) }
### Result or rsort
rsort($keys_arranged, SORT_NUMERIC);
var_dump($keys_arranged);
{
[0]=> float(15.686809055276)
[1]=> float(14.478273306964)
[2]=> float(13.290508819344)
[3]=> float(13.165002546636)
[4]=> float(11.903327742296)
[5]=> int(5)
[6]=> float(4.6264742674547)
... }
echo var_export($keys_arranged);
array ( 0 => 3.142678516658294, 1 => 1.0, 2 => 1.0, 3 => 14.478273306963985, 4 => 13.165002546635966, 5 => 1.0, 6 => 1.0005037081114851, 7 => 1.0, 8 => 4.6264742674547001, 9 => 15.686809055275578, 10 => 1.0, 11 => 11.903327742295504, 12 => 13.29050881934397, 13 => 1.0, 14 => 1.0, 15 => 3.5421134937189365, 16 => 1.0, 17 => 0.010999999999999999, 18 => 3.2999566681750605, 19 => 5, 20 => 1.2282984802843129, 21 => 1.0, 22 => 2.9748253120971184, 23 => 0.44855992975075798, 24 => 0.99999999999999989, 25 => 3.8350475954623371, 26 => 1.0625975061426283, 27 => 1.0000072792091179, 28 => 0.99999987785487132, 29 => 1, 30 => 0.0, 31 => 1.0, 32 => 1.0, 33 => 1.0, 34 => 0.0, 35 => 1.0972568578553616, 36 => 1.0, 37 => 1.4077661823957415, 38 => 1.0, 39 => 0.0, 40 => 3.6038030347555705, 41 => 1.0, 42 => 1.0, 43 => 1.0636876768842174, 44 => 1.0, 45 => NAN, 46 => 1.0, 47 => NAN, 48 => NAN, 49 => NAN, 50 => NAN, 51 => 1.0, 52 => 1.0, 53 => NAN, 54 => 0.99958680716631509, 55 => 1.0, 56 => NAN, 57 => 1.0, )
I got some incorrect result from array_multisort. It has 8 different keys and all the keys but this key(say A) works fine.
To figure out why that happened, I played with A in the array. And I could see that not only in the function of array_multisort, but also in 'sort' function, an incorrect result prompted as well.
As you can see the result of rsort seems okay, the result of sort works strangely when it comes to
13.16 < 14.47 < 4.62 < 13.29 < 15.68
Does anyone know why this occurred?
// Data in readible format
array (
0 => 3.142678516658294,
1 => 1.0,
2 => 1.0,
3 => 14.478273306963985,
4 => 13.165002546635966,
5 => 1.0,
6 => 1.0005037081114851,
7 => 1.0,
8 => 4.6264742674547001,
9 => 15.686809055275578,
10 => 1.0,
11 => 11.903327742295504,
12 => 13.29050881934397,
13 => 1.0,
14 => 1.0,
15 => 3.5421134937189365,
16 => 1.0,
17 => 0.010999999999999999,
18 => 3.2999566681750605,
19 => 5,
20 => 1.2282984802843129,
21 => 1.0,
22 => 2.9748253120971184,
23 => 0.44855992975075798,
24 => 0.99999999999999989,
25 => 3.8350475954623371,
26 => 1.0625975061426283,
27 => 1.0000072792091179,
28 => 0.99999987785487132,
29 => 1,
30 => 0.0,
31 => 1.0,
32 => 1.0,
33 => 1.0,
34 => 0.0,
35 => 1.0972568578553616,
36 => 1.0,
37 => 1.4077661823957415,
38 => 1.0,
39 => 0.0,
40 => 3.6038030347555705,
41 => 1.0,
42 => 1.0,
43 => 1.0636876768842174,
44 => 1.0,
45 => NAN,
46 => 1.0,
47 => NAN,
48 => NAN,
49 => NAN,
50 => NAN,
51 => 1.0,
52 => 1.0,
53 => NAN,
54 => 0.99958680716631509,
55 => 1.0,
56 => NAN,
57 => 1.0, )
It seems as you actually do have discovered a bug. On large arrays containing NaN values, represented by the NAN constant in PHP, the built-in function sort fails.
The comparision with NaN should always result as non-ordered as mentioned by kuh-chan in the question comments. However, as soon as there is at least one operand NaN, in recent (March 2019) versions of PHP the spaceship operator <=> returns 1 (first operand greater than second one) and -1 (first operand less than second one) in some other versions.
echo var_dump( NAN <=> 1.23 );
echo var_dump( 1.23 <=> NAN );
echo var_dump( NAN <=> -1.23 );
echo var_dump( -1.23 <=> NAN );
echo var_dump( NAN <=> 0 );
echo var_dump( NAN <=> NAN );
I'm not very famimilar with the internals of the Zend engine. However, I guess the sort algorithm terminates too soon on large arrays with several NaN values, likely in order to the order comparision algorithm alway returns "greater (or less) than" which probably leads to multiple exchanges of the same elements.
I experienced that calling sort multiple times seems to continue the sorting. However, that would not be a proper workaround.
You can use a custom comparision algorithm with usort instead. If you want to order NaN at the start of the array, return -1 when the first operand is NaN, 1 when the second operand is NaN and 0 (equal) if both are. Otherwise return the comparision result of the spaceship operator.
usort($keys_arranged,
function(&$v1, &$v2)
{
switch( (is_nan($v1) ? 1 : 0) | (is_nan($v2) ? 2 : 0) )
{
case 0: return $v1 <=> $v2;
case 1: return -1;
case 2: return 1;
case 3: return 0;
}
}
);
Similar bitwise logic as above, but in a more compressive and direct form:
usort( $keys_arranged,
function(&$v1, &$v2){ return -2 === ($b = (is_nan($v1) ? -1 : -2) ^ (is_nan($v2) ? -1 : 0)) ? $v1 <=> $v2 : $b; }
);

Multidimensional array without repeating

I have two MySQL tables, one is called "version" and the other is called "lines" inside one DB called "project".
The "version" table consist of:
id (PRIMARY / AI) = int
version = string
Rows:
# | version
------------
0 | 100
1 | 200
3 | 400
The "lines" table consist of:
id (PRIMARY / AI) = int
lines = string
version_id = string (ID from table version)
Rows:
# | line | version_id
--------------------------
0 | line #1 | 0
1 | line #2 | 0
2 | line #3 | 1
3 | line #4 | 0
4 | line #5 | 1
How can I create multidimensional array to output an example JSON (pseudo)
"full" =>
"version" => "100"
"id" => "0", (version id table)
"line" =>
"row_0" => "line #1", (from lines table)
"row_1" => "line #2",
"row_2" => "line #4",
"version" => "200"
"id" => "1",
"line" =>
"row_0" => "line #3",
"row_1" => "line #5",
"version" => "300"
"id" => "3",
"line" => "EMPTY" (no lines for this version)
]
I rewrote the code a couple of times but I can't make it work. Either I stuck or I finish in infinite loop of errors. This is what I got for now:
function returnJson() {
$db = DB::query("SELECT * FROM version");
foreach ($db as $row) {
$i++;
$lines = DB::Query("SELECT * FROM lines WHERE version_id=%i", $row['id']);
// approach to nested array?
}
}
I'm using MeekroDB so any approach to MySQL is offset. You can write an example in PDO if you are more familiar with it.
I assume that the array you want would look like this in php:
"full" =>
"100" => array (
"versionId" => "0", (version id table)
"line" =>
"row_0" => "line #1", (
"row_1" => "line #2",
"row_2" => "line #4"
)
, "200" => array (
"versionId" => "1",
"line" => array (
"row_0" => "line #3",
"row_1" => "line #5" )
)
, "300" => array (
"versionId" => "3",
"line" => array()
)
]
Use a JOIN
SELECT v.id AS versionId, v.version l.id as linesId, l.lines
FROM version v
INNER JOIN lines l ON v.id = l.version_id
And then a loop with some if statement to build the array
$versions = array();
foreach($db as $row) {
if (!isset($versions[$db["version"]]))
$versions[$db["version"]] = array (
"versionId" => $db["versionId"],
"line" => array()
);
if (!empty($db["lines"]))
$versions[$db["version"]][lines"][] = $db["lines"];
}
Try the accepted answer in this SO post which also deals with nested JSON data.
Also you may want to reduce your SQL to below and just use one loop instead of 2 nested loops as in the SO post above.
SELECT *
FROM version
INNER
JOIN lines
ON version.id = lines.version_id
Hope this helps.

Concatenate strings from 2 array based on key

so i have a bit difficulty in combining arrays in php. So let say i have these 2 array
array:4 [▼
20 => "University"
21 => "Polic Station"
22 => "Ambulance"
1 => "Zoo"
]
array:4 [▼
20 => "abc"
21 => "def"
22 => "ghi"
1 => "jkl"
]
How do i actually combine this to this
array:4 [▼
20 => "abc University"
21 => "def Polic Station"
22 => "ghi Ambulance"
1 => "jkl Zoo"
]
Here's the result:
$arr = array(
20=>'University',
21=>'Polic Station',
22=>'Ambulance',
1=>'Zoo');
$arr2= array(
20=>'abc',
21=>'def',
22=>'ghi',
1=>'jkl');
$arr_out = array();
foreach($arr as $key=>$el) {
$arr_out[$key] = $arr2[$key] ." ".$el;
}
var_dump($arr_out);
Obviously, you'll need to keep in mind to check whether the key exists in the second array so you do not get an error when accessing the value.

php warning -Invalid argument supplied for foreach()

i installed a project edusec school management system which work on php mysql yii framework.but when we copy it root directory and run index.php on local server it give following error ? what i do ??please help me?
PHP warning
Invalid argument supplied for foreach()
C:\xampp\htdocs\yiitest\protected\yii\framework\collections\CMap.php(288)
276 * #param array $b array to be merged from. You can specifiy additional
277 * arrays via third argument, fourth argument etc.
278 * #return array the merged array (the original arrays are not changed.)
279 * #see mergeWith
280 */
281 public static function mergeArray($a,$b)
282 {
283 $args=func_get_args();
284 $res=array_shift($args);
285 while(!empty($args))
286 {
287 $next=array_shift($args);
288 foreach($next as $k => $v)
289 {
290 if(is_integer($k))
291 isset($res[$k]) ? $res[]=$v : $res[$k]=$v;
292 else if(is_array($v) && isset($res[$k]) && is_array($res[$k]))
293 $res[$k]=self::mergeArray($res[$k],$v);
294 else
295 $res[$k]=$v;
296 }
297 }
298 return $res;
299 }
300
Stack Trace
#0
– C:\xampp\htdocs\yiitest\protected\yii\framework\base\CModule.php(468): CMap::mergeArray(array("class" => "CDbConnection"), 1)
463 foreach($components as $id=>$component)
464 {
465 if($component instanceof IApplicationComponent)
466 $this->setComponent($id,$component);
467 else if(isset($this->_componentConfig[$id]) && $merge)
468 $this->_componentConfig[$id]=CMap::mergeArray($this->_componentConfig[$id],$component);
469 else
470 $this->_componentConfig[$id]=$component;
471 }
472 }
473
#1
+ C:\xampp\htdocs\yiitest\protected\yii\framework\base\CComponent.php(153): CModule->setComponents(array("user" => array("allowAutoLogin" => true, "class" => "RWebUser"), "phpThumb" => array("class" => "ext.EPhpThumb.EPhpThumb"), "authManager" => array("class" => "RDbAuthManager"), "urlManager" => array("urlFormat" => "path", "rules" => array("<controller:\w+>/<id:\d+>" => "<controller>/view", "<controller:\w+>/<action:\w+>/<id:\d+>" => "<controller>/<action>", "<controller:\w+>/<action:\w+>" => "<controller>/<action>")), ...))
#2
+ C:\xampp\htdocs\yiitest\protected\yii\framework\base\CModule.php(483): CComponent->__set("components", array("user" => array("allowAutoLogin" => true, "class" => "RWebUser"), "phpThumb" => array("class" => "ext.EPhpThumb.EPhpThumb"), "authManager" => array("class" => "RDbAuthManager"), "urlManager" => array("urlFormat" => "path", "rules" => array("<controller:\w+>/<id:\d+>" => "<controller>/view", "<controller:\w+>/<action:\w+>/<id:\d+>" => "<controller>/<action>", "<controller:\w+>/<action:\w+>" => "<controller>/<action>")), ...))
#3
+ C:\xampp\htdocs\yiitest\protected\yii\framework\base\CApplication.php(144): CModule->configure(array("name" => "College Management System", "preload" => array("log"), "import" => array("application.models.*", "application.extensions.jtogglecolumn.*", "application.extensions.AjaxList.AjaxList", "application.components.*", ...), "modules" => array("gii" => array("class" => "system.gii.GiiModule", "password" => "secure", "generatorPaths" => array("ext.gii-extended"), "ipFilters" => array("127.0.0.1", "::1", "192.168.0.163")), 0 => "notification", 1 => "webservice", "rights" => array("install" => false, "superuserName" => "SuperAdmin", "authenticatedName" => "Authenticated", "userIdColumn" => "user_id", ...), ...), ...))
#4
+ C:\xampp\htdocs\yiitest\protected\yii\framework\YiiBase.php(127): CApplication->__construct("C:\xampp\htdocs\yiitest/protected/config/main.php")
#5
+ C:\xampp\htdocs\yiitest\protected\yii\framework\YiiBase.php(100): YiiBase::createApplication("CWebApplication", "C:\xampp\htdocs\yiitest/protected/config/main.php")
#6
– C:\xampp\htdocs\yiitest\index.php(18): YiiBase::createWebApplication("C:\xampp\htdocs\yiitest/protected/config/main.php")
13
14 // specify how many levels of call stack should be shown in each log message
15 defined('YII_TRACE_LEVEL') or define('YII_TRACE_LEVEL',3);
16
17 require_once($yii);
18 Yii::createWebApplication($config)->run();
19 ?>
20
The function array_shift() at line 287 has returned null, so $next is not an array.
And of course foreach() requires an array.
Validate the value before passing into the loop. This will catch when the array is empty.
$next=array_shift($args);
if ($next != null)
{
foreach($next as $k => $v)
{
// do things here
}
}

Categories