I'm building a website using CI, HMVC and Smarty. It's my first time using HMVC and I don't understand how I can use common libraries within the modules.
I prefer using Smarty on my sites and usually it's a piece of cake: I create a wrapper for smarty, autoload it and use it in controllers where necessary. But now I need to use smarty within the module controller and I don't know how to access it. Any ideas how I can do that?
I've been researching the issue for a couple of days, with no luck.
There are some answers which I just don't get: like this one
EDIT: CI 2.1.0, HMVC 5.4, Smarty 3.1.6 (but this is irrelevant)
Here are a couple of ways:
In application/libraries
Just put the common libraries in application/libraries folder and load using $this->load->library('my_library');
Create a common module
Another option would be to create a new module, lets say common, in which you can have folders libraries,models,helpers. Here you can put files which are common to other modules. You can then load them using $this->load->library('common/my_library');
I hope that helps.
You can extend your smarty in your modules with modules. path.
Example:
class MySmartie extends Smartie {
function __construct()
{
parent::__construct();
$this->template_dir = APPPATH . "modules/client/views/templates";
$this->compile_dir = APPPATH . "modules/client/views/templates_c";
}
}
And load this class in your modules class constructor like this:
public function __construct()
{
$this->load->library(['mysmartie' => 'smarty']);
}
Note: don't load smarty in config/autoload.php it may create conflict in loading.
Related
I'd like to use the controllers from the /third_party/myapp/controllers folder without having to move them to the /application/controllers one
It doesn't seem possible (at least not without hacking the core). Though the question concerns loading model, limitations are mentioned here
I don't feel like using HMVC - as stated in the solution proposed there, cause I don't need any other functionality than avoiding to multiply file transfer in CI base folders (i don't really need the 'hierarchical' part of it)
But I don't really get it... if one declares its third_party app, CI will load resources from those folders (as stated by the doc)
config/
helpers/
language/
libraries/
models/
[metaphysical] Why wouldn't it be possible to simply load controllers as well ?
[pragmatic] is it a good idea to try to hack the core system or should I stay on the "HMVC or do copy your files" choice ?
[optimistic] do someone have a solution ?
EDIT
While looking further to trajchevska tip in another installation of CI, I tried to implement DFriend example of spl_register. I read several times the manual and this answer as well :
So far I understood that spl_autoload_register is triggered when a class is called, which allows to skip their manual loading
So I've tried simply adding the spl_autoload_register at the end of the config file in application/config/config.php, expecting it to print Auto load ClassName when a first class is called - a bit naïve, I know.
but from what I understood (thanks to DFriend), this spl_autoload_register would NOT work with controllers, as CI will always check if the file exists (in its own path) before trying to declare the controller.
It seems on the other hand that it could work with other classes (core, model ... see DFriend answer below)
Conclusion
So, after a few hairs pulled out of my head, I decided to try the HMVC extension for CI - MX from WireDesign. It solved my problem of loading any resources from different folder, along with bringing a brand new scope of shared classes and their attached issues (what is available where ?).
As it's the beginning the project I had the opportunity to switch to the "hierarchical" side, otherwise I'd followed Dfriend's advice of
going with the flow and putting controllers for third-party packages
where CI expects them to be
You could use PHP's spl_autoload_register to implement an autoloader. A google search will reveal multiple approaches for using one within the CI framework.
One that works and is often described is to register the autoloader in config.php or maybe a site-specific constants file. Such a solution is to put something like this in one of the mentioned files.
spl_autoload_register(function($class)
{
if(strpos($class, 'CI_') !== 0)
{
if(file_exists($file = APPPATH.`/third_party/myapp/controllers/`.$class.'.php'))
{
require_once $file;
}
}
});
You can use hooks if you want to avoid hacking config.php or some other file. Here's one way to do that.
application/config/config.php
$config['enable_hooks'] = TRUE;
application/config/hooks.php
$hook['pre_system'][] = array(
'class' => '',
'function' => 'register_autoloader',
'filename' => 'Auto_load.php',
'filepath' => 'hooks'
);
application/hooks/Auto_load.php
<?php
defined('BASEPATH') OR exit('No direct script access allowed');
function register_autoloader()
{
spl_autoload_register('my_autoloader');
}
function my_autoloader($class)
{
if(strpos($class, 'CI_') !== 0)
{
if(file_exists($file = APPPATH.`/third_party/myapp/controllers/`.$class.'.php'))
{
require_once $file;
}
}
}
Addendum
On further digging and consideration the above will not work because CI insists that Controllers be in the application/controllers directory or a subdirectory thereof.
PHP will run a registered autoloader when you try to use a class/interface which hasn’t been defined yet. Controllers are php classes so you might expect an autoloader to come to the rescue. But CI is very explicit about where it looks for controller files. If the file is not found then it never attempts any calls to the class. Instead it abandons all hope and immediately issues an 404 error. The autoloader never gets a chance to look for the file.
The answer to the metaphysical question is that CI's routing and URL parsing are tightly coupled to the file storage structure making the desired functionality impossible. (without some serious core hacking)
The answer to the pragmatic question is very subjective. I'm not fond of the HMVC approach and personally would opt for going with the flow and putting controllers for third-party packages where CI expects them to be.
Start: Serious diversion from question at hand
So, what good is registering an autoloader in the CI environment?
Controllers are defined like so.
class Home extends CI_Controller{ ...
The class being extended, CI_Controller, is a core class. If you want to extend this core class for use by multiple other controllers you can use the CI convention of prepending the class name with "MY_". e.g.
class MY_Controller extends CI_Controller
(
//class implementation
}
and then use it to define actual controllers using the extended core class
class Home extends MY_Controller{ ...
The problem is that you can only extend the core CI_Controller once using this convention. What if you have a need for more than one extension to the CI_Controller core class? One solution is registering an autoloader. (A good discussion of this and other ways to overcome the MY_Controller monopoly is HERE.)
An autoloader for these purposes could look this.
spl_autoload_register(function($class)
{
if(strpos($class, 'CI_') !== 0)
{
if(file_exists($file = APPPATH.'libraries/'.$class.'.php'))
{
require_once $file;
}
elseif(file_exists($file = APPPATH.'models/'.$class.'.php'))
{
require_once $file;
}
elseif(file_exists($file = APPPATH.'core/'.$class.'.php'))
{
require_once $file;
}
}
}
Note that the above also allows you to extend models from other models.
End: Serious diversion from question at hand
I assume it's because of the routing process - the CI Router checks whether a corresponding controller exists in the application folder, or a respective route is defined in the config. If none of them is found, 404 is returned.
You can override the Router file to enable loading controllers from other locations. In the core folder, create a MY_Router file that will extend the CI_Router. Then extend the _validate_request function, to allow loading controller files from different path than the default.
UPDATE: So, I've spent some time on this and didn't manage to extend the Router to get the controller file from the third party folder. It's easy to do when it comes to subfolders of the default controllers directory, but setting up a custom directory for reading the controllers is not that straightforward and unfortunately, I couldn't find any documentation on that.
Say I want a constant, a function or a class to be available in all my models, views and controllers code (within a particular web site (application)). Where can I put them? I don't mind importing them explicitly in every file I need them in but I don't know how (simple require_once does not seem to work).
You can put them in the vendor folder (in application/vendor or modules/MOD/vendor). Then you can load it like this:
require Kohana::find_file('vendor', 'folder/file','ext');
You can read up more on this in the user guide
Now, it should be stated you should in general not use functions or globals.
I declare Constants in Bootstrap.php and create my own Helpers for general functions under application/classes/Helpers.
If you need to integrate a third party library into Kohana or want to make code available to other Kohana users consider creating a module instead.
You can define all your constants in new php file and place it in the application/classes directory. In your Template controller or in the main controller like Welcome or Website, just place the code in the __constructor()
require_once Kohana::find_file( 'classes', 'filename' );
I suggest you to put your constant variables in the bootstrap.php file because this is loaded by the framework before every request.
You can simply put your classes in the root of the classes directory, the framework will find.
This worked well for me...
In application/config/constants.php:
define('SOME_COOL_CONSTANT', 'foo');
return array();
In index.php:
Kohana::$config->load('constants');
SOME_COOL_CONSTANT should then be available globally.
I'm building a library for our CodeIgniter app, but it requires many classes (currently I'm at 12).
Is there a best practice for packaging these many clients into one library. So I can just make one call to load it. i.e:
$this->load->library('soaplibrary');
Thanks!
As Summer points out, they have handled this situation somewhat elegantly in CI 2.0 with the concept of Drivers.
With a Driver, you actually create a subdirectory within your 'libraries' directory that contains your 'super' class, and another directory for 'child' classes. Better visual representation of the structure...
This was taken from Here.
and once you have constructed your library, here is the documentation on how to use it.
In CI 2.0, there are drivers to handle this situation. Good luck!
In CodeIgniter 3.1.9 when you load a library file, all classes in this file are included into code.
Let's say in soaplibrary.php you have
class SoapLibrary {
public function someMethod(...
class Test {
public function anotherMethod(...
In your controller you can do:
$this->load->library('soaplibrary');
//now on you can do
$this->soaplibrary->someMethod();
//but also
$test = new Test();
$test->anotherMethod();
CodeIgniter attempts to call the constructor of class SoapLibrary, hence a class with that name must be in there.
I came across the __autoload function in PHP and would like to use it with my MVC folder structure. The function itsself is pretty easy, but how do I achieve a dynamic folder scanning after some kind of naming, please see example:
-application
--controller
--models
---entities
----house
---factories
----houseFactory
--views
-library
-public
As you maybe recognise its very close based on zend framework or other frameworks -as I come from those, however I would like to develop a website without framework and just started to write bootsrap file.
Maybe sombody could help me with the autoload in this - i think - advanced usage.
My Classnames will be like
Model_Entities_House
or
Model_Factory_HouseFactory
witch can be applied to the folder structure.
What I do mostly is use the SPL autoload function, which will help you to accomplish this quite easily. It should be something like this:
spl_autoload_register("MyClass::Autoloader");
Then, you can do something like this
class MyClass
{
public static function Autoloader($className)
{
//parse $className and decide where to load from...
}
}
If you´re using a naming convention, then you should be available to load the required file by just using the name.
I am currently using CodeIgniter to support one site, whose main purpose is to display multiple editable tablekit tables, and handle the AJAX that arrives when you edit them. A kind of PHPMyAdmin [VERY] Lite. It has a number of core helpers and controllers, which run the main workings of the site, mixed in with some site specific controllers and helpers.
I would like to restructure my site so that I can reuse the core code-base in another site. However, I would still like to be have some default controller functions and some cutsom functions in the same controller; i.e. in a system file somewhere:
class My_core extends Controller{
/*
Lots of base functions
*/
}
and on one site:
class site_1 extends My_Core{
/*
Site specific functions
*/
}
Then on the other site:
class site_2 extends My_Core{
/*
Site specific functions
*/
}
Does anyone have any guidance on how I can do this?
Thanks,
Lemiant
If you are using CodeIgniter 2.0 you can achieve most of this with with packages. They will let you load helpers, libraries and models from anywhere, so in each application simply configure a package to be loaded from that shared folder.
As for core libraries (which MY_Controller will be) you will have to implement your own __autoload() function:
http://php.net/manual/en/language.oop5.autoload.php
You can put an autoloader at the bottom of config.php. As long as it is checking the correct folders (local first, then the shared folder structure) it should all work pretty nicely.
I don't know if this is still helpful to you but heres what I've done.
say I have 2 websites, palladium.com and osmium.com.
my file tree looks like this
/var/www/system/ (the CI system folder)
/var/www/palladium/application
/var/www/palladium/public/index.php
/var/www/osmium/application
/var/www/osmium/public/index.php
inside those index.php files are lines that define where /system/ is stored. I've got that set to
$system_folder = "../../system";
Now inside /var/www/system/libraries i have a file named MY_TestClass
<?php
class MY_TestClass {
public function MY_TestClass() {
echo "this is a test of the emergency broadcast system";
}
}
From anywhere inside BOTH palladium.com and osmium.com i can call
$this->load->library('MY_TestClass');
and "this is a test of the emergency broadcast system" will show up.