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
Related
I have a basic mvc like framework, and I would like to use pimple for dependance injection, but I don't know how to use it inside the framework. This is my app structure.
x-framework
- config
- app
controller
homeController.php
- core
- vendor
pimple
lib
pimple.php
- public
Now, in homeController.php I would like to use Pimple, but without actually doing new Pimple as seen in this example.
use vendor\pimple;
class homeController
{
function index(){
$app = new Pimple();
$app['orm'] = $app->share({ return new vendor\orm; });
$orm = $app['orm'];
$orm->table('foo');
$orm->findFirst(['name'=>'john']);
}
}
It seems as seen in this example, it would be a very cumbersome task to initialize the pimple class on every controller. How is this done correctly?
My answer was not relevant, though the principle of abstract classes stays interesting. Now:
I would like to use Pimple, but without actually doing new Pimple as seen in this example.
At some point you have to instantiate an object, if you want to use it.
Pimple uses a container to store and retrieve services and parameters:
$container = new \Pimple\Container();
// define some services
$container['session_storage'] = function ($c) {
return new SessionStorage('SESSION_ID');
};
this exemple from the doc defines an anonymous function which returns a session storage object
integrating a container
Pimple, or any container, can be made available using the dependency injection pattern.
either pass it as a parameter to the index
function index(\Pimple $app){
or pass it to homeController's constructor
function __construct(\Pimple $app){
$this->app = $app;
then use it as a property or a variable
$orm = $app['orm']; // through index() parameters
$orm = $this->app['orm']; // through constructor
abstract classes allow you to define a method for every extending classes, or forcing every extending classes to define a method.
here, we define a constructor for every extending classes, typehinting the Pimple class so that php will ensure your controller receives a real pimple object
abstract class Pimpleized {
function __construct(\Pimple $pimple) {
$this->app = $pimple;
}
}
then your controller
class homeController extends Pimpleized {
function foo() {
$this->app->accessSomePimpleMethod();
}
}
that way, you only have to create your Pimple object once, then pass it to your controllers:
$pimp = new Pimple();
$controller = new homeController($pimp);
Just extend HomeController class with pimple
class HomeController extends Pimple {
public function __construct() {
$this['orm.class']= 'vendor\orm';
$this['orm'] = $this->share(function($c){ return new $c['orm.class']; });
}
}
//and use it directly just after instanciation
$controller = new HomeController();
// you can modify parameters if you need
$controller['orm.class'] = 'myothervendor\orm';
//And get class
$orm = $controller['orm'];
$orm->table('foo');
$orm->findFirst(['name'=>'john']);
i hope it's you want :) cheers
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();
}
}
So for example, i want to access config on CI from my class library.
Class A {
funcion x() {
$this->config->load('my_config'); // accessing my_config
}
}
that obviously won't work unless you extends and then call parent::__construct().
As far as i know, it can only be done from classes that extend CI_Controller or CI_Model. How to access CI stuff (config, helper, model, etc) on non-CI class ?
Thanks.
How about initiating the class from the construct?
include ("CI_Page.php");
class A {
protected $_CIInstance1;
protected $_CIInstance2;
public function __construct(){
$this->_CIInstance1 = new xxxx();
$this->_CIInstance2 = new yyyy();
}
public function x(){
$this->_CIInstance1->load('my_config');
}
}
You probably want to access the instance of CI as if it were the super variable, $this. In reality what you need is the ability to access the same functionality as $this and in order to do this, you'll need to use $CI =& get_instance();
You can find it directly in the documentation for Creating Libraries
I'm writing a power plugin for wordpress that basically supplies a bunch of functions to make development easier.
Don't worry about the wp stuff though, this is a PHP question. I have one master class 'my_wp_funcs', and a few other large classes that do different things, which I've written separately and work on their own, for example: insert a new post.
I would like to be able to use this syntax:
$wpfuncs = new funcs;
$wpfuncs->createpost($args);
$wpfuncs->addimage();
where createpost class extends funcs class, along with other classes that extend funcs too.
I've been reading up on abstraction, but am getting continual errors. Here's a trimmer version of what I have:
<?php
$wpfuncs = new funcs;
$wpfuncs->createpost($args);
abstract class funcs
{
abstract protected function createpost();
public function createpost($args){
$tool = new $this->boss_posttype('derp', 'derps');
}
}
class createpost extends funcs{
public function __construct(){
//do stuff
}
}
Cheers for any help!
You can't define the method as abstract in the abstract class and then define it for real in the same class. You also can't call the abstract class directly.
You probably want something like this:
abstract class funcs
{
abstract public function createpost($args);
}
class myFuncs {
public function createpost($args){
$tool = new $this->boss_posttype('derp', 'derps');
// do other stuff
}
}
$wpfuncs = new myFuncs();
$wpfuncs->createpost($args);
Note that your implementation goes in your own class, and that implementation has to match your abstract definition. (they both have to be public and they have to accept the same arguments)
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();