Using Symfony 2.0, I am trying to make it work together with XCache.
XCache is properly installed.
As for the offitial Symfony documentation, we have this XcacheClassLoader.php that should make it. As for the same documentation, we get this piece of advice:
/**
* XcacheClassLoader implements a wrapping autoloader cached in Xcache for PHP 5.3.
*
* It expects an object implementing a findFile method to find the file. This
* allows using it as a wrapper around the other loaders of the component (the
* ClassLoader and the UniversalClassLoader for instance) but also around any
* other autoloader following this convention (the Composer one for instance)
*
* $loader = new ClassLoader();
*
* // register classes with namespaces
* $loader->add('Symfony\Component', __DIR__.'/component');
* $loader->add('Symfony', __DIR__.'/framework');
*
* $cachedLoader = new XcacheClassLoader('my_prefix', $loader);
*
* // activate the cached autoloader
* $cachedLoader->register();
*
* // eventually deactivate the non-cached loader if it was registered previously
* // to be sure to use the cached one.
* $loader->unregister();
*
* #author Fabien Potencier <fabien#symfony.com>
* #author Kris Wallsmith <kris#symfony.com>
* #author Kim Hemsø Rasmussen <kimhemsoe#gmail.com>
*
* #api
*/
If I am getting it right, the autoload.php should contain that code. This is what I am doing in autoload.php:
Normal loader is declared:
$loader = new UniversalClassLoader();
All stuff is done to that $loader, like registerNamespaces, registerPrefixes and all external dependencies are loaded to the $loader:
$loader
->registerNamespaces(
array(
'Symfony' => array(__DIR__ . '/../vendor/symfony/src',
__DIR__ . '/../vendor/bundles'),
'Sensio' => __DIR__ . '/../vendor/bundles',
'JMS' => __DIR__ . '/../vendor/bundles',
'Doctrine\\Common' => __DIR__. '/../vendor/doctrine-common/lib',
'Doctrine\\DBAL' => __DIR__
etc...
Once all the "normal" stuff is made to the $loader, I declare the $cachedLoader, just as said in the documentation:
// register classes with namespaces
$loader->add('Symfony\Component', __DIR__.'/component');
$loader->add('Symfony', __DIR__.'/framework');
$cachedLoader = new XcacheClassLoader('my_prefix', $loader);
// activate the cached autoloader
$cachedLoader->register();
// eventually deactivate the non-cached loader if it was registered previously
// to be sure to use the cached one.
$loader->unregister();
Am I getting it right? Well obviously not, because all what I get is a completely blank page in my browser and not even logs are written in case they could give me some clue.
Thank you in advance.
I didnt use XCache but i can suggest you an alternative way to increase class loading performance and as far as i can remember it is the best way of doing so.
Check Use Composer's Class Map Functionality section of the official documentation.
Refs:
By default, the Symfony2 standard edition uses Composer's autoloader in the
autoload.php file. This autoloader is easy to use, as it will automatically find
any new classes that you've placed in the registered directories.
Unfortunately, this comes at a cost, as the loader iterates over all configured
namespaces to find a particular file, making file_exists calls until it finally
finds the file it's looking for.
The simplest solution is to tell Composer to build a "class map" (i.e. a big
array of the locations of all the classes). This can be done from the command
line, and might become part of your deploy process:
php composer.phar dump-autoload --optimize
Internally, this builds the big class map array in
vendor/composer/autoload_namespaces.php.
If you aren't already at 2.2, I recommend you upgrade to 2.2 if at all possible. 2.0 is now at the end of its maintenance cycle.
But, since we have experience in both - for symfony 2.0 there isn't an XcacheClassLoader included, you have to write it yourself and then put it in app/autoload.php (in the same place the the APC loader would go). For symfony 2.2 that's no longer the case.
Next, I recommend you make sure that your xcache is working right - you may want to create a php file and do a test like this:
<?php
$something="test";
xcache_set('key', $something, 0);
if (xcache_get('key') !== $something)
echo "something's wrong...";
else
echo "xcache appears to be working";
Last, what we what we did is pretty much what's in the latest version of Symfony/web/app.php (modified for XcacheClassLoader) - something that would (in its simple form) look like this:
<?php
use Symfony\Component\ClassLoader\XcacheClassLoader;
use Symfony\Component\HttpFoundation\Request;
$loader = require_once __DIR__.'/../app/bootstrap.php.cache';
$loader = new XcacheClassLoader('sf2', $loader);
$loader->register(true);
require_once __DIR__.'/../app/AppKernel.php';
require_once __DIR__.'/../app/AppCache.php';
$kernel = new AppKernel('prod', false);
$kernel->loadClassCache();
$kernel = new AppCache($kernel);
// rest of app.php
This symfony2 documentation link below should explain things (including the other poster's comment on having composer dump the autoload files (note the 'current' in the url):
http://symfony.com/doc/current/book/performance.html
Related
I'm trying to use PHP SQL Query Builder in a project I'm working on. I am installing it manually. I did this by copying the src directory into my project and then using the following code within my class:
$this->builder = new NilPortugues\Sql\QueryBuilder\Builder\GenericBuilder();
The error I get whenever the builder is used is:
[18-Apr-2017 12:57:48 UTC] PHP Fatal error: Interface 'NilPortugues\Sql\QueryBuilder\Builder\BuilderInterface' not found in /home/thomassm/public_html/php/lib/sqlbuilder/Builder/GenericBuilder.php on line 24
GenericBuilder.php
namespace NilPortugues\Sql\QueryBuilder\Builder;
use NilPortugues\Sql\QueryBuilder\Builder\Syntax\WriterFactory;
use NilPortugues\Sql\QueryBuilder\Manipulation\AbstractBaseQuery;
use NilPortugues\Sql\QueryBuilder\Manipulation\QueryInterface;
use NilPortugues\Sql\QueryBuilder\Manipulation\QueryFactory;
use NilPortugues\Sql\QueryBuilder\Manipulation\Select;
use NilPortugues\Sql\QueryBuilder\Syntax\Column;
use NilPortugues\Sql\QueryBuilder\Syntax\Table;
/**
* Class Generic.
*/
class GenericBuilder implements BuilderInterface
{//...}
BuilderInterface.php
namespace NilPortugues\Sql\QueryBuilder\Builder;
use NilPortugues\Sql\QueryBuilder\Manipulation\QueryInterface;
/**
* Interface BuilderInterface.
*/
interface BuilderInterface
{
/**
* #param QueryInterface $query
*
* #return string
*/
public function write(QueryInterface $query);
/**
* #param QueryInterface $query
*
* #return string
*/
public function writeFormatted(QueryInterface $query);
}
I assume the error is somehow caused by the way the files are called, any suggestions?
I am installing it manually. I did this by copying the src directory into my project and then using the following code within my class: ...
Every source file should be included through include/requrie before using. But PHP allow to setup autoloading for classes, interfaces and traits. In short, when runtime meets an undefined class then a special callback invokes, which can load the relevant file.
Although formally the autoloading rules can be arbitrary, but most of the modern projects supports the common community standard: PSR-4 Autoloader. So, you need an implementation of this standard.
As said in the library description, the recommended way to install is through Composer:
php composer.phar require nilportugues/sql-query-builder
Composer provides own PSR-4 implementation and generates file vendor/autoload.php. Usually this file included at the application entry point. It allow using the classes from all required libraries.
You can use the packages without the Composer (relevant answer). But it requires a lot of work (you still need an PSR-4 autoloader) and this way is rarely used today.
I am really new to symfony but a long year developer. Now I decided to look at symfony but as it is with new things, problems aint far :)
I want to include a class into my project. Everytime I create a instanec of the class
$fw = new FloydWarshall($graph, $nodes);
i'll receive an internal error 500.
What am I doing wrong ?
Structure:
app/
...
bin/
...
src/AppBundle/
Controller/MyController.php
Entity/
...
Model/
fw.class.php
Reposetory/
...
var/
...
vendor/
...
web/
...
So in my class the namespace looks like
namespace AppBundle\Controller;
use AppBundle\Entity\lpNodes;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use AppBundle\Model\FloydWarshall;
....
In my fw.class.php the header looks like:
<?php
/**
* #package FloydWarshall
* #author Janne Mikkonen <janne dot mikkonen at julmajanne dot com>
* #date $Date: 2013/03/23 05:10:48 $
* #version $Revision: 1.1.1 $
* #license GNU General Public License, version 2 http://www.opensource.org/licenses/GPL-2.0
**/
namespace AppBundle\Model;
class FloydWarshall {
the constructor of FloydWarshall:
/**
* Constructor
* #param array $graph Graph matrice.
* #param array $nodenames Node names as an array.
*/
public function __construct($graph, $nodenames='') {
$this->weights = $graph;
$this->nodes = count($this->weights);
if ( ! empty($nodenames) && $this->nodes == count($nodenames) ) {
$this->nodenames = $nodenames;
}
$this->__floydwarshall();
}
As per comment, Symfony 3 uses either PSR-0 or PSR-4. Assuming that you're using Composer, you configure which one to support in your composer.json file.
With PSR-4, your filenames must correspond to your class names, and your directory names must match your namespaces. So if your entity is called FloydWarshall in the namespace AppBundle\Entity:
it must be in the directory src/AppBundle/Entity
the file must be called FloydWarshall.php
The reason for this strictness is the autoloader which comes with Composer. When you do new AppBundle\Entity\FloydWarshall, the autoloader knows where to find the file for that class. In your case, you had named it fw.class.php so the autoloader couldn't find it.
Tangentially to the question, are you using the dev environment? If you are, Symfony will give you a very helpful error message which will help you to diagnose the problem much quicker.
I am attempting to use JMSSerializer as a stand alone library to map JSON responses from an API to my model classes and am running into some issues.
Executing the following code results in an exception:
<?php
require dirname(__DIR__) . '/vendor/autoload.php';
use JMS\Serializer\Annotation AS JMS;
class Trii {
/**
* User ID for this session
* #JMS\SerializedName("userID")
* #JMS\Annotation(getter="getUserId")
* #JMS\Type("string")
* #var string
*/
private $userId;
public function getUserId() {
return $this->userId;
}
public function setUserId($userId) {
$this->userId = $userId;
}
}
$serializer = \JMS\Serializer\SerializerBuilder::create()->setDebug(true)->build();
$object = $serializer->deserialize('{"userID":"Trii"}', 'Trii', 'json');
var_dump($object);
?>
Here is the exception
Doctrine\Common\Annotations\AnnotationException: [Semantical Error] The annotation "#JMS\Serializer\Annotation\SerializedName" in property Trii::$userId does not exist, or could not be auto-loaded.
I have the following libraries installed for the project via composer
{
"require": {
"jms/serializer": "1.0.*#dev"
}
}
Is there something obvious I am missing since I am not using the whole Doctrine 2 solution?
EDIT: my final solution was to create a bootstrap file with the following content:
<?php
// standard composer install vendor autoload magic
require dirname(__DIR__) . '/vendor/autoload.php';
// Bootstrap the JMS custom annotations for Object to Json mapping
\Doctrine\Common\Annotations\AnnotationRegistry::registerAutoloadNamespace(
'JMS\Serializer\Annotation',
dirname(__DIR__).'/vendor/jms/serializer/src'
);
?>
Pretty sure this enables silent auto-loading which is much more convenient than registering the namespaces yourself.
AnnotationRegistry::registerLoader('class_exists');
I ran into the same problem and found your question through Google. Unfortunately you hadn't yet received any answers, so I had to dig in myself. :P
The thing is, Doctrine Annotations, which JMSSerializer Annotations uses, does NOT use normal PHP autoloading.
How are these annotations loaded? From looking at the code you could guess that the ORM Mapping, Assert Validation and the fully qualified annotation can just be loaded using the defined PHP autoloaders. This is not the case however: For error handling reasons every check for class existence inside the AnnotationReader sets the second parameter $autoload of class_exists($name, $autoload) to false. To work flawlessly the AnnotationReader requires silent autoloaders which many autoloaders are not. Silent autoloading is NOT part of the PSR-0 specification for autoloading.
This means you have to register the Annotation file(s) yourself:
AnnotationRegistry::registerFile(
<PROJECT ROOT> .
"/vendor/jms/serializer/src/JMS/Serializer/Annotation/SerializedName.php");
... or the whole namespace (preferred method):
AnnotationRegistry::registerAutoloadNamespace(
'JMS\Serializer\Annotation',
<PROJECT ROOT> . "/vendor/jms/serializer/src");
Be careful with the path in registerAutoloadNamespace. I first tried to register the whole path to annotations in the same manner with registerFile:
<PROJECT ROOT> . "/vendor/jms/serializer/src/JMS/Serializer/Annotation
but that failed miserably. :D
I hope this gets you a step further. :)
#SirArturio has the correct answer to this Autoloading puzzle, and I just wanted to add a touch more clarity in response to #messified or anyone else struggling to get this working. As he eloquently explained, the automatic PSR-0 handler in composer, or SPL isn't going to cut it for loading these annotations since they use Doctrine's autoloading.
So here is small complete example. Whenever you create your JMS Serializer object to begin serialization is a good time to add the annotation namespace to doctrine's autoloader. For clarity sake I'm assuming no IoC, and fully qualified namespaces (hint hint, use dependency injection):
<?php
Doctrine\Common\Annotations\AnnotationRegistry::registerAutoloadNamespace(
'JMS\Serializer\Annotation',
$your_app_basepath . "/vendor/jms/serializer/src");
$serializer = JMS\Serializer\SerializerBuilder::create()->build();
$json_output = $serializer->serialize('MyProject\MyClass', 'json');
Then in your MyProject\MyClass:
<?php
use JMS\Serializer\Annotation as JMS;
class MyClass{
/** #JMS\Exclude */
private $something_secret;
}
And that should cut it, autoloading the proper annotation file using doctrine instead of composer.
Check the capitalisation of your annotations. I had a similar problem when deploying from a Windows dev environment to an Ubuntu server which was caused by a typo in the case of my annotation. Windows files are case-insensitive so it works there but fails on Linux.
If you use Composer, you can get loader by specifying a path in require:
$loader = require(__DIR__ . '/../vendor/autoload.php');
AnnotationRegistry::registerLoader(array($loader, 'loadClass'));
Here is the solution
1.go to php directory then install composer
php composer-setup.php
2. go to project sdk directory
e.g.
cd /Applications/XAMPP/xamppfiles/htdocs/streetreturn/adn_sdk-php-master
update composer to install dependencies
php /Users/zakir/composer.phar update
*Note: /Users/zakir/composer.phar will be located when install composer in step 1
I'm pretty new to Doctrine 2 and am using annotations to do my database mapping. I want to take things a little bit further and use some custom annotations. The aim is to be able to make forms and such that can have settings created through annotations. I'm having trouble reading ANY annotations - even class ones such as #Table aren't being returned from the parser.
I am using Codeigniter 2 and Modular Extensions. In my controller I have:
$reader = new \Doctrine\Common\Annotations\AnnotationReader();
$reader->setDefaultAnnotationNamespace('MyCompany\Annotations');
$reflClass = new ReflectionClass('models\User');
$classAnnotations = $reader->getClassAnnotations($reflClass);
print_r($classAnnotations);
Which returns an empty array.
I then have a file in my libraries/annotations folder, Bar.php:
namespace MyCompany\Annotations;
class Bar extends \Doctrine\Common\Annotations\Annotation
{
public $foo;
}
and lastly, my user model:
/**
* #Entity
* #Table(name="user")
* #MyCompany\Annotations\Bar(foo="bar")
* #MyCompany\Annotations\Foo(bar="foo")
*/
class User {
}
I am trying to follow this example:
http://www.doctrine-project.org/projects/common/2.0/docs/reference/annotations/en#setup-and-configuration
Thanks for your help in advance!
Mark.
use
Doctrine\Common\Annotations\AnnotationRegistry
AnnotationRegistry::RegisterLoader($universalClassLoader);
AnnotationRegistry::RegisterFile(__DIR__ . ' PATH_TO_DoctrineAnnotations.php ');
As you've figured out, you need to include your custom annotation files/classes before you can use them.
Though including them in your controller would work, why not do it the Doctrine way!
Doctrine2's ORM has a file called DoctrineAnnotations.php in the Doctrine/ORM/Mapping/Driver/ folder. It looks like this:
...
require_once __DIR__.'/../GeneratedValue.php';
require_once __DIR__.'/../Version.php';
require_once __DIR__.'/../JoinColumn.php';
require_once __DIR__.'/../JoinColumns.php';
require_once __DIR__.'/../Column.php';
...
So, what I've done is created a similar file in my library and load my annotations by including this "driver" (eg. in your bootstrap).
In my ZF-based app (using Guilherme Blanco's fabulous Zf1-D2 set-up), I just added my "annotations driver" to my application.ini, like this (all on one line):
resources.doctrine.orm.entityManagers.default
.metadataDrivers.annotationRegistry.annotationFiles[]
= APPLICATION_PATH "/path/to/my/library/ORM/Mapping/Driver/MyAnnotations.php"
I am looking at doctrine2 and how to handle data fixtures. I am especially interested in reading them from flat files (csv, yaml, xls).
In doctrine 1.2 data fixtures are handled like this: http://www.doctrine-project.org/projects/orm/1.2/docs/manual/data-fixtures/en#data-fixtures
Any suggestion how to handle this in doctrine2?
As already mentioned by Steven the fixture-feature comes as a separate repo.
It took me some time to figure out how to install the data fixtures feature in Symfony2, so here is how I did it:
add sources to your deps file:
[doctrine-fixtures]
git=http://github.com/doctrine/data-fixtures.git
[DoctrineFixturesBundle]
git=http://github.com/symfony/DoctrineFixturesBundle.git
target=/bundles/Symfony/Bundle/DoctrineFixturesBundle
update your vendors
$ php bin/vendors install
register in in autoload.php:
$loader->registerNamespaces(array(
//...
'Doctrine\\Common\\DataFixtures' => __DIR__.'/../vendor/doctrine-fixtures/lib',
'Doctrine\\Common' => __DIR__.'/../vendor/doctrine-common/lib',
//..
));
add class which subclasses FixtureInterface:
<?php
use Doctrine\ORM\EntityManager,
Doctrine\Common\DataFixtures\FixtureInterface;
/**
*
* setup of initial data for the unit- and functional tests
* #author stephan
*/
class LoadTestingData implements FixtureInterface{
/**
*
* #param EntityManager $manager
*/
public function load($manager) {
$user = new User();
$user->setUsername("testuser");
$manager->persist($user);
}
//...
load data fixtures via console command
./app/console doctrine:data:load
There is a git submodule for that in the official doctrine git repo https://github.com/doctrine/data-fixtures
I am currently using it and it works pretty well.
I use class-based fixtures, much better this way because you can handle associations and dependencies easily with the EntityManager directly, also easy for using in unit tests.
Here is the library I use with Zend Framework modules, but you can just write your own loader. There is a command line script too.