I am writing a ZF application. I had some abstract parent classes in a library directory. Netbeans could generate test skeletons for the child classes no problems, and I could run the tests no problem.
Later on I decided to move the abstract parents out of the library and in to the application directory (to improve readability). I updated my application code accordingly, and it runs no problem.
However, now when I use netbeans to generate test skeletons for the child classes, it gives a fatal error saying it can not find the parent. I then constructed a test class manually and ran it from the command line, and PHPUnit gave the same error.
What do I need to do to get this pathing working correctly? In the PHPUnit bootstrap I tried adding the Application directory to the include path, and registering Application as a namespace with the Zend Autoloader. I don't think this is a recommended practice, and it failed anyhow...
I really do struggle with path issues, finding files, etc...
Any assistance is much appreciated.
OK, so I can move the classes from the library to the core code directories, and the core code finds them no problems because they conform to the standard naming conventions autoladed by ZF.
Other applications (e.g. PHPUnit) won't be able to find them though. I could get around this by setting their autoloading the same ZF. Alternatively, I could incorporate required files with require_once (which would negate the use of autoloading in the first place).
So, it seems that my best shot is to put the shared classes back in the library. My original PHPUnit bootstrap adds the library prefix to the ZF autoloader, so I'm good to go.
All-in-all, I've just learned another good use for libraries.
[EDIT:] Another Alternative...
My test classes are boostrapping Zend Application which sets up the autoloading for PHPUnit. The only drawback doing it this way is that PHPUnit (via my netbeans IDE) can't create the skeleton tests for me. I guess I'll have to live with that.
Related
I am working on very old legacy code, mostly procedural. Trying to improve it. Rewriting applications is impossible right now. The plan is to add a few libraries which would help organize things and improve that way.
I added a Symfony dependency-injection component in order to do that. It would provide the possibility to fetch needed services with its dependency easy.
I watched symfonycast tutorial on how to play with container. And with that knowledge, I managed to write a simple loader to start the container and to use services made by me. It is simple, it guesses FQCN based on file path, and then uses reflection to get dependencies. But I can not figure out how to load vendor classes, because here you can not guess namespace that way. :)
The question is: What exactly Symfony uses to load classes from the vendor folder, does it reads composer.json files to see namespaces, does it uses some composer feature, or something else?
Loading classes is different than instancing services.
The first can in fact use regular composer facilities to discover vendored classes in a legacy project like yours, even if they weren't installed with composer. This uses the standard php autoload mechanism with some added magic.
To include the, let's say lib/ legacy directory in the discoverable files you would add the following to composer.json:
"autoload": {
"classmap": ["lib/"]
}
And then run composer dump-autoload. Note that by including vendor/autoload.php in your legacy files you could even forego the require directives for your dependencies and rely on composer as well. This can be a path for migrating them to composer-managed dependencies, too.
Service instancing requires not only being able to locate the classes themselves, but also their respective dependencies so the container can create the object tree automatically. This usually involves hand-writing service definition files: classes in the vendor/ folder are not automatically registered as services. A bundle (or your own definitions) enables support for an specific library.
Take for instance the Mailer component: you can use it as a standalone library, but for framework integration (which includes service definitions and depen) you'd need to install Mailer bundle as well.
The exception where automatic service registration applies (when using symfony framework, not the standalone dependency injection component) is for files under src/. During container compilation, services.yaml is loaded and the ContainerConfigurator with help from FileLoader, looks for *.php files the directories configured as a resource, creating service definitions for them.
I guess you could do a similar thing for your legacy dependencies in a CompilerPass by using a similar technique or by trying to leverage the composer classmap but, specially if your legacy dependencies do not follow a PSR loading standard, I'd advise against it, since it can pull in tests, example files, etc.
I'm encountering a wholly predictable yet incredibly annoying and tough to resolve problem.
I've been working on a PHP framework for developing WordPress plugins. It's using Composer for dependency management. Of course, the problem is if you have two instances of my framework in the same installation of WordPress, you have two vendor folders, and two copies of any packages required by the framework. Which leads to an error.
The framework functions as a separate plugin which is then inherited by any apps/plugins that are build on it.
Move the vendor folder to the core framework folder?
Problems: I don't know what would happen if I have two composer.json files and two composer.phar files writing to the same vendor folder and using the same autoloader. Presumably it wouldn't be good. Besides that, it doesn't solve the problem of collisions with composer packages that could be used by any other script or plugin outside of what I'm trying to handle.
So I'm stuck. Is this a problem that can be solved, or is it just inherent in PHP?
Composer is not really meant to be used multiple times in same project. On other hand there is nothing terribly wrong with it either, however you lose its dependencies features and need to treat this like generic case of dependencies in WordPress environment.
In other words - if you are not doing dependencies Composer way and WordPress is not doing dependencies at all, it becomes your personal problem how to deal with it.
I don't know what would happen if I have two composer.json files and two composer.phar files writing to the same vendor folder and using the same autoloader
I am not following why the vendor folder would be same if you are using multiple composer installs... Could you elaborate on how you structure it and is it meant for public or private use?
I'm not very familar with Composer or the plugin framework you are using, but in general - avoiding function/class name collisions in WordPress plugins is done in the following manner:
Assuming that your plugin (e.g. MyCoolPlugin) is written object-oriented, e.g. as a class named MyCoolPlugin, you may include the helper class/library as a subclass of MyCoolPlugin.
class_exists(), this is PHPs way of finding if a class has been defined. Assuming your helper class the following:
class MyHelperClass{
}
You may use the following check before declaring the class in each of your plugins:
if(!class_exists('MyHelperClass')){
class MyHelperClass{
}
}
Of course, there is a trade-off here, because only the first instance of the class will be used throughour WordPress. E.g. if you have two plugins with two different versions of the helper class - only one of them will be active and available at any given moment.
A global variable - e.g. define('MY_HELPER_IS_LOADED', true); in the helper files (in case you are including them via include() or require()). Then in the beginning of each included helper file check with if(defined('MY_HELPER_IS_LOADED')) return;, which will cause the currently requested file for include/require to NOT be included.
Again the tactics above are used in PHP in general, I am not sure how your plugin framework is set up exactly.
I played with the zf2-tutorial successfully, but I was totally confused when trying to integrate an external library like "jpgraph". I know I must do this with autoload or servicemanager but it won't work.
The php-files of jpgraph are in the vendor/graph directory. I use a module called Jpgraph, in the controller indexAction I try:
$graph = new Graph($width,$height);
this gives me an error:
Fatal error: Class 'Jpgraph\Controller\Graph' not found in ...
the jpgraph library don't use namespaces.
i also tried this way without success
what's the best way to integrate such things?
I would be glad for every tip or help
Add the library to your composer.json and add the class with Classmap and/or the include path as phpunit does
https://github.com/sebastianbergmann/phpunit/blob/master/composer.json#L48
One option, as Maks3w pointed out, is to use Composer. If you've never heard of or used composer before it's definitely worth a look. I was surprised how easy it was to set up and use 3rd party libraries. It's also very easy to set up your own library to work with composer, and use any source controlled (git or svn) library of your own - works well with GitHub repos - just add a composer.json file.
On the other hand, you do not need to use composer to do what you want, it would make it very easy, but it may be overkill. Zend Framework 2 has a very flexible autoloader system, and although it works well with PSR-0, you can have any class autoloading sytem that you like. Take a look at the different components of Zend\Loader, in particular I think the ClassMapAutoloader will be the one to suit your needs.
What is the best way to integrate an external script into the Zend Framework? Let me explain because I may be asking this the wrong way. I have a script that downloads and parses an XML file. This script, which runs as a daily cron job, needs to dump its data into the database.
I am using Zend Framework for the site which uses this script and it seems to me that it would be best to use my subclassed model of Zend_Db_Abstract to do the adding and updating of the database. How does one go about doing this? Does my script go in the library next to the Zend Components (i.e. library/Mine/Xmlparse.php) and thus have access to the various ZF components? Do I simply need to include the correct model files and the Zend DB component in the file itself? What is the best way to handle this sort of integration?
Yes, you should put your own classes that maybe inherit Zend Framework classes or add further classes into your own folder next to the Zend Framework folder in library.
When you have Zend_Loader s auto-loading enabled, the class names will automatically map to the class you created, e.g.:
My_Db_Abstract will map to My/Db/Abstract.php .
In your library directory you should have your own library next to the Zend library folder. Whatever you call it (Mylib, Project, ...) you should include it into the Zend Autoloader and that's done as follows:
require_once 'Zend/Loader/Autoloader.php';
$loader = Zend_Loader_Autoloader::getInstance();
$loader->registerNamespace('Project_');
$loader->setFallbackAutoloader(true);
if ($configSection == 'development')
{
$loader->suppressNotFoundWarnings(false);
}
In order for you library to integrate nicely with ZF and the Autoloader you should stick to the ZF naming conventions. This means two things:
if you extend an existing ZF class, replicate the ZF folder structure so that your file has the same path and name except for the library name. E.g. /library/Zend/Db/Abstract.php => /library/Project/Db/Abstract.php.
if you write your own classes, still stick to the ZF naming conventions for the autoloader to find them.
I just came across something that may be germane to this question. This IBM developerWorks article.
The author recommends simply creating a scripts folder in the ZF hierarchy and the using it as one normally would within ZF (though he does set the ini path and call autoload). Is it that simple? Does simply being in the hierarchy of the framework and including the path and autoloader grant your script access to all of the goodies?
I'm not 100% sure what you're trying to ask but I will try to help. If at any point you add a reference to "/path/to/zend/framework" into your php include path then you have in essence enabled the Zend Framework. From there if you do:
require_once('Zend/Loader.php');
Zend_Loader::registerAutoload();
Then at any point in your script you can pretty much just create new Zend Framework objects and Zend_Loader will handle the rest.
One of the big things about the Zend Framework though is not forcing you to do things a certain way. That's why sometimes there are several ways to accomplish the same thing. So, if you feel you need to make your script use the Zend Framework just for the sake of doing so this is not really necessary. But if you think it may improve your script in some way then go for it.
I usually put custom stuff that I think could be used across projects in a custom folder in the library. So I have a library/Ak33m folder that has scripts that may be outside of the framework.
As a ZF noob myself, I think I understand some of what the OP is trying to figure out. So, I'll just explain a bit of what I understand in the hope that it is helpful either to the OP (or more likely, to a future reader, since the original question is so old and I imagine that OP is now a ZF guru).
I understand that ZF claims to be largely "use at will", so that you need no buy into an entire structure, like the Zend_Application, the Zend_Bootstrap class, the entire MVC approach, etc.
Further, I understand conventions for class naming and file locations that enable easy autoloading. Ex: class App_Model_User resides in a folder App/Model/User.php
I think what can be potentially confusing is that in the script context, where you have not yet
done the .htaccess magic that pushes all request to public/index.php
set your APPLICATION_PATH and include paths in public/index.php
created your Application or Bootstrap object tied to a config file
it can be a little bit unclear how best to avail yourself of most of the ZF goodness we get in that context and want in another context.
I guess my answer to the original question would be that the usual entry point sequence of
http request -> .htaccess -> index.php -> config
sets up much of our environment for us, we would need to duplicate some of that for different entry path.
So, for your script, my first instinct would be to create a common include file that mirrors much of what happens in index.php - set the include paths, the APPLICATION_PATH, instantiates and calls a bootstrap, and then does your script-specific processing.
Even better, it might be desirable to create a single entry point for all your scripts, like we do in the http/web context. Extend Zend_Application for your own script purposes so that $application->run(); no longer starts up the MVC router-controller-dispatch processing, but rather does your own stuff. In that way, this single script entry point would look almost identical to the web entry point, the only difference being which application object gets instantiated. Then pass the name of your desired Application class as a command line parameter to the script.
But here I confess to being less confident and just throwing out ideas.
Hope all this helps someone. It actually helped me to write it all down. Thanks and cheers!
Update 2009-09-29: Just ran across this article: Using Zend Framework from the Command Line
Update 2009-11-20: And another article: Cron jobs in Zend Framework | GS Design
Update 2010-02-25: Easy command line scripts with Zend Application - David Caunt
I've been looking for a good PHP ORM tool to use, and I recently found a good ORM class in Kohana. It has a fairly good and simple ORM implementation. The problem is, the code is unreusable outside of the Kohana framework without a rewrite/refactor. It relies on the Kohana class loader and various framework loading strategies to even work in the first place. Further, the required classes aren't packaged into a single dependency directory, or even multiple directories.
When I do this rewrite, I intend to republish the code via sourceforge or something, and those guys can of course reuse it if they want. So, should I just package the fileset needed into one directory, and make the appropriate classes do a require_once on any dependant classes, and 2 should I stick with the original class names that are project dependent (like Kohana_exception) even though it is pretty much unrelated to the Kohana project as a whole?
A second option would be to write another classloader that is a simplified version of the Kohana Framework classloader, and only cares about the ORM related stuff...
If you think what you are doing will be a marked improvement to the Kohana project you should make your changes and submit a patch to be considered by the project's maintainers. You probably aren't the first person to appreciate a part of their framework and component-izing their framework into smaller bits may be something you could help encourage by submitting a patch (though that will require much more time on your part to engineer).
It sounds like you are extracting a piece of their framework for independent use so it doesn't sound like you're forking at all, though I can imagine removing all of those dependencies may sure seem like a fork.