Bug found, exception when using Nette\Database\Table\Selection::fetchPairs with null parameters

kasi
Member | 2
+
0
-

When using

Nette\Database\Table\Selection::fetchPairs(string|int|null $key = null, string|int|null $value = null)

, i expected that the function result will be something like:

array<int, {col1, col2, col3, ...}>

but instead of this, I am getting MemberAccessException, because when null is passed as key to function

 Nette/Database/Helpers::toPairs(array $rows, $key = null, $value = null)

function will assign first array key as key variable which is in this case table (because ActiveRow keys are table, data, dataRefreshed)

m.brecher
Generous Backer | 758
+
0
-

@kasi

Hi,

I do not understand the problem in full, but I´m standardly using Selection::fetchPairs() for getting data for form input select, where are data in form of array required. So I typically use it like this:

   $selectItems = $this->database->table('tableName')->where(...)->order(...)->fetchPairs('id', 'title');

   .....

   $form->addSelect('field', 'Caption', $selectItems);

This works without any problems.

The data $selectItems look like this:

[
   '2' => 'green',   //  id => title
   '6' => 'yellow',
   .....
]

But you may be use the method fetchPairs() in other way, send eventually more code samples in case you will not solve the problem ;).

m.brecher
Generous Backer | 758
+
0
-

@kasi

i expected that the function result will be something like: array<int, {col1, col2, col3, …}>

No, I dont think so, as the name of method says the result is simple associative php array like array<col1, col2> the pair means pair of columns col1 + col2

To get result like you expect, you have to use another method Selection::fetchAssoc() ;)

Last edited by m.brecher (2023-03-09 13:23)

kasi
Member | 2
+
0
-

m.brecher wrote:

@kasi

Hi,

I do not understand the problem in full, but I´m standardly using Selection::fetchPairs() for getting data for form input select, where are data in form of array required. So I typically use it like this:

   $selectItems = $this->database->table('tableName')->where(...)->order(...)->fetchPairs('id', 'title');

   .....

   $form->addSelect('field', 'Caption', $selectItems);

This works without any problems.

The data $selectItems look like this:

[
   '2' => 'green',   //  id => title
   '6' => 'yellow',
   .....
]

But you may be use the method fetchPairs() in other way, send eventually more code samples in case you will not solve the problem ;).

So for example if you will have table

id username password
1 user1 hash1
2 user2 hash2

and i want to fetch normal indexed array, i need to write something like this

public function arrayFrom(Nette\Database\Table\Selection $selection):array {
        $rows = [];
        while ($row = $selection->fetch()) {
            $rows[] = iterator_to_array($row->getIterator());
        }
        return $rows;
    }

which will produce following array ->

[
	0 => [
		'id' => 1,
		'username' => user1,
		'password' => hash1,
	],
	1 => [
		'id' => 2,
		'username' => user2,
		'password' => hash2,
	],
]

And i think it should work like this if you dont push null parameters to

Nette\Database\Table\Selection::fetchPairs(string|int|null $key = null, string|int|null $value = null)

because when you will write something like this:

$rows = $this->database->table('user')->select('id, username')->fetchAll();
$rowsOnlyData = [
    1 => [
        'data' => [
            'id' => 1,
            'username' => 'user1'
        ]
    ],
    2 => [
        'data' => [
            'id' => 2,
            'username' => 'user2'
        ]
    ]
];
$result = Nette\Database\Helpers::toPairs($rowsOnlyData);

then the $result will be:

[
	0 => [
		'id' => 1,
		'username' => 'user1',
	],
	1 => [
		'id' => 2,
		'username' => 'user2',
	],
]

In the other words, if function

 Nette\Database\Helpers::toPairs(array $rows, $key = null, $value = null)

does not get parameters $key and $value it will take it from array_keys.

I think, it is confusing. Function

Nette\Database\Table\Selection::fetchPairs(string|int|null $key = null, string|int|null $value = null)

should not has null values, or may be customized in working way.

m.brecher
Generous Backer | 758
+
+1
-

Hi,

now I understand in full your post. You complain, that Nette\Database\Helpers::toPairs() works in a different way than Nette\Database\Table\Selection::fetchPairs().

I havent seen yet Nette\Database\Helpers and found it only in api documentation:

https://api.nette.org/…Helpers.html

but not in the standard documentation https://doc.nette.org/…ase/explorer

In my opinion Nette\Database\Helpers are not designed for public using, but is merely an internal package for another Nette packages.

You need not Nette\Database\Helpers, everything you need in data manipulation you'll find in standard documentation.

You are right that Selection::fetchPairs() throws exception if you call it with no parameters, but such a call hase no sence. And Nette\Database\Helpers nobody use, or at least it is not intention to be used publically.

Look how Selection::fetchPairs() works:

$table = $this->database->table('test');

$table->fetchPairs(key: 'id', value: 'name'); // [0 => 'Karel', 1 => 'Josef']

$table->fetchPairs(key: 'id');          // [1 => ActiveRow, 2 => ActiveRow]

$table->fetchPairs(value: 'name');// [0 => 'Karel', 1 => 'Josef']

$table->fetchPairs();     // Exception: Cannot read an undeclared column

$table->fetchAssoc('id'); // [1 => array, 2 => array]

So any type of output data you need you can get it. And call $table->fetchPairs() does not make sense.

Last edited by m.brecher (2023-03-11 13:51)