Sähköisten asiointipalveluiden toteuttaminen

Sorakuilu

Demo 13 (1908Tivia02), MVC-malli

Tehtävä: Muunna aikaisemmin tehtyä demoa 12 MVC-mallin mukaiseksi.

Alla oleva kuva esittää lopputulokseksi tulevaa pikkuriikistä järjestelmää, jolla voidaan ylläpitää pelaajien tietoja.

käsitteellinen sivukartta

Kansiot

Tiedostot organisoidaan uudestaan, ne sijoitetaan seuraavaan kansiorakennelmaan:

kansiot

MVC

Tietokanta ja yhteys

Tietokanta harjoitukseen

./database/connection.php (soveltaen omilla tiedoilla)

<?php
$dsn 
"mysql:host=magnesium;dbname=18aphpljn";
$user "leena";
$passwd "lmjn";

$pdo = new PDO($dsn$user$passwd);
?>

./database/models/Player.php

Aloitamme siirtämällä SQL-koodi funktioina tiedostoon ./database/Player.php

<?php
/*  
CREATE TABLE IF NOT EXISTS `players` (
  `playerID` int(10) NOT NULL AUTO_INCREMENT,
  `nickname` varchar(15) NOT NULL,
  `password` varchar(255) NOT NULL,
  `email` varchar(50) NOT NULL,
  `current_character` varchar(15) NOT NULL,
  `money` decimal(10,0) NOT NULL DEFAULT '500',
  `lastLogin` date NOT NULL,
  `banned` tinyint(1) NOT NULL DEFAULT '0',
  `teamID` int(10) DEFAULT NULL,
  PRIMARY KEY (`playerID`),
  KEY `teamID` (`teamID`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=6 ;
*/

require "./database/connection.php";

function 
getAllPlayers()
{
    global 
$pdo//Kohta 1 ota yhteys

    
$sql "SELECT * FROM players";//Kohta 2 rakenna SQL
    
$stm $pdo->query($sql); //Kohta 3 suorita sql

    
$players $stm->fetchAll(PDO::FETCH_ASSOC);

    return 
$players;

}

function 
getPlayerById($id)
{
    global 
$pdo;

    
$sql "SELECT * FROM players WHERE playerID = ?";
    
$stm $pdo->prepare($sql);

    
$stm->bindValue(1$id);
    
$stm->execute();

    
$player $stm->fetchAll(PDO::FETCH_ASSOC);
    return 
$player;
}


function 
getPlayerByNickname($nickname)
{
    global 
$pdo;

    
$sql "SELECT * FROM players WHERE nickname = ?";
    
$stm $pdo->prepare($sql);

    
$stm->bindValue(1$nickname);
    
$stm->execute();
    
    
$player $stm->fetchAll(PDO::FETCH_ASSOC);
    return 
$player;
}


function 
addPlayer($data)
{
    global 
$pdo;
    
var_dump($data);
    
$sql "INSERT INTO players (nickname,password,email,current_character,lastLogin) VALUES (?,?,?,?,?)";
    
$stm $pdo->prepare($sql);
    
$ok $stm->execute($data); //palauttaa true tai false
    
return $ok;
}

function 
editPlayer($data)
{
    global 
$pdo;

    
$sql ="UPDATE players SET nickname = ?, email = ?, current_character = ?, banned = ? WHERE playerID = ?";

    
$stm $pdo->prepare($sql);
    
$ok $stm->execute($data); //palauttaa true tai false
    
return $ok;
}

function 
deletePlayer($id)
{
    global 
$pdo;

    
$sql "DELETE FROM players WHERE playerID = ?";
    
$stm $pdo->prepare($sql);
    
$stm->bindValue(1$id);

    
$ok $stm->execute();
    return 
$ok;
}

//funktio tarkistaa, löytyykö käyttäjä tietokannasta
function loginPlayer($nickname,$password)
{
    global 
$pdo//yhteys

    
$sql "SELECT nickname,password FROM players WHERE nickname = ?";

    
$stm $pdo->prepare($sql);
    
$stm->bindValue(1,$nickname);
    
$stm->execute();

    
$player $stm->fetchAll(PDO::FETCH_ASSOC);

    
//tarkistetaan, vastaavatko salasanat toisiaan
    
if($player) {
        if(
password_verify($password,$player[0]["password"]))  {
            return 
TRUE;
        } else return 
FALSE;
    } else return 
FALSE;
}

Testitiedosto

<?php
require "./database/models/Player.php";

