I've forked a Symfony 3 project and I'm trying to add a new Entity and the matching form type, but I can't make it work.
I've tried with the generator and manually, both won't work. A solution with the generator would be the best option
I've generated my entity School with php bin/console doctrine:generate:entity, but when I'm trying to generate the Form, I get the error Class GreenBundle\Entity\School does not exist.
I then tried to create the Form manually and got : Expected to find class "GreenBundle\Form\SchoolType" in file "/var/www/symfony/src/GreenBundle/Form/SchoolType.php" while importing services from resource "../../src/GreenBundle/*", but it was not found! Check the namespace prefix used with the resource.
My school entity generated by the command line is simple
<?php
namespace GreenBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* School
*
* #ORM\Table(name="school")
* #ORM\Entity(repositoryClass="GreenBundle\Repository\SchoolRepository")
*/
class School
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="nom", type="string", length=255)
*/
private $nom;
(... Some other variables, the getters and setters )
}
The SchoolType I added is :
<?php
namespace GreenBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\Extension\Core\Type\RepeatedType;
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\OptionsResolver\OptionsResolver;
class SchoolType extends AbstractType
{
/**
* #param OptionsResolver $resolver
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'GreenBundle\Entity\School',
));
}
/**
* #return string
*/
public function getName()
{
return 'green_mainbundle_school';
}
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('nom', TextType::class, array(
'label' => "Nom de l'école",
'required' => false,
'attr' => array(
'class' => 'form-control',
'placeholder' => 'ex: École Saint-Exupéry')
));
}
}
And the block In services.yml the error code is referring to is :
# this creates a service per class whose id is the fully-qualified class name
GreenBundle\:
resource: '../../src/GreenBundle/*'
# you can exclude directories or files
# but if a service is unused, it's removed anyway
exclude: '../../src/GreenBundle/{Entity,Repository,Tests}'
Do you know what I'm doing wrong to get the server to run with the new SchoolType and be able to use it in a controller ?
Thanks
======== Edit
I do have Symfony 3
php bin/console --version
Symfony 3.4.14 (kernel: app, env: dev, debug: true)
The project architecture is classic I guess, I have the default folders of Symfony
In the src folder I have :
AppBundle (unused)
GreenBundle
Controller
DataFixtures
DBAL
DependencyInjection
Entity
Form
Repository (Empty, I don't think they created entities with the generator)
Service
Tests
Twig
GreenBundle.php
======== Edit 2
The namespace I use in GreenBundle.php is GreenBundle, you can see the file below
namespace GreenBundle;
use Symfony\Component\HttpKernel\Bundle\Bundle;
class GreenBundle extends Bundle
{
public function getParent()
{
return 'FOSUserBundle';
}
}
In case anybody ever have the same kind of issue, I was running my project in a Docker container and it was a synch problem. The Symfony file themselves are correct. Docker detected that new file were added but didn't set the content properly. Rebuild and/or changing the way I use docker with this app fixes the issue
Related
I'm trying to make a website with Symfony 4 and Doctrine. I'm a complete beginner (both with Symfony and PHP in general), so I apologise if my question is trivial.
I want to create a database with doctrine, which means that I have to create classes in src/Entity. But I also want to add forms to the site, and they also require classes in src/Entity. I'd like to separate these classes in two subfolders: src/Entity/database and src/Entity/forms. I tried to edit config/packages/doctrine.yaml as follows:
doctrine:
#...
orm:
#...
mappings:
App:
#...
dir: '%kernel.project_dir%/src/Entity/database'
prefix: 'App\Entity\database'
But I when I use bin/console make:entity Entity it creates the file in src/Entity and gives the following error:
[ERROR] Only annotation mapping is supported by make:entity, but the
<info>App\Entity\Entity</info> class uses a different format. If you
would like this command to generate the properties & getter/setter
methods, add your mapping configuration, and then re-run this command
with the <info>--regenerate</info> flag.
When I run bin/console make:entity Entity --regenerate it says:
[ERROR] No entities were found in the "Entity" namespace.
I also tried bin/console make:entity database/Entity, but it fails with:
[ERROR] "App\Entity\Database/Entity" is not valid as a PHP class name (it must start with a letter or underscore,
followed by any number of letters, numbers, or underscores)
If I do the same with a backslash (database\Entity) it creates a DatabaseEntity.php file in the wrong directory and gives the same error as the first one.
Be very careful, because with such approach you might mess your architecture up. This question is a bit opinionated, but I'm gonna tell you how we make it with entities and forms.
First, my strong belief, Entities and Forms should be separated. Therefore, we contain Entites in src/Entity and Forms in src/Form. The connection between them is a FormType, we contain those in src/FormType.
Here's an example User entity contained in src/Entity/User.php:
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Validator\Constraints as Assert;
/**
* #UniqueEntity("username")
*
* #ORM\Entity()
* #ORM\Table(name="users")
*/
class User implements UserInterface, \Serializable
{
/**
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*
* #var int
*/
private $id;
/**
* #Assert\NotBlank()
* #Assert\Email
* #Assert\Length(max="255")
*
* #ORM\Column(type="string", length=255, unique=true)
*
* #var string
*/
private $username;
/**
* #ORM\Column(type="string", length=64)
*
* #var string
*/
private $password;
/**
* #return int
*/
public function getId(): int
{
return $this->id;
}
/**
* #return string The username
*/
public function getUsername()
{
return $this->username;
}
/**
* #param null|string $username
*
* #return User
*/
public function setUsername(?string $username): User
{
$this->username = (string) $username;
return $this;
}
/**
* #return string
*/
public function getPassword(): string
{
return $this->password;
}
/**
* #param null|string $password
*
* #return User
*/
public function setPassword(?string $password): User
{
$this->password = (string) $password;
return $this;
}
}
Now, we need a user to be able to register. For this we create a FormType and a Form. Take a look at src/FormType/User.php:
namespace App\FormType;
use App\Entity;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type as NativeType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Validator\Constraints\NotBlank;
class User extends AbstractType
{
public function getParent(): string
{
return BaseType::class;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
// This maps `Entity\User::username` to the respective field
$builder->add(
'username',
NativeType\EmailType::class,
['label' => 'username']
);
// This maps `Entity\User::password` to the respective field
$builder->add(
'password',
NativeType\RepeatedType::class,
[
'constraints' => [new NotBlank()],
'invalid_message' => 'nonMatchingPasswords',
'first_options' => ['label' => 'password'],
'second_options' => ['label' => 'password again'],
'type' => NativeType\PasswordType::class,
]
);
}
// This tells Symfony to resolve the form to the `Entity\User` class
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(['data_class' => Entity\User::class]);
}
}
And now the Form itself, it's src/Form/UserRegistration.php:
namespace App\Form;
use App\FormType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type as NativeType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Validator\Constraints;
class UserRegistration extends AbstractType
{
public function getParent()
{
// Note this!
return FormType\User::class;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(
[
'fields' => ['username', 'password'],
'translation_domain' => 'forms',
]
);
}
}
And a final stroke on this. In src/Controller/Registration.php we do this:
$form = $this->createForm(
Form\UserRegistration::class,
$user = new Entity\User()
);
The rest (how to handle forms etc.) you know. If you don't, read Symfony docs, they cover it perfectly.
I have cut out / edited some sensitive or non-essential things from this example. For instance, we do not bind password to password, we ask for plain password and then encrypt it. I have not tested the above, so it might not be stable. But for a demonstration on how your architecture should be done it's a good example, IMO.
I use Doctrine with Gedmo extension in standalone noframework application.
Autoloading is done via composer, composer.json content:
{
"autoload": {
"psr-0": {
"App": "src"
}
},
"require": {
"doctrine/orm": "^2.5",
"gedmo/doctrine-extensions": "^2.4"
}
}
App core classes are placed in /src directory, composer files are placed in /vendor
Doctrine is configured via factory, its main code is below:
<?php
namespace App\Factory;
use Doctrine\Common\Annotations\AnnotationReader;
use Doctrine\Common\Annotations\AnnotationRegistry;
use Doctrine\Common\Annotations\CachedReader;
use Doctrine\Common\Cache\CacheProvider;
use Doctrine\Common\Cache\FileCache;
use Doctrine\Common\EventManager;
use Doctrine\Common\Persistence\Mapping\Driver\MappingDriverChain;
use Doctrine\ORM\Configuration;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\Mapping\Driver\AnnotationDriver;
class DoctrineFactory implements FactoryInterface
{
/**
* #param ContainerInterface $c
* #return mixed
*/
public function __invoke(ContainerInterface $c)
{
// Set up caches
$cache = new FileCache('runtime/cache/doctrine');
// Annotation reader
$annotationReader = new AnnotationReader;
$cachedAnnotationReader = new CachedReader($annotationReader, $cache);
AnnotationRegistry::registerLoader(array(require 'vendor/autoload.php', 'loadClass'));
// Add Gedmo extensions
$driverChain = new MappingDriverChain();
\Gedmo\DoctrineExtensions::registerAbstractMappingIntoDriverChainORM($driverChain, $cachedAnnotationReader);
// Set up driver to read annotations from entities
$annotationDriver = new AnnotationDriver($cachedAnnotationReader, 'src'));
$driverChain->addDriver($annotationDriver, 'App\Entity');
// General doctrine configuration
$doctrineConfig = new Configuration;
$doctrineConfig->setProxyDir(sys_get_temp_dir()));
$doctrineConfig->setProxyNamespace('App\Entity\Proxy');
$doctrineConfig->setAutoGenerateProxyClasses(false);
$doctrineConfig->setMetadataDriverImpl($driverChain);
$doctrineConfig->setMetadataCacheImpl($cache);
$doctrineConfig->setQueryCacheImpl($cache);
// Event manager to hook extensions
$evm = new EventManager();
// Tree extension
$treeListener = new \Gedmo\Tree\TreeListener;
$treeListener->setAnnotationReader($cachedAnnotationReader);
$evm->addEventSubscriber($treeListener);
// Create EntityManager
// $config['conn'] is connection credentials
return EntityManager::create($config['conn'], $doctrineConfig, $evm);
}
}
My entity is:
<?php
namespace App\Entity;
use \Doctrine\ORM\Mapping as ORM;
use \Gedmo\Mapping\Annotation as Gedmo;
/**
* Class ProductCategory2
* #package App\Entity
*
* #Gedmo\Tree(type="nested")
* #ORM\Entity(repositoryClass="Gedmo\Tree\Entity\Repository\NestedTreeRepository")
*/
class ProductCategory2
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue
*/
private $id;
/**
* #ORM\Column(type="string", length=50)
*/
private $name;
/**
* #Gedmo\TreeLeft
* #ORM\Column(type="integer")
*/
private $lft;
/**
* #Gedmo\TreeLevel
* #ORM\Column(type="integer")
*/
private $lvl;
/**
* #Gedmo\TreeRight
* #ORM\Column(type="integer")
*/
private $rgt;
/**
* #Gedmo\TreeRoot
* #ORM\Column(type="integer", nullable=true)
* #var
*/
private $root;
/**
* #Gedmo\TreeParent
* #ORM\ManyToOne(targetEntity="ProductCategory2", inversedBy="children")
*/
private $parent;
}
My cli-config.php is configured properly.
I run doctrine cli tool to generate entities boilerplate code via command:
“vendor/bin/doctrine” orm:generate-entities src
It answers me:
Processing entity
“Gedmo\Translatable\Entity\MappedSuperclass\AbstractPersonal\Translation”
Processing entity
“Gedmo\Translatable\Entity\MappedSuperclass\AbstractTranslation”
Processing entity “Gedmo\Loggable\Entity\MappedSuperclass\AbstractLogEntry”
Processing entity “Gedmo\Tree\Entity\MappedSuperclass\AbstractClosure”
Processing entity “App\Entity\ProductCategory2”
Entity’s working fine, but command adds extra files into my src folder:
src\Gedmo
├───Loggable
│ └───Entity
│ └───MappedSuperclass/AbstractLogEntry.php
├───Translatable
│ └───Entity
│ └───MappedSuperclass/AbstractTranslation.php
└───Tree
└───Entity
└───MappedSuperclass/AbstractClosure.php
If I generate entities one more time via aforementioned command, I get error.
PHP Fatal error: Cannot redeclare class
Gedmo\Loggable\Entity\MappedSuperclass\AbstractLogEntry in
\src\Gedmo\Loggable\Entity\MappedSuperclass\AbstractLogEntry.php
on line 9
To fix it, I need remove <ROOT>/src/Gedmo dir before.
May anybody help to find a bug in config to prevent this annoying extra files to be appeared?
Thank for help
I've added hack to clear annoying directory after doctrine generate-entities command. Complete listing of cli-config.php is below:
<?php
use Doctrine\ORM\Tools\Console\ConsoleRunner;
use Interop\Container\ContainerInterface;
use Symfony\Component\Console\Application;
use Symfony\Component\Console\ConsoleEvents;
use Symfony\Component\Console\Event\ConsoleTerminateEvent;
use Symfony\Component\EventDispatcher\EventDispatcher;
require "vendor/autoload.php";
/** #var ContainerInterface $container */
$container = require 'app/bootstrap.php';
$dispatcher = new EventDispatcher();
// Post terminate cli command listener
$dispatcher->addListener(ConsoleEvents::TERMINATE, function(ConsoleTerminateEvent $event) {
$commandName = $event->getCommand()->getName();
switch($commandName) {
case 'orm:generate-entities':
// clear /src/Gedmo dir
\App\Utils\FilesystemUtils::removeDir('src/Gedmo');
break;
}
});
// Create doctrine cli environment via helper
$helperSet = ConsoleRunner::createHelperSet($container->get(\Doctrine\ORM\EntityManager::class));
// Wrap it into Symfony Console App and add some extra commands
$app = new Application('Doctrine Command Line Interface', \Doctrine\ORM\Version::VERSION);
$app->setDispatcher($dispatcher);
$app->setCatchExceptions(true);
$app->setHelperSet($helperSet);
// add default commands
ConsoleRunner::addCommands($app);
// here you may add extra commadts via $app->add(..)
$app->run();
Official docs:
How to wrap doctrine cli command into symfony console app
How to inject event system into symfony console app
Because of the problems I had with symfony version 2.7 (404 page error right away after installing a project) I started using Symfony version 3.0. After some minor problems I figured out that "app/console" is replaced by "bin/console". So I'm working now on a new project and I have already build a new bundle with 1 entity called
Codeit/RestaurantBundle && CodeitRestaurantBundle:Reserveren
Format is annotation, and the entity has an id and 1 field called "naam" (string, 255). I updated the schema's, I generate the entities of Codeit and after that was succesfully done I generated a crud with write actions. The format was again annotation and the prefix is /reserveren.
So if I visit the page web/reserveren I am getting a show page of my entity. Unfortunately if I try to add a new entry I am getting the following error:
Expected argument of type "string", "Codeit\RestaurantBundle\Form\ReserverenType" given
My Bundle/Form/ReserverenType.php
<?php
namespace Codeit\RestaurantBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class ReserverenType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('naam')
;
}
/**
* #param OptionsResolver $resolver
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Codeit\RestaurantBundle\Entity\Reserveren'
));
}
}
My entity code
<?php
namespace Codeit\RestaurantBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Reserveren
*
* #ORM\Table(name="reserveren")
* #ORM\Entity(repositoryClass="Codeit\RestaurantBundle\Repository\ReserverenRepository")
*/
class Reserveren
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="Naam", type="string", length=255)
*/
private $naam;
/**
* Get id
*
* #return int
*/
public function getId()
{
return $this->id;
}
/**
* Set naam
*
* #param string $naam
*
* #return Reserveren
*/
public function setNaam($naam)
{
$this->naam = $naam;
return $this;
}
/**
* Get naam
*
* #return string
*/
public function getNaam()
{
return $this->naam;
}
}
Forms have changed quite a bit in 3.0. You might be better off sticking with 2.8 for now.
You did not show it but I suspect, based on the error message, that your controller code looks like:
$form = $this->createForm(new ReservernType(), $item);
That is the 2.x way of doing things. For 3.x use:
$form = $this->createForm(ReservernType::class, $item);
http://symfony.com/doc/current/book/forms.html#creating-form-classes
try with:
$builder
->add('naam', TextType::class);
// If you use PHP 5.3 or 5.4 you must use
// ->add('naam','Symfony\Component\Form\Extension\Core\Type\TextType')
instead of this
$builder
->add('naam');
And add the use statement:
use Symfony\Component\Form\Extension\Core\Type\TextType;
Motivation: from the upgrade guide:
Type names were deprecated and will be removed in Symfony 3.0. Instead
of referencing types by name, you should reference them by their
fully-qualified class name (FQCN) instead. With PHP 5.5 or later, you
can use the "class" constant for that:
Hope this help
Try like this:
/.../
use Symfony\Component\Form\Extension\Core\Type\TextType;
/.../
class ReserverenType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('naam', TextType::class);
}
}
add this to your entity's class replace name with an attribute that suits you.
public function __toString() {
return $this->name;
}
I have a class I want to serialize, but exclude a public property. So far I tried #Exclude but I did not work (see Result).
Any ideas how to solve this problem?
Entity:
class Checkout extends Entity
{
/**
* #Exclude()
*/
public $normalizerCallbacks = [
'a' => 1,
'b' => 2,
];
..........
Serialize:
$checkout = $this->getDoctrine()->getRepository('App:Checkout')->find($id);
$serializer = $this->get('jms_serializer');
$data = $serializer->serialize($checkout, 'json');
Result:
{
normalizer_callbacks: {
a: 1
b: 2
}
}
Edit: Trial 2015-09-10 18 --> Not working
use JMS\Serializer\Annotation as JMS;
/**
* User
*
* #ORM\Table(name="checkout", options={"collate"="utf8_general_ci"})
* #ORM\Entity
*
* #JMS\ExclusionPolicy("none")
*/
class Checkout extends Entity
{
/**
* #JMS\Exclude();
*/
public $normalizerCallbacks = [
...
Edit: Trial 2015-09-11 09 (Update 12) --> Configuration
Add to "jms/serializer-bundle": "^1.0" composer and run update
Add new JMS\SerializerBundle\JMSSerializerBundle() to AppKernel
Add jms_serializer.camel_case_naming_strategy.class: JMS\Serializer\Naming\IdenticalPropertyNamingStrategyto parameters.yml
Then used it as in Serialize
Try whether you included it correctly:
use JMS\Serializer\Annotation as JMS;
and then use it like:
#JMS\Exclude();
in your annotation.
As well make sure your class is annoted with #ExclusionPolicy("none") (see http://jmsyst.com/libs/serializer/master/reference/annotations).
You can as well do it the other way round, specifically #Expose while class is annotated with #ExlucsionPolicy("all").
Make sure to clean your cache before re-testing it.
So I am not sure what the issue is here, or how this class even gets loaded. But my model (or as their actually called, entity) looks like this:
<?php
namespace ImageUploader\Models;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
/**
* #ORM\Entity
* #ORM\Table(name="users")
* #UniqueEntity(fields="userName")
* #UniqueEntity(fields="email")
*/
class User {
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue
*/
protected $id;
/**
* #ORM\Column(type="string", length=32, nullable=false)
* #Assert\NotBlank()
*/
protected $firstName;
/**
* #ORM\Column(type="string", length=32, nullable=false)
* #Assert\NotBlank()
*/
protected $lastName;
/**
* #ORM\Column(type="string", length=100, unique=true, nullable=false)
* #Assert\NotBlank(
* message = "Username cannot be blank"
* )
*/
protected $userName;
/**
* #ORM\Column(type="string", length=100, unique=true, nullable=false)
* #Assert\NotBlank()
* #Assert\Email(
* message = "The email you entered is invalid.",
* checkMX = true
* )
*/
protected $email;
/**
* #ORM\Column(type="string", length=500, nullable=false)
* #Assert\NotBlank(
* message = "The password field cannot be empty."
* )
*/
protected $password;
/**
* #ORM\Column(type="datetime", nullable=true)
*/
protected $created_at;
/**
* #ORM\Column(type="datetime", nullable=true)
*/
protected $updated_at;
}
In my I have an action called createAction that gets called when a user attempts to sign up. It looks like this:
public static function createAction($params){
$postParams = $params->request()->post();
if ($postParams['password'] !== $postParams['repassword']) {
$flash = new Flash();
$flash->createFlash('error', 'Your passwords do not match.');
$params->redirect('/signup/error');
}
$user = new User();
$user->setFirstName($postParams['firstname'])
->setLastName($postParams['lastname'])
->setUserName($postParams['username'])
->setEmail($postParams['email'])
->setPassword($postParams['password'])
->setCreatedAtTimeStamp();
$validator = Validator::createValidatorBuilder();
$validator->enableAnnotationMapping();
$errors = $validator->getValidator()->validate($user);
var_dump($errors);
}
When this action is called I get the following error:
Fatal error: Class 'doctrine.orm.validator.unique' not found in /var/www/html/image_upload_app/vendor/symfony/validator/ConstraintValidatorFactory.php on line 47
I am not sure how to resolve this issue. My composer file is as such:
{
"require": {
"doctrine/orm": "2.4.*",
"doctrine/migrations": "1.0.*#dev",
"symfony/validator": "2.8.*#dev",
"symfony/doctrine-bridge": "2.8.*#dev",
"slim/slim": "~2.6",
"freya/freya-exception": "0.0.7",
"freya/freya-loader": "0.2.2",
"freya/freya-templates": "0.1.2",
"freya/freya-factory": "0.0.8",
"freya/freya-flash": "0.0.1"
},
"autoload": {
"psr-4": {"": ""}
}
}
So I am not sure if I am missing a package or if I am doing something wrong ....
My bootstrap.php file has the following contents in it:
require_once 'vendor/autoload.php';
$loader = require 'vendor/autoload.php';
\Doctrine\Common\Annotations\AnnotationRegistry::registerLoader(array($loader, 'loadClass'));
use Doctrine\ORM\Tools\Setup;
use Doctrine\ORM\EntityManager;
/**
* Set up Doctrine.
*/
class DoctrineSetup {
/**
* #var array $paths - where the entities live.
*/
protected $paths = array(APP_MODELS);
/**
* #var bool $isDevMode - Are we considered "in development."
*/
protected $isDevMode = false;
/**
* #var array $dbParams - The database paramters.
*/
protected $dbParams = null;
/**
* Constructor to set some core values.
*/
public function __construct(){
if (!file_exists('db_config.ini')) {
throw new \Exception(
'Missing db_config.ini. You can create this from the db_config_sample.ini'
);
}
$this->dbParams = array(
'driver' => 'pdo_mysql',
'user' => parse_ini_file('db_config.ini')['DB_USER'],
'password' => parse_ini_file('db_config.ini')['DB_PASSWORD'],
'dbname' => parse_ini_file('db_config.ini')['DB_NAME']
);
}
/**
* Get the entity manager for use through out the app.
*
* #return EntityManager
*/
public function getEntityManager() {
$config = Setup::createAnnotationMetadataConfiguration($this->paths, $this->isDevMode, null, null, false);
return EntityManager::create($this->dbParams, $config);
}
}
/**
* Function that can be called through out the app.
*
* #return EntityManager
*/
function getEntityManager() {
$ds = new DoctrineSetup();
return $ds->getEntityManager();
}
/**
* Function that returns the conection to the database.
*/
function getConnection() {
$ds = new DoctrineSetup();
return $ds->getEntityManager()->getConnection();
}
Do I need to add something else to it to get this error to go away?
Update 1
So I went ahead and set up the AppKernel as I didn't have one before, and because I don't believe I need a config.yml (at least not yet). Everything seems to be working - kernel wise, but the error still persists.
namespace ImageUploader;
use Symfony\Component\HttpKernel\Kernel;
use Symfony\Component\Config\Loader\LoaderInterface;
class AppKernel extends Kernel {
public function registerBundles() {
$bundles = array(
new \Doctrine\Bundle\DoctrineBundle\DoctrineBundle()
);
return $bundles;
}
public function registerContainerConfiguration(LoaderInterface $loader) {}
}
I then started the kernel in the bootstrap file, by adding:
use \ImageUploader\AppKernel;
$kernel = new AppKernel();
$kernel->boot();
Everything, from what I have read, is correct - minus the missing config file that shouldn't be an issue. But I still receive the error in question
How i worked around this:
First, created a custom ConstraintValidatorFactory that'd allow me to add validators
<?php
namespace My\App\Validator;
use Symfony\Component\Validator\ConstraintValidatorFactory as SymfonyConstraintValidatorFactory;
use Symfony\Component\Validator\ConstraintValidatorInterface;
/**
* Class ConstraintValidatorFactory
*
* #package My\App\Validator
*/
class ConstraintValidatorFactory extends SymfonyConstraintValidatorFactory
{
/**
* #param string $className
* #param ConstraintValidatorInterface $validator
*
* #return void
*/
public function addValidator($className, $validator): void
{
$this->validators[$className] = $validator;
}
}
Then i could do:
<?php
use My\App\Validator\ConstraintValidatorFactory;
use Symfony\Component\Validator\Validation;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntityValidator;
$factory = new ConstraintValidatorFactory();
$factory->addValidator('doctrine.orm.validator.unique', new UniqueEntityValidator($registry));
$builder = Validation::createValidatorBuilder();
$builder->setConstraintValidatorFactory($factory);
$builder->enableAnnotationMapping();
$validator = $builder->getValidator();
$violations = $validator->validate($entity);
This worked for me, using symfony components with zend service manager.
Bare in mind that Symfony's UniqueEntityValidator depends on \Doctrine\Common\Persistence\ManagerRegistry.
I use a single EntityManager for my project and had to wrap it in a ManagerRegistry class to make this work.
You are missing the Doctrine bundle, which integrates doctrine into the Symfony framework. Install it with composer require doctrine/doctrine-bundle and then register it in your AppKernel.
Related to Update #1
You still need some configuration and set up the doctrine ORM. Without this configuration, ORM services (like the one missing here) are not loaded.
This is an old question but as I just stumbled upon it and find the chosen answer not entirely satisfying I would like to contribute a bit.
As I understood from the comments this is not about full-stack Symfony but only about the Symfony-validator component.
Because the validator constraint UniqueEntity is based on Doctrine integration and hard-coding class names or the such is not recommended to prevent tight-coupling, Symfony uses a much used pattern called services (see service container).
This allows defining services through configuration which would then prevent hardcoding class names (and its dependencies!) into the Validator codebase. This allows dependencies between both project to be configurable (less compatibility-breaks) and optional.
This 'doctrine.orm.validator.unique' "class" that is being searched for is actually just a reference to an instance of the actual class. For it to be found one must add two things:
A service container, which resolves this service name to the class instance
And the actual configuration of this service, which defines the class to instantiate and its constructor parameters (dependencies).
Looking at your composer.json I think we need the Symfony DependencyInjection component, I don't think you need the AppKernel for this. The following code might work (not tested it) but in any case should give you roughly the idea of what we need:
use Symfony\Component\DependencyInjection\ContainerBuilder;
$container = new ContainerBuilder();
$container
->register('doctrine.orm.validator.unique', 'Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntityValidator')
->addArgument(new Reference('doctrine'));
# register doctrine here in the same way as we just registered the validator
So in conclusion, this answer will probably be a year or two too late for the OP but might be useful to others stumbling upon this. Cheers!
In the first you can get the kernel
After using the kernel to get service validator.
For example : $validator = $kernel->getContainer()->get('validator');