Några frågor om Model-View-Controller (MVC)

Trädvy Permalänk
Medlem
Plats
Linköping
Registrerad
Jun 2005

Några frågor om Model-View-Controller (MVC)

Hej,

Jag är relativt ny med MVC och har några frågor:

- Om jag hämtar data från ett formulär som sedan ska in i en databas - ska jag då samla in datan i kontrollern och skicka den till modellen som i din tur skickar den till databasen eller ska jag låta modellen sköta både hämtningen från formuläret och skickningen till databasen?

- Om jag hämtar data från en databas som behöver formateras på ett eller annat sätt innan den visas - ska jag då formatera datan i modellen innan den skickas till kontrollern eller ska jag första hämta datan från modellen och sedan formatera den i kontrollern innan den visas?

Hoppas att jag har formulerat mina frågor bra.

Trädvy Permalänk
Medlem
Plats
Stockholm
Registrerad
Jun 2005

Jag är ingen expert på MVC, men jag skulle lägga den första grejen du beskriver i kontrollen (eller i viewn?), och den senare i modellen. På så vis behöver du inte ha formatering av data på flera ställen i din kod (exempelvis i flera kontroller). Oavsett hur du gör tycker jag dock att det viktigaste är att du är konsekvent. Det kan vara svårt, men it pays off.

Trädvy Permalänk
Medlem
Plats
Göteborg
Registrerad
Jun 2004
Citat:

Ursprungligen inskrivet av Superb
- Om jag hämtar data från ett formulär som sedan ska in i en databas - ska jag då samla in datan i kontrollern och skicka den till modellen som i din tur skickar den till databasen eller ska jag låta modellen sköta både hämtningen från formuläret och skickningen till databasen?

Beror lite på vilket språk och hur resten av arkitekturen ser ut, men det vanligaste är att göra båda i modellen.

Citat:

Ursprungligen inskrivet av Superb
- Om jag hämtar data från en databas som behöver formateras på ett eller annat sätt innan den visas - ska jag då formatera datan i modellen innan den skickas till kontrollern eller ska jag första hämta datan från modellen och sedan formatera den i kontrollern innan den visas?

Formateringen av data du hämtat görs vanligtvis i kontrollern. Men om du hämtar data vars formatering bygger på nästa hämtning av data, kan det bli bäst att göra formateringen i modellen. Det ska helst vara undantagsfall enligt MVC-modellen, men som Wishie var inne på; var hellre konsekvent och bli nöjd med din struktur än att hålla på och lusläsa specifikationen för MVC. Det är ett hjälpmedel, inte en lag. Om du arbetar i en grupp som kör MVC kommer ni överens om detaljerna.

Trädvy Permalänk
Medlem
Plats
Göteborg
Registrerad
Maj 2007

azoapes första svar håller jag inte med om (men svaret på fråga 2 var bra ), för tänk om du genom modellen vill lägga till data som inte kommer från ett formulär? För mig är det en självklarhet att kontrollern bestämmer vilken data som modellen ska ha, modellen ska inte behöva bry sig om varifrån datan kommer (post, get, manuell, soap, o.s.v.).

Trädvy Permalänk
Medlem
Plats
Göteborg
Registrerad
Jun 2004
Citat:

Ursprungligen inskrivet av bjornie
azoapes första svar håller jag inte med om

Nej inte jag heller när jag tänker efter Jag menade såhär; validering gör man i kontrollern, och jag brukar försöka formatera texten i kontrollern också (behandla inför databasskick). Men när man har har en applikation och ändrar något i efterhand brukar det (tyvärr) sluta med att man sitter i modellen och gör mer och mer, för att man annars måste uppdatera kommunikationen mellan kontrollern och modellen.

Så nej, du har rätt, egentligen ska formateringen ligga i kontrollern så långt som möjligt, modellen ska bara kunna samla ihop data och skjuta in i DBn. Men för mig har det blivit så att jag vet på förhand att det kommer sluta med att jag sitter och gör små formateringar i modellen, och då har det oftast slutat med att jag gör "MVC-fel" redan från början.

Trädvy Permalänk
Medlem
Plats
Göteborg
Registrerad
Maj 2007

Jag förstår precis hur du menar. Ett knep för att slippa ha databasspecifik kod i modellerna är att istället för rena modeller, använda entiteter och en O/R-M som sköter allt med datakällan. Doctrine är välanvänd och omtyckt. På så sätt kan man sätta upp *Manager-klasser för att sköta entiteterna genom Doctrine, och använda dessa *Manager-klasser som "M":et i MVC-mönstret.

Trädvy Permalänk
Medlem
Plats
Linköping
Registrerad
Jun 2005

Tack för alla bra svar.

Så, om jag har förstått rätt så ligger det till ungefär så här:

