Skip to content

Instantly share code, notes, and snippets.

@tom--
Last active November 29, 2016 18:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tom--/b5626e3a999c8aea73b872c3c428281d to your computer and use it in GitHub Desktop.
Save tom--/b5626e3a999c8aea73b872c3c428281d to your computer and use it in GitHub Desktop.
Conceptual demo of data mapping in a Yii webapp. It's no prototype to elaborate into real software. It's only an object of philosophical contemplation.
<?php
/**
* A global Persister "static" class isolates the location of any persistence logic from its users.
* In this example, persitence logic for UserMovieRating objects is located in this class but it
* could be moved around ad hoc.
*/
class Persister
{
private static function _UserMovieRatingSave(UserMovieRating $object)
{
(new Rating([
'userId' => $object->userId,
'movieId' => $object->movieId,
'stars' => $object->rating,
]))->insert(false);
}
// todo: Methods for finding UserMovieRating models, updating or deleting them, as needed
public static function save($object)
{
// Locate the save method for the object according to its type.
$method = '_' . get_class($object) . 'Save';
self::$method($object);
}
}
<?php
class RateController extends \yii\base\Controller
{
public function actionRate()
{
$form = new RateForm();
if ($form->load(\Yii::$app->request->post()) && $form->validate()) {
// The controller understands nothing of input mapping (from form model to data object)
// except that the form model provides it.
$dataObject = $form->getDataObject(Yii::$app->user->identity);
// And understands nothing of storage mapping (from data object to persistent storage),
// not even where it is.
Persister::save($dataObject);
return $this->redirect(['somewhere']);
}
return $this->render('rate', ['model' => $form]);
}
}
<?php
/**
* Standard Yii form model except for the addition of methods containing logic
* mapping between a form instance and whatever data object(s) it uses.
*/
class RateForm extends yii\base\Model
{
public function rules()
{
// whatever you need. familliar stuff
}
public function getDataObject(User $user)
{
return new UserMovieRating([
'userId' => $user->id,
'movieId' => $this->movieId,
'rating' => $this->rating,
]);
}
}
<?php
// Standard AR model without any form or validation stuff. This does nothing except
// provide a standard API to the persistent storage data structures. This is not an
// abstract API, it reflects e.g. DB schema, so DB migrations may cause rework of
// Persister logic.
class Rating extends \yii\db\ActiveRecord
{
public static function tableName()
{
return 'rating';
}
}
<?php
/**
* In this example, just data. But it could have logic too. The main point is that this
* class is reusable within the app and is isolated from forms and from DB. If either of
* those changes, the corresponding changes to mapping logic are isolated elsewhere.
*/
class UserMovieRating
{
public $userId;
public $movieId;
public $rating;
}
@samdark
Copy link

samdark commented Sep 29, 2016

The concept of repositories is OK but I'd make it non-static.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment