Loading vendor files

Published on and tagged with cakephp  tip  vendor

The traditional way to load files from the “vendors” folders — using the vendor() function — has been deprecated a while ago in the development branch (you get a warning if you use this function).

The new way is to use App::import(). To load a file named “example.php”, you have to use the following snippet:

App::import('Vendor', 'example');

Unfortunately, there’s a snag to it: it only works if the name is in lowercase, i.e. the following snippet won’t load the file “Example.php”:

App::import('Vendor', 'Example');

Instead you have to use:

App::import('Vendor', 'example', array('file' => 'Example.php'));

The second parameter can be any string except an empty string or null, but I don’t know what the meaning of this parameter is in this context…

The same also applies for folder names:

App::import('Vendor', 'example'.DS.'example'); // loads example/example.php
App::import('Vendor', 'example', array('file' => 'Example'.DS.'example.php')); // loads Example/example.php

It’s quite illogical, but according to some newly added tests it is supposed to work in this way…

32 comments baked

  • nao

    “CakePHP: the rapid development php framework.”

    lol

  • nao

    “CakePHP: the rapid development php framework.”

    App::import(‘Vendor’, ‘example’, array(‘file’ => ‘Example’.DS.’example.php’)); // loads Example/example.php

    lol

  • Brendon Kozlowski

    nao, you apparently haven’t seen how the Zend Framework imports files into its bootstrap. It’s about the same as Cake’s long example above (last I’ve seen it anyhow, they may have updated it). Cake truly does make development much more rapid, regardless of some nuances that Dan will tell us about (so that we do not run into the same problems that he does).

  • cakebaker

    @nao, Brendon: Thanks for your comments!

    @nao: *g*

    @Brendon: I think the problem is not necessarily that you have to write more, the problem is that the current solution is inconsistent. And that’s what slows you down, not the typing of some more characters.

  • Nik Chankov

    Daniel, thanks for the info. Hope the development team correct this. I don’t experience problems with this but I really wont like to see app crashing while I upgrade the framework.

  • luke

    to be fair, I think you should include the offical trac mentions of this – it seems to point to a naming convention (dot syntax?) being implemented in this re-mixed vendor import code.

    https://trac.cakephp.org/changeset/6600

  • cakebaker

    @Nik: Yes, I also hope it will get corrected, but I think it won’t happen as recently two respective tickets were closed and tests were added to verify this behavior…

    @luke: Yes, it is mentioned that the failing approaches don’t follow the naming conventions for file and directory names. But according to the manual there are no conventions for vendors ;-)

  • luke

    ah, didnt know that… but doesnt that just mean it is a problem with the manual therefore ;)

  • blueballoon

    What happend to the good old vendor inclusion function ?
    vendor(‘Example’);

    For cake 1.2 couldn’t it be made like this :
    App::import(‘Vendor’, array(‘file’ => ‘Example.php’));

  • Mark Story

    this definitely makes vendor imports far more difficult to use than they used be. But looking at how App::import works. There isn’t a lot of room for adapting something simpler without having to rewrite the entire app:import. Another option is to always specify the 3rd parameter. That would at least keep your vendor imports looking clean and predictable.

  • cakebaker

    @luke: The explanation in the manual makes sense to me :)

    @blueballoon: Personally I would prefer the same syntax as you could use with the vendor function:

    App::import('Vendor', array('Example1', 'Example2'));
    

    @Mark: Yes, specifying always the 3rd parameter is a possible option. Another option is to copy the code of the vendor() function and to create your own “vendor” function in bootstrap.php.

    But those are only workarounds, the main problem remains. I think it wouldn’t be that difficult to refactor App::import() accordingly. In the simplest case you could check whether the type is “Vendor” and then call a method which handles the import of vendor files.

  • Migrating from CakePHP 1.2beta to RC1 - cakebaker

    […] which don’t follow the cake conventions have to be treated differently (see also Loading vendor files). […]

  • Luizz » Blog Archive » Vendors e App::import nella nuova release

    […] non è uno di quelli segnalati da Cakebaker nei suoi post Migrating from CakePHP 1.2beta to RC1 e Loading vendor files, bensì legato alla logica di funzionamento di questi […]

  • Alejandro García

    The manual has documented a bit more the App::import method. If the class you’re importing has the same filename (example: class Dog, file dog.php) then you use: App::import(‘Vendors’, ‘dog’). If the class has a different filename or a filename with dots or file inside folder (example: class PHPMailer, file class.phpmailer.php inside phpmailer folder in vendors dir) then you use: App::import(‘Vendors’, ‘PHPMailer’, array(‘file’ => ‘phpmailer’.DS.’class.phpmailer.php’). Note that when you specify the filename, you must include the file extension.
    Seems to work this way because everything gets automagically configured, class name and file name.
    Cheers.

  • cakebaker

    @Alejandro: Thanks for your comment! Yes, in principle you can say that the short form can be used if you follow the cake naming conventions, and in the other cases you have to use the array with the “file” key.

  • Anand

    helped me a lot.Thanks

  • cakebaker

    @Anand: I’m glad this article was helpful for you!

  • Justin

    Thanks for this, the DOCS never mentioned anything about it needing to be lower case. Was pulling my hair out until finding this.

  • cakebaker

    @Justin: You are welcome!

  • francis

    hi there, is it possible to import just the folder name and it automatically import all the files that the folder contains?

  • cakebaker

    @francis: Thanks for your comment!

    As far as I know App::import() doesn’t provide such a feature. And so you have to do it manually by looping over the file names of the respective folder and calling App::import() for each file. To make this functionality reusable, you might want to put it into its own method.

    Hope that helps!

  • francis

    i thought so.. thanks for the suggestion.. i did it and i think it worked fine.. ill post the code here.. maybe it’ll be helpful to others too.. :)

    // Recursively adds a whole folder as a vendor.
    function importVendorFolder($dir)
    {
    	//store ".php" files in current directory
    	$files = Configure::__list($dir, ".php");
    	foreach($files as $file)
    	{
    		//import php file.
    		app::import("Vendor", $file);
    	}
    	//store folders in current directory
    	$folders = Configure::__list($dir);
    	foreach($folders as $folder)
    	{
    		read_my_dir("{$dir}/{$folder}");
    	}	
    }

    in here i used the built in cake function “Configure::__list” to check if the file is a folder or a file..

    and to call it:

    //parameter is path to the vendor folder.
    importVendorFolder("../vendors/lib");

    hope this will be useful to you guys.. :D

  • francis

    correction..

    //store folders in current directory
    	$folders = Configure::__list($dir);
    	foreach($folders as $folder)
    	{
    		read_my_dir("{$dir}/{$folder}");
    	}

    “read_my_dir” was supposed to be “importVendorFolder”

  • cakebaker

    @francis: Thanks for sharing your solution!

    An idea to simplify your function is to use CakePHP’s Folder::findRecursive() to get the file names (as a side effect you would also get rid of using the “private” method Configure::__list()).

  • dojo

    and where do i add the code to import the vendor at?

    App::import(‘Vendors’, ‘PHPMailer’, array(‘file’ => ‘phpmailer’.DS.’class.phpmailer.php’).

  • cakebaker

    @dojo: You can call the import() method wherever you want. Often it is done right before the class definition, e.g.:

    <?php
    App::import('Vendors', 'some vendor file);
    
    class Xy {
    }

    Hope that helps!

  • Calvin

    When you App::import() a vendor library, does it do anything other than include() the file in your vendors directory? If not, could you simply write a vendor file that contains an include statement (or multiple include statements if your vendor library has multiple dependencies)? This way, you can use App::import(‘Vendors’, ‘my_vendor’) in your application instead of having to using the 3rd parameter or have multiple App::import()s.

  • cakebaker

    @Calvin: Thanks for your comment!

    Yes, this approach should work and it could be handy for including multiple files to avoid having multiple imports. However, I think it is a bit of overkill to use this approach to avoid the 3rd parameter when importing a single file ;-)

  • steven

    Hi,

    I am using App::import(‘Vendors’, ‘somevendorfile’); to import a file in my controller, but i am unable to use variable which are used in somevendorfile.php. can anyone help me on this?

    Thanks,

  • cakebaker

    @steven: I don’t think this is possible because such variables are only visible within the method in which the include happens, i.e. they are only visible in some method of the App class.

    To get access to your variable, you have to use include/require directly. See also the documentation about the include function. However, if possible, I would avoid using a variable defined in another file as it makes the code harder to read…

    Hope this helps!

  • jak

    Hi, I had imported the vendor file into my controller function instead of the include line in cakephp 2.1.

    But in vendor file I can’t use the $this directly.

    And It throws the error.

    Like : Using $this when not in object Context

    Anu one can help me on this?

  • cakebaker

    @jak: Hm, I’m not sure I understand your problem. Can you provide more information about what you are trying to accomplish and/or show some code? And what error do you get?

Bake a comment




(for code please use <code>...</code> [no escaping necessary])

© daniel hofstetter. Licensed under a Creative Commons License