PHP - MVC, is my aproach correct? - php

So I have Model, View and Controller, my code works but i have no one to educate me if I do work with it properly.
I won't copy paste the whole code, so therefor I've drawed how it works:
THE PICTURE: MVC
The part of code:
class Site {
protected $config;
function __construct() {
$this->config = include("resources/config.php");
}
private function connect() { /*database connection*/ }
public function getData($var) {
/* connecting, $var = amout of rows, and storing the data in array() */
}
}
class SiteView {
private $data;
function __construct(Site $data) {
$this->model = $data;
}
public function output() {
if(!empty($this->model->data)) { /* displays the data */ }
}
public function render($template) {
return include("$template");
}
}
class SiteController {
public function __construct(Site $respond) {
$this->model = $respond;
}
public function condition() {
$view = new SiteView($this->model);
$view->render("header.php");
if(!isset($_GET['action'])) {
$view->render("body.php");
} else if($_GET['action'] === "report" AND isset($_GET['id'])) {
$view->render("report_body.php");
} else if ...
}
So the model and view is used in templates, and I'm not sure if it is a good thing or bad. Thanks for any kind of help or showing me the way.

The MVC or Model, View and Controller approach is Model is for data which used by user, Controller is the backend logic and View is the output in HTML or the User Interface (UI).
Normally every request come to the controller first. Controller is connected with the Model and View. Controller collect the data according to the request from Model and send the data to the View for show. View can not able to connect with model.
For more details see this link, Click Here

Related

How to pass variables into different functions inside a php controller

I`m trying to create a form-select field displaying all of the schools with a specified type. The laravel functionality of the code works. As I had this on one page and it all worked fine. But I have been asked to move them on to two separate pages. And my question is how do I get my $type variable from my storeType function into my school Selection function properly? See Code :
public function schoolSelection(School $school,$type)
{
$schools=$school->where('type','=',$type)->get();
return view('auth.schoolSelection',compact('schools'));
}
public function storeType(Request $request, School $school)
{
$data=$request->all();
$type=$data['schoolType'];
return redirect()->route('schoolSelection',compact('type'));
}
Routes :
Route::get('schoolSelection/type',[RegisteredUserController::class,'schoolType'])->name('schoolType');
Route::get('schoolSelection/school',[RegisteredUserController::class,'schoolSelection'])->name('schoolSelection');
Route::post('schoolSelection/type',[RegisteredUserController::class,'storeType'])->name('type.store');
Route::post('schoolSelection/school',[RegisteredUserController::class,'schoolSelection'])->name('schoolSelection.store');
if both the functions are in same controller than you can make type as global variable .
class TestController extends Controller
{
private $type;
public function storeType(Request $request, School $school)
{
$data=$request->all();
$this->type=$data['schoolType'];
return redirect()->route('schoolSelection',compact('type'));
}
public function schoolSelection(School $school)
{
$type = $this->$type;
$schools=$school->where('type','=',$type)->get();
return view('auth.schoolSelection',compact('schools'));
}
}

MVC Class between controller and Model

I'm building application in Phalcon PHP where I have database with access from website and API.
In normal website I would create MVC like here:
- app
-- controllers
-- models
-- views
- public
but I have problem with duplicate code for API and Web.
Sample code:
class Users extends Model {
// ...
protected $id;
protected $username;
protected $email;
// setters and getters, validation
}
class UserController extends ControllerBase {
// ...
public function loginAction() {
if ($this->request->isPost()) {
// ... get post
// check login is correct
// create session
// redirect
}
$this->view->var = $var;
}
}
class ApiController extends ControllerBase {
// ...
public function loginAction() {
if ($this->request->isPost() //or put) {
$json = $this->request->getJsonRawBody();
// ... get json
// check login is correct
// create session
}
$response->setStatusCode('2xx/4xx', 'msg');
$response->setJsonContent([
'status' => 'OK / ERROR',
'message' => '$msg / $ex->getMessage()'
]);
}
}
Now I would create class with logic for check is user data correct.
I think about class like this:
class MyClass extends ParentClass {
public function login($username, $password) {
$user = Users::findFirstByEmail($email);
if ($user->password === hash($password)) {
$successLogin = new UserSuccessLogins();
$successLogin ->setId('id');
$successLogin ->setIpAddress('ip');
$successLogin ->save();
} else {
$failedLogin = new UserFailedLogins();
$failedLogin->setId('id');
$failedLogin->setIpAddress('ip');
$failedLogin->save();
}
}
}
And now I could use it in controllers like here:
class UserController extends ControllerBase {
public function loginAction() {
if ($this->request->isPost()) {
$c = new MyClass();
if ($c->login($username, $password)) {
// redirect
}
}
$this->view->var = $var;
}
}
class ApiController extends ControllerBase {
public function loginAction() {
if ($this->request->isPost() //or put) {
$c = new MyClass();
if ($c->login($username, $password)) {
// send json OK
} else {
// send json Error
}
}
}
}
What is best way for this? I don't want logic in model class.
I have read about Plugin and Component, but I don't know how create good self commented code.
You might be looking for Phalcon Multimodule, have a look at this example. Besides "Front-End" and "Back-End" modules, you can add "API" module.
OK, I'm going to extend my project with components like here:
-app
--components
--controllers
--models
--views
-public
Now, my code may looks like below:
use Phalcon\Mvc\Model;
class Users extends Model {
// ...
protected $id;
protected $username;
protected $email;
// setters and getters, validation
}
use Phalcon\Mvc\User\Component;
class UserComponent extends Component {
// class with access to dependecy injector
public login ($email, $password) {
$user = Users::findFirstByEmail($email);
// logic with setting session in $di
}
}
class UserController extends ControllerBase {
public function loginAction() {
if ($this->request->isPost()) {
$userComponent = new UserComponent();
if ($userComponent ->login($username, $password)) {
return $this->response->redirect($this->url->getBaseUri(), false, 301);
} else {
$this->flash->error('message');
}
}
// setting view variables if not post or login filed
$this->view->var = $var;
}
}
class ApiController extends ControllerBase {
public function loginAction() {
if ($this->request->isPost()) {
$userComponent = new UserComponent();
if ($userComponent ->login($username, $password)) {
//json OK
} else {
//json Error
}
}
}
}
If no one have better proposition I'll close this topic as solved in few days.
Your suggestion is a good option, however if you want to decouple and segregate responsibilities in a better way, you can try to use a service layer like in this example https://github.com/phalcon/mvc/tree/master/multiple-service-layer-model. Where you will have:
entities ( the models generated by phalcon)
repositories ( all the operations that requires fetching, updating or persisting data)
services (where the business logic is).
Whit this the call graph can be summarised as follow:
controllers -> services -> repositories -> entities
Note that the dependencies go in a single direction, nonetheless for simple tasks you can use a repo inside the controller directly o a entity inside the service, is up to you how hard or flexible your architecture will be.
I hope It is clear regards.

Routing independant controllers and models in fat free framework

I am trying to create Main site navigation, Sidebar Navigation and Footer navigation in Fat Free environment. I am just starting to work with frameworks especially with MVC type.
My problem, since my navigation will be almost on every page of the website, I was thinking about creating separate controller and model to handle all this staff, but not sure how it would work without making routing?
Also, I am not sure how to handle join in the model, I could not find any information about this online at all.
Here is my current Category Controller
class Categories extends DB\SQL\Mapper
{
public function __construct(DB\SQL $db)
{
parent::__construct($db, 'categories');
}
public function all()
{
$this->load();
return $this->query;
}
public function getByID($id)
{
$this->load(array('id=?', $id));
return $this->query;
}
public function getBySlug($category_slug)
{
$this->load(array('category_slug=?', $category_slug));
return $this->query;
}
public function add()
{
$this->copyfrom('POST');
$this->save();
}
public function edit($id)
{
$this->load(array('id=?', $id));
$this->copyfrom('POST');
$this->update();
}
public function delete($id)
{
$this->load(array('id=?', $id));
$this->erase();
}
}
any ideas or pointers will help me to go a long way.
Thanks in advance
I don't know if understood what your issue is, but if you want to make the categories available for all methods in a Controller, you could use the beforeRoute() method:
class TestController extends MainController {
// runs before routing
// if another controller extends TestController and also has a
// beforeRoute, this will be overriden
function beforeRoute() {
// Load Categories
$categories = new Categories($this->db);
// Assiging ->all() to variable makes the method return an array of all results
$categoriesArray = $categories->all();
// Set an array in the hive for template use
$this->f3->set('categories', $categoriesArray );
// Clear the instance
$categories->reset();
}
function renderPage() {
// the 'categories' hive variable is available because beforeRoute has been run
// Set the page title from the dictionary file
$this->f3->set('pageTitle', $this->f3->get('DICT_'.'page_whatever') );
// Render the View
$this->f3->set('view','page.whatever.htm');
$template=\Template::instance();
echo $template->render('layout.sidebar.htm');
}
// End of Controller
}
And of course, in the template:
<repeat group="#categories" value="#category">
<li>
{{ #category.label }}
</li>
</repeat>
ps: You might be using $f3 instead of $this->f3 (and the same for $db)

PHP OOP-based login system

Lets say I am building an OOP-based user authentication system, and I would like to incorporate the following principles: Direct Injection, Inheritance, Encapsulation, Polymorphism and the Single Responsibility Principle.
My background in programming is has always relied on procedural programming, and thus, am finding it difficult to really put these practices into correct use.
Assume I have these classes:
class Config
{
public function set($key, $value);
public function get($key, $default = null);
}
class User
{
public function __construct(PDO $dbh, $id = null);
public function setProfile(Profile $profile);
}
class Auth
{
public function __construct(Config $config);
public function login($username, $password, $keepLoggedIn = true);
public function isLoggedIn();
public function getLoggedInUser();
public function logout();
public function register(array $data);
}
class Session
{
public function start($sessionName = null);
public function write($key, $value);
public function read($key, $default = null);
}
class Profile
{
public function setAddress(Address $address);
public function setName($name);
public function setDOB(DateTime $date);
public function getAge();
}
class Validator
{
public function validate($input);
}
I have intentionally left off the function bodies to keep things simple.
To the best of my knowledge, I believe I'm using the principles correctly. However, I am still unclear as to how you would connect classes like: the Validator to the User model, the User model to the Auth and the Session to the Auth class. All of which depend on each other.
You are on the right track. The way these classes connect to each other is called extending. I tend to go towards an MVC setup, meaning Model, View, Controller.
Your logic goes into the controller, all your DB queries and concrete back end methods go in the model. The controller receives requests and returns responses. It's the middleman. It talks to the back end after a request has been made to it, and feeds the front in via response.
So you have a core controller (keep it bare minimal), then each class you make extends the core controller. So your controller is where you tie all this together.
<?php
//your main core controller, where you load all these things you need avilable, so long as this class is extended
class CoreController {
public $auth
public $session;
public $view;
function construct__ ()
{
$this->auth = instantiateAuthClassHere();
$this->session = instantiateSessionClassHere();
$this->view = instantiateViewClassHere();
}
public function anotherHelperForSomething(){
//helper stuff for this method
}
}
//index, page, or content controller, depending on how many you need, i.e. if you want a controller for each page, thats fine, e.g indexController, etc..
//this is the middle man, has logic, receives requst, returns response to view.
class Controller extends CoreController {
public function index (){
$userModel = new userModel();
//do something with this
$session = $this->session;
$content = 'some html';
$userInfo = $userModel->getUsers();
$view = $this->view->render( array(
'content' => $content,
'userInfo' => $userInfo,
));
return $view;
}
}
//Core LIbraries
class Validator {
//your validator stuff
}
//Core LIbraries
class Session {
//your validator stuff
}
//Core LIbraries
class Auth {
//your validator stuff
}
class CoreModel{
public $validator;
function __construct(){
$this->validator = instantiateValidatorClassHere();
}
}
//a user model class (back end). you want a model class for each db table pretty much.
class UserModel extends CoreModel {
// if you need the validator anywhere inside this class, its globally available here inside any class that extends the CoreModel, e.g. $this->validator->methodName()
public function getUsers (){
$sql = 'SELECT * from users';
$result = $db->get($sql);
return $result;
}
}
Notice, on the Controller, this is a generic name for something like indexController, or anything custom. Also, I have the word extends there. It inherits all the objects from the parent that it extends. Inside it, now they will be available via $this->. See my example where I get $this->session.
Try to avoid constructs - you probably don't need them anywhere except for the core, and under special circumstances, which you might then need to check for yourself before you do even that. I dont use constructs much anymore. It can be a bit clunky and unmanageable.

MVC - how to make the url not to change when a method is called

I have
login controller,model and view
url http://mySite/login
Now when i am at http://mySite/controller it shows the login form and then when i submit the form the run method is called so the url change to http://mySite/login/run
how can i stop this :?
P.S // I creat my own MVC following this tut : http://www.youtube.com/watch?v=2Eu0Nkpo6vM
login controller
class Login extends Conroller {
function __construct() {
parent::__construct();
}
function index()
{
$this->view->render('authentication/enter');
}
function run()
{
$this->model->run();
}
}
login model
class Login_Model extends Model
{
public function __construct()
{
parent::__construct();
}
public function run()
{
$sth = $this->dbh->connect()->prepare("SELECT UserID FROM users WHERE
username = :login ");
$sth->execute(array(':login' => $_POST['login']));
$data = $sth->fetch();
$count = $sth->rowCount();
if ($count > 0) {
// login
Session::set('loggedIn', $_POST['login']);
header('location: ../dashboard');
} else {
echo 4;
}
}
}
withour .htacces
the url is
http://mySite/index.php?url={controller name}
or
http://mySite/index.php?url={controller name}/{some method from the contoller}
Without watching that entire video or wondering too hard why you're re-inventing the PHP MVC wheel, here's my best guess.
Change your view's form to submit to the index action
<form method="post" action="login" ...
In your index action, detect a POST request and run the model's run() method from there
function index()
{
if ($this->request->isPost()) { // seriously, I'm just guessing here
$this->model->run();
}
$this->view->render('authentication/enter');
}
A couple of notes...
Don't do controller tasks (ie redirecting) from the model
Always exit; after sending a Location response header
Drop this mess and try a proven and tested MVC framework like Symfony or Zend

Categories