ActiveRow – jak zjistit existenci sloupce?

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
OK3
Člen | 91
+
0
-

Podle dokumentace by mělo fungovat $row->offsetExists('sloupec'), jenže pro sloupec s hodnotou NULL to vrací FALSE.

Používám sqlite3 driver, jestli to hraje roli.. Díky za vysvětlení ;)

petr.jirous
Člen | 128
+
0
-

a co isset($row[‚sloupec‘])?

OK3
Člen | 91
+
0
-

Díky za reakci, bžel to nefunguje. isset vrací pro hodnotu NULL též FALSE, což je myslím napsáno i v dokumentaci.

Zatím to řeším blokem try/catch, jen se divím, proč se nejde na existenci sloupce prostě nějakým jednoduchým způsobem zeptat? Našel jsem pár let staré diskuse, kde se to řešilo, ovšem vyšlo to jaksi doztracena.

<?php
// v obálce nad ActiveRow...
try {
	return $this->row->$key;
} catch (\Nette\MemberAccessException $e) {
	// vyhodit vlastní výjimku
}
?>
uestla
Backer | 799
+
+3
-

Zjišťovat existenci databázového sloupce na instanci ActiveRow považuju za nešťastné z následujících důvodů:

  • ActiveRow představuje výsledek Table\Selection dotazu
  • může obsahovat aliasované sloupce (xyz AS abc)
  • na úrovni ActiveRow se mohou cachovat jen použité sloupce (pokud nepoužiješ explicitně $selection->select('xyz'))

Pokud potřebuješ zjistit, zda sloupec existuje v určité tabulce, je IMHO vhodnější využít Nette\Database\Structure:

/* $structure instanceof Nette\Database\Structure */
$columnExists = in_array('my_column', array_column($structure->getColumns('my_table'), 'name'), TRUE);

EDIT

Popř. pokud ti nejde o existenci sloupce v tabulce, ale potřebuješ jen zjistit, že daná „property“ (nejde přímo o property třídy) na ActiveRow existuje, zkusil bych

$columnExists = array_key_exists('my_column', $row->toArray(), TRUE);

Editoval uestla (28. 3. 2016 13:33)

David Matějka
Moderator | 6445
+
0
-

Co se konkretne snazis vyresit, ze potrebujes vedet, jestli sloupec existuje? pripada mi, ze se spis snazis vyresit nejaky spatny navrh db/aplikace.

Jinak ActiveRow ma funkci accessColumn, ktera vrati bool dle toho, jestli sloupec existuje. Ale pozor je interni (tzn snadno muze dojit ke smazani nebo ke zmene chovani bez ohledu na BC)!

OK3
Člen | 91
+
0
-

Díky @uestla za elaboraci nad tématem. Asi jsem se na začátku nevyjádřil přesně. Nejde ani tak o zjištění existence sloupce v tabulce jako o zjistění existence odvozeného atributu v objektu ActiveRow. Jednotlivé modely netuší nic o své struktuře a požadavané atributy vytahují z „ze zdroje“ on-the-fly. Pokud v kódu požaduji atribut, který není k dispozici, uvědomí mě o tom výjimka. Cílem je mít přehledný a jednoduchý kód (bez zbytečné práce třeba ve formě převádění objektu na pole a zjišťování těch věcí na něm).

@DavidMatějka Mám jednoduchou aplikaci, jejíž modely jsou obálky nad ActiveRow. Pro přístup k hodnotám se používá magický getter a setter. Konkrétní modely (potomci BaseModel) pak obsahují jen anotace @property (pro napovíddání v IDE) a případně implementují jen další gettery a settery, když jsou potřeba.

(kód je osekán)

<?php

namespace App\Models;

use Nette\Database\Table\ActiveRow;
use App\Error;

class BaseModel
{
	/** @var \Nette\Database\Table\ActiveRow */
	protected $source;

	/**
	 * @param ActiveRow $row
	 */
	public function __construct(ActiveRow $row)
	{
		$this->source = $row;
	}

	/**
	 * @param string $key Attribute
	 * @return mixed
	 * @throws Error if property or getter is missing
	 */
	public function __get($key)
	{
		// getter lookup
		$getter = sprintf('get%s', ucfirst($key));
		if (method_exists($this, $getter)) {
			return $this->$getter();
		}
		$booler = sprintf('is%s', ucfirst($key));
		if (method_exists($this, $booler)) {
			return $this->$booler();
		}

		// tady by se mi víc líbilo něco jako
		if ($this->source->columnExists($key)) {	// stačilo by i offsetExists($key)
			return $this->source->$key;
		}

		throw new Error(sprintf('No such attribute (getter): %s (%s, %s)', $key, $getter, $booler));


		// ale místo toho musím mít tohle
		try {
			return $this->source->$key;
		} catch (\Nette\MemberAccessException $e) {
			throw new Error(...);
		}
	}

}
?>

Editoval OK3 (30. 3. 2016 14:39)

David Matějka
Moderator | 6445
+
0
-

V tomhle pripade je spravne reseni chytat vyjimku a vyhodit vlastni (s tim, ze bys mel original vyjimku uvest do previous)

OK3
Člen | 91
+
0
-

Dobrá, díky za radu, zařídím se podle toho ;)