Entita Post a jeho metadata z druhé tabulky

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

Ahoj,

mám entitu Post, která reprezentuje příspěvek. Může existovat několik druhů příspěvků (textový, s fotkou, ale potom i velmi specifické). V databázi jsem se to rozhodl řešit po vzoru WordPressu, takže mám dvě tabulky:

*post*
- id
- user_id
- type
- modified
- status
- created_at
*postmeta*
- id
- post_id
- meta_key
- meta_value

Každý příspěvek bude mít vlastnosti z tabulky post a k tomu vždy libovolné vlastnosti z tabulky postmeta.

Příklad:

Příspěvek má všechny hodnoty z tabulky post a k tomu existují pro tento příspěvek dva zápisy v tabulce postmeta:
1) meta_key = image_path, meta_value = logo.png
2) meta_key = image_description, meta_value = "Logo"

Využívám kdyby/Doctrine a hledám nejlepší způsob, jak to namapovat, aby se mi s tím co nejlépe pracovalo.

Editoval David Kregl (23. 11. 2016 15:55)

srigi
Nette Blogger | 558
+
0
-

Akurat vcera som nasiel Persisting Value Objects in Doctrine Mozno sa to bude hodit.

newPOPE
Člen | 648
+
0
-

@DavidKregl treba sa to pozerat z uplne ineho uhla a to aplikacneho. Ono to, ze si zacal tym, ze si si navrhol tabulky si to v podstate zobral z uplne zlej strany.

Skus to otocit a navrhnut si ako by sa ti s tym pracovalo najlepsie. To co popisuje @srigi su Value Objecty ktore su z principu immutable cize nemenne (idu len vytvorit alebo zahodit). Osobne si myslim, ze to nebude tvoj pripad :).

Mne osobne by sa s tym napr. pracovalo dobre takto:

// hlavne properties
$post->type(); // vrati mi type
$post->status(); // vrati mi status

// tvoje metadata
$post->meta(PostMeta::IMAGE_PATH);
$post->meta(PostMeta::IMAGE_DESCRIPTION);

No a teraz je otazka ako to implementovat aby si to vedel ukladat. Kludne by som to urobil ako JSON (v MySQL napr. ako TEXT, v 5.7+ mozes vyuzit JSON type) jeho properties budu spravovane samotnou entitou. Pri nacitani si to mozes naparsovat napriklad aby si to mal ready. Pred ulozenim zase vratit spat na JSON.

Tie meta data proste ber ako nieco co tam chces ale nechces s tym pracovat v DB (vyhladavat, agregovat a neviem co este.)

Editoval newPOPE (23. 11. 2016 20:34)

David Kregl
Člen | 52
+
0
-

Ahoj @newPOPE!

Díky! Tvůj přístup vypadá super. Asi jsem se nechal okouzlit tím WP návrhem a už jsem nepřemýšlel nad tím, jak se mi s tím bude pracovat. Takže, pokud tomu správně rozumím, mám si v tabulce post vytvořit sloupeček meta, který bude držet JSON a ten bude uchovávat potřebné meta informace?

Potom budu mít Entitu PostMeta, která bude mít definované konstanty mnou známých meta informací. Ale nerozumím tomu, jak ta entita bude přebírat ten JSON.

Můžeš mě ještě trochu popostrčit?

newPOPE
Člen | 648
+
0
-

@DavidKregl ono tych pristupov ako to urobit je viac ale povedzme ze chces v DB mat JSON.

Tak napr. takto (viac o Doctrine Type json http://docs.doctrine-project.org/…e/types.html#json):

class Post {

  /**
   * @Column(type="json")
   * @var array
   */
  private $meta;

  public function __construct ()  {
    $this->meta = [];
  }

  public function meta ($identificator) {
    return isset($this->meta[$identificator]) ? $this->meta[$identificator] : null;
  }

  public function updateMeta ($identificator, $value) {
	$this->meta[$identificator] = $value;
  }
}

// keby si to chcel mat vseobecnejsie tak napr. class Meta (pozor toto nie je entita ale len nieco ako library class ktora ti pomoze k tomu aby si nemusel vypisovat stringy)
class PostMeta {

  const IMAGE_PATH = 'imagePath';
  const IMAGE_DESCRIPTION = 'imageDescription';
}

Advanced: keby si chcel este ist v tomto dalej tak teraz by si mohol brat jeden zaznam v $meta ako ValueObject. Pekny priklad je taky image ktory ma $path a $description

Editoval newPOPE (24. 11. 2016 8:59)

leninzprahy
Člen | 150
+
+2
-

Možná bych se zkusil kouknout na Inheritance Mapping a zkombinovat to.

Např takto:

/**
 * @Entity
 * @InheritanceType("SINGLE_TABLE")
 * @DiscriminatorColumn(name="type", type="string")
 * @DiscriminatorMap({"text" = "PostText", "image" = "PostImage", "another" = "PostAnother", ...})
 */
class Post {

	/**
	 * @Column(type="string")
	 * @var string
	 */
	private $status;

	...

	/**
	 * @Column(type="json")
	 * @var array
	 */
	private $meta;

	protected function getMeta ($identificator) {
		return isset($this->meta[$identificator]) ? $this->meta[$identificator] : null;
	}

	protected function updateMeta ($identificator, $value) {
		$this->meta[$identificator] = $value;
	}
}


/**
 * @Entity
 */
class PostImage extends Post {

    const IMAGE_PATH        = 'imagePath';
	const IMAGE_DESCRIPTION = 'imageDescription';


	public function setImagePath($path) {
		$this->updateMeta(self::IMAGE_PATH, $path);
	}

	public function getImagePath() {
		return $this->getMeta(self::IMAGE_PATH);
	}

	...
}

Tabulka bude stejná, ale rozhraní entit bude pevně dané.