Intro
I'm developing an MVC framework, and I've run into a problem. It seems what I was trying to accomplish is known as the Singleton Design method -- initializing classes only once. Remember that I'm trying to put as less code in the controller "acontroller" as possible.
With that said, a final question remains: how can I add objects to an object that has already been instantialized?
It may help to have or at least see actual source instead of just example source, so I have pushed my source to my github. You can find that here: https://github.com/derekmaciel/uMVC
Code explanation
What's happening "under the hood" is first,
The Controller class loads a controller located in /application/controller, in this case "acontroller".
After, the acontroller class loads a model (called "amodel") using the Load class, using $this->load->model("amodel"), which was instantialized in the Controller __construct.
The final outcome of $this->load->model("amodel") is: $controller->amodel =& new Amodel(), where $controller is the Controller instance (not acontroller, because the controller loading the model will vary).
Step 4: Allow acontroller access to models that were loaded (amodel).
Code result
A copy of the current output of these scripts can be found here: http://pastebin.com/EJxuXaki
The first thing you'll notice is that I'm given a warning for using a deprecated assignment. I'm going to focus on the error for now.
The second thing you'll notice is that I first print_r()'d the Controller instance. Inside there is an amodel object, which is want to add to acontroller.
After that, I print_r()'d the $this (acontroller) object. It has everything it got from __construct(), but not amodel.
If I can get acontroller to "see" amodel, then my problem will be solved.
Also:
Is there anyway for me to remove "parent::init()" from the controller acontroller? I only did that so acontroller could have access to both the Load and Model class, but I'm trying to put as less code as possible in acontroller, so having the acontroller have access to Load and Model automatically would help a lot.
I hope I was clear. Thanks for any help
I personally do not think that singleton methods belong within an MVC Framework, the reason for this is because the main objects that are loaded are Models,Libraries and controllers, everything else such as the Router is usually hard coded.
The structure that i would do is create the following classes:
ModelLoader
LibraryLoader
and have them included during system boot, then within your main controller do the following:
class Controller
{
public $library;
public $model;
public function __construct()
{
$this->library = new LibraryLoader();
$this->model = new ModelLoader();
}
}
this would expose the 2 loaders to the child controller, your model/library should hold a private array storing the loaded objects, a little something like this:
class LibraryLoader extends ObjectLoader
{
protected $_path = "/app/library/";
protected $_ext = '.php';
}
class ModelLoader extends ObjectLoader
{
protected $_path = "/app/models/";
protected $_ext = '.php';
}
the object loader would look like so:
class ObjectLoader
{
protected $_path = "/app/";
protected $_ext = '.php';
public function __get($item)
{
/*
* Load item here, the paths above would be overwritten
* store the object in an array, make sure you check if its already loaded
*/
}
}
this is pretty basic, but within your child controllers such as index / home etc you can do the following:
class indexController extends Controller
{
public function index()
{
$this->model->users->getUser(22);
$this->library->security->validateInput("get","key");
//As the objectLoader manages whats loaded, any further calls to the above would
//use the same objects initiated as above.
}
}
This should get you started, its more streamline them using the singleton approach.
I guess you need to include Model.php in your controller.php to be able to use model class.
include 'Model.php';
include 'Load.php';
Since PHP 5.3 you can use the static keyword to instantiate a class
abstract class singleton
{
/**
* Holds an insance of self
* #var $instance
*/
protected static $instance = NULL;
/**
* Prevent direct object creation
*/
final private function __construct() { }
/**
* Prevent object cloning
*/
final private function __clone() { }
final public static function getInstance()
{
if(null !== static::$instance){
return static::$instance;
}
static::$instance = new static();
return static::$instance;
}
}
class myclass extends singleton
{
}
$myclass = myclass::getInstance();
Related
I've written this code for check behavior of my app and i don't why this code works. I have 2 classes and 1 entry point
PHP 7.2
class Base{
public function check(){
return $this->checkUnexist();
}
}
class Main extends Base
{
public function checkUnexist()
{
return 'UNEXIST METHOD CALLED';
}
}
$main = new Main();
echo $main->check();
Expected result something like called method unexist. But it calls method from child class with "this". Why? And where i can read about this issue ?
Trying to access child values from base(parent) class is a bad design. What if in the future someone will create another class based on your parent class, forget to create that specific property you are trying to access in your parent class?
As per my understanding, When you extend the class the child class have all the property, methods available for the Main class object, which are accessible outside the class.
So when you created an object of Main class your class internally looks like
class Main
{
public function checkUnexist()
{
return 'UNEXIST METHOD CALLED';
}
public function check(){
return $this->checkUnexist();
}
}
the check method exists and you will get the response. Try to make the method checkUnexist private or protected you will see the difference.
I have a class that contains methods used globally, and am using them by extending the class:
App.php
final class App extends Core {
// The app class handles routing and basically runs the show
}
Core.php
abstract class Core {
public function __construct() { // Here we bring in other classes we use throughout the app
$this->Db = new Db($this);
$this->Mail = new Mail($this);
}
// Then we define multiple methods used throughout the app
public function settings($type) {
// You see this used by the model below
}
}
index.php
$App = new App(); // This fires up the app and allows us to use everything in Core.php
Up until now, this is all great, because everything is handled throughout the site from within $App. However, within my MVC structure, the models need to pull data from the database, as well as retrieve other settings all contained in Core. We do not need the entire $App class to be used by the models, but we need Core to be.
MyModel.php
class MyModel extends Core {
public function welcome() {
return 'Welcome to '.$this->settings('site_name');
}
}
Once MyModel.php comes into play, the Core constructor is run a second time. How do I keep the Core constructor from being run twice?
you can use a static instance in the core class and reuse it.
abstract class Core {
public static $instance; //create a static instance
public function __construct() { // Here we bring in other classes we use throughout the app
$this->Db = new Db($this);
$this->Mail = new Mail($this);
self::$instance = $this; // initialise the instance on load
}
// Then we define multiple methods used throughout the app
public function settings($type) {
// You see this used by the model below
}
}
in the model class, use it like this
class MyModel extends Core {
public function welcome() {
$_core = Core::instance; // get the present working instance
return 'Welcome to '.$_core->settings('site_name');
}
}
you can take a look at this singleton reference
additionally you can check this answer explain-ci-get-instance
This is a follow-up to my previous question about resolving the diamond issue in php.
As I state in that question, I resolve my problem by using traits and passing the instance of the class to the method of the trait. Such as:
trait SecurityTrait
{
public function beforeExecuteRouteTrait($controller, Dispatcher $dispatcher)
{
// Do something that makes use of methods/members of the controller
}
}
class AppController extends Controller
{
use SecurityTrait;
public function beforeExecuteRoute(Dispatcher $dispatcher)
{
return $this->beforeExecuteRouteTrait($this, $dispatcher);
}
}
However, I am still uncomfortable with this as I don't think this is how traits are really supposed to be used. In my reading I haven't found any way in which to access class members in traits (make $this inside a trait refer to the class using it). Is this possible? Or is there another way to implement a similar behaviour?
After reading some of the answers...
Previously I thought I had received errors when using $this->... inside the trait and this led me to believe the trait could not access anything to do with the underlying class. After reading the answers I tried altering my code to use $this->... inside a trait again and it works - which means a typo several weeks ago has given me far too much headache...
The example given previously now looks like this
trait SecurityTrait
{
public function beforeExecuteRoute(Dispatcher $dispatcher)
{
// Do something that makes use of methods/members of the controller
}
}
class AppController extends Controller
{
use SecurityTrait;
}
Much cleaner and more easily understandable but provides the same functionality.
If you use a trait inside a class then that trait has full access to all class's members and vice versa - you can call private trait methods from the class itself.
Think of traits as code that literally gets copy/pasted into the class body.
For example:
trait Helper
{
public function getName()
{
return $this->name;
}
private function getClassName()
{
return get_class($this);
}
}
class Example
{
use Helper;
private $name = 'example';
public function callPrivateMethod()
{
// call a private method on a trait
return $this->getClassName();
}
}
$e = new Example();
print $e->getName(); // results in "example"
print $e->callPrivateMethod(); // results in "Example"
In my view referencing classes in traits is not the best way to use them but there's nothing stopping anyone from doing it.
No, that's exactly what Traits are for. Your class already extends a class so you can't inherit the methods and variables of any other classes.
Think of a Trait like copy/paste for code execution. When a class includes a Trait, it's just as if you had written all that code into the class itself.
Using Restler 3.0.0-RC6, which internally packages swagger-ui, I have an API method defined like so:
<?php
namespace v1:
class PostgreSQL {
public function fetchArray($sql, $args = null) {
And then all of my classes that I include via Restler's addAPIClass extend that PostgreSQL class. That means when swagger runs, every single API shows a fetchArray function. I'd like to have that method not appear in the swagger documentation as it's not really part of the API. Other 'things' on the website also use the class though so I can't change the modifier from public.
What's the proper syntax to hide that method from swagger-ui's webpage?
There are two ways to achieve this,
One is to mark the fetchArray method as private with #access private comment. This will remove fetchArray from all api urls while keeping the fetchArray still accessible for PHP
Problem in your case is that you don't want to modify the PostgreSQL as its part of a framework that is maintained by composer. Instead of directly extending it from the base class use an intermediary class which adds the comment and then extend that class as shown below
class Base {
public function fetchArray(){
return array();
}
}
class Intermediary extends Base {
/**
* #access private
*/
public function fetchArray(){
return array();
}
}
class MyApi extends Intermediary { //instead of extends Base
//other api methods here
//see in the explorer to note that fetchArray is no longer listed
}
Another way is to just exclude it on Explorer with
use Luracast\Restler\Explorer;
Explorer::$excludedPaths = array('myapi/fetcharray','another/fetcharray');
You should not extend your API layer class from a data layer class. Just use the data layer class.
class DataLayer
{
public function fetchArray()
{
return array();
}
}
class ApiLayer
{
private $dl;
function __construct()
{
$this->dl = new DataLayer();
}
public function getAll()
{
return $this->dl->fetchArray();
}
}
I am having some trouble with Symfony2. Namely in how to use the __construct() function. the Official Documentation is shockingly bad!
I want to be able to use the following:
public function __construct()
{
parent::__construct();
$user = $this->get('security.context')->getToken()->getUser();
}
How ever I get the following error:
Fatal error: Cannot call constructor in /Sites/src/DEMO/DemoBundle/Controller/Frontend/HomeController.php on line 11
Line 11 is "parent::__construct();"
I removed it and got the following, new error
Fatal error: Call to a member function get() on a non-object in /Sites/vendor/symfony/symfony/src/Symfony/Bundle/FrameworkBundle/Controller/Controller.php on line 242
I think I might need to set up the ContainerInterface DIC, but I have no idea how to do this (I tried and failed, miserably)
Any ideas folks?
Update - Tried changing to extend ContainerAware and got this error:
Fatal error: Class DEMO\DemoBundle\Controller\Frontend\HomeController cannot extend from interface Symfony\Component\DependencyInjection\ContainerAwareInterface in /Sites/src/DEMO/DemoBundle/Controller/Frontend/HomeController.php on line 43
Using the following code in the controller:
<?php
namespace DEMO\DemoBundle\Controller\Frontend;
use Symfony\Component\DependencyInjection\ContainerAware;
class HomeController extends ContainerAwareInterface
{
protected $container;
public function setContainer(ContainerInterface $container = null)
{
$this->container = $container;
}
I'm assuming you are extending the default Symfony controller? If so, a look at the code will reveal the answer:
namespace Symfony\Bundle\FrameworkBundle\Controller;
use Symfony\Component\DependencyInjection\ContainerAware;
class Controller extends ContainerAware
{
Notice that there is no Controller::__construct defined so using parent::__construct will not get you anywhere. If we look at ContainerAware:
namespace Symfony\Component\DependencyInjection;
class ContainerAware implements ContainerAwareInterface
{
protected $container;
public function setContainer(ContainerInterface $container = null)
{
$this->container = $container;
}
}
Again, no constructor and the container is not available until setContainer is called. So override setContainer and put your logic there. Or else just make a stand alone controller that does not extend the base controller class and inject your dependencies directly into the constructor.
Update Aug 2017
Still getting a few hits on this. If you really want to execute something before each controller then use a kernel controller listener. If all you need is the user then of course use getUser(). And please don't override setContainer(). In some cases it would work but it would just convolute your code.
I also frequently want an instance of the current User in most of my controllers. I find it is easiest to just do something like this:
class SomeController extends Controller
{
protected $user;
public function getUser()
{
if ($this->user === null) {
$this->user = $this->get('security.context')->getToken()->getUser();
}
return $this->user;
}
}
However, this is an overly simplistic example case. If you want to do more work before a Controller action is started, I suggest you define your Controller as a Service.
Also take a look at this article: Moving Away from the Base Controller
I have to retrieve the 'facade' manager for my rest api's resource. Not using the constructor and using a private function seems the easiest and simplest for me.
/**
* Class ExchangesController
* #RouteResource("Exchange")
*/
class ExchangesController extends Controller
{
/**
* Get exchange manager
* #return ExchangeManager
*/
protected function getExchangeManager()
{
return $this->get('exchange_manager');
}
/**
* #ApiDoc(
* description="Retrieve all exchanges",
* statusCodes={
* 200="Successful"
* }
* )
*/
public function cgetAction()
{
return $this->getExchangeManager()->findAll();
}
PS It's ok for me to use private/protected functions in my controller as long as it contains zero conditionals
You cannot call getUser() or get() for services in controller constructors. If you remember that, you will save lots of debugging time.
I know the question is very old, but I didn't found an answer until now. So I'll share it.
The goal here, is to execute a code everytime a action in our controller is called.
The __construct method doesn't work, because it's called before anything else, so you can't access the service container.
The trick is to overload each method automatically when they are called :
<?php
namespace AppBundle\DefaultController;
class DefaultController extends Controller {
private function method1Action() {
return $this->render('method1.html.twig');
}
private function method2Action() {
return $this->render('method2.html.twig');
}
public function __call($method, $args) {
$user = $this->get('security.tokenStorage')->getToken()->getUser();
// Do what you want with the User object or any service. This will be executed each time before one of those controller's actions are called.
return call_user_func_array(array($this, $method), $args);
}
}
Warning ! You have to define each method as a private method ! Or the __call magic method won't be called.
There are only two solutions to this problem:
Use a private method as pointed out by #Tjorriemorrie here. But this is a dirty method for purists. (I'm using this! :D );
Define the controller as a service, but this way you will lose all the shortcuts provided by Symfony\Bundle\FrameworkBundle\Controller\Controller. Here is the article that shows how to do this.
As told, personally, in my situation, I prefere a solution like this:
class MyController extends Controller
{
/** #var AwesomeDependency */
private $dependency;
public function anAction()
{
$result = $this->getDependency();
}
/**
* Returns your dependency.
*/
private function getDependency()
{
if (null === $this->dependency)
$this->dependency = $this->get('your.awesome.dependency');
return $this->dependency;
}
}
This is typically a class that I call MyManager where I put the code that I use in more than one action in the controller or that unusefully occupies lines (for example the code to create and populate forms, or other code to do heavy tasks or tasks that require a lot of code).
This way I mantain the code in the action clear in its purposes, without adding confusion.
Maybe the use of a property to store the dependency is an overoptimization, but... I like it :)
As i see, Controller extends ContainerAware, and if we take a look of ContainerAware it implements ContainerAwareInterface. So, ContainerAware must have declared the exact methods in it's interface. Add this line
public function __construct();
to the ContainerAwareInterface definition and it will be solved.