Zwischentabelle automatisch füllen?

Also angenommen ich habe folgende Tabellen:

[sql]

±------+ ±------------+ ±-------+

| Image | | ImageViewer | | Viewer |

±------+ ±------------+ ±-------+

| id | | imageId | | id |

±------+ | viewerId | | ip |

       +-------------+  | time   |


                        +--------+

[/sql]

Angenommen meine Models sehen so aus:




class Image extends CActiveRecord

{

  public function relations()

  {

    return array(

      'viewer' => array(self::HAS_MANY, 'ImageViewer', 'imageId)'),

    );

  }

}


class ImageViewer extends CActiveRecord

{

  public function relations()

  {

    return array(

      'image' => array(self::BELONGS_TO, 'Image', 'imageId',),

      'viewer' => array(self::HAS_MANY, 'Viewer', 'viewerId)'),

    );

  }

}


class Viewer extends CActiveRecord

{

  public function relations()

  {

    return array(

      'views' => array(self::HAS_MANY, 'ImageViewer', 'viewerId)'),

    );

  }

}



[list=1]

[*]So. Wenn jetzt ein Besucher sich ein Bild anschaut soll überprüft werden ob der Besucher innerhalb der letzten 24 Stunden bereits andere Bilder angesehen hat. Wenn nein soll der Besucher angelegt werden.

(Klartext: Wenn die IP-Adresse innerhalb der letzten 24 Stunden nicht als Besucher aufgetaucht ist, wird ein neuer Eintrag in der Tabelle Viewer erstellt)

[*]Danach soll überprüft werden ob er genau DIESES Bild schoneinmal gesehen hat. Wenn nicht soll ein entsprechender Eintrag in der Zwischentabelle erfolgen.

(Klartext: Wenn ImageViewer(imageId, viewerId) schon existiert muss/darf nichts passieren. Sonst den Eintrag einfügen)

[/list]

Aber irgentwie habe ich das Gefühl dass das keine Aufgabe für den Controller ist, sondern vielmehr für das Model. Ich weiß nur nich wie ich das mit Yii umsetzen kann?

Also #1 würde ich noch im Controller umsetzen:




// Die nötigen scopes vorrausgesetzt

if(Viewer::model()->last24h()->findByAttributes(array('ip' => Yii::app()->getRequest()->userHostAddress))->count() == 0)

{

  $viewer = // ... Neuen viewer anlegen

}



Aber kann man #2 nicht irgentwie im model umsetzen? Ich meine, ich habe grade irgentwo einen riesen Denkfehler. Denn auf die "Pflege" der Zwischentabellen sollte ich doch eigentlich mit activerecord verzichten können - oder?!

Mach doch eine trackView() Methode im Model. Im controller callst du dann einfach $imageModel->trackView(). Anlegen musst du ImageViewer dann natürlich selber in der Methode. Alles weitere lässt sich dann aber mit den beforeX/afterX Methoden bzw. direkt über die Datenabank lösen.

Hmm ok, Danke… habe es nun so:

[PHP]

class Image extends CActiveRecord

{

public function relations()


{


	return array(


		'uploader' => array(self::BELONGS_TO, 'User', 'owner',),


		'viewers' => array(self::HAS_MANY, 'ImageViewer', 'imageId'),


	);


}





public function logView()


{


	$viewer = Viewer::getCurrentViewer();


	


	if(ImageViewer::model()->findByAttributes(array('imageId' => $this->id, 'viewerId' => $viewer->id)) === NULL)


	{


		$imageViewer = new ImageViewer;


		$imageViewer->imageId = $this->id;


		$imageViewer->viewerId = $viewer->id;


		$imageViewer->save();


	}


}

}

class ImageViewer extends CActiveRecord

{

public function relations()


{


	return array(


		'image' => array(self::BELONGS_TO, 'Image', 'imageId',),


		'viewer' => array(self::BELONGS_TO, 'Viewer', 'viewerId'),


	);


}

}

class Viewer extends CActiveRecord

{

public function relations()


{


	return array(


		'images' => array(self::HAS_MANY, 'ImageViewer', 'viewerId'),


	);


}





public function scopes()


{


	return array(


		'last24' => array(


			'condition' => '`time` >= ' . (time() - 60 * 60 * 24)


		),


	);


}





public static function getCurrentViewer()


{


	$ip = sprintf('%u', ip2long(Yii::app()->getRequest()->userHostAddress));


	$viewer = Viewer::model()->last24()->findByAttributes(array('ip' => $ip));


	


	if($viewer === NULL)


	{


		$viewer = new Viewer;


		$viewer->save();


	}


	


	return $viewer;


}





protected function beforeSave()


{


	if($this->isNewRecord && !$this->hasErrors())


	{


		$this->ip = sprintf('%u', ip2long(Yii::app()->getRequest()->userHostAddress));


		$this->time = time();


	}


	


	return parent::beforeSave();


}

}

[/PHP]

Zum loggen rufe ich dann einfach $image->logView() auf.

Ist das nach dem MVC Prinzip und den Möglichkeiten von Yii richtig umgesetzt? Ist die static methode im Viewer model so sinnvoll?

Oder sollte ich die Überprüfung in Image::logView() ob ein Eintrag in der Zwischentabelle vorhanen ist lieber nach Viewer auslagern? (Also im Image model dann: if(!$viewer->hasViewed($this->id)) )

@Coksnuss:

Sieht super aus und ist voll nach MVC. Eine gute Strategie ist hier das “Fat model - Thin controller”-Prinzip. Also möglichst viel in die Models zu packen und die Controlleractions schlank zu halten. Wo du was in deine Models packst ist deinem persönlichen Stil überlassen. Aber m.E. hast du das schon sauber gelöst. Genau da hätt ich nach der Logik gesucht, wenn ich an dem Projekt beteiligt wäre ;)