I'm currently building a fairly large Symfony 2 application with a number of ever increasing bundles that I'm struggling to keep count of.
I try to keep all bundles specific to each module of the system, which has provided me with a nice easy to manage structure. What isn't so nice is my app/config/config.yml that's very quickly grown out of control. Understand imports can be done within this file which have helped me somewhat but I'd like to move a whole range of config specific to each bundle which should help to keep these bundles reusable within our other applications.
Here of some examples of what I'd like to move to individual bundles.
1) Dependency Injection
We use JMSDiExtraBundle within all internal bundles as we find it makes developing a little bit quicker and easier to manage.
# Annotations/Config
jms_di_extra:
locations:
bundles:
- AppBundle
- BlogBundle
- ContentBundle
- StoreBundle
- UserBundle
I'd like this block to be moved to each individuals bundle config.yml or better yet this would be enabled in each bundles DependencyInjection/AppBundleExtension.php.
2) Routing
Use for route config, but each bundle still needs including within app/config/routing.yml leaving us with a pretty large unmanageable file.
Some examples
app:
resource: "#AppBundle/Controller"
type: annotation
blog:
resource: "#BlogBundle/Controller"
type: annotation
content:
resource: "#ContentBundle/Controller"
type: annotation
oneup_uploader:
resource: .
type: uploader
3) OneUp Uploader
This is my biggest biting point, this configuration is over 500 lines long currently between the 20+ bundles we use. Here are some examples pulled from app/config/uploader.yml which is imported from config.yml. If I could somehow get these into each bundles config I'd be very happy!
# Uploader
oneup_uploader:
mappings:
bundle_name_reference1:
frontend: blueimp
storage:
type: gaufrette
filesystem: gaufrette.local_filesystem
bundle_name_reference2:
frontend: blueimp
storage:
type: gaufrette
filesystem: gaufrette.local_filesystem
My thoughts are by getting all these configs into each individual bundle, I can enable/disable them really easily by just updating AppKernel.php. I'm assuming all of this is possible as Symfony is incredibly flexible, I'm just a little lost when it comes to these lower level alterations.
You could simply just add
oneup_uploader:
#...
to src/Vendor/WhateverBundle/Resources/config/services.yml
OR
There is a cookbook entry on how to decouple bundles from app/config:
How to Load Service Configuration inside a Bundle
I think the ideal, low-coupling, solution would be to create a bundle extending the other bundle (e.g. MyOneUpUploaderBundle) and using the cookbook approach there.
Related
I recently got to know the Sylius project and was trying to reuse its components in a separate project (study only).
My goal was to test if I can use the sylius components in a separate project. Only a few components.
Following the documentation (http://sylius-older.readthedocs.io/en/latest/components/Order/basic_usage.html), I was able to install the components and use their classes, but how do I do the database tables?
I installed the doctrine and tried to map the classes, but I could not.
I was thinking of creating the migration (doctrine or eloquent) for each table and doing the actions (CRUD).
Thank you so much guys.
Assuming you have installed the OrderBundle using Composer you will probably have to tell Doctrine where to read the entity mapping. In case of Sylius' OrderBundle they are stored as xml files in Resources/config/doctrine/models, e.g. Order.orm.xml. If you look at the sample configuration in the DoctrineBundle-recipe you can find a reference for a manual mapping. In your case it probably should look something like this:
# app/config/config.yml (in Symfony 3.4)
# config/packages/doctrine.yaml (in Symfony 4)
doctrine:
dbal:
...
orm:
mappings:
SyliusOrderBundle:
is_bundle: false
type: xml
dir: '%kernel.project_dir%/../vendor/sylius/order-bundle/Resources/config/doctrine/models'
prefix: 'Sylius\Component\Order\Model'
alias: SyliusOrder
You might have to tweak this, e.g. if you have a Symfony 4 app, but with this you should be able to create the appropriate schema using the default Doctrine commands. You might also have to adjust auto_mapping under doctrine.orm and possibly manually map your own entities if you do this.
I have a symfony project where i have seperated my code into two different bundles lets say HomeBundle and AppBundle however the routes are commonly accessible inside both bundle.
eg:- /home defined in HomeBundle can also be accessed from AppBundle
and
/App defined in AppBundle can also be accessed from HomeBundle
what i want is to access /home ONLY from HomeBundle and /App from Only AppBundle I'm looking for 'structuring' my code in a way where i dont have to write any logic to accomplish this, but instead leverage symfony frameworks structure to do this for me, something along the lines of restricting routing to only within the bundle, or some way where the route definition goes 'out of scope' when inside the wrong bundle
im using annotaions for routing, and defined in app/config/routing.yml
edit: the application requires subomain partitions so i'm also using this host/default with placeholder
any help would be appreciated :) thanks
Unfortunately this isn't going to be possible, primarily because of the architecture of Symfony bundles. While separating your code into bundles is good from a cognitive point of view, Symfony doesn't have the concept of being "in" a bundle; what code is run (specifically your controller actions) is usually handled by routes, and routes have to be compiled together from ALL bundles to ensure that a request can be routed successfully.
You would have to write extra code to accomplish what you're asking - my initial thought would be your own Controller class (maybe extending from FrameworkBundle\Controller\Controller) that ran some code before a request (see documentation that may achieve this).
Fundamentally this is an architectural decision for you and my question would be - why do you not want to be able to access /home from the AppBundle? Would a security / role set up work as well or are you trying to sandbox code?
EDIT After some further detail, it turns out that the requirement is for two different actions for the same URL path (e.g. /home) but on different domains e.g. www.example.com/home and subdomain.example.com/home. In this instance it wasn't about code sharing but URLs so Symfony's host/domain based routing solution worked.
I was under the assumption that business logic inside bundles are isolated and would not be 'aware' of routes defined inside other bundles, turns out the routes are globally available to all bundles, i wanted to use the framework of symfony to achieve what i asked for, it happens so there is no way to do it. i probably should use Listeners or before filters etc to achieve this. John Noel answered this.
Luckily for me, the bundles happen to operate on separate Domains (one on the main domain and the other on the subdomain) i noticed this after a chat with #John Noel he suggested matching the Route Based on the Host/Domain. i had this in place previously, upon a second look i figured out i have to -based on the domain redirect all (except for a white list of routes) routes to a controller that throws a 404 exception. Here is what i mean.
Home_restrict:
path: /{slug}
host: "{domain}"
defaults:
_controller: HomeBundle:Home:notfound
requirements:
domain: example.com|www.example.com
slug: ^(?!.*(admin|login)$).*
Routes that appear on top of the list on the page takes precedence, so this should be placed appropriately
You can add a routing.yml per bundle, and include these in your "global" routing:
# src/HomeBundle/Resources/config/routing.yml
home:
resource: "#HomeBundle/Controller/HomeController.php"
type: annotation
and
# src/AppBundle/Resources/config/routing.yml
home:
resource: "#AppBundle/Controller/AppController.php"
type: annotation
then import them in app/config/routing.yml, and maybe even prefix it over there?
# app/config/routing.yml
app:
resource: "#AppBundle/Resources/config/routing.yml"
prefix: /app
I'm having a tough time setting up doctrine ORM configuration using Symfony2. I'm setting up the ORM files using yml.
I've looked at a couple of open source Symfony2 projects(mostly Sylius) and the norm seems to be placing Entities outsides of the bundles in a folder called Components but placing the ORM definitions in the bundles. Can anyone suggest any useful resources to help me set this up? The default seems to require my entities to be within bundles which I don't want to do because some of my entities have scope across multiple bundles.
I've noticed in the documentation you can configure entity managers individually but I can't see how the configuration options below can achieve what I'm after, especially because the entities may not all share the same prefix:
mappings:
AcmeOrderBundle:
type: ~
dir: ~
alias: ~
prefix: ~
is_bundle: ~
Any help with this would be greatly appreciated and I can provide more information if necessary.
Here is an example using a couple of the options:
entity_managers:
games:
connection: games
mappings:
CeradGameBundle:
type: yml
dir: Resources/config/doctrine2
prefix: Cerad\Bundle\GameBundle\Doctrine\Entity
The dir points to where the orm.yml files live. As shown it is relative to the bundle. But you can replace it with an absolute path if you want.
The prefix is basically the namespace of your entities.
As far as multiple prefixes go, you can have multiple mappings for a given manager. Make one mapping per prefix.
The tutorials I've read for Symfony 2 instructs users to enter their routing information in
app/config/routing.yml
If users want to have routing information in their own bundles, they're instructed to add a routing.yml file to their Bundle, and then point to their file from app/config/routing.yml with something like
my_route_stuff:
resource: "#CustomstuffBundle/resources/config/routing.yml"
Is there any way to skip the "add this extra configuration to the app/config/routing.yml file? I'm looking for the ability to hand off a bundle to someone else, and have them be able to deploy it into their Symfony application without needing to edit their own app/config/routing.yml.
If this isn't possible, bonus point if anyone can explain why (i.e: the general philosophy behind) routing information is part of the AppKernel instead of the individual Bundles. I'm still a little unclear on the differences between routing.yml files and the normal Symfony config.yml files.
Is there any way to skip the "add this extra configuration to the app/config/routing.yml file?
No, this is the way SonataAdminBundle, FOSUserBundle and a bunch of others handle it.
Why?
Routing belongs to the application, not each and every bundle. If every bundle started including their own routing files and Symfony2 autoloaded them, you would quickly have a mess of routes you may or may not want to enable in your application.
What if SonataAdminBundle wanted you to use /admin, but you already had a route there and wanted Sonata to use /sonata/admin instead? You'd need a file to override those routes and then you're back to square one!
Additionally, although caching mitigates this part, looking up files is expensive and would significantly slow down the development environment. This is why translation files are read from cache even in dev mode and you must clear the cache when you add a new translation resource. See: http://symfony.com/doc/current/book/translation.html#message-catalogues
Finally, leaving the routing out of config.yml is simply a matter of organization. Routing and configuration are two different things and don't belong in the same file.
The general idea is that every file is a thing and should only do that thing.
I would like to ask, what is the best way to structure a project with frontend and backend in Symfony2? In other versions of Symfony this is easy to achieve, because you can create two applications - frontend and backend - then all the libraries/models will become shared between those applications.
Now in Symfony2, everything is a bundle. What is not really clear for me is how could I represent the "two" applications, frontend and backend. Should I create two namespaces - frontend and backend? I would like to keep my entities in just one place, rather than accessing them from the two applications.
Just have one application, create an AdminBundle or BackendBundle or whatever for your project that has all the tools you'll need in the back end, and use firewalls and access control lists in security.yml to create separate routes for the two.
No need to create separate app directories, mess with the console script, or anything like that. By default, Symfony knows how to find entities and other resources for any bundle that you have registered, so you'll be able to share them easily.
This documentation entry on Security is a good place to start learning about access control and firewalls. Here's a quick sample of what my security config looks like:
firewalls:
main:
pattern: /.*
anonymous: true
form_login: true
access_control:
- { path: /admin/.*, roles: ROLE_ADMIN }
- { path: /.*, roles: IS_AUTHENTICATED_ANONYMOUSLY }
If you want complete authentication separation for / and /admin, create a new admin firewall: firewalls do not share authentication information between each other, so you can track users and their sessions separately if you'd like.
I have tried the approach suggested by PAStheLoD (creating app_backend and web_backend, etc) but I found it too much hassle; you have to remember which app to target from console, maintain separate bootstrap files, and the directory structure gets messy.
The method recommended by the Symfony documentation Symfony documentation is to have a separate project for each app. You can then create a separate area for your source code, write most (if not all) of your bundles there and then simply adjust how they are included in autoload.php of both apps.
e.g.
admin_app/
app/
bin/
src/
web/
frontend_app/
app/
bin/
src/
web/
common_src/
Acme/
AdminBundle/
DataBundle/
jQueryBundle/
Then in *_app/app/autoload.php:
$loader->registerNamespaces(array(
'Acme' => __DIR__ . '/../../common_src'
));
As far as I know you still can do the more or less the same thing with Symfony2. Just rename app/ to app_frontend and make a copy to app_backend, also duplicate web/ the same way. Then everything else can live in bundles. Bundles are very powerful, because they can contain routes, configuration or anything else, so you can share what you want and perfectly isolate what you don't want to share.
There might be some problems with the bin/ scripts due to renamed directories, but you just have to correctly configure them (or raise it as an issue at Symfony's Github site.)
How about having one app and creating three bundles, src/Vendor/BackendBundle,src/Vendor/FrontendBundle and src/Vendor/SharedBundle. SharedBundle holds the entities and other shared parts betweeen the FrontendBundle and BackendBundle