/************************************* */
$players getAllPlayers(); //kutsuu funktiota, pitäisi saada arvokseen funktion hakemat pelaajat

echo "<pre>";
var_dump($players);
echo 
"</pre>";

/************************************** */

$player getPlayerById(2);

echo 
"<pre>";
var_dump($player);
echo 
"</pre>";


/**************************************** */
$player getPlayerByNickname("Armas");

echo 
"<pre>";
var_dump($player);
echo 
"</pre>";


/***************************************** */

$data = array("untoliini","pasusasa","eh@gmail.com","olio","2020-12-12");
$ok addPlayer($data);
if(
$ok) echo "Lisätty";
else echo 
"Ei onnaa";

/*************************************** */

$data = array("uusinimi","uusi@gmail.com","ötökkä",1,7);

$ok editPlayer($data);
if(
$ok) echo "Muutettu";
else echo 
"Ei onnaa";

/*************************************** */

$ok deletePlayer(8);
if(
$ok) echo "Poistettu";
else echo 
"Ei onnaa";
?>

Kohta A - index.php - reititys

Tehdään reititys edelleen aikaisempaan tapaan eli $_GET kertoo, mikä sivu sisällytetään - tämä tapahtuu index-sivussa. Index-sivu ei kuitenkaan tulosta mitään, vain require (kontrolleri tai view)on sallittu.

Muu koodi jaetaan kolmeen erilaiseen kategoriaan: mallit (models), kontrollerit ja näkymät (views). Tässä kohdassa laadimme vain yhden mallin jokaista tietokannan taulua varten, samaten yhden kontrollerin taulua kohti.

Yhteysfunktiota voit käyttää sellaisenaan.

./index.php

index-sivu ohjaa kaikki pyynnöt eteenpäin.

Lähdekoodi:

<?php
session_start
(); //aloittaa istunnon
//pyynnöt ovat muotoa index.php?action=edit&id=5

if(isset($_GET["action"])) $action $_GET["action"];
else 
$action "index";//mitä tehdään

$method strtolower($_SERVER["REQUEST_METHOD"]); //onko post vai get
//otetaan kirjastot käyttöön
require "./controllers/playercontroller.php";
require 
"./helpers/auth.php";

switch(
$action) {

    case 
"index":
    
indexcontroller(); //funktio, joka hakee etusivun tarvitsemat asiat
    
break;

    case 
"register":
    if(
$method=="get")
    require 
"./views/registerform.view.php";
    else 
postregistercontroller();
    break;

    case 
"login":
    if(
$method =="get")
    require 
"./views/loginform.view.php";
    else 
postlogincontroller();
    break;

    case 
"admin":
    if(
islogged()) {
        
admincontroller();
    } else require 
"./views/loginform.view.php";
    break;

    case 
"logout":
    if(
islogged()) {
        
logoutcontroller();
    } else 
indexcontroller();
    break;

    case 
"deleteplayer":
    if(
islogged()) {
        
deleteplayercontroller();
    } else require 
"./views/loginform.view.php";
    break;

    case 
"editplayer":
    if(
islogged()) {
        if(
$method == "get") {
            
geteditplayercontroller();
        }
        else 
posteditplayercontroller();
    } else require 
"./views/loginform.view.php";
    break;



    default:
    echo 
"404";
}

Kohta B etusivu

Laadi etusivu pelaajille (listaa näkyville kaikki pelaajat).

Käytä ratkaisussa MVC-mallia. Siis: index-sivu ohjaa pyynnön oikealle näkymälle tai kontrollerille (controllers), joka keskustelee tietokantafunktioiden kanssa (models).

Tässä

./controllers/playercontroller.php

<?php
require "./database/models/Player.php";
require 
"./helpers/helper.php";

function 
indexcontroller()
{
    
$players getAllPlayers();
    
//var_dump($players);
    
require "./views/index.view.php";
}

function 
admincontroller()
{
    
$players getAllPlayers();
    
//var_dump($players);
    
require "./views/admin.view.php";
}

function 
postregistercontroller()
{
    if(isset(
$_POST["nickname"],$_POST["password"],$_POST["password2"],$_POST["email"],$_POST["character"])  &&  $_POST["password"] === $_POST["password2"])   {
        echo 
"Formi perillä";
        
$nickname sanit($_POST["nickname"]);
        
$password sanitpassword($_POST["password"]);
        
$email sanit($_POST["email"]);
        
$current_character sanit($_POST["character"]);
        
$lastLogin date('Y-m-d');

        
$data = array($nickname,$password,$email,$current_character,$lastLogin);

        
var_dump($data);

        
$ok addPlayer($data);

        if(
$ok) {
            
$message "Rekisteröinti onnistui";
            
$players getAllPlayers(); //hakee kaikki pelaajat kannasta
            
require "./views/index.view.php";
        }
        else {
            
$message "Rekisteröinti ei onnistu...";
            require 
"./views/registerform.view.php";
        }
    } else {
        
$message "Tiedoissa vikaa...";
        require 
"./views/registerform.view.php";
    }
}

