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.
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 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.
I've installed the ffmpeg.so extension on my server. I want to use the ffmpeg-php library in my Symfony 2 application. If I do:
$ffmpeg = new ffmpeg_movie('movie.flv');
In a standalone php file, it works beautifully. But if I put the same code into my Symfony2 controller, I get
Fatal error: Class 'Example\ExampleBundle\Controller\ffmpeg_movie' not found in...
It must have to do with Symfony's namespace options, but I'm not sure how to resolve it.
When you're within a particular namespace, any class references without a namespace will be treated as a class local to that namespace. In your example, its treating ffmpeg_movie as a Example\ExampleBundle\Controller namespace class.
If you want to access another namespace, which includes the global namespace (which includes PHP classes, interfaces, as well as any custom defined global items), you have two choices.
Access it using it's full namespace (which is \ for global) & class name:
$obj = new \ffmpeg_movie;
$obj = new \DateTime;
Reference the external class using use:
use ffmpeg_movie;
use DateTime as AwesomeDateTimeClass;
$obj = new ffmpeg_movie;
$obj = new AwesomeDateTimeClass;
Oops, turns out you can just add
use ffmpeg_movie;
At the top of your controller, same as any other class. Silly me.
I have a trivially small PHPUnit test that looks like this:
<?php
namespace VNN\PressboxBundle\Tests\Entity;
namespace VNN\PressboxBundle\Entity;
use VNN\PressboxBundle\Entity\User;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
use Phactory\Sql\Phactory;
class UserTest extends EntityTest
{
public function testCreate()
{
Phactory::reset();
}
}
When I try to run it, I get this:
There was 1 error:
1) VNN\PressboxBundle\Entity\UserTest::testCreate
ErrorException: Runtime Notice: Non-static method Phactory\Sql\Phactory::reset() should not be called statically, assuming $this from incompatible context in /Users/jason/Web/pressbox/src/VNN/PressboxBundle/Tests/Entity/UserTest.php line 13
What's up with that? All the docs call it statically.
I'm doing this on Symfony 2.0, if that makes a difference.
The documentation says you should be using the top-level Phactory class directly under lib/--not the individual implementations such as Phactory/Sql/Phactory which get instantiated based on the PDO object you pass to setConnection. Change
use Phactory\Sql\Phactory;
to
require_once 'Phactory/lib/Phactory.php';
The main class is in the global namespace and doesn't require a use statement.
https://github.com/chriskite/phactory/issues/30
From the code, setConnection, define and create are not static functions but the README and website guide do not reflect that.
e.g. test code
https://github.com/chriskite/phactory/blob/next/tests/Phactory/Sql/PhactoryTest.php
use Phactory\Sql\Phactory;
...
$this->pdo = new \PDO("sqlite:test.db");
$this->phactory = new Phactory($this->pdo);
$this->phactory->define('user');
$this->phactory->reset();
I don't know when it has been changed.
Too late anyways...
The current version, 0.3.2, is not backward compatible with the static method structure that is documented.
Here is the breaking commit: https://github.com/chriskite/phactory/commit/d3b60eeedea955ab7b5803ec29446d19888d3849
Unfortunately, the documentation has not been updated on http://phactory.org and the pearhub repo is no longer available.
I would look to the tests for examples: https://github.com/chriskite/phactory/blob/next/tests/Phactory/Sql/PhactoryTest.php