Are there native codeigniter functions I can use to tell if a certain model has already been loaded? Can php's class_exists() be used to tell if a model has already been loaded?
I would be tempted to extend the CI_Loader core class. (See extending Core Class)
class MY_Loader extends CI_Loader {
function __construct()
{
parent::__construct();
}
/**
* Returns true if the model with the given name is loaded; false otherwise.
*
* #param string name for the model
* #return bool
*/
public function is_model_loaded($name)
{
return in_array($name, $this->_ci_models, TRUE);
}
}
You would be checking for a given model with the following:
$this->load->is_model_loaded('foobar');
That strategy is already being used by the CI_Loader class.
This solution supports the model naming feature of CI, where models can have a different name than the model class itself. The class_exists solution wouldn't support that feature, but should work fine if you aren't renaming models.
Note: If you changed your subclass_prefix configuration, it might not be MY_ anymore.
The simplest solution is to use PHP function class_exists
http://php.net/manual/en/function.class-exists.php
For example. if you want to check if Post_model has been defined or not.
$this->load->model('post_model');
/*
a lot of code
*/
if ( class_exists("Post_model") ) {
// yes
}
else {
// no
}
The simplest is the best..
Edited:
You can use the log_message() function.
Put this in your model’s constructor (parent::Model())
log_message ("debug", "model is loaded");
don’t forget to set the log config to debug mode in the config.php file
$config['log_threshold'] = 2;
And set the system/logs directory permission to writable (by default CI will create the log files here)
or set the logs directory in another dir
$config['log_path'] = 'another/directory/logs/';
CI will then create the log file in the directory. monitor the log files as you like. You can get the debug message to see if your model is already loaded or not in the log files.
Riffing off what Maxime Morin & Tomexsans have written, this is my solution:
<?php
class MY_Loader extends CI_Loader {
/**
* Model Loader
*
* Overwrites the default behaviour
*
* #param string the name of the class
* #param string name for the model
* #param bool database connection
* #return void
*/
function model ($model, $name = '', $db_conn = FALSE) {
if (is_array($model) || !class_exists($model)) {
parent::model($model, $name, $db_conn);
}
}
}
?>
This way, you don't ever need to (consciously) check whether a model's loaded or not :)
Related
I get
Call to undefined method ContestsCpController::getAfterFilters()
on a specific controller. All other controllers are working fine and I do not remember any change that would cause this breakage. In fact, I haven't touched the code in weeks. The last thing I did was some refactoring.
Route
Route::get("contestscp/home", "ContestsCpController#getHome");
Controller
<?php
class ContestsCpController extends BaseController
{
public function getHome() {
return Redirect::to("contestscp/give_award");
}
...
some other methods
...
}
?>
Debug output
/vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php
* #param \Illuminate\Routing\Route $route
* #param \Illuminate\Http\Request $request
* #param string $method
* #return mixed
*/
protected function assignAfter($instance, $route, $request, $method)
{
foreach ($instance->getAfterFilters() as $filter) //fails here
{
// If the filter applies, we will add it to the route, since it has already been
Google and SO suggest that this is caused when controller does not extend BaseController but this is obviously not the case. So I assume that for some reason my class is not being extended. Or.. the class fails to initialize and $instance is null. But I have no idea why and how to debug this.
Any suggestions?
I knew this had to be something stupid.. because it always is.
The problem was my refactoring. I used to have all validators extended in a single file. When I separated the validators into different files I misnamed my ContestsCpValidator class as ContestsCPController (duh..). So I had a second class with the same name with no methods obviously.
So basically, if you happen to have this error and you are indeed extending the BaseController make sure you don't autoload another class with the same name.
I have found out how to do a view override in Phalcon with the help of this: https://stackoverflow.com/a/19941928/74651
The problem is that it uses this method for the layout to, but if the directory does not exists on the original viewpath it does enter in this method.
Where does phalcon checks the directory for the layout and how to override it?
Here and kind of here.
So, you could do three things. First, change the layout dir, second, just set the layout, or third, change both :)
$view->setLayoutsDir('custom/layouts/');
$view->setLayout('outrageouslyCustomLayout');
See all methods in the documentation. If I remember correctly, paths must be relative to your views directory.
Standard view offers quite a few ways of controlling your rendering, it might be that you don't really need to override things – http://docs.phalconphp.com/en/latest/reference/views.html#control-rendering-levels
Checkout this framework: https://github.com/alanbarber111/cloud-phalcon-skeleton
Allows you to have design packages on a per website basis with the ability to setup a "Fall back" directory and an "override" directory. If nothing else, take a look at app/code/Core/Model/App/Design.php and app/code/core/Model/View* to see how we've completed this.
Use this in your controller... worked for me
public function initialize() {
parent::initialize();
$this->view->setTemplateAfter('yourtemplate');
}
Ok i just figured it out after some debugging.. cannot dump vars in view class which is a bit annoying ;)
My problem was indeed, that the layout needs to be relative to the view dir. When you override the view dir as on: https://stackoverflow.com/a/19941928/74651 it will look for the layout on the original view dir not the override.
It's possible to override this in _engineRender a bit annoying that they force the relative directory and only trigger and event if a file has been found not very flexible.
<?php
namespace Phapp\Mvc;
class View extends \Phalcon\Mvc\View {
/**
* #param array $engines
* #param string $viewPath
* #param boolean $silence
* #param boolean $mustClean
* #param \Phalcon\Cache\BackendInterface $cache
*/
protected function _engineRender($engines, $viewPath, $silence, $mustClean, $cache) {
// Layout override
if ($this->getCurrentRenderLevel() !== \Phalcon\Mvc\View::LEVEL_LAYOUT) {
return parent::_engineRender($engines, $viewPath, $silence, $mustClean, $cache);
}
foreach ($engines as $extension => $engine) {
if (!$engine instanceof View\Engine\ThemeInterface) {
continue;
}
$layout = $engine->getThemePath().$viewPath.$extension;
if (is_readable($layout)) {
$originalViewDir = $this->getViewsDir();
$this->setViewsDir($engine->getThemePath());
$content = parent::_engineRender($engines, $viewPath, $silence, $mustClean, $cache);
$this->setViewsDir($originalViewDir);
return $content;
}
}
}
}
I use the config.php to store all the form_validation rules...But I would like to store the callback function in one single file too, how can I do so? Any ideas? Thank you....
Now my file is something like this:
User_controller
under user controller have many customized callback_valid , but I ready move all the rules in the config.php. I would like to put the _valid callback to one class. Thank you .
By default, the Form_validation lib uses it's $CI property to see if the callback method exists. Normally this looks at the current controller. However, you can change this behavior by extending the validation class and altering the run() method.
class MY_Form_validation extends CI_Form_validation {
/**
* Support for validation callbacks from any object
*
* #access public
* #param object The object to run callbacks from
* #param string Is there a validation rule for the particular URI being accessed?
* #return bool Validation status
*/
function run($obj = '', $group = '')
{
// Assign the callback object
if (is_object($obj)) $this->CI =& $obj;
// Run the validation as normal
return parent::run($group);
}
}
We're just reassigning the $CI property. So to use callbacks from a class called user_validation for instance, you can do this:
$callback_class = $this->user_validation;
if ($this->form_validation->run($callback_class)) {}
Any loaded class will work, so you can store callback rules in models or libraries, just pass the object you want to handle callbacks with to the run() method.
What I would do in this case is just create a MY_Form_validation class to extend CodeIgniter's form validation. Place the "_valid" checks in the newly created MY_Form_Validation file and set the rules for the "_valid" checks the same way that you do for the default form_validation rules.
Something like...
class MY_Form_validation extends CI_Form_validation {
function valid_user($str)
{
}
function valid_password($str)
{
}
}
I'm using PHP Storm as my IDE, but I believe that other IDE's such as Netbeans will have the same issue as I'll explain below.
When using a framework like Symfony2, we have the wonderful world of Dependency Injection added. So objects can simply be instantiated using code like the following snippet:
$myThingy = $this->get('some_cool_service');
This is very handy, as objects are already configured beforehand. The one problem is, that auto-completion breaks entirely in basically any PHP IDE, as the IDE does not know what type the get() method is returning.
Is there a way to preserve auto-completion? Would creating for example an extension of Controller be the answer? For example:
class MyController extends Controller {
/**
* #return \MyNamespace\CoolService
*/
public getSomeCoolService() {
return new CoolService();
}
}
and then for application controllers, specify MyController as the base class instead of Controller?
What about using a Factory class, or any other possible methods?
It is more involving, but you can still do this with eclipse PDT:
$myThingy = $this->get('some_cool_service');
/* #var $myThingy \MyNamespace\CoolService */
UPDATE:
The example on this page shows you may also use the other way round with phpStorm:
$myThingy = $this->get('some_cool_service');
/* #var \MyNamespace\CoolService $myThingy */
You could define private properties in your controllers
class MyController extends Controller
{
/**
* #var \Namespace\To\SomeCoolService;
*/
private $my_service;
public function myAction()
{
$this->my_service = $this->get('some_cool_service');
/**
* enjoy your autocompletion :)
*/
}
}
I use base Controller class for bundle. You need to annotate the return in method. At least that works on Eclipse.
/**
* Gets SomeCoolService
*
* #return \Namespace\To\SomeCoolService
*/
protected function getSomeCoolService()
{
return $this->get('some_cool_service');
}
I don't like /*var ... */, because it gets too much into code.
I don't like private properties, because you can wrongly assume that services are already loaded.
I use Komodo Studio, and tagging variables with #var, even inside methods, preserves auto completion for me.
namespace MyProject\MyBundle\Controller;
use Symfony\Component\DependencyInjection\ContainerAware;
use Symfony\Component\HttpFoundation\Request;
class WelcomeController extends ContainerAware
{
public function indexAction()
{
/*#var Request*/$request = $this->container->get('request');
$request->[autocomplete hint list appears here]
}
}
working with netbeans IDE 7.1.2 PHP
In one of my controllers, i use codeigniter's form validation helper. One of my validation rules is a custom function that i created that returns true or false.
Problem is, that this validation function is declared inside the controller's class. How do i prevent users from browsing to my validation function as a controller action (mysite/mycontroller/my_callback_func)?
P.S. - Tried to set the function as private but I'm getting an error that it's not accessible for the validation helper.
Just start the function/method name with an underscore.
Straight out of ./system/core/CodeIgniter.php:
/*
* ------------------------------------------------------
* Security check
* ------------------------------------------------------
*
* None of the functions in the app controller or the
* loader class can be called via the URI, nor can
* controller functions that begin with an underscore
*/
$class = $RTR->fetch_class();
$method = $RTR->fetch_method();
if ( ! class_exists($class)
OR strncmp($method, '_', 1) == 0
OR in_array(strtolower($method), array_map('strtolower', get_class_methods('CI_Controller')))
)
{
show_404("{$class}/{$method}");
}
simply define your function private and put an uderscore befor the function name for example :
class Some_class extends CI_Controller{
private function _some_method(){}
}
I would instead make it a helper function. To do so, put a file in your system/application/myval_helper.php, then add your function in there. Then just call:
$this->load->helper('myval');
And you'll be able to access the function. Another alternative is to simply use .htaccess to block that exact URL.