I'm writing a helper function to check whether any address information is present in my database by checking if any of the relevant fields don't equal null.
So, I have two models which I need to accept in the function as an argument.
App\Customer
App\Supplier
The variable passed can be either one.
For a function that should only accept one kind of model, I can just do this:
function check_for_address_info(App\Customer $customer) {
// other unrelated stuff
}
Is there a way to accept both models, or do I have to manually check it in the function by doing something like this:
function check_for_address_info($param) {
if(!is_a($param, 'App\Customer' || !is_a($param, 'App\Supplier')) {
// not an instance of either model
return false;
}
// do stuff as normal
}
Any ideas on how to accept two different models as a function argument?
I'm on Laravel 5.8.
There is two approaches, if it makes sense inheritance wise, you can extend a parent model and declare it as the type of the parameter. This will be checked on run time and provide an error if you pass the wrong type to the method.
public class Profile extends Model {
}
public class Customer extends Profile {
}
public class Supplier extends Profile {
}
function check_for_address_info(App\Profile $customerOrSupplier) {
}
In weak typed languages, it is common to have parameters that are generic. The way PHP solve this problem, is you can declare it in PHP Doc blocks. This will not check types on run time and is mostly for typehinting, documentation and static analysis tools.
/**
* #parameter \App\Customer|\App\Supplier $customerOrSupplier
**/
function check_for_address_info($customerOrSupplier) {
}
This is just a general question around a solution I'm trying to find.
I have potentially many providers of the same type of service and I need a way to be able to have a default, but then also manually call a switcher method to change them.
Currently, I've bound an Interface to an Implementation via configuration settings and this works well - but it means I can only support one active provider per type of service.
I noticed the Cache::disk() method is really what I'm looking for, but I'm not sure where this type of switch method should be defined.
Current:
interface IProvider {
public function getServiceInfo($args);
public function setServiceInfo($args);
}
class GoldService implements IProvider {
// implementation of the two interface methods
}
class SilverService implements IProvider {
}
// ProviderServiceProvider
public function register()
{
$this->app->bind(
App/IProvider,
App/GoldService
);
}
// Controller
public function getServiceInfo(Service $serviceId)
{
$provider = $app->make('App/IProvider');
$provider->getServiceInfo($serviceId);
}
Want to have.
// What I want to be able to do
public function getServiceInfo(Service $serviceId)
{
// Using a facade
if ($serviceId > 100)
{
Provider::getServiceInfo($serviceId);
}
else
{
Provider::switch('SilverService')
->getServiceInfo($serviceId);
}
}
I know I've thrown in an additional requirement there of the Facade - not sure if I've confused Contracts/Facades here - but essentially I want the interface to enforce the instance methods, but Facade for easy access to the instances.
Not really looking for code here - that'll be the easy part. I'm just not sure I've really grok'd this and looking for a nudge in the right direction..
Using an interface to ensure a service implements the methods you require makes sense.
But with regard to using a different service based on the properties of an object instance; that sounds more like the Factory pattern to me.
http://www.phptherightway.com/pages/Design-Patterns.html
I realize this topic has been asked and addressed repeatedly, and although I've read through countless similar questions and read through countless articles, I'm still failing to grasp a few key concerns... I'm attempting to build my own MVC framework for learning purposes and to better familiarize myself with OOP. This is for personal private use, not to imply that as an excuse for being lazy, but rather I'm not so concerned with having all the bells and whistles of more robust frameworks.
My directory structure is as follows:
public
- index.php
private
- framework
- controllers
- models
- views
- FrontController.php
- ModelFactory.php
- Router.php
- View.php
- bootstrap.php
I have an .htaccess file with directs all requests to index.php, this file contains basic configuration settings such as timezone and global constants, and it then loads the bootstrap.php file. The bootstrap contains my autoloader for classes, starts the session, defines global functions to use throughout my project, and then calls the router. The router picks apart the request from the URL, validates it using a ReflectionClass, and executes the request in the form of example.com/controller/method/params.
All of my controllers extend the FrontController.php:
<?php
namespace framework;
class FrontController
{
public $model;
public $view;
public $data = [];
function __construct()
{
$this->model = new ModelFactory();
$this->view = new View();
}
// validate user input
public function validate() {}
// determines whether or not a form is being submitted
public function formSubmit() {}
// check $_SESSION for preserved input errors
public function formError() {}
}
This front controller loads the ModelFactory:
<?php
namespace framework;
class ModelFactory
{
private $db = null;
private $host = 'localhost';
private $username = 'dev';
private $password = '********';
private $database = 'test';
// connect to database
public function connect() {}
// instantiate a model with an optional database connection
public function build($model, $database = false) {}
}
And base View:
<?php
namespace framework;
class View
{
public function load($view, array $data = [])
{
// calls sanitize method for output
// loads header, view, and footer
}
// sanitize output
public function sanitize($output) {}
// outputs a success message or list of errors
// returns an array of failed input fields
public function formStatus() {}
}
Finally, here is an example controller to demonstrate how a request is currently processed:
<?php
namespace framework\controllers;
use framework\FrontController,
framework\Router;
class IndexController extends FrontController implements InterfaceController
{
public function contact()
{
// process form if submitted
if ($this->formSubmit()) {
// validate input
$name = isset($_POST['name']) && $this->validate($_POST['name'], 'raw') ? $_POST['name'] : null;
$email = isset($_POST['email']) && $this->validate($_POST['email'], 'email') ? $_POST['email'] : null;
$comments = isset($_POST['comments']) && $this->validate($_POST['comments'], 'raw') ? $_POST['comments'] : null;
// proceed if required fields were validated
if (isset($name, $email, $comments)) {
// send message
$mail = $this->model->build('mail');
$to = WEBMASTER;
$from = $email;
$subject = $_SERVER['SERVER_NAME'] . ' - Contact Form';
$body = $comments . '<br /><br />' . "\r\n\r\n";
$body .= '-' . $name;
if ($mail->send($to, $from, $subject, $body)) {
// status update
$_SESSION['success'] = 'Your message was sent successfully.';
}
} else {
// preserve input
$_SESSION['preserve'] = $_POST;
// highlight errors
if (!isset($name)) {
$_SESSION['failed']['name'] = 'Please enter your name.';
}
if (!isset($email)) {
$_SESSION['failed']['email'] = 'Please enter a valid e-mail address.';
}
if (!isset($comments)) {
$_SESSION['failed']['comments'] = 'Please enter your comments.';
}
}
Router::redirect('contact');
}
// check for preserved input
$this->data = $this->formError();
$this->view->load('contact', $this->data);
}
}
From what I'm able to understand, my logic is off for the following reasons:
Validation should be done in the Model, not the Controller. However, a Model should not have access to $_POST variables, so I am not entirely sure whether or not I'm doing this part correctly? I feel like this is what they call a "fat controller" which is bad, but I'm not sure what needs to change...
The controller should not send data to the View; instead, the View should have access to the Model to request its own data. So would moving the $data property out of the FrontController and into the ModelFactory, and then calling the View from the Controller without passing along data resolve this issue? Technically it would then adhere to the MVC flowchart, but the proposed solution seems like such an insignificant or even trivial detail, assuming it's that simple, which it probably isn't..
The part that has me questioning my whole implementation is that I have a User object that is instantiated with a users corresponding roles and permissions, and I've been trying to figure out how or more specifically where to create an isAllowed() method that can be called from both the Controller and View. Would it make sense then to put this method in the Model, since both the Controller and View should have access to the Model?
Overall, am I on the right track here or what glaring problems do I need to address in order to get on the right track? I'm really hoping for a personal response specific to my examples rather than a "go read this".. I appreciate any honest feedback and help.
The $_POST superglobals should be abstracted by a request instance, as explained in this post.
Input validation is not the responsibility of the controllers. Instead it should be handles by domain objects within model layer.
Model factory is no a model.
Defining class parameter visibility as public breaks the object's encapsulation.
HTTP location header (redirect) is a form of response. Thus, it should be handled by view instance.
In its current form, your controllers are directly manipulating superglobals. This causes tight coupling to the globals state.
Authorization checks should be performed outside controller. Not inside of it.
Your "model factory" should instead be a service factory, that is injected in both controller and view. It would ensure that each service is instantiated only once and thus let your controllers work with same model layer's state.
First, I think it's great you are trying to create you own framework. Many say that everyone should do this, if only for learning purposes.
Second, I would suggest you read this Wikipedia article on frameworks. Many people don't realize there are different patterns for routing (url dispatch, traversal), and views (push, pull).
Personally, I don't see a need to abstract out the super globals since they are already abstractions (by php) from the raw input (php://input) and can be modified. Just my opinion.
You are right that validation should be done by the Model. You don't validate forms, you validate data. As for the View accessing the data, that depends on the pattern you choose. You can push the data to the View, or the View can pull the data.
If you are curious, my attempt at a MVC basic framework is on github. Its 4 files, less 2K line of code (DB layer is 1K lines). It implements traversal (component) routing and pulls data, there were already plenty of frameworks that implement the alternate patterns.
Validation should be done in the Model, not the Controller. However, a
Model should not have access to $_POST variables, so I am not entirely
sure whether or not I'm doing this part correctly? I feel like this is
what they call a "fat controller" which is bad, but I'm not sure what
needs to change...
That is right, Model should know nothing about the request, so, you need to pass $_POST to the models, but it will not know that are request parameters.
One thing: validation that has nothing to do with business logic should stay in controller. Let's say, you create a CSRF token for your forms for security reasons, this valitadion should be inside the controller, because it handles requests.
The controller should not send data to the View; instead, the View should have access to the Model to request its own data. So would moving the $data property out of the FrontController and into the ModelFactory, and then calling the View from the Controller without passing along data resolve this issue? Technically it would then adhere to the MVC flowchart, but the proposed solution seems like such an insignificant or even trivial detail, assuming it's that simple, which it probably isn't..
That's not necessarily true. This approach is called Active Model, and normally you use the Observer pattern, with models being observed by the views. If some model changes, it notifies the view that will update itself. This approach is more suitable for desktop applications, not web-based ones. In web applications, the most common is to have controllers as intermediaries between model and view (Passive Model). There's no right approach, you should choose the one you like the most.
The part that has me questioning my whole implementation is that I have a User object that is instantiated with a users corresponding roles and permissions, and I've been trying to figure out how or more specifically where to create an isAllowed() method that can be called from both the Controller and View. Would it make sense then to put this method in the Model, since both the Controller and View should have access to the Model?
Well, this one there's no way, I'll have to tell you to read about ACL.
I am writing a validation class in PHP which I would like to be extendible without editing the main parent class. I have provided a simplified version below of what I hope to achieve. I am passing a function/method name to validate() which first checks if it exists and if it does invokes it to check the variable I passed is valid. I am new to OOP and having problems with scope / visibility as I'm unable to get any custom validation rules in the child class working without hardcoding the name of the child class in the parent class. What is the best way to go about this? Many thanks for any assistance you can provide.
$rule = "number";
$var = "abcdef";
class Validation
{
public static function validate($rule, $var) {
if (is_callable("self::{$rule}")) {
return self::$rule($var);
}
}
protected static function number($var) {
return (preg_match("/^[0-9]+$/i", $var));
}
}
class MyRules extends Validation
{
public static function letter($var) {
return (preg_match("/^[a-zA-Z]+$/i", $var));
}
}
print MyRules::validate($rule, $var) ? "Valid!" : "Not valid!"; // Not valid!
Firstly, you can prevent overriding of the validate method using the final keyword:
public static final function validate($rule, $var) {
As for not being able to call static methods of subclasses, this can be done using Late Static Binding:
class Validation {
public static final function validate($rule, $var) {
if (is_callable("static::$rule")) {
return static::$rule($var);
}
}
}
This sounds like a job for strategy design pattern. It can be used if you want different variants of an algorithm, in your case the validation.
Here is how i work with my self made framework / libraries :
Like most n-tier systems , (MVC is like that) , the data must be checked b4 it is passed to the back-end tier(the database) ... so in a mvc arhitecture u can make a model that is the corespoindent to a db table , put in there the queries connection and validation... That model class needs to know only about that table data and nothing more...
If ull get to a point and see that ur validations get to some kind of routine... u can make a library... Or u can think from start what kind of data will ur app have...
P.S. : so for each data type in a table write a the correspondent validation, if the validations repeat make a library and call the lib validation method for the coresponding db data type
EDIT: Previous title, because no one was reading the question: "If I'm making AJAX calls in an MVC framework, is it common to have 'getter' controller methods over the model?"
It's all in the title: If I want to make an AJAX call to delete a user, that DB code clearly lives in the model $this->userModel->delete($id).
If I'm making all of the CRUD calls via AJAX, do I just have passthrough controller methods to expose those model calls to a URL?
function delete($id) {
$this->userModel->delete($id);
}
etc? This seems silly, but it also makes sense... but it also makes me feel like I'm missing something. Is this the most common pattern?
Thanks!
When it comes down to Ajax under the MVC Framework I usually tend to have each function with a specified keyword such as fetch / set.
something like this
class Users extends Controller
{
public function Fetch($id){}
public function Create(){}
public function Update($id){}
public function Remove($id){}
}
To answer your question: yes
The task of the controller is the decision maker, so that you would perform authentication checks etc within the controller for security purposes.
Think of it this way, you would not use the same controller for changing records in your administration as you would within your users front-end, but you would use the same models.
the models should be used in more places than just the front end, so you would not place a session check, input validation in the model methods as you would perform different checks depending on the location the action is taking place.
Your frontend controller would have something along the lines of:
public function Fetch($id)
{
if($this->session->get_userdata("auth_level") & USER_AUTH_LEVEL_READ)
{
//Show data
}
}
where as your administration would have:
public function Fetch($id)
{
if($this->session->get_userdata("auth_level") & IS_ADMINISTRATOR)
{
//Show data
}
}
if you place the very same check in your models then you would have generate several models that would do return the same data regardless of the location.