I'm trying to follow these steps:
http://docs.doctrine-project.org/projects/doctrine1/en/latest/en/manual/hierarchical-data.html
Please, correct me if I am wrong. Firstly, I've created this class in AppBundle/Model route:
namespace AppBundle\Model;
class Item extends Doctrine_Record
{
public function setTableDefinition()
{
$this->hasColumn('name', 'string', 255);
}
public function setUp()
{
$this->actAs('NestedSet');
}
}
And then I use it in a controller like this:
$treeObject = Doctrine_Core::getTable('Category')->getTree();
I have two questions:
- Where do I have to define the Category table and how
- With this previous code I ran into this error: Attempted to load class "Doctrine_Core" from namespace "AppBundle\Controller\Admin
Any idea please? Thanks
Doctrine has it's bundle for Symfony, that allows to store all config data in YML. https://symfony.com/doc/current/bundles/StofDoctrineExtensionsBundle/index.html - it has "Tree extension" and it is exactly what you're looking for.
Classes Doctrine_Record and Doctrine_Core are part of Doctrine in 1.x version, Symfony2 is using Doctrine 2.x which is completely different than 1.x version. For example Doctrine 2.x does not use Active Record approach and this is what you are trying to use. In Doctrine 2 Model classes (Entities) don't extend any class
Check this piece of doc how to use Doctrine2 in Symfony2
Ok, I followed these steps:
Install this: http://symfony.com/doc/master/bundles/StofDoctrineExtensionsBundle/index.html
Don't forget to set up the configuration for the extensions, in this case for tree like this in config.yml:
stof_doctrine_extensions:
orm:
default:
tree: true
Related
I would like to use the AlterPHP extension as well as the Wandi extension with EasyAdminBundle.
But we face some issue configuration both of them at the same time.
We used to have this config file when using only AlterPhp :
#routes/easy_admin.yaml
easy_admin_bundle:
resource: '#EasyAdminExtensionBundle/Controller/EasyAdminController.php'
prefix: /admin
type: annotation
And it was fine when we only used this bundle. However, now we want to use this bundle as well as the one quoted previously but it also needs to replace the easyadmin controller by the one from the new bundle.
So both extension wants to do the same thing and both extend the BaseAdminController from EasyAdmin.
What would be the best way to use both in the same project ?
I found a solution by making a custom controller that extends the AdminController from Wandi and copying the methods from the AdminController from Alterphp inside the custom controller. However, it seems like an odd solution to this problem.
I decided to contact both AlterPHP and Wandi on github and send a pull request on their extensions to use trait in their controller to make it easier to use multiple extensions.
So both of them answered to me :
Wandi reviewed my PR and merged it to master. It is now available in release 2.0.2.
AlterPHP reviewed my PR and merged it to master. It is now available in release 3.0.1
So with those changes it is way easier to use both extensions (and similar EasyAdminExtension) by using those new traits :
use Wandi\EasyAdminPlusBundle\Controller\AdminController as WandiController;
use EasyCorp\Bundle\EasyAdminBundle\Controller\EasyAdminController;
use Wandi\EasyAdminPlusBundle\Controller\AdminControllerTrait as WandiTrait;
use AlterPHP\EasyAdminExtensionBundle\Controller\AdminExtensionControllerTrait as AlterPHPTrait;
class CustomAdminController extends EasyAdminController
{
use AlterPHPTrait, WandiTrait;
//You may have to solve conflict between those traits
}
You may have multiple problems such as services not known by the controller or methods defined multiple time.
I just had to redefine getSubscribedServices in my controller to add those used by AlterPHP and Wandi, as well as resolving a conflict with the method isActionAllowed defined in both traits.
use AlterPHP\EasyAdminExtensionBundle\Security\AdminAuthorizationChecker;
use EasyCorp\Bundle\EasyAdminBundle\Controller\EasyAdminController;
use Wandi\EasyAdminPlusBundle\Controller\AdminControllerTrait as WandiTrait;
use AlterPHP\EasyAdminExtensionBundle\Controller\AdminExtensionControllerTrait as AlterPHPTrait;
use Wandi\EasyAdminPlusBundle\Exporter\Configuration\NormalizerConfigPass;
use Wandi\EasyAdminPlusBundle\Exporter\Configuration\PropertyConfigPass;
use Wandi\EasyAdminPlusBundle\Exporter\Configuration\TemplateConfigPass;
class CustomAdminController extends EasyAdminController
{
use AlterPHPTrait,WandiTrait { AlterPHPTrait::isActionAllowed insteadof WandiTrait; }
//It is important to set the subscribed services from the trait because they cannot use them otherwise.
public static function getSubscribedServices(): array
{
return \array_merge(parent::getSubscribedServices(), [
AdminAuthorizationChecker::class, //This one is for AlterPHP and those below for Wandi
'wandi.easy_admin_plus.exporter.configuration.normalizer_config_pass' => NormalizerConfigPass::class,
'wandi.easy_admin_plus.exporter.configuration.property_config_pass' => PropertyConfigPass::class,
'wandi.easy_admin_plus.exporter.configuration.template_config_pass' => TemplateConfigPass::class,
]);
}
}
I had to modify my services.yaml to be able to redefine getSubscribedServices for Wandi.
#services.yaml
services:
#...
Wandi\EasyAdminPlusBundle\Exporter\Configuration\NormalizerConfigPass: '#wandi.easy_admin_plus.exporter.configuration.normalizer_config_pass'
Wandi\EasyAdminPlusBundle\Exporter\Configuration\PropertyConfigPass: '#wandi.easy_admin_plus.exporter.configuration.property_config_pass'
Wandi\EasyAdminPlusBundle\Exporter\Configuration\TemplateConfigPass: '#wandi.easy_admin_plus.exporter.configuration.template_config_pass'
I got my some custom classes in my vendor folder which I use in my Symfony project. Now I need to access some parameters from my parameters.yml which is located in
C:\xampp\htdocs\myproject\app\config\parameters.yml
In my regular Symfony code I just do
$this->getParameter('myparameter');
and all set, but not in vendor folder. I guess I need to import some namespaces, but could not find which?
Any help would be appreciated. Thank you.
UPD1 The issue was solved by adding the following code to AppBundle.php
class AppBundle extends Bundle
{
private static $containerInstance = null;
public function setContainer(\Symfony\Component\DependencyInjection\ContainerInterface $container = null)
{
parent::setContainer($container);
self::$containerInstance = $container;
}
public static function getContainer()
{
return self::$containerInstance;
}
}
and then calling the container from my vendor code with the following:
use AppBundle\AppBundle;
AppBundle::getContainer()->getParameter('myparameter');
Thanks everyone for help.
DependencyInjection/YourBundleExtension.php
$container->setParameter('myparameter', $config);
https://symfony.com/doc/current/create_framework/dependency_injection.html#main
After that, add this config to your service (for example)
Resources/config/services.yml
services:
your.service:
class: App\YourBundle\Service\YourService
arguments:
- %myparameter%
You can either define your services in
C:\xampp\htdocs\myproject\app\config\services.yml
The Resources\config directory of a bundle. See How to Load Service Configuration inside a Bundle.
You simply define your services by giving them a name, specifying the class and then listing any arguments the class has to be injected into it when it is instantiated. To reference a parameter from parameters.yml you wrap the name of the parameter in %% as I did below.
services:
my_project.some_service:
class: Vendor\Class\Name\Here
arguments: ['%some.parameter.name%']
In 99% of scenarios you definitely should not inject the dependency injection container into your own classes. Having your classes depend on the container is not good - have them depend on other services from your project or simple values such as strings, integers etc.
I'm trying to create a menu for my page with ezpublish5. I followed this tutorial http://partialcontent.com/Code/working-with-ez-publish-5-subrequests.
I'm pretty new to Symfony, but I have my own bundle there and running, at least it is using my own pagelayout.html.twig.
I understand, what routing does, but I as far as I'm concerned in order to create a menu I need something else, probably a service, so I can do this in my twig-template
{{ render( controller( "myMenuController:myFunction" ) ) }}
So I add this to my my\Bundle\Resources\config\services.yml
parameters:
my_root.menucontroller.class: my\Bundle\Controller\MenuController
services:
my_root.controller:
class: %my_root.menucontroller.class%
arguments: [#ezpublish.view_manager]
calls:
- [setContainer, [#service_container] ]
myalias:
alias: my_root.controller
When I open it in the browser it says:
You have requested a non-existent service "myalias".") in "{% extends "Bundle::pagelayout.html.twig" %}
I checked other repos of ezp5 installations on github, they have pretty much the same yml-setup.
I also realized, that when I make syntax errors on purpose in my services.yml it (while leaving out the call to the controller in the template) it doesn't change anything.
Also I realized, that when I do the same in my\Bundle\DependencyInjection\myBundleExtension.php (which is supposed to load my services.yml file) it doesn't happen anything either.
So I'm getting the feeling something with bundle-setup is wrong, that somehow not everything is loaded correctly. But what could it be?
Somewhere in the docu of symfony2 it says that the load-method in the Bundle\DependencyInjection\xyzExtension.php gets called automatically.
Would anyone have an idea of what could possibly be wrong with my setup? I'm really running out of ideas.
And for the ezpublish5 part.. is this really the best way to create a menu right now?
It does seem like your services are not being loaded.
Symfony relies on a naming convention to load xyzExtension.php. It's tripped me up a few times. You can stick a die statement in xyzExtension.load just to verify it is indeed being called.
If it is not being called than you can either change the extension class name to meet the convention or do what I do and just override the convention in your bundle class.
namespace Cerad\Bundle\GameV2Bundle;
use Symfony\Component\HttpKernel\Bundle\Bundle;
use Cerad\Bundle\GameV2Bundle\DependencyInjection\GameExtension;
class CeradGameV2Bundle extends Bundle
{
public function getContainerExtension()
{
return new GameExtension();
}
}
And of course xyzExtension should have something like:
namespace Cerad\Bundle\GameV2Bundle\DependencyInjection;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
use Symfony\Component\Config\FileLocator;
class GameExtension extends Extension
{
public function load(array $configs, ContainerBuilder $container)
{
$loader = new YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
$loader->load('services.yml');
}
public function getAlias() { return 'cerad_game_v2'; }
}
From the command line you can verify your service is getting picked up:
app/console container:debug : grep my_root
In a Symfony2 project, when you use a Controller, you can access Doctrine by calling getDoctrine() on this, i.e.:
$this->getDoctrine();
In this way, I can access the repository of such a Doctrine Entity.
Suppose to have a generic PHP class in a Symfony2 project. How can I retrieve Doctrine ?
I suppose that there is such a service to get it, but I don't know which one.
You can register this class as a service and inject whatever other services into it. Suppose you have GenericClass.php as follows:
class GenericClass
{
public function __construct()
{
// some cool stuff
}
}
You can register it as service (in your bundle's Resources/config/service.yml|xml usually) and inject Doctrine's entity manager into it:
services:
my_mailer:
class: Path/To/GenericClass
arguments: [doctrine.orm.entity_manager]
And it'll try to inject entity manager to (by default) constructor of GenericClass. So you just have to add argument for it:
public function __construct($entityManager)
{
// do something awesome with entity manager
}
If you are not sure what services are available in your application's DI container, you can find out by using command line tool: php app/console container:debug and it'll list all available services along with their aliases and classes.
After checking the symfony2 docs i figured out how to pass your service
in a custom method to break the default behavior.
Rewrite your configs like this:
services:
my_mailer:
class: Path/To/GenericClass
calls:
- [anotherMethodName, [doctrine.orm.entity_manager]]
So, the Service is now available in your other method.
public function anotherMethodName($entityManager)
{
// your magic
}
The Answer from Ondrej is absolutely correct, I just wanted to add this piece of the puzzle to this thread.
I'm creating a class that will have one public method, which returns a value indexed by a parameter. I have a single bundle at present. The directories inside the bundle I currently have are:
/Controller
/DataFixtures
/DependencyInjection
/Document
/Entity
/Resources
/Tests
What is the convention for placement of a class like this?
Symfony official website suggest src/AppBundle/Utils
Source : http://symfony.com/doc/current/best_practices/business-logic.html
Your question is a bit subjective, but according to what is outlined in Bundle Structure and Best Practices, a Bundle is just namespaced code. If the utility class is of first-grade, why don't you place it into the root-dir of the Bundle?
Namespace Bundle\HelloBundle;
Class Utility {
public static function returnIndexedValueByParameter($parameter) {
...
}
}
Filename:
Bundle/HelloBundle/Utility.php