Revision 93ed1f08-dbb2-4fb5-a42e-ffa8c99d43d8 - Code Review Stack Exchange

I know the Model, Controller and View's purpose, but I have never really found a good concrete class example of a View class.

Usually I see people having some small `render()` method being called from the Controller, or their Controller holds all the View logic. So I tried my best and tried to create a View class that seemed proper and somewhat clean to me.

I've found a useful [image][1] that shows how the data flow is supposed to be and how the View sits in it.

- **Is this a valid View class?**

- **Any points I could improve on (suggestions)?**

 Readability, usability, efficiency.

---

**LoginView.php**

 namespace View;

 use View\View;
 use Http\HttpResponse;

 class LoginView extends View
 {
 private $templatePath;
 private $templateData;
 private $isUserLoggedIn;
 private $isTokenValid;

 public function __construct(HttpResponse $httpResponse)
 {
 parent::__construct($httpResponse);

 $this->templatePath = ABSPATH . DS . 'View' . DS . 'Template' . DS . 'Login' . DS . 'Index.php';

 $this->templateData['title'] = 'Log In';
 $this->templateData['styleSheets'] = ['/stylesheets/login.css'];
 $this->templateData['javaScripts'] = [
 '//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js',
 '/javascripts/login-form-handler.min.js'
 ];
 }

 public function index()
 {
 if ($this->isUserLoggedIn) {
 $this->httpResponse->redirect('/');
 }

 if ($this->isTokenValid === false) {
 $this->httpResponse->redirect();
 }

 $formErrorMessages = [
 'email' => [
 'NotEmpty' => 'Enter your email address.',
 'Email' => 'You did not enter a valid email address.'
 ],
 'password' => [
 'NotEmpty' => 'Enter your password.'
 ]
 ];

 if (isset($this->templateData['form']['errors'])) {
 $this->templateData['form']['errors'] = $this->replaceArrayKeys($this->templateData['form']['errors'], $formErrorMessages);
 }

 $this->renderTemplate($this->templatePath, $this->templateData);
 }

 public function setIsUserLoggedIn($boolean)
 {
 $this->isUserLoggedIn = $boolean;
 }

 public function setIsTokenValid($boolean)
 {
 $this->isTokenValid = $boolean;
 }

 public function setFormValueOf($name, $value)
 {
 $this->templateData['form']['values'][$name] = $value;
 }

 public function setFormErrorCodeOf($name, $code)
 {
 $this->templateData['form']['errors'][$name] = $code;
 }

 public function setPersistentUserLoginCookie($name, $userId, $seriesNumber, $token)
 {
 $this->httpResponse->makeCookie($name, [
 'uid' => $userId,
 'sno' => $seriesNumber,
 'token' => $token
 ], strtotime('+90 days'));
 }

 public function setHasLoginFailed($boolean)
 {
 $this->templateData['hasLoginFailed'] = $boolean;
 }
 }

Parent **View.php**

 <?php
 namespace View;

 use \Http\HttpResponse;

 abstract class View
 {
 protected $httpResponse;

 public function __construct(HttpResponse $httpResponse)
 {
 $this->httpResponse = $httpResponse;
 }

 public function replaceArrayKeys(array $array, array $source)
 {
 foreach ($array as $k => $v) {
 for ($i = 0, $c = count($v); $i < $c; ++$i) {
 if (isset($source[$k][$v[$i]])) {
 $array[$k][$i] = $source[$k][$v[$i]];
 }
 }
 }

 return $array;
 }

 public function renderTemplate($path, $data)
 {
 extract($data);

 include_once ABSPATH . DS . 'View' . DS . 'Template' . DS . 'Header.php';
 ob_start([$this, 'ob_indent']);
 require_once $path;
 ob_end_flush();
 include_once ABSPATH . DS . 'View' . DS . 'Template' . DS . 'Footer.php';
 }

 private function ob_indent($buffer)
 {
 $content = '';
 $lines = explode(PHP_EOL, $buffer);

 foreach ($lines as $line) {
 $content .= str_repeat(' ', 12) . $line . PHP_EOL;
 }

 return $content;
 }
 }



**LoginController.php** (for clarification)

 namespace Controller;

 use View\LoginView;
 use Http\HttpRequest;
 use Controller\Controller;
 use Model\Application\AntiCsrfService;
 use Model\Application\AuthenticationService;
 use Model\Application\FormValidationService;

 class LoginController extends Controller
 {
 private $antiCsrfService;
 private $formValidationService;

 public function __construct(
 HttpRequest $httpRequest,
 AuthenticationService $authenticationService,
 LoginView $loginView,
 AntiCsrfService $antiCsrfService,
 FormValidationService $formValidationService
 ) {
 parent::__construct($httpRequest, $authenticationService, $loginView);

 $this->antiCsrfService = $antiCsrfService;
 $this->formValidationService = $formValidationService;

 if ($this->authenticationService->findLoggedInUser()) {
 // User has no reason to be on this page,
 // so it will redirect to somewhere.
 $this->view->setIsUserLoggedIn(true);
 $this->view->index();
 }
 }

 public function index()
 {
 $this->view->setFormValueOf('csrfToken', $this->antiCsrfService->getToken());
 $this->view->setFormValueOf('remember', true);
 $this->view->index();
 }

 public function submit()
 {
 $token = $this->httpRequest->findParameter($this->antiCsrfService->getToken()['name']);

 if ($this->antiCsrfService->isTokenValid($token)) {
 $isLoginFormValid = $this->formValidationService->isLoginValid(
 trim($this->httpRequest->findParameter('email')),
 $this->httpRequest->findParameter('password')
 );

 if ($isLoginFormValid) {
 $isLoginSuccessful = $this->authenticationService->loginUser(
 trim($this->httpRequest->findParameter('email')),
 $this->httpRequest->findParameter('password'),
 $this->httpRequest->findParameter('remember') ? true : false
 );
 }

 if (!$isLoginFormValid || !$isLoginSuccessful) {
 $this->view->setHasLoginFailed($isLoginFormValid ? true : false);

 $this->view->setFormValueOf('csrfToken', $this->antiCsrfService->getToken());
 $this->view->setFormValueOf('email', $this->httpRequest->findParameter('email'));
 $this->view->setFormValueOf('remember', $this->httpRequest->findParameter('remember', false));

 foreach ($this->formValidationService->findErrorsOf('Login') as $key => $value) {
 $this->view->setFormErrorCodeOf($key, $value);
 }

 $this->view->index();

 return null;
 }

 // TODO let view create persistent user login cookie if opted

 $this->view->setIsUserLoggedIn(true);

 $this->antiCsrfService->regenerateToken();
 } else {
 $this->view->setIsTokenValid(false);
 }

 $this->view->index();

 return null;
 }
 }


 [1]: https://i.sstatic.net/GeL0I.jpg

AltStyle によって変換されたページ (->オリジナル) /