Accessing controller methods inside a model with Kohana/MVC Framework - php

I need to able to access controller methods from a model using the Kohana V2.3 framework. At the moment I'm passing the controller object (by ref.) to the model on creation which works perfectly fine but I can't help think there is a more "cleaner" way - does anybody have any suggestions? Would Kohana V3 resolve this with its HMVC pattern?
This may help: http://www.ifc0nfig.com/accessing-the-calling-controller-in-a-model-within-kohana/

Why do you need the controller inside the model? This violates the concept of MVC because now the model (data layer) is dependent on the Controller layer.
The functions your model needs in your controller should be offloaded to a generic library. Then accessible from both the controller and model.

You're instantiating the Facebook connector in the controller, and you don't want to do that twice so it makes sense that you'd want the model to have access to it. So far so good. There are two ways to do this.
1) Create a library which has a singleton instance that wraps the Facebook instance. That would look like this:
// libraries/FacebookApi.php
class FacebookApi {
// this stores the singleton FacebookApi
protected static $instance = null;
// this is the singleton's Facebook instance
protected $facebook = null;
// Return the single FacebookApi wrapper
public static function instance() {
if (!isset(FacebookApi::$instance)) {
self::$instance = new FacebookApi();
}
return $instance;
}
// Construct a single FacebookApi containing a single Facebook
protected function __construct() {
$this->facebook = new Facebook(
Kohana::config('mysubs.facebook_apikey'),
Kohana::config('mysubs.facebook_secret')
);
}
}
both your controller and your model would access it like this:
$facebook = FacebookApi::instance()->facebook;
$facebook->require_login(); // etc
Example code from Kohana 2.x:
http://dev.kohanaframework.org/projects/kohana2/repository/entry/trunk/system/libraries/Database.php
2) Since you're probably not going to do anything with an actual library other than just access the Facebook class, just create a simple helper that wraps a singleton:
// helpers/facebook_api.php
class facebook_api {
static $facebook = null;
static function instance() {
if (!self::$facebook) {
self::$facebook = new Facebook(
Kohana::config('mysubs.facebook_apikey'),
Kohana::config('mysubs.facebook_secret')
);
}
return self::$facebook;
}
}
both your controller and your model would access it like this:
$facebook = facebook_api::instance();
$facebook->require_login(); // etc

Related

PHP: How to prevent multiple instances of extended class

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

PHP MVC: Where should I put the model searching logic?

I'm building a MVC PHP framework from scratch, and I have some problems regarding the model layer.
What I have right now is a relatively basic MVC implementation, here's my entry point ( index.php ):
//get the URI
$uri = isset($_SERVER['REQUEST_URI'])
? $_SERVER['REQUEST_URI']
: '/';
//Initializes the request abstraction from URI
$request = new request($uri);
//getting the view class from the request
$viewFactory = new viewFactory();
$view = $viewFactory->getView($request);
$view->setDefaultTemplateLocation(__DIR__ . '/templates');
//getting the data mapper from the connection string
$connectionString = "mysql:host=localhost;dbname=test;username=root;";
$dataMapperFactory = new dataMapperFactory($connectionString);
$dataMapper = $dataMapperFactory->getDataMapper();
$modelFactory = new modelFactory($dataMapper);
//getting controller and feeding it the view, the request and the modelFactory.
$controllerFactory = new controllerFactory();
$controller = $controllerFactory->getController($request,$view,$modelFactory);
//Execute the necessary command on the controller
$command = $request->getCommand();
$controller->{$command}($request);
//Produces the response
echo $view->render();
I think this is self explanatory, but if you don't get something, or if you think I did some horrible mistake, feel free to tell me.
Anyway, the modelFactory is in charge of returning whatever model the controller could require. I now need to implement the "model research" logic, and in my opinion there's two ways of doing it:
First way: Implementing a modelSearch class containing all research logic, then make my model inheriting it ( like in Yii2 ). I don't like this method because it would make me instantiate some model and have it returning other instance of itself. So I have the same model instantiated once to research and once ( or more ) with all datas, and no use of search methods.
so my controller would look like that:
class site extends controller{
public function __construct($view, $modelFactory){
parent::__construct($view, $modelFactory);
/* code here */
}
public function index()
{
$searchModel = $this->modelFactory->buildModel("exemple");
$model = $searchModel->get(["id"=>3])->one();
$this->render('index',['model' => $model]);
}
}
Second way: Implementing a modelSearch class containing all research logic, then in the entry point, instead of instantiating the modelFactory, I could istantiate the modelSearch, and feeding it the dataMapper. Then I give the modelSearch to the controller, and the controller would get any model he wants by asking the modelSearch ( which would use the modelFactory to instantiate models and return them ), like that:
class site extends controller{
public function __construct($view, $searchModel){
parent::__construct($view, $searchModel);
}
public function index()
{
$model = $this->searchModel->get("exemple",["id"=>3])->one();
$this->render('index',['model' => $model]);
}
}
This way seems more correct to me, but has the disadvantage of having to call the modelSearch class to return any model, even empty ones.
Thoughts?
TL;DR: modelSearch: Do I use it as independant tool to get models, or do I make models inherit from it?
Searching logic should be within the model itself as the MVC describes model,view & controller. Model should have only one responsibilities that is work with database itself. While as controller should be responsible for manipulating of data and passing the data.
First read any MVC pattern PHP framework as CI, CakePHP and YII, and then you will see the model (how it works with database). and you can create there self model searching logic and you can see YII framework for best searching logic in model and usability in controllers.

Injecting objects, which extends from a parent class in Slim

I'm playing around with Slim PHP framework and stumbled upon a situation I cannot work out.
First, I'll explain the basic setup:
Using slim-skeleton, I have a dependencies.php file, where the DIC is set up. It's the default slim-skeleton's setup with two more things:
$container['db'] = function ($c) {
return new PDO('mysql:host=localhost;dbname=****', '********', '********');
};
$container['model.user'] = function ($c) {
$db = $c['db'];
return new Dash\Models\User($db);
};
So, as you can see, I have two new things registered in the DIC - A PDO object and a User object.
But passing a database object for each and every other model is a bit of a pain... I would like to be able to inject the PDO object to a parent class, called Model.
So the Model should look like this:
class Model
{
protected $db;
public function __construct($db)
{
$this->db = $db;
}
}
And the User model:
class User extends Model
{
public function getById($id)
{
$this->db->... // I have access to the database object (PDO) from the parent class.
}
}
The thing is that I cannot have a parent object, because the slim's container returns a new instance of User and does not instantiate the parent Model class.
Any ideas on how to achieve inheritance, using Slim's container in a clean and usable way?
Thanks in advance.
That's not how inheritance works. User is an instance of Model. So when you do new User($c['db']), it'll work fine.

How to integrate pimple in a custom mvc framework?

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

class instantiation for use across all models in Laravel3

I am using Laravel 3 (new to it). I have an API helper class that I'm using as a library. I want to have that class instantiated so I can use it within all my models to access the API. I am struggling with figuring out how to do it without instantiating it once in each model. An example would be awesome. Thanks.
There are a few ways you can go about doing this, the easiest would probably be just creating a base model where you instantiate the API helper class, then extending that base model for all of the models which you want to access the API.
It might look something like:
// base.php
class Base {
public static function api()
{
return new YourApiClass;
}
}
// user.php
class User extends Base {
public static function name()
{
return parent::api()->callApiMethod();
}
}
You could also use Laravel 3's IoC container, which might be the better choice depending on what you are doing.
Use an IoC container.
Instantiate your class:
IoC::register('mailer', function()
{
$transport = Swift_MailTransport::newInstance();
return Swift_Mailer::newInstance($transport);
});
And then when you need to access your instance you just have to:
IoC::instance('mailer', $instance);
Reference: http://laravel.com/docs/ioc

Categories