Zend autloading different namespaces from the same directory? - php

I have a models directory in my project, and I would like to save/files classes there with different namespaces.
Example:
models/User.php with classname Model_User
models/Table_User.php with classname Model_Table_User
For the first namespace I have this in bootstrap.php
$resourceLoader->addResourceTypes(array(
'model' => array(
'namespace' => 'Model',
'path' => 'models'
)
));
I can't figure out how to add the second namespace so it detects files starting with Table_ Any ideas?
For now I've added a second directory named 'tables' but it's getting confusing because I have each model name twice (once in the models diretory and once in the tables directory)

Its because of the _ in Table_User. The autoloader is probably looking for:
models/Table/User.php
Try renaming the file to
TableUser.php
And the class to:
Model_TableUser
Or create the Table folder and put User.php in there.

That's something I do myself.
I have "Model_" sat in '{APPLICATION_PATH}/models/' and "DbTable_" sat in '{APPLICATION_PATH}/models/dbtables/'.
$resourceLoader->addResourceTypes(array(
'model' => array(
'namespace' => 'Model_',
'path' => APPLICATION_PATH.'/models/'
),
'dbtable' => array(
'namespace' => 'DbTable_',
'path' => APPLICATION_PATH.'/models/dbtables/'
));
You should of course modify this to according to your classnames and folder structure.
APPLICATION_PATH is defined in your index.php -- but I don't remember if it contains a trailing slash, so check that just in case. (I'm not on my pc at the moment so I cannot check...)
Simple as that! :)

Related

Phalcon Router and Loader for subfolder structure getting bigger. How to set up?

I have a quite big project that I need to program. I used to code with CodeIgniter but since they stopped maintaining the framework, I decided to switch to another. I chose Phalcon framework. The folder structure of the application that I want to implement is next:
app/
controllers/
admin/
users/
UsersController.php
UserGroupsController.php
dashboard/
system/
another_subfolder/
AnotherSubFolderController.php
production/
settings/
SettingsController.php
dashboard/
flow/
another_subfolder/
AnotherSubFolderController.php
website1/
customers/
CustomersController.php
CompaniesController.php
another_subfolder .... /
models/
sub_folder_structure/ // The same as controllers
This is just example of the folder structure of the application. There will be quite a lot of folders and sub-folders in this project to make it manageable.
From my understanding I need to register all namespaces at the loader for each sub-folder, so that Phalcon knows where to search and load the class.
//Register an autoloader
$loader = new \Phalcon\Loader();
$loader->registerNamespaces(array(
// Main
'Controllers' =>'app/controllers/',
'Models' =>'app/models/',
// Admin Routing
'Controllers\Admin'=>'app/controllers/admin',
'Models\Admin'=>'app/models/admin',
'Controllers\Admin'=>'app/controllers/admin',
'Models\Admin'=>'app/models/admin',
'Controllers\Admin\Users'=>'app/controllers/admin/users',
'Models\Admin\Users'=>'app/models/admin/users'
))->register();
The loader will look quite big.
Then I have to set-up the router so that requests redirected to the right controller. Right now I have next:
// Setup Router
$di->set('router', function(){
$router = new \Phalcon\Mvc\Router(false);
$router->removeExtraSlashes(true);
$router->add('/', array(
'namespace' => 'Controllers',
'controller' => "login"
));
$router->add('/:controller/:action/', array(
'namespace' => 'Controllers',
'controller' => 1,
'action' =>2
));
$router->add('/admin/:controller/:action/', array(
'namespace' => 'Controllers\Admin',
'controller' => 1,
'action' =>2
));
$router->add('/admin/users/:controller/:action/', array(
'namespace' => 'Controllers\Admin\Users',
'controller' => 1,
'action' =>2
));
return $router;
});
That will be also very big if I need to manually setup router for each sub-folder and namespace.
So the questions that I have are this:
Is there any way to make a loader prettier and smaller? As it will grow bigger.
How can I setup router so that I don't need to enter all of the namespaces and combinations of subfolders? Is there any way to make it smaller? May be modify dispatcher or any other class? Or is there a way I can set a path variable in the router to the location of the controller?
I have researched Phalcon documentation but could not find the way to do that.
Any help and suggestions are very much appreciated.
Thanks
Ad. 1. You can change your namespaces to be more PSR-0 (in my opinion), so I would make:
app
controllers
Admin
Users
UsersController.php
The you can register one namespace Admin or any other. Then you need to register only the top most namespace to work (keep in mind that your UsersController must have namespace Admin\Users\UsersController; to work). Thena autoloader should have only:
$loader
->registerDirs(
array(
// It's taken from my config so path may be different
__DIR__ . '/../../app/controllers/'
// other namespaces here (like for models)
)
);
I'm using registerDirs so I only point loader to the folder in which some namespace exists.
Ad. 2.
For this you can use groups of routes so you can pass a namespace as a parameter for config array of constructor and then do the repeative task in one place. Then just create new instances with different parameters;
$router->addGroup(new MahGroup(array('namespace' => 'Mah\\Controller'));
So inside MahGroup class could be:
class MahGroup extends Phalcon\Mvc\Router\Group {
public function _construct($config = array()) {
$this->setPrefix('/' . $config['perfix']);
$router->add('/:controller/:action/', array(
'namespace' => $config['namespace'],
'controller' => 1,
'action' => 2
));
// etc...
}
}
And then configuring routes:
$router->addGroup( new MahGroup(array('prefix' => 'mah-namespace', 'namespace' => 'Mah\\Namespace' )) );
$router->addGroup( new MahGroup(array('prefix' => 'mah-other-namespace', 'namespace' => 'Mah\\Other\\Namespace' )) );
But given examples for second question are just what could be done. I usually create Group class for each namespace and then declare some routes that my app uses since I'm not using english names for routes and I need rewriting polish urls to controllers which have also some namespaces.

Phalcon router doesn't react to subfolders and namespace declaration

So I've been reading a ton of stackoverflow and phalcon forum threads.. (I'm starting to hate this framework), but nothing seem to work and it doesn't explain why like Laravel does, for example.
I'm just trying to be able to operate with this application structure:
As you can see, all I want is to use namespaced controllers in subfolders to make more order for my code.
According to all explanations, here's my loader.php:
<?php
$loader = new \Phalcon\Loader();
/**
* We're a registering a set of directories taken from the configuration file
*/
$loader->registerDirs(
array(
$config->application->controllersDir,
$config->application->modelsDir,
$config->application->pluginsDir
)
)->register();
AFAIK, Phalcon should traverse all subfolders for not found classes when used via registerDirs.
Then I define my routes to specific controller after the main route to index controllers in base directory:
<?php
$router = new Phalcon\Mvc\Router(false);
$router->add('/:controller/:action/:params', array(
'namespace' => 'App\Controllers',
'controller' => 1,
'action' => 2,
'params' => 3,
));
$router->add('/:controller', array(
'namespace' => 'App\Controllers',
'controller' => 1
));
$router->add('/soccer/soccer/:controller', array(
'namespace' => 'App\Controllers\Soccer',
'controller' => 1
));
$router->add('/soccer/:controller/:action/:params', array(
'namespace' => 'App\Controllers\Soccer',
'controller' => 1,
'action' => 2,
'params' => 3
));
return $router;
And one of my controllers look like:
<?php namespace App\Controllers\Soccer;
use App\Controllers\ControllerBase as ControllerBase;
class IndexController extends ControllerBase
{
public function indexAction()
{
}
}
What's wrong here? Default top namespace is not registered? Am I missing something?
This just doesn't work. When I try to open myserver.com/soccer which I expect to go to app/controllers/soccer/IndexController.php, but instead it tells me:
SoccerController handler class cannot be loaded
Which basically means it's looking for SoccerController.php in /controllers directory and totally ignores my subfolder definition and routes.
Phalcon 1.3.0
Stuck on this for a week. Any help - Much appreciated.
I was having a problem with loading the ControllerBase and the rest of the controllers in the controllers folder using namespaces. I was having a hard time since other example projects worked fine and I realized that I was missing a small detail in the despatcher declaration where I was supposed to setDefaultNamespace
(ref: https://github.com/phalcon/vokuro/blob/master/app/config/services.php)
$di->set('dispatcher', function () {
$dispatcher = new Dispatcher();
$dispatcher->setDefaultNamespace('App\Controllers');
return $dispatcher;
});
or you can specify it directly on the routing declaration file like this
$router->add("/some-controler", array(
'namespace' => 'App\Controllers'
'controller' => 'some',
'action' => 'index'
));
that should work as well, it might be a bit confusing at first with namespaces but once you get a hang of it you will love this extremely fast framework
It looks like your namespaces have capitals
App\Controllers\Soccer
and your folder structure does not
app\controllers\soccer
In my app I have controllers with a namespace and I have just tried changing the case of the folders so they don't match and I get the missing class error.
Of course it does raise a question, how many controllers are you planning on having that namespacing them is worthwhile? Are you grouping controllers and action by function or content? I used to have loads of controllers in Zend, but now I have grouped them by function I only have 16 and I am much happier. e.g. I suspect soccer, rugby, hockey etc will probably be able to share a sport controller, articles, league positions etc will have a lot of data in common.
ps Don't give up on Phalcon! In my experience it is sooo much faster than any other PHP framework I have used it is worth putting up with a lot :)
Are you sure Phalcon traverses subfolders when registering directories to the autoloader? Have you tried adding a line to your autoloader which explicitly loads the controllers\soccer directory?
Alternatively, if your soccer controller is namespaced, you can also register the namespace: "App\Controllers\Soccer" => "controllers/soccer/" with the autoloader.

Doctrine2 entities in multiple namespaces

I'm developing a web application using Zend Framework 2 which will be made of several modules, and I'd like to put the entity classes in the module to which they belong.
Is it possible to do this using Doctrine2 ORM? By reading the docs, it seems to always expect to have all the entities under at most one namespace, while I'd like to have
Module1\Entity
Module2\Entity
and so on...
How could this be made possible?
Thanks to all!
The first step to doctrine configuration is within your global configuration file to set up the connection. Personally i do this in two files, the first is ./config/autoload/global.php and the second one being ./config/autoload/local.php
This is for one very reason and this is that anything containing local doesn't get posted into my git repositories. So my credentials are safe.
./config/autoload/global.php
return array(
'doctrine' => array(
'connection' => array(
'orm_default' => array(
'driverClass' => 'Doctrine\DBAL\Driver\PDOMySql\Driver',
'params' => array(
'host' => 'localhost',
'port' => '3306',
'dbname' => 'dbname'
)
)
)
),
);
./config/autoload/local.php
return array(
'doctrine' => array(
'connection' => array(
'orm_default' => array(
'params' => array(
'user' => 'root',
'password' => ''
)
)
)
),
);
The second step would be to create a driver for your entities. This is done on Module Namespace base.
./modules/ModuleNamespace/config/module.config.php
<?php
namespace ModuleNamespace;
return array(
//... some more configuration
'doctrine' => array(
'driver' => array(
__NAMESPACE__ . '_driver' => array(
'class' => 'Doctrine\ORM\Mapping\Driver\AnnotationDriver',
'cache' => 'array',
'paths' => array(__DIR__ . '/../src/' . __NAMESPACE__ . '/Entity')
),
'orm_default' => array(
'drivers' => array(
__NAMESPACE__ . '\Entity' => __NAMESPACE__ . '_driver'
)
)
)
)
);
What's happening there? Well, we extend the doctrine['driver'] array by adding a new driver. The driver has the namespace of our module. For this we also need to define the namespace in our configuration file. The driver defines that all Entities for this driver are within a certain path.
The next step done is that the orm_defaults driver gets extended by an assignment defining that all ModuleNamespace\Entity classes are loaded from our ModuleNamespace_driver configuration.
And ultimately this is done for each single module. So no matter if you're having a Filemanager\Entity\File or PictureDb\Entity\File classes, both will work and both will get loaded. Modules are - by nature - independant from each other. Though they can have dependencies, or rather work well together, they function on their own. So multiple modules with multiple entities are no problem at all ;)
I hope this makes you understand the topic a little bit. For live working examples i have wrote two blog posts covering the topic.
Installing Doctrine 2 for Zend Framework 2
First Steps with Doctrine 2
These may also help you out a little bit.
If you are using the DoctrineORMModule Proxies will be written to /data/DoctrineORMModule/Proxy. I'm not sure if you have to create the folder manually and adapt privileges.
Attention:
For some reason the ZendSkeletonApplication ships without namespaces set!
ZendSkeletonApplication / module / Application / config / module.config.php
You may get this error if you forget to set the namespace in each module.config.php!
The class ... was not found in the chain configured namespaces ZfcUser\Entity, \Entity, ZfcUserDoctrineORM\Entity

Zend Framework Modules with common resources

I'm having a lot of trouble figuring out how we can have a modular directory structure, with the ability to load resources that are to be shared across modules. I.e.,
application
--- /forms
--- /models
--- /modules
------/module1/
---------/models
------/module2/
---------/models
Now, what I'm trying to do is load forms in /application/forms from within the modules. Everything I've tried results in these classes to not being loaded.
I've tried:
1) Letting Zend try and figure it out automagically.
2) Specifying all the paths in the main bootstrap for the application path as well as the modules. I.e.,
protected function _initAutoload()
{
$front = $this->bootstrap("frontController")->frontController;
$modules = $front->getControllerDirectory();
$default = $front->getDefaultModule();
$moduleloader = new Zend_Application_Module_Autoloader(array(
'namespace' => 'Application',
'basePath' => APPLICATION_PATH
));
foreach (array_keys($modules) as $module) {
$moduleloader = new Zend_Application_Module_Autoloader(array(
'namespace' => ucfirst(strtolower($module)),
'basePath' => $front->getModuleDirectory($module))
);
}
}
3) Smashing my head on my desk many times.
.. and yes, I realize I do not need that loop for modules, as I have blank bootstraps in each module directory.
Any suggestions are welcome. Thanks!
Try this:
protected function _initAutoload()
{
$autoloader = new Zend_Application_Autoloader_Resource(array(
'namespace' => 'Application',
'basePath' => APPLICATION_PATH,
'resourceTypes' => array(
'form' => array(
'path' => 'forms/',
'namespace' => 'Form'
)
)
));
return $autoloader;
}
you don't need the module part, as you already seem to know. Add other resource types as required.
Since this is very close to what you have already, there may be another issue. The above should work assuming that:
APPLICATION_PATH points at the /application directory in your app
The form classes are named Application_Form_Something
The filenames of these classes are Something.php (case sensitive)
e.g. if you have a contact form, you might call the class Application_Form_Contact and this would live at application/forms/Contact.php.
If you're still having issues, please include an example of a form class that isn't being found, along with how and where you are calling it from.

Autoload models with zend in bootstrap.php

I really can't figure this out:
I've created a file called User.php in application/models. The classname in it is Model_User.
When I try to create an object in my Controller, I get this error:
Fatal error: Class 'Model_User' not found in C:\xampplite\htdocs\code\application\controllers\IndexController.php on line 14
I googled around, and found this code, which is supposed to autoload controllers for me, it is located in bootstrap.php The code isn't working though. The example that used this code was working with ZF 1.8 so that might be the reason but I can't figure it out.
How should I autoload my models?!
private function _initAutoload(){
$modelLoader = new Zend_Application_Module_Autoloader(array(
'namespace' => '',
'basePath' => APPLICATION_PATH
));
return $modelLoader;
}
Any ideas?
The important bit in the answer to the question I linked above is the namespace:
$resourceLoader->addResourceTypes(array(
'model' => array(
'namespace' => 'Model',
'path' => 'models'
)
));
The namespace parameter tells the Autoloader to look in the defined path (relative to basePath) when encountering a class that starts with Model_. You have the first part right, but you're missing the call to addResourceTypes.

Categories