Zum Inhalt springen

Collection wird nicht in DB geschrieben

Erstellt am 14. Februar 2014 · 8 Antworten · letzte Antwort am 21. Februar 2014

Tags: Extbase, Datenbank, Frage

kuwiano ·

Hallo ich versuche schon verzweifelt eine Collection in einer Datenbank zu speichern.
Zuerst der Ablauf.

Ich habe eine Flow Webseite auf der Mithilfe einer <select> View Studenten ausgewählt werden. Diese werden dan erfolgreich an meinen Controller weitergeben (Es wird ein ganzen Projekt Model übergeben).

Dort speichere ich diese in das Repository. (Mithilfe von repo.update())

Hier die Models:

<Project>

<?php
namespace BBS\ConnectYou\Domain\Model;

/*                                                                        *
 * This script belongs to the TYPO3 Flow package "BBS.ConnectYou".        *
 *                                                                        *
 *                                                                        */

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Query;
use TYPO3\Flow\Annotations as Flow;
use Doctrine\ORM\Mapping as ORM;

/**
 * Ein Projekt
 *
 * @Flow\Entity
 */
class Project {

	/**
	 * @var string
	 */
	protected $name;

	/**
	 * @var string
     * @Flow\Validate(type="Text")
     * @Flow\Validate(type="StringLength", options={ "minimum"=1, "maximum"=1000 })
     * @ORM\Column(length=1000)
	 */
	protected $description;

	/**
	 * @var string
	 */
	protected $type;

	/**
	 * @var \Doctrine\Common\Collections\Collection<\BBS\ConnectYou\Domain\Model\Assignments>
     * @ORM\Column(nullable=true)
	 */
	protected $assignments;

	/**
	 * @var \Doctrine\Common\Collections\Collection<\BBS\ConnectYou\Domain\Model\Student>
     * @ORM\OneToMany(mappedBy="project")
     * @ORM\Column(nullable=true)
	 */
	protected $team;

	/**
	 * @var \BBS\ConnectYou\Domain\Model\Client
     * @ORM\Column(nullable=true)
     * @ORM\ManyToOne
	 */
	protected $client;

	/*/**
	 * @var \BBS\ConnectYou\Domain\Model\Widgets
     * @ORM\OneToOne
     * @ORM\Column(nullable=true)
	 */
	/*protected $widgetsPublic;*/

	/*/**
	 * @var \BBS\ConnectYou\Domain\Model\Widgets
     * @ORM\OneToOne
     * @ORM\Column(nullable=true)
	 */
	/*protected $widgetsPrivate;*/

    /**
     * @var boolean
     */
    protected $archived;

    /**
     * @var string
     */
    protected $year;

    /**
     * @var \BBS\ConnectYou\Domain\Model\Teacher
     * @ORM\ManyToOne
     * @ORM\Column(nullable=true)
     */
    protected $caretaker;

    public function __construct() {
        $this->team = new ArrayCollection();
        $this->assignments = new ArrayCollection();
        $this->widgetsPrivate = new ArrayCollection();
        $this->widgetsPublic = new ArrayCollection();
    }

    /**
     * @return \BBS\ConnectYou\Domain\Model\Teacher
     */
    public function getCaretaker(){
        return $this->caretaker;
    }

    /**
     * @param \BBS\ConnectYou\Domain\Model\Teacher $caretaker
     */
    public function setCaretaker($caretaker){
        $this->caretaker = $caretaker;
    }

    /**
	 * @return string
	 */
	public function getName() {
		return $this->name;
	}

	/**
	 * @param string $name
	 * @return void
	 */
	public function setName($name) {
		$this->name = $name;
	}

	/**
	 * @return string
	 */
	public function getDescription() {
		return $this->description;
	}

	/**
	 * @param string $description
	 * @return void
	 */
	public function setDescription($description) {
		$this->description = $description;
	}

	/**
	 * @return string
	 */
	public function getType() {
		return $this->type;
	}

	/**
	 * @param string $type
	 * @return void
	 */
	public function setType($type) {
		$this->type = $type;
	}

	/**
	 * @return \Doctrine\Common\Collections\Collection<\BBS\ConnectYou\Domain\Model\Assignments>
	 */
	public function getAssignments() {
		return $this->assignments;
	}

	/**
	 * @param \Doctrine\Common\Collections\Collection<\BBS\ConnectYou\Domain\Model\Assignments> $assignments
	 * @return void
	 */
	public function setAssignments($assignments) {
            $this->assignments = $assignments;
	}

	/**
	 * @return \Doctrine\Common\Collections\Collection
	 */
	public function getTeam() {
		return $this->team;
	}

    /**
     * @param \Doctrine\Common\Collections\Collection<\BBS\ConnectYou\Domain\Model\Student> $team
     * @return void
     */
    public function setTeam($team) {
        $this->team->clear();
        foreach($team as $t){
            $this->addTeammember($t);
        }
    }

    /**
     * @param \BBS\ConnectYou\Domain\Model\Student $student
     * @return void
     */
    public function addTeammember($student){
        $student->setProject($this);
        $this->team->add($student);
    }

    /**
	 * @return \BBS\ConnectYou\Domain\Model\Client
	 */
	public function getClient() {
		return $this->client;
	}

	/**
	 * @param \BBS\ConnectYou\Domain\Model\Client $Client
	 * @return void
	 */
	public function setClient($Client) {
		$this->client = $Client;
	}

	/**
	 * @return \Doctrine\Common\Collections\Collection<\BBS\ConnectYou\Domain\Model\Widget>
	 */
	public function getWidgetsPublic() {
		return $this->widgetsPublic;
	}

	/**
	 * @param \Doctrine\Common\Collections\Collection<\BBS\ConnectYou\Domain\Model\Widget> $widgetsPublic
	 * @return void
	 */
	public function setWidgetsPublic(\Doctrine\Common\Collections\Collection $widgetsPublic = NULL) {
        if($widgetsPublic->isEmpty()) // Prüft ob die Collection leer ist wenn ja wird NULL reingeschrieben (und keine leere Collection!)
		    $this->widgetsPublic = NULL;
        else
            $this->widgetsPublic = $widgetsPublic;
	}

	/**
	 * @return \Doctrine\Common\Collections\Collection<\BBS\ConnectYou\Domain\Model\Widget>
	 */
	public function getWidgetsPrivate() {
		return $this->widgetsPrivate;
	}

	/**
	 * @param \Doctrine\Common\Collections\Collection<\BBS\ConnectYou\Domain\Model\Widget> $widgetsPrivate
	 * @return void
	 */
	public function setWidgetsPrivate(\Doctrine\Common\Collections\Collection $widgetsPrivate = NULL) {
        if($widgetsPrivate->isEmpty()) // Prüft ob die Collection leer ist wenn ja wird NULL reingeschrieben (und keine leere Collection!)
		    $this->widgetsPrivate = NULL;
        else
            $this->widgetsPrivate = $widgetsPrivate;
	}

    /**
     * @param bool $archived Archiviert?
     * @return void
     */
    public function setArchived($archived){
        if($archived != NULL)
            $this->archived = $archived;
        else
            $this->archived = 0;
    }

    /**
     * @return bool
     */
    public function getArchived(){
        return $this->archived;
    }

    /**
     * @param string $year
     * @return void
     */
    public function setYear($year){
        $this->year = $year;
    }

    /**
     * @return bool
     */
    public function getYear(){
        return $this->year;
    }
}
?>

<Student>

<?php
namespace BBS\ConnectYou\Domain\Model;

/*                                                                        *
 * This script belongs to the TYPO3 Flow package "Party".                 *
 *                                                                        *
 * It is free software; you can redistribute it and/or modify it under    *
 * the terms of the GNU Lesser General Public License, either version 3   *
 * of the License, or (at your option) any later version.                 *
 *                                                                        *
 * The TYPO3 project - inspiring people to share!                         *
 *                                                                        */

use Doctrine\ORM\Mapping as ORM;
use TYPO3\Flow\Annotations as Flow;

/**
 * Ein Student
 *
 * @Flow\Entity
 */
class Student extends \TYPO3\Party\Domain\Model\AbstractParty {

	/**
	 * @var string
	 */
	protected $fname;

    /**
     * @var string
     */
    protected $lname;

    /**
     * @var string
     */
    protected $class;

    /**
	 * @var string
	 */
	protected $email;

    /**
     * @var \BBS\ConnectYou\Domain\Model\Project
     * @ORM\ManyToOne(inversedBy="team")
     */
    protected $project;

    /**
     * @var string
     * @FLow\Identity
     */
    protected $bbsid;

    /**
	 * Constructs this Person
	 *
	 */
	public function __construct() {
		parent::__construct(); // für AbstractParty den Konstruktor ausführen
	}

    /**
     * Setzt die bbsid
     * @param string $bbsid
     * @return void
     */
    public function setBbsid($bbsid){
        $this->bbsid = $bbsid;
    }

    /**
     * Gibt die bbsid
     * @return string BBSID
     */
    public function getBbsid(){
        return $this->bbsid;
    }

    /**
     * Setzt das Projekt
     *
     * @param \BBS\ConnectYou\Domain\Model\Project
     * @return void
     */
    public function setProject($project = NULL){
        $this->project = $project;
    }

    /**
     * Gibt das Projekt zurück
     *
     * @return \BBS\ConnectYou\Domain\Model\Project
     */
    public function getProject(){
        $this->project;
    }

    /**
     * Setzt die Klasse
     *
     * @param string $class
     */
    public function setClass($class){
        $this->class = $class;
    }

    /**
     * Gibt die Klasse Zurück
     *
     * @return string Klasse
     */
    public function getClass(){
        return $this->class;
    }

    /**
	 * Setzt den Vornamen
	 *
	 * @param string $fname der neue Vorname des Studenten
	 * @return void
	 */
	public function setFname($fname) {
		$this->fname = $fname;
	}

	/**
	 * Gibt den Vornamen zurück
	 *
	 * @return string Vorname des Studenten
	 */
	public function getFname() {
		return $this->fname;
	}

    /**
     * Setzt den Nachnamen
     *
     * @param string $lname Nachname des Studenten
     * @return void
     */
    public function setLname($lname) {
        $this->lname = $lname;
    }

    /**
     * Gibt Familienname zurück
     *
     * @return string Nachname des Studenten
     */
    public function getLname() {
        return $this->lname;
    }

    /**
     * Gibt den ganzen Namen Zurück (fname . " " . lname => "Dominik Falkner"
     *
     * @return string der ganze Name des Studenten
     */
    public function getName(){
        return $this->fname . " " . $this->lname;
    }

    /**
	 * Gibt die Email zurück
	 *
	 * @return string
	 */
	public function getEmail() {
		return $this->email;
	}

	/**
	 * Setzt die Email
	 *
	 * @param string The electronic address
	 * @return void
	 */
	public function setEmail($email) {
		$this->email = $email;
	}
}
?>

Jetzt die <f:form... von der geschickt wird

 <label for="team">Team (Mit STR Auswählen)</label><br />
        <f:form.select name="team[]" property="team" options="{students}" multiple="multiple" optionValueField="{student}" optionLabelField="name" /><br />

Und die Controller Aktion (Update)

    public function initializeUpdateAction(){
        $pmc = $this->arguments['project']->getPropertyMappingConfiguration();
            $pmc->forProperty('team.*') // Sagt den Converter er soll zu Collection konvertieren
                ->setTypeConverterOption('TYPO3\Flow\Property\TypeConverter\PersistentObjectConverter', \TYPO3\Flow\Property\TypeConverter\PersistentObjectConverter::CONFIGURATION_TARGET_TYPE, '\Doctrine\Common\Collections\Collection');
            $pmc->forProperty('team.*') // Sagt es darf ein neue Collection erstellt werden
                ->setTypeConverterOption('TYPO3\Flow\Property\TypeConverter\PersistentObjectConverter', \TYPO3\Flow\Property\TypeConverter\PersistentObjectConverter::CONFIGURATION_CREATION_ALLOWED, TRUE);
            $pmc->forProperty('team.*')
                ->setTypeConverterOption('TYPO3\Flow\Property\TypeConverter\PersistentObjectConverter', \TYPO3\Flow\Property\TypeConverter\PersistentObjectConverter::CONFIGURATION_MODIFICATION_ALLOWED, TRUE);
    }

	/**
	 * @param \BBS\ConnectYou\Domain\Model\Project $project
	 * @return void
	 */
	public function updateAction(\BBS\ConnectYou\Domain\Model\Project $project) {

		$this->projectRepository->update($project);
		#$this->addFlashMessage('Updated the project.');
		$this->redirect('index');
	}

Bräuchte dringend eine Lösung.

Schon einmal danke für die Hilfe.

Schweriner ·

Du musst die Studenten auch an deinen Controller übergeben und mit $project->setTeam() oder addTeammember die Mitglieder hinzufügen und dein Repository danach updaten.

kuwiano ·

Aber das Team befindet sich schon in $project.

hier der Veränderte Code der Update:

	/**
	 * @param \BBS\ConnectYou\Domain\Model\Project $project
	 * @return void
	 */
	public function updateAction(\BBS\ConnectYou\Domain\Model\Project $project) {
        echo get_class($project->getTeam()) . "<br />";
        foreach($project->getTeam() as $t){
            echo get_class($t) . "<br />";
            echo $t->getName() . "<br />";
        }
		$this->projectRepository->update($project);
		#$this->addFlashMessage('Updated the project.');
		#$this->redirect('index');
	}

und hier der Output:

Doctrine\ORM\PersistentCollection
BBS\ConnectYou\Domain\Model\Student
Vorname Nachname
BBS\ConnectYou\Domain\Model\Student
Vorname Mittelname Nachname

(Die Namen hab ich aus Datenschutzgründen entfernt ... es funktioniert allerdings einwandfrei)

Danach Update ich die Repo.... und in der DB passiert nichts. Andere Felder wie z.B.: caretaker funktioniert einwandfrei.

Hier nochmal der Ganze Code der Form.

<f:form action="update" name="project" object="{project}" >
  <label for="name">Name</label><br />
  <f:form.textfield property="name" /><br />

  <label for="description">Beschreibung</label><br />
  <f:form.textarea property="description" /><br />

  <label for="type">Typ</label><br />
  <f:form.textfield property="type" /><br />

  <f:security.ifHasRole role="BBS.ConnectYou:Teacher">
    <f:then>
        <label for="team">Team (Mit STR Auswählen)</label><br />
        <f:form.select name="team[]" property="team" options="{students}" multiple="multiple" optionValueField="{student}" optionLabelField="name" /><br />

        <label for="client">Client</label><br />
        <f:form.select name="client" property="client" options="{clients}" optionValueField="{client}" optionLabelField="name" prependOptionLabel="- Wähle -" /><br />

        <label for="caretaker">Betreuungslehrer</label><br />
        <f:form.select name="caretaker" property="caretaker" options="{teachers}" optionValueField="{teacher}" optionLabelField="name" prependOptionLabel="- Wähle -" />
      </f:then>
    </f:security.ifHasRole>
  <f:form.submit value="Speichern" class="btn btn-large btn-block btn-primary"/>
</f:form>
Unbekannter Benutzer ·

Doctrine verlangt immer, dass bei einer ManyToOne Relation dort und nicht in der Gegenseite gespeichert wird. Du musst also in setTeam() über die Persons iterieren und bei denen das $this (also das Projekt setzen, dann sollte es klappen.

kuwiano ·

Hallo danke für die Antwort.

Ich habe hier nun den setter im Student Model:

    /**
     * @param \Doctrine\Common\Collections\Collection $team
     * @return void
     */
    public function setTeam($team) {
        foreach($team as $t){
            // Code
        }
    }

Allerdings verstehe ich nicht ganz wie ich jetzt im Studenten Model das Projekt setzen soll? Ich bekomme hier ja nicht das Projekt und $this ist ja die erste Person in der Collection?

kuwiano ·

Und wieder hier...

Die Methode fürs Team im Project Model sieht so aus:

    /**
     * @param \Doctrine\Common\Collections\Collection<\BBS\ConnectYou\Domain\Model\Student> $team
     * @return void
     */
    public function setTeam($team) {
        $this->team->clear();
        foreach($team as $t){
            $this->addTeammember($t);
            $t->setProject($this);
        }
    }

Nachher kann ich in der UpdateAction den User vom Projekt auslesen und dessen Projekt auch!

        foreach($project->getTeam() as $t){
           // echo $t->getAccounts()[0]->getAccountIdentifier();
            echo $t->getName() . " - ";
            echo $t->getProject()->getName() . "<br />";

        }

Output:
VN NM - Projectname
VN MN NM - Projectname

Danach verspeichere ich das Projekt:

        $this->projectRepository->update($project);

Und in der Datenbank ändert sich nichts. Ich habe zwar ein jointable für students und project und die Studenten haben auch eine Spalte project allerdings sind die alle leer (NULL). Es ändert sich auch nichts wenn ich die Studenten über studentrepo verspeichere.

morlock · · Beste Antwort

Ich fuchse mich selbst gerade in Flow ein - soweit ich sehe sollte aber folgendes reichen:

1. In der UpdateAction sicherstellen, dass bei den Studenten das Project gesetzt wird:

public function updateAction(\BBS\ConnectYou\Domain\Model\Project $project) {

foreach($project->getTeam() as $t){
$t->setProject($project);
}

2. Sicherstellen, dass Doctrine beim Speichern des Projekts automatisch die Studenten mit speichert (neu wäre das cascade={"persist"}):

	/**
* @var \Doctrine\Common\Collections\Collection<\BBS\ConnectYou\Domain\Model\Student>
  * @ORM\OneToMany(mappedBy="project",cascade={"persist"})
  * @ORM\Column(nullable=true)
*/
protected $team;

Ich hoffe, ich habe das Problem richtig verstanden und das hilft etwas.

Gruß,
Christian

morlock ·

Kein Problem. Markier' doch einfach meinen Post als "Lösung" (über den Pfeil), dann ist es in der Thread-Übersicht direkt erkennbar.