Nastavení ‚magických‘ vlastností DibiRow jako private

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

Ahoj, při práci s modelem používám vlastní třídu odvozenou od DibiRow (viz příklad TodoList v distribuci) a potřeboval bych všechny vlastnosti (které si ona třída nějak sama vytáhne z výsledků) nastavit jako private a navenek zpřístupnit jen moje vlastní gettery a settery.

Máte s tím někdo zkušenosti, pls?

P.S. Předpokládám, že ten příklad TodoList většina nettistů zná. Jestli není jasný co potřebuji, mohu to trochu víc rozvinout.

///edit: Tak to nastavení proměnných probíhá v konstruktoru DibiRow (https://api.dibiphp.com/…Row.php.html#21) na řádku 26, ale nevím jak je zprivátnit.

Editoval Šaman (13. 8. 2010 9:50)

westrem
Člen | 398
+
0
-

Vyuzi magicke metody __get() a __set().

Je trochu skoda, ze triedy v dibi nededia od Object pretoze by si mal vystarane, kazdopadne premenne si nastav na private. V __get() potom len skontroluj ci dana premenna naozaj ako private existuje a ak ano tak ju nastav ak nie, vyhod vynimku.

Šaman
Člen | 2635
+
0
-

Tak jsem to vyřešil, ale nevím jestli jsem to moc nezbastlil.

Pomocí setRowClass jsem si nastavil vlastní třídu která od DibiRow nedědí, ale v konstruktoru si ji vytváří.

<?php
class Location extends Object
{
  private $dibiRow = null;

  public function  __construct($locationData)
  {
    $this->dibiRow = new DibiRow($locationData);
  }

...

  /**
   * Vrátí název lokace
   * @return string název lokace
   */
  public function  getLabel()
  {
    return $this->dibiRow->label;
  }

}
?>

Zdá se, že všechno funguje, přístup k datům mám ošetřený přes gettery, IDE mi je našeptává, ALE v dokumentaci se u setRowClass (https://api.dibiphp.com/…ult.php.html#191) píše, že třída by měla být odvozena od DibiRow. Což není, pouze akceptuje stejný argument v konstruktoru. A otázka zní – vadí to, případně může to vadit při nějaké budoucí aktualizaci Nette?
Díky.

hrach
Člen | 1834
+
0
-

hm, měl by tám být nějaká interface…

Šaman
Člen | 2635
+
0
-

westrem napsal(a):

Vyuzi magicke metody __get() a __set().

Je trochu skoda, ze triedy v dibi nededia od Object pretoze by si mal vystarane, kazdopadne premenne si nastav na private. V __get() potom len skontroluj ci dana premenna naozaj ako private existuje a ak ano tak ju nastav ak nie, vyhod vynimku.

Aha, chvíli jsem nechápal jak nastavit na privátní, ale pak mi došlo, že pokud si je v mé odvozené třídě explicitně definuji, tak ten konstruktor mi je jenom naplní.
Existenci proměnné ani nemusím kontrolovat v __get(), ale stačí jen nevolat parent construct, a naplnit si proměnné ve vlastním konstruktoru sám.
Díky, to bude asi nejlepší řešení.

Editoval Šaman (13. 8. 2010 12:59)

westrem
Člen | 398
+
0
-

Problem bude v:

class DibiRow implements ArrayAccess, IteratorAggregate, Countable

Teda tvojmu objektu chybaju tieto metody, ktore sa mozu vyuzivat v DibiResult ak sa nemylim.

Viem, ze riesenie, ktore teraz navrhnem je z hladiska navrhu kodu typu prasackeho ale myslim si, ze v tomto pripade sa da nad tym prizmurit ocko.

Jednoducho do tvojej classy pridaj vsetko co je v DibiRow a zaroven si poded od Object, cim ziskavas presne co si chcel.

Osobne tak trochu nechapem preco aj DibiRow nededi od DibiObject, asi aby nevznikali nejake nezrovnalosti, ale clovek by to cakal.

Šaman
Člen | 2635
+
0
-

Díky, už jsem to změnil zpátky a moje třída dědí DibiRow.
Ve vlastním konstruktoru si kontroluji existenci proměnné a jen pokud už existuje, tak ji nastavuji.

<?php
class Location extends DibiRow
{

// seznam promennych ktere ocekavame v poli $locationData
// pokud nejaka promenna neni definovana, je vyhozena vyjimka
private $id_location;	// read only
private $label;
private $gps_n;
private $gps_e;
private $description;

/**
 * Location constructor
 * @param	array
 */
public function  __construct($locationData)
{
  foreach ($locationData as $key => $value)
  {
    if (property_exists('Location', $key))
    {
      $this->$key = $value;
    }
    else
    {
      throw new Exception("Pokus o přístup k neznámé proměnné: Location->$key");
    }
  }
}

/**
 * Vrátí ID lokace
 * @return	int	ID lokace
 */
public function  getId()
{
  return $this->id_location;
}

...
}
?>

Jediný problém, který ale zatím nehodlám řešit, je přístup k privátním proměnným přes pomocné metody třídy DibiRow. Např:

<?php
/**
 * Converts value to boolean.
 * @param  string key
 * @return mixed
 */
public function asBool($key)
{
  $value = $this[$key];
  if ($value === NULL || $value === FALSE) {
    return $value;
  } else {
    return ((bool) $value) && $value !== 'f' && $value !== 'F';
  }
}
?>

Editoval Šaman (13. 8. 2010 13:53)

Šaman
Člen | 2635
+
0
-

Tak po celodením testování si už připadám jako král Půlnoční země: ovdolávám co jsem odvolal a nařizuji co jsem nařídil :p

Pokud třída odvozená od DibiRow má všechny vlastnosti private, jeví se při iterování jako prázdná a tudíž ztrácí vlastnosti DibiRow. Přišel jsem na to při pokusu implementovat funkci save().

Vracím se tedy k mezivrstvě – třídě která od DibiRow nedědí, ale obaluje jí. DibiRow tak funguje jako přepravka na data (o něco chytřejší pole) a moje třída zaručí veškerou obsluhu. Viz. 3. příspěvek.

Ale abych výledky do mé vlastní třídy dostal, musím ji nastavit pomocí setRowClass(), kde je varování, že by tato měla být typu DibiRow.
Takže ještě jednou otázka: Vadí nějak Nette či Dibi to, že moje třída nemá vlastnosti ArrayAcess, Iterable apod.?
Mě to nijak neva – pro mě je to třída modelu, nikoliv výsledek dotazu. Zdá se mi, že jediné, jak musí být kompatibilní je, aby akceptovala stejná vstupní data, což splňuji.

westrem
Člen | 398
+
0
-

Šaman napsal(a):
Pokud třída odvozená od DibiRow má všechny vlastnosti private, jeví se při iterování jako prázdná a tudíž ztrácí vlastnosti DibiRow. Přišel jsem na to při pokusu implementovat funkci save().

To je nejake divne, nemal by tam dovod tohto chovania. Mozes ukazat implementaciu tej funkcii save?

v6ak
Člen | 206
+
0
-

Jako každopádně je to určitý hack a to, co nevadí dnes, může vadit zítra.
Dědíš-li z DibiRow (nebo obecně nějaké třídy) a přepisuješ-li konstruktor, měl bys volat parent constructor před prvním voláním metody předka (popř. přístupu k jeho vlastnosti), jinak bude tato metoda pracovat s potenciálně nekonzistentním objektem.
To, že nedědí z DibiRow, se také může časem vymstít. Dibi třeba může přidat možnost nějakého seskupení a nebude to fungovat.