I am new with Symfony 2. I would like to add classes like libraries in my project but I dont know how.
Suppose I have 2 classes A and B.
I located them at this position : vendor/my_vendor_name/xxxx/A.php and vendor/my_vendor_name/xxxx/B.php
in each classes I defined the same namespace :
namespace my_vendor_name/xxxx
Now I would like to use those 2 classes in my bundles by calling :
use my_vendor_name/xxxx/A or my_vendor_name/xxxx/B
But It is like my namespaces do not exist (class not found)... maybe I have to declare those namespaces somewhere, to register them.
My app/autoload.php
<?php
use Doctrine\Common\Annotations\AnnotationRegistry;
$loader = require __DIR__.'/../vendor/autoload.php';
// intl
if (!function_exists('intl_get_error_code')) {
require_once __DIR__.'/../vendor/symfony/symfony/src/Symfony/Component/Locale/Resources/stubs/functions.php';
$loader->add('', __DIR__.'/../vendor/symfony/symfony/src/Symfony/Component/Locale/Resources/stubs');
}
AnnotationRegistry::registerLoader(array($loader, 'loadClass'));
return $loader;
This is not the correct way to procede.
You have, in this order:
Create a bundle under src/ directory
Register your bundle into app/AppKernel.php file
Create your classes under your bundle
Use those classes wherever you want
Real example:
Bundle Creation
Create a directory under src/ dir. This dir wll contains all your bundles. By convention, this directory should have to be your "company" name (for our example, say it is Foo).
After that, create a directory for your bundle, with name of your bundle. For our example. we decide to call it FooBundle.
So, you'll have this directory tree: src/Foo/FooBundle/
Into FooBundle/ you have to create a file that is used for bundle registration. This file is reported here:
<?php
namespace Foo\FooBundle;
use Symfony\Component\HttpKernel\Bundle\Bundle;
class FooBundle extends Bundle
{
}
File name is FooFooBundle.php
Register your bundle
Go into app/AppKernel.php file and add this line
public function registerBundles()
{
[...]
$bundles = array(
[...]
new Foo\FooBundle\FooFooBundle());
[...]
Congratulation! Your bundle is now registered!
Create your classes
Simply create your classes into your bundle. I suggest you to pack them into a directory like Core or whatever you want
Use your classes
Suppose that you have defined a class called A, into your brand new bundle.
Use it is quite simple:
use Foo\FooBundle\Core\A
into the file you want to use it
All should work now
Little Note:
A bundle inserted into src is different from a bundle inserted into vendor one only because your bundle (src one) is used by you, into your project only. A vendor bundle is someone else bundle that you use into your project. Behaviours (how to create bundle, how to register and use it) are exactly the same.
Little Note 2:
If you have to use external library or "old" php plain classes, Ahmed answer gives you a good point of start
Take a deeper look at the documentation. It's well explained in the The ClassLoader Component section.
From the documentation,
If the classes to autoload use namespaces, use the registerNamespace() or registerNamespaces() methods.
For classes that follow the PEAR naming convention, use the registerPrefix() or registerPrefixes() methods.
Note, The documentation is full of examples that fit your needs (Adding external classes or PHP libraries to your project)
Also, Take a look at the autoload section of Composer documentation.
Related
Since a week I'm in love with Symfony2. I've a feedbackmessagebundle: src/Erwine/FeedBackMessageBundle .
I put some custom classes from another project in: src/Erwine/FeedBackMessageBundle/FeedBackMessage.
All classes has the same namespace: Erwine\FeedBackMessageBundle\FeedBackMessage.
I've several implementations in different files. Let's say:
- FeedBackMessageClassOne
- FeedBackMessageClassTwo
- FeedBackMessageClassThree
The first one lives in his own file. If Two extends from One I got a failure. I've tried use... etc.
Two and Three lives as twins in the same file. If Three inherits from Two, it works.
An instance of One in the controller is no problem.
It seems to me, the inheritance of classes in the same namespace in different files doesn't work. No, no, no, course not, I do something wrong. Isn't it? But what? Is it autoloading in Symfony2 for custom classes?
I am using composer for the dependencies.
UPDATE
Here is my implementation:
<?php
namespace Erwine\FeedBackMessageBundle\FeedBackMessage;
class FeedBackMessageHandlerImpl extends FeedBackMessageHandlerImplTwee
{
public function __construct()
{
//var_dump('constructed');
//parent::__construct();
}
//public function getFeedBackMessageGeneralOverride(){};
}
Provided your autoloading is set up correctly, it should just be something like this:
Folder structure:
src/
Erwine/
FeedBackMessageBundle/
FeedBackMessage/
FeedBackMessageClassOne.php
FeedBackMessageClassTwo.php
FeedBackMessageClassThree.php
FeedBackMessageClassOne.php:
<?php
namespace Erwine\FeedBackMessageBundle\FeedBackMessage;
class FeedBackMessageClassOne
{
// Contents of class...
}
FeedBackMessageClassTwo.php:
<?php
namespace Erwine\FeedBackMessageBundle\FeedBackMessage;
class FeedBackMessageClassTwo extends FeedBackMessageClassOne
{
// Contents of class...
}
You shouldn't need a use statement for the extend in the second file as the file resides in the same namespace, therefore by defining the same namespace in the second class, you are able to use the first class without the use statement.
Make sure that your autoloading is set up properly.
It's important that you keep every class in a separate file, and also that you name the files the same as the classes.
This is because Symfony uses PSR-0 by default if you're using the composer autoloader. Go here to read more about PSR-0
I asked a similar questions before but had no right answers. Maybe I did not explain good.
I have 2 classes of my own that I would like to add in symfony project.
seculibs/collections/A.php and seculibs/collections/B.php (it is not on github, it is local).
I would like to add my seculibs folder in the vendor folder and ask symfony to load the classes.
Obviously everything happens in app/autoload.php
I thought that doing this would be okay but not :
$loader->add('seculibs/collections',__DIR__ . '/../vendor/seculibs/collections/');
it still cannot find the classes.
Can somebody tell me exactly what to do? I am with Symfony 2.3.6
Please do not refer to composer.json neither to the UniversalClassLoader and its registerNamespaces method as this is not the class I am dealing with in this autoload.php
So I found the right syntax... It will help some others
$loader->add('seculibs\\collections',__DIR__ . '/../vendor');
Do you HAVE to autoload the classes? I have used my own classes by simply giving them a namespace in my project, and then including them with a use statement in the file that I would like to use them in. For example, I have a class that I put in a custom location within my project, src/My/AppBundle/Utils/MyClass.php, and within the MyClass.php file, I gave the namespace My/AppBundle/Utils
Now in a controller, I include that class with a normal use statement.
use My/AppBundle/Utils/MyClass.php
// .....
class MyController extends Controller {
// ....
}
This way I can use my class anywhere in my application by referencing the namespace. I know this approach is different from what you may have expected, but it works great.
UPDATE:
It doesn't matter where you put the files. If you want them in the vendor folder, put them there, and give them a namespace that makes sense.
So maybe you have something like this:
// in vendors/MyUtils/Classes/MyClass.php
namespace MyUtils/Classes
class MyClass {
// ....
}
And then you can still include the class with a use statement like I mentioned.
Look at vendor/composer/ClassLoader.php
You can see that the add method expects a prefix as the first argument. You can leave it blank if your classes have no namespace.
Assuming your classes are not namespaced then use:
$loader->add(null,__DIR__ . '/../vendor/seculibs/collections/');
$a = new \A();
If they do have a namespace then just pass the prefix of your namespace to add.
$loader->add('Cerad',__DIR__ . '/../vendor/seculibs/collections/');
namespace Cerad\Collections;
class A {}
$a = new Cerad\Collections\A();
Of course you also have to have the Cerad\Collections directory structure under your vendor directory.
==============================================
Update
If you have in /vendor/seculibs/collectionsA.php:
namespace seculibs\collections;
class A {
Then use:
$loader->add('seculibs',__DIR__ . '/../vendor/');
And
use seculibs\collections\A;
$a = new A();
I'm relatively new to Symfony2, so I'm learning by doing. My controller classes are getting pretty big. I'd like to break it up with functions() or objects->method(). Unfortunately I can't figure out where to put the code. (actually its really simple functions... but I can wrap that in an object...)
--I can't add it to the bottom of my DefaultController.php file. It errors out, and not pretty code to boot, either inside or outside of the { }.
--I can't simply add a new NewObject.php file to the controller directory. That errors out. The error: FatalErrorException: ...NewObject not found.
--I've toyed with manual mods to ../app/autoload.php but that doesn't really make sense for a simple class add to my ./SRC/ bundle. Perhaps I should build a ./src/autoload.php file (similiar to ./vender/autoload.php) but the contents of that file don't make sense to me at all. I simply can't figure out how the AnnotationRegistry Loader works.
Am I missing something? This seems way too hard.. what I want is a wrapped up 'include' so I can use the class in dev and after deployment.
How do I include NewObject.php (and the accompanying $newObject->function() ) in my code?
I'm told I can add a service, yet that seems like outrageous overhead for such a seemingly simple task (again, all I'm trying to do is clean up my very long controller php code...)
thanks in advance for your advice.
So you've got a project structure that looks something like this, right?
project
-- app
-- bin
-- src
-- SomeName
-- SomeBundle
-- Controller
-- Entity
-- Resources
-- ...
-- vendor
-- web
And you're just looking to have some kind of "helper" class that's used throughout your bundle. Is that correct?
If so, then you can really put it wherever you want to inside your src/ directory... Just make sure that the class name matches the file name, and that the path to the file matches the namespace you define at the top of your PHP code.
Sometimes when I do this, I'll create a simple directory under my bundle called "Helper/". Other times, when the application is more complex, I might be a little bit more explicit. But here's what the first case would look like...
First, add your /Helper directory under your bundle, and create the class file:
project
-- app
-- bin
-- src
-- SomeName
-- SomeBundle
-- Controller
-- Entity
-- Helper
-- SomeHelper.php
-- Resources
-- ...
-- vendor
-- web
The contents of SomeHelper.php might look like this:
<?php
namespace SomeName\SomeBundle\Helper;
class SomeHelper
{
public function doSomething()
{
...
}
}
Because your namespace matches the file path, it gets autoloaded, so you don't need to worry about include statements. You can instantiate that class anywhere in your bundle, as long as you include a use statement:
<?php
namespace SomeName\SomeBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use SomeName\SomeBundle\Helper\SomeHelper;
class DefaultController extends Controller
{
public function indexAction()
{
...
$helper = new SomeHelper();
$helper->doSomething();
...
}
}
Regarding the usage of services... Yes, that might be overkill, depending on what you're using it for. It's helpful to create services when the class needs to be aware of the application around it. For example, if you're creating a service that emails a User, it might want to access your database through the Doctrine service, or it might want to log the email activity through the Monolog service.
However, if your class doesn't need to know about the application (referred to as the "service container"), for example if it's just used to transfer data, then a helper class is probably more appropriate.
I have created Bundles and they share some Common code. (File Upload Class, Gmailer Class) Now I want to create a separate file within my Bundles or Anywhere, where i can put this common code and then I want to create objects of its classes inside all my bundles.
Here is my folder structure
-src
-College
-StudentBundle
-Controller
-Entity
-OtherApplication
-All3rdPartyClasseshere.php
-UserBundle
-TeacherBundle
Now when I tried to auto load it like this
autoload.php
$loader->registerPrefixes(array(
'Twig_Extensions_' => __DIR__.'/../vendor/twig-extensions/lib',
'Twig_' => __DIR__.'/../vendor/twig/lib',
'Uploader_' => __DIR__.'/../../src/College/StudentBundle/OtherApplications',
But when i try to create an object in my controller it gives an error. I didnt use or include anything inside my controller. How could i create objects of the classes that i separated in another file.
First of all, third-part libraries, even if they are specifically related to your bundle, should not be inside the bundle structure.
The recommended way to handle your non-bundle common code is to treat it as external libraries, and manage them with composer.json.
About the Bundle structure, maybe this question can help you get in the right path.
I am trying to add an external library (PHP Simple DOM Parser, http://simplehtmldom.sourceforge.net/index.htm) to a Symfony2 project. I took a tutorial that explains how to include third party libraries to Symfony2 http://www.kiwwito.com/article/add-third-party-libraries-to-symfony-2.
I set up a class file like:
# vendor/phpsimpledom/lib/Phpsimpledom/simple_html_dom.php
require_once __DIR__.'/src/simple_html_dom.php';
class Phpsimpledom_Phpsimpledom extends simple_html_dom_node {
}
and registered my class in my Autoloader (autoload.php):
$loader->registerNamespaces(array(
...
'Phpsimpledom' => __DIR__.'/../vendor/phpsimpledom/lib/',
...
),));
I am trying to call:
$phpsimpledom = new \Phpsimpledom();
but this throughs me an error (Fatal error: Class 'simple_html_dom_node' not found).
However: The main file of the library (simple_html_dom.php) consists of functions that do not belong to a class.
When I try to use the file directly, it also doesn't work:
$loader->registerNamespaces(array(
...
'Phpsimpledom' => __DIR__.'/../vendor/phpsimpledom/lib/Phpsimpledom/src/simple_html_dom.php',
...
),));
Any hints?
THANKS!
You're trying to register a namespace but your class has no namespace. Try adding a namespace to it or use RegisterPrefixes().
BTW: did you know that one of the Symfony components is basically doing the same thing as php simpledom? It's called DomCrawler and it has a support for both xpath and CSS selectors.
I'm new to Symfony2 but as i can see, you are not respecting the PSR for autoloader.
I'm presumable thinking you should do:
# /vendor/phpsimpledom/lib/Phpsimpledom/Phpsimpledom.php
require_once __DIR__.'/src/simple_html_dom.php';
class Phpsimpledom_Phpsimpledom extends simple_html_dom_node {
}
Note that the correct filename would be /vendor/phpsimpledom/lib/Phpsimpledom/Phpsimpledom.php as the call must include the namespace to work.
Hope it works now.