Controller folders and the new Autoloader in Zend Framework - php

After introduction of Autoloader, I started to port existing ZF app.
The immediate error was that IndexController was extended by BaseController,
which is now cannot be found, although it resides in application/controllers folder, with other controllers.
Does the autoloader paradigm require that BaseController is renamed to My_BaseController and put into library folder? On the other hand, it's so nice to keep all controllers in one folder with a BaseController.

The module autoloader does not load from the Controller's folder by default. You can either add the folder to the included Module autoloader or create your own resource autoloader.
See http://framework.zend.com/manual/en/zend.loader.autoloader-resource.html#zend.loader.autoloader-resource.module for info on the Resource / Module autoloader.
You could do things the old fashioned way though and just require_once('BaseController.php');

I haven't actually seen anything use application/controllers before
Generally, stuff would go into application/modules/<module>/controllers/ where "generic" controllers would go into the default module
You might get a better answer if the above is incorrect if you mention what versions your transitioning between, and how you're trying to call the controller?

Related

class overrides and rewrites with namespace psr-4

i've worked with older php frameworks such as magento 1.x line where class rewriting (other then by core/community/local overrides) is done using framework config and framework getModel() or getSingleton() like calls, that have the opportunity to check the config before loading the class.
in other words, it could very well be that the config is loading a class under a completely different name not just path.
my question is, how could rewrites like this be supported in a newer psr4/composer aware framework where classes are instantiated directly with the new keyword instead of some getModel() call?
you could perhaps put the config checks directly into the autoloader instead of using a method to get the class, but then what about composer libs, using their own autoloaders like vendor/autoload.php? just chaining the autoloaders would give a hit on the wrong class if the rewrite uses another class name and both exists.
some link or explanation on how to perform both overriding (as in core/community/local) and rewrites (as in config myClassName -> newClassName) using newer namespace, psr4 & composer aware techniques would be most welcomed.

How does the PHP 'use' keyword work (in Symfony 2)?

In Symfony 2, all requests are getting routed through app_dev.php (or app.php).
The first few lines look like:
<?php
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Debug\Debug;
...
In theory, I get that this just imports the specified namespace (or class) to the current scope. What I don't understand is how PHP maps this to a file. For example, the Debug class is located in:
vendor/symfony/symfony/src/Symfony/Component/Debug/Debug.php
How does PHP know to look in vendor/symfony/symfony/src/?
I'm probably misunderstanding what is happening, but any clarification would be appreciated.
Knowing which file a class lives in isn't the job of the language, it's the job of the autoloader.
All the use keyword does is this instance is create an alias:
use Symfony\Component\HttpFoundation\Request;
This is saying in the following script, when I refer to Request I really mean Symfony\Component\HttpFoundation\Request. If I use Request object in some way (by either creating an instance or calling a static method on it) then the autoloader will go and try to load the file that class is defined in if it hasn't been loaded already.
The inner workings of the autoloader, though, is different from project to project. There has been a move to standardize autoloader behavior à la PSR-4, but there's nothing in the language saying that you have to adhere to that standard. You could, for instance, have a scheme where all class files reside in a single directory and your autoloader just loads all classes from there, regardless of what namespace they're in.
That scheme would suffer from the fact that you could only have a single class of every name, but there's nothing stopping you from doing it that way.
To answer your question: "How does it know that "Symfony\Component\Debug\Debug" is a valid namespace?"
It doesn't, because it's not actually going out and trying to load that class at this point. If in any random PHP script you put something like this at the top:
use \Non\Existant\ObjectClass;
But don't ever actually use ObjectClass anywhere, you will get no errors. If you try to say new ObjectClass, though, you will get a class not found error.
Simplistically speaking, you have to load all the files beforehand into memory for PHP. PHP does not inherently have any standards to where files are located, the rules for loading files has to be done by your code.
When PHP attempts to load a file, it will check its memory if the class definition exists, if not it will attempt to autoload the file that may contain your class definition; see PHP: Autoloading Classes and spl_autoload_register
Some common autoloading strategies have been defined by the PHP Framework Interop Group:
PSR-0 (Autoloading standard)
PSR-4 (Improved Autoloading standard)
In this case, autoloading is done by Composer, all you need to do is include vendor/autoload.php in any of your scripts and vendor code downloaded via composer can be autoloaded. You can manually add classes into the composer autoloader as well. See: Composer Autoloading

Adding action helper path in Zend Framework 1.11 for namespaced (5.3) classes