function 
postlogincontroller()
{
   if(isset(
$_POST["nickname"],$_POST["password"]))  {
       
$nickname sanit($_POST["nickname"]);
       
$password sanit($_POST["password"]);

       
$ok loginPlayer($nickname,$password); //tietokantamallissa

       
if($ok) {
           
$player =getPlayerByNickname($nickname);
           
$id $player[0]["playerID"];
           
$ip $_SERVER["REMOTE_ADDR"];

           
//asetetaan istuntomuuttujan arvot

           
$_SESSION["id"] = $id;
           
$_SESSION["ip"] = $ip;

           
$players getAllPlayers();
           require 
"./views/admin.view.php";
       } else {
           
$message "Käyttäjää ei löydy";
           require 
"./views/loginform.view.php";
       }
   } else {
       
$message "Täytä kaikki tiedot!";
       require 
"./views/loginform.view.php";
   }
}

function 
logoutcontroller()
{
    if(isset(
$_SESSION["ip"],$_SESSION["id"]))  {
        
session_unset(); //poistaa istuntomuuttujat
        
session_destroy();//poistaa koko istunnon
        
header("Location:./index.php");
    } else 
header("Location:./index.php");

}

function 
deleteplayercontroller()
{
    if(isset(
$_GET["playerID"])) {
        
$playerID $_GET["playerID"];
        if(
deletePlayer($playerID)) $message="Pelaaja on poistettu";
        else 
$message="Pelaaja ei poistunut";
        
$players getAllPlayers();
        require 
"./views/admin.view.php";
    } else 
header("Location:./index.php?action=admin");
    
/* myös 
    } else { $players = getAllPlayers();
        $message = "ei poistettavaa id:tä";
        require "./views/admin.view.php";
    }*/
}

// hakee id:n mukaan pelaajan tiedot kannasta ja antaa ne muokkauslomakkeelle
function geteditplayercontroller()
{
    if(isset(
$_GET["playerID"])) {
        
$playerID=$_GET["playerID"];
        
$player getPlayerById($playerID);
        
var_dump($player);
        require 
"./views/editplayerform.view.php";
    } else {
        
$message="Ei valittuna pelaajaa";
        
$players getAllPlayers();
        require 
"./admin.view.php";
    }
}

function 
posteditplayercontroller()
{
    if(isset(
$_POST["playerID"],$_POST["nickname"],$_POST["email"],$_POST["character"])) {
        
$playerID $_POST["playerID"];
        
$nickname sanit($_POST["nickname"]);
        
$email sanit($_POST["email"]);
        
$current_character sanit($_POST["character"]);
        if(isset(
$_POST["banned"])) $banned 1;
        else 
$banned=0

        
$data = array($nickname,$email,$current_character,$banned,$playerID);

        if(
editPlayer($data)) {
            
$message "Muokkaus on tehty";

        } else {
            
$message "Muokkaus ei onnistunut";  
        }
    } else { 
        
$message "Lomakkeelta puuttuu tietoja";         
    }
    
$players getAllPlayers();
    require 
"./views/admin.view.php";
}

?>

./views/index.view.php

<?php
include "./views/partials/head.php";
?>

<h1>Kaikki pelaajat</h1>

<?php
if(isset($message)) echo $message;
?>


<?php
foreach($players as $player) { ?>
<h4><?=$player["nickname"];?></h4>
<?php
}
include 
"./views/partials/end.php";
?>

./views/partials/head.php (adminhead.php, end.php)

./views/partials/adminhead.php

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>Pelaajahallinta</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>

<a href="./index.php?action=logout">Kirjaudu ulos</a><br>
<hr>

./views/partials/head.php

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>Pelaajahallinta</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>

<a href="./index.php?action=register">Rekisteröidy</a><br>
<a href="./index.php?action=login">Kirjaudu</a><br>
<hr>

./views/partials/end.php

</body>
</html>

Kohta C pelaajan lisääminen

Toteuta pelaajan lisääminen MVC-mallilla

Tässä

./views/registerform.view.php

<?php
include "./views/partials/head.php";
?>

<h1>Rekisteröidy</h1>

<?php
if(isset($message)) echo $message;
?>

<form method ="post">
<label for="nickname">Nickname</label><br>
<input type ="text" name ="nickname" required><br>

<label for ="password">Salasana</label><br>
<input type="password" name="password" required><br>

<label for="password2">Salasana uudelleen</label><br>
<input type="password" name="password2" required><br>

<label for="email">Email</label><br>
<input type="email" name="email" required><br>

<label for="character">Hahmo</label><br>
<select name="character">
    <option value="hirviö">hirviö</option>
    <option value ="keiju">keiju</option>
    <option value="olio">olio</option>
</select><br><br>

<input type="submit" value="Rekisteröi pelaaja">
</form>

<?php
include "./views/partials/end.php";
?>

./helpers/helper.php

<?php

function sanit($input)
{
    
$input trim($input); //poistaa tyhjät välilyönnit alusta ja lopusta
    
$input filter_var($input,FILTER_SANITIZE_STRING);
    return 
$input;
}

function 
sanitpassword($password)
{
    
$password password_hash($password,PASSWORD_DEFAULT);
    return 
$password;
}

Kohta D Kirjautuminen

Kirjautumisessa käytetään hyväksi istuntoa: kun käyttäjä on kirjoittanut käyttäjätunnuksen ja salasanan lomakkeelle, niiden olemassaolo tarkistetaan tietokannasta. Jos tiedot löytyvät, asetetaan istuntomuuttujaan id ja käyttäjän ip.

Periaate tiedostotasolla näkyy seuraavassa sekvenssikaaviossa:

sekvenssi login -toimintoon

Tässä

./views/loginform.view.php

<?php
include "./views/partials/head.php";
if(isset(
$message)) echo $message;
?>

<form method ="post">

<label for="nickname">Käyttäjätunnus</label><br>
<input type="text" name="nickname"><br>

<label for="password">Salasana</label><br>
<input type="password" name="password"><br>

<input type="submit" value="Kirjaudu">
</form>

<?php
include "./views/partials/end.php";
?>

./views/admin.view.php

<?php
include "./views/partials/adminhead.php";
?>
<h1>Hallintapaneeli</h1>

<?php
if(isset($message)) echo $message;
?>


<?php
foreach($players as $player) { ?>
<h4><?=$player["nickname"];?></h4>
<a href="./index.php?action=editplayer&playerID=<?= $player["playerID"];?>">Muokkaa</a><br>
<a href="./index.php?action=deleteplayer&playerID=<?= $player["playerID"];?>">Poista</a><br>

<?php
}
include 
"./views/partials/end.php";
?>

Kohta E, tarkista kirjautumisen olemassaolo

Tässä

./helpers/auth.php

<?php
function islogged()
{
    if(isset(
$_SESSION["id"],$_SESSION["ip"]) && $_SESSION["ip"] == $_SERVER["REMOTE_ADDR"])  {
        return 
TRUE;
    } else return 
FALSE;
}

Kohta F, kirjaudu ulos

Tässä

Kohta G, poista pelaaja

Tässä

Kohta H

Toteuta pelaajan muokkaaminen MVC-mallilla.

Tässä

./views/editplayerform.view.php

<?php
include "./views/partials/adminhead.php";
?>
<h1>Hallintapaneeli</h1>

<?php
if(isset($message)) echo $message;
?>

<form method ="post">

    <input type ="hidden" name="playerID" value="<?= $player[0]["playerID"];?>">

    <label for="nickname">Nickname</label><br>
    <input type ="text" name ="nickname" value ="<?= $player[0]["nickname"];?>" required><br>

   
    <label for="email">Email</label><br>
    <input type="email" name="email" value ="<?= $player[0]["email"]; ?>" required><br>

    <label for="character">Hahmo</label><br>
    <select name="character">
        <option value="hirviö"<?php if($player[0]["current_character"] == "hirviö") echo " selected";?>>hirviö</option>
        <option value ="keiju"<?php if($player[0]["current_character"] == "keiju") echo " selected";?>>keiju</option>
        <option value="olio"<?php if($player[0]["current_character"] == "olio") echo " selected";?>>olio</option>
    </select>
    <br>
    <label for="banned">Bannattu</label>
    <input type ="checkbox" name="banned" <?php if($player[0]["banned"] == 0) echo "value=\"0\"";
    else echo 
"value=\"1\" checked";?>><br>


    <input type="submit" value="Muuta pelaajaa">
    </form>



<?php 
include "./views/partials/end.php";
?>