- Modellens uppgift är enbart att hämta och skicka data från och till en datakälla. Inget mer, inget mindre.

- Kontrollerns uppgift är att bearbeta datan som kommer från modellen innan den skickas för visning. Om man hämtar data från ett formulär så ska datan från förmuläret bearbetas och valideras i kontrollern innan den skickas till modellen.

exempel:

kontrollern:

class Member extends Controller { public function register() { /* data från förmuläret ska hämtas och bearbetas här innan den skickas till modellen som skickar datan till databasen */ } //hämtar data från databasen som måste formateras innan visning public function getData() { /* hämtar data från modellen och formaterar den innan visning */ } }

modellen:

class Member_model extends Model { public function register() { /* litar blint på att kontrollern har bearbetat och validerat datan och skickar bara vidare den till databasen. */ } public function getData() { /* hämtar data från databasen och skickar den vidare till kontrollern utan att göra något med den */ } }

Är det tillvägagångssättet korrekt? Jag har alltså en funktion i kontrollern och en i modellen som sammarbetar. getData() i modellen skickar data till getData() i kontrollern som i sin tur formaterar datan innan visning. Jag skulle lika gärna kunnat formatera datan i modellen i samband med att den hämtas från databasen, men så borde jag alltså inte göra?

Trädvy Permalänk
Medlem
Plats
Göteborg
Registrerad
Maj 2007

Det ser ok ut, tycker jag. Ett motexempel som använder sig av Doctrine:

models/User.php <?php class User extends Doctrine_Record { public function setTableDefinition() { $this->hasColumn('username', string, 50); $this->hasColumn('email', string, 75); } } controllers/UserController.php <?php class UserController extends Controller { public function register() { try { $userName = MyValidator::validate($_POST['user_fullname'], MyValidator::USERNAME_PATTERN); $userEmail = MyValidator::validate($_POST['user_email'], MyValidator::EMAIL_PATTERN); $user = new User(); $user->username = $userName; $user->email = $userEmail; } catch(ValidatorException $e) { $view->showErrorPage($e->getMessage); } } public function show() { try { $userName = MyValidator::validate($_GET['user'], MyValidator::USERNAME_PATTERN); $user = Doctrine_Query::create() ->select('u.username, u.email') ->from('User u') ->where('u.username = ?', $userName) ->fetchOne(); $view->assign('username', $user->username); $view->assign('email', $user->email); } catch(ValidatorException $e) { $view->showErrorPage("User not found"); } } }

Typ.

Trädvy Permalänk
Medlem
Plats
Linköping
Registrerad
Jun 2005
Citat:

Ursprungligen inskrivet av bjornie
Det ser ok ut, tycker jag. Ett motexempel som använder sig av Doctrine:

models/User.php <?php class User extends Doctrine_Record { public function setTableDefinition() { $this->hasColumn('username', string, 50); $this->hasColumn('email', string, 75); } } controllers/UserController.php <?php class UserController extends Controller { public function register() { try { $userName = MyValidator::validate($_POST['user_fullname'], MyValidator::USERNAME_PATTERN); $userEmail = MyValidator::validate($_POST['user_email'], MyValidator::EMAIL_PATTERN); $user = new User(); $user->username = $userName; $user->email = $userEmail; } catch(ValidatorException $e) { $view->showErrorPage($e->getMessage); } } public function show() { try { $userName = MyValidator::validate($_GET['user'], MyValidator::USERNAME_PATTERN); $user = Doctrine_Query::create() ->select('u.username, u.email') ->from('User u') ->where('u.username = ?', $userName) ->fetchOne(); $view->assign('username', $user->username); $view->assign('email', $user->email); } catch(ValidatorException $e) { $view->showErrorPage("User not found"); } } }

Typ.

Det där ser intressant ut. Jag ska kolla på Doctrine.
Det känns som att den här delen:

$user = Doctrine_Query::create() ->select('u.username, u.email') ->from('User u') ->where('u.username = ?', $userName) ->fetchOne();

inte hör hemma i kontrollern. Varför inte ha den i en metod i modellen (managern)?
Jag har ingen koll på doctrine så det kanske är en dum fråga.

Trädvy Permalänk
Medlem
Plats
Göteborg
Registrerad
Maj 2007

Jo, du har helt rätt. Visst kan den ligga i en UserManager-klass som jag menade i ett föregående inlägg (tillsammans med valideringen av indata, kontrollern kanske enbart ska anropa register() i UserManager). Jag var lite stressad när jag skrev exemplet, så det var egentligen bara för att visa hur man kan bygga upp entiteter med Doctrine (Doctrine-project kallar dock entiteterna för modeller, men jag tycker att entitet är en bättre beskrivning).