Does anyone know how to tell Zend Framework 1.11 how to find my namespaced action helper classes? I'm using proper PHP5.3 Namespaces so not the normal My_Helper etc.
I would love to do this without using an ini file also as I'm not using Zend_Application and don't really want to refactor all my set up.
I can register the view helper path fine with an ini file but cant get action helpers to work.
Working view helper ini config:
resources.view.helperPath.Foo\View\Helper\ = APPLICATION_PATH "/../library/Foo/View/Helper/"
Non-working action helper ini config:
resources.frontController.actionhelperpaths.Foo\Helper\ = APPLICATION_PATH "/../library/Foo/Helper/"
Cant seem to find any information about it?
If you know how to do it without using Ini files that would be awesome too :)
AFAIK, although ZF1 autoloader can handle genuine PHP namespaces, neither the plugin loader used for view helpers nor the standard resource autoloader (typically used for models, forms, etc) can deal with genuine PHP-5.3 namespace path/prefix mappings (see here).
It is probably necessary to:
write your own plugin loader and feed it to the view during bootstrap
write your own resource autoloader and invoke it in application/model bootstraps.
Bummer. Hope I am wrong.
ZF2 - still in late beta as the time of this writing - is fully capable to dealing with true PHP namespaces.

Zend Framework Plugin Package Loader

The challenge:
I want to modularize my library folder in my zend framework app. This is fine, if you want to put everything in the same namespace such "App_." But the problem comes in when you have a dozen packages such as a SignUp package, ACL Package, Navigation Package, Foo Package etc. Now each packages has some view helpers, some controller plugins, some action helpers plus some other base classes. You could add each view helper path individually, but that could junk up your application.ini file/ bootstrap.
So the question is, is anyone aware of 'Plugin Package' loader for ZF?
To clarify, it would be nice to have a resource plugin that you pass the package name, it adds the namespace, registers some default options like helper paths and then you can configure it to add helpers to Action Helper brokers. Each plugin package might have to have its own ini file or an init class that where the programmer could initialize the plugin package. Any thoughts or knowledge of something like this would be appreciated.
Your question is difficult to find a solution to. ZF doesn't seem to be used in the manner you wish.
For example you want the following packages
Navigation
ACL
Sign Up
These are all completely separate and don't all 'plugin' to ZF in a similar manner.
Navigation needs to be stored and built for each request that needs the package, the navigation object then needs to be used in Zend_View objects or perhaps not. What happens when the navigation is referenced in a view but it doesn't exist?
The ACL package is so specific, it integrates into ZF in a lot of different ways, it needs a Zend_Controller_Plugin, it needs a way of meaningful way of storing and building the Zend_Acl object for querying on an application to application basis.
Sign Up needs a controller, an action and a form which is passed to Zend_View and the form needs to be process. This then needs to be plugged into your ACL object, presumably a database and perhaps various other parts of your site it it requires more specific permissions that fall outside of the use for ACL
Its not impossible to do what you want, but there must be a better way. It almost sounds like your trying to build a CMS with optional, plug-able packages?
The ACL issue I have resolved by having a Library of controllers, helpers, models, forms, etc. A Zend_Controller_Plugin runs and attempts to log in the user, this plugin is run for every app I create, it works well uses an ACL object format which I have used for a while.
For Sign Up I have a RegisterController in my Library, if my application requires registration it has its own RegisterController which extends the RegisterController in the Library. If the application doesn't need registration then it doesn't have its own RegisterController.
I hope that helps, I really think that doing this in the abstracted way suggested isn't worth it and will never be so solid and tight you can truly rely on it because each application is specific.
Generally, in this case you should use modules which are already modularized instead of modularizing the library.
modules/
signup/
models/
plugins/
The default module resource autoloader is configured by default to load plugins:
See: http://framework.zend.com/manual/en/zend.loader.autoloader-resource.html:
If you really need to modularize the library, the customized autoloader will be the best solution (there is an easy to extend abstract autoloader).
You may also consider separate library for each module, added to your include path (not recommended, because it will slow down the app):
modules/
signup/
models/
library/

Is registering the autoloader needed zend_loader::registerAutoload()

I'm guessing this line registers the autoload function, which in turn loads needed Zend classes.
Zend_Loader::registerAutoload();
My question: is this line meant to be used in applications that call some zend components but aren't fully zend applications? or is needed also in applications that are fully zend and use zend MVC?
Well, first we should note that Zend_Loader::registerAutload() is deprecated (since 1.8.0). Better is:
Zend_Loader_Autoload::getInstance();
What this does is register an SPL __autoload($classname) function that attempts load classes when they are called for but not-yet-loaded. The default behavior of this autoloader in a non-framework application is to map a class name to a file name (relative to the currently defined include_path) and include() that file in the hopes that the requested class will be defined there.
The specific mapping uses the PEAR 1-class-1-file convention in which a class named something like My_ComponentName_ClassName will reside in the file My/ComponentName/ClassName.php.
See this answer for more details.

Categories