How to structure of a Symfony 2 application to support multiple applications? - symfony

Background
We are planning to migrate our current code to a Symfony2 project.
In our case, each application is considered to be a country where we operate. As such:
Each application has a unique top-level domain.
Each application will have the same subdomains.
Each application has its own database. The database structure for each application is the same.
Applications will share the same business logic. Any differences in business logic will be abstracted into a configuration file. There should be a base configuration file that applications can override with application-specific configurations.
Applications will share most of the templates, but there may be application-specific templates too.
Possible approaches
Multiple repos
Each application would be a Symfony2 project by itself.
All development would take place in bundles, each application loading the same bundles thru composer.
This approach would make development quite cumbersome. Ideally I would like to test any changes in all countries without running composer etc.
Multiple apps within a single repo with multiple Kernels
Each application would have its own app in the app/ folder as suggested in here.
Duplicating the whole app folder seems a bit hackish. Not sure if this is a recommended practice?
Modify Symfony2 to support multiple applications
Modify the Symfony2 Kernel/Console/Whatever to support multiple applications.
Are there any existing bundles/examples already doing this?
[Your idea here]
Are there any other possible approaches?
Question
What would be the best approach to add support for multiple applications in Symfony2?

This is a fine approach but if you find you are sharing a lot of code...
The creator of Symfony2 does not recommend this practice. If you need multiple kernels, you most likely need multiple projects. https://groups.google.com/d/msg/symfony-devs/yneojUuFiqw/sZ8BZrzFLbwJ
IDK
For a project I have built the changes come from a $_GET parameter. What I do is, I have a primary project bundle that handles the common functionality and references the app/view for basic layout. Inside the "core" functionality, I created a controller and use it as a service so that all my application-specific bundles can use it at any point. Then I create a Symfony2 extension for each of my application-specific config definitions so that each application can have yml configs while keeping high-level config in app/config/config.yml. An advantage of this is that in the CoreBundle's controller I can create generic page routes and render like:
$this->render('Name'.$project.'Bundle:index.html.twig', array('params' => $params));

Related

Deploy multiple webapp projects (different areas) to same site?

Multiple Asp.Net Framework 4.6.2 MVC/Razor projects within a single solution.
They use Areas, and each project will implement one or more Areas, distinct from the other.
One project acts as the "primary", and includes the global.asax.
The "subordinate" apps can know about the "primary", but not vice versa.
Is it possible to deploy these to the same web site? (on-prem VM).
There would be some collisions, such as the _Layout.cshtml.
Some how I'd have to be able to setup dependency injections for the classes in the "subordinate" project assembly.
Thanks
-John
I don't think this is possible easily, because so much of an MVC site is pre-compiled into DLLs, and yet some of it (e.g. view files) must be actually physically deployed outside the DLL. You are likely to run into conflicts or confusion I think. It's certainly not a reliable, definable process that you could count on in production.
Here are some alternative suggestions to solve the underlying problem, based on what you described in the comments. These are just ideas, some of which I've done or seen done, and might not suit you, but any of them should be a lot easier to manage than trying to bodge the deployment process:
1) Try building the areas in separate projects as you do now, but without all the generic MVC stuff that surrounds it. I.e. Do it as if they were libraries only containing the files specific to their functionality. Then you can package them up as Nuget packages. When they're ready, install the packages into the "main" site to create the combined solution. That way you won't run into conflicts of layout pages etc. If one of the sub-projects changes, then the main site can just upgrade the NuGet package. You can create private NuGet feeds either via Visual Studio Online (if you have a subscription) or on the simplest level via a shared network folder. I think other online vendors offer private feeds as well. We've done that quite successfully to apply some default styles, scripts, layouts etc to all our various MVC apps.
2) Re-architect your solution as a series of separate apps (that's the bit you've already got), but with a central service that provides federated authentication/authorisation (e.g. ADFS, IdentityServer or similar), and a web API (or APIs) that the other sites can call to access other centralised services and functions programatically. I'm pretty confident you can use routing config and shared sessions to make it all hang together as if it was actually one site.
3) Build it all out as just one site, but with clear separation for the various teams about the back-end services, classes etc that they are responsible for, so they don't interfere with each other's code. Each team can check-in code to different branches in source control and only merge to the shared branches for integration/system testing and deployment. You can use a continuous integration server to test the build process after each check-in, and if you have robust code review and gated check-ins you can stop people changing stuff that they shouldn't. You also have the flexibility to release with/without updates from the various areas, if the development lifecycles are going at different speeds.
4) Some combination of all of the above!

Deploy project with same code base but different content to multiple sites

I have an ASP.NET MVC project that is deployed via Visual Studio's Web Deployment - all works fine so far.
I now need to deploy another version of the same project (e.g. for a different customer) - with the same code base/functionality, but with a different layout, i.e. other CSS and images (maybe even with different views/Razor code). Ideally, the content from the other configuration would not be published at all.
I know I can use different connection strings for the persistence layer - but is there a way to configure also configure other content elements?
I'd like to avoid having two versions (or later even more) that required branching/merging - but rather like to simply deploy the latest version with the different "themes"...
I have a MVC project with 4 class libraries. And i deployed it into 3 other domains.
I copied only MVC project without controllers or code classes for each client, and added them into my solution. I use them only for visual changes or themes. Not for server side functionality. So the copied projects' assemblies shouldn't be deployed. Only the UI files should be deployed. Assemblies are deployed from the original MVC project's output folder.
I build solution and publish dll's into 3 domain, and publish only each client's UI files into it's server.
This enables me to develop server-side functionality in only one MVC project. Separate UI files from server side functionality.
Hope this helps.
are you using MVC then?
What you can do is to override the default razor engine and create your own. What the razor engine does is mainly to map your requests to views in particular folders, you can tell the razor engine when to map those requests to views in one folder or another.
MVC4 Razor Custom View Locator
A full fledged explaination is here :
http://nickberardi.com/creating-your-first-mvc-viewengine/
That is for views, if you just want the CSS or JS to be different, you just have to map your requests to a razor bundle and then vary what the content of the bundle is depending on a variable, or the pressence of a configuration file, or by filling a variable with a value from the database.
As you can see here bundling is very easy :
http://www.asp.net/mvc/tutorials/mvc-4/bundling-and-minification
Say your html points to : /assets/mycssbundle.css , but what that file would actually contain can be altered by where you tell to the bundling function that the files are located.
This seems like a design question. If you foresee possible changes like this in the future, and you already swap content via DB, then you should consider loading css file from database. There're of course many other ways to do this but simple and efficient is preferable.
This would mean structuring your html properly to ensure all layout is properly handled via CSS and can be achieved via ViewData or ViewBag. See case example.
Edit:
Not css data but the relevant css file.
You have two options:
A) Develop a custom view engine that switches between different page sets depending on the configuration. This will allow you to switch between the page sets just by changing the web.config settings, which fits well with the visual studio's built in deployment model (different web.config transformations kick-in for different deployment environments). One implementation that comes to mind - switch between view engines for different deployment environments (in different web.config transformations).
Unlike the other suggestion to load pages from the DB, I would recommend loading them from folder or physical location (e.g. different view engines targeting different sub-folders of the project). DB approach is not developer friendly when it comes to developing and fixing pages and their markups that are in the DB.
B) Develop all page sets (all variations) under the same project and then write custom deployment scripts which deploy particular page sets depending on the deployment environment. Drawback of this approach is that it's hard to notice issues like page sets intersecting or links crossing the page set boundaries.
While plan B sounds a little bit simpler development-wise, it can become a nightmare maintenance- and deployment-wise.
So, I recommend plan A.
Your Question is too broad.
However we have also a similar use case. We put all the theme related stuff (css, images, etc) as an embedded ressource in a separate assembly. We have Customer1.Theme.dll and Customer2.Theme.dll etc.
The App loads dynamically the Theme.dll and references the ressrouces from there.
Among other solutions,
assuming that you are using asp.net mvc.
and assuming that you have content1 and content2 folder available in the same repository or making available in same repository is not a concern.
and assuming your are bundling your contents.
and assuming your images are referenced only using css.
You can have a app config key which will tell you whether you want content1 or content2.
something like,
<add key="sitecontent" value="content1"/>
Now in your Application start in global asax, read the app config key and depending on the value, call the
BundleConfig.RegisterContent1Bundles(BundleTable.Bundles);
BundleConfig.RegisterContent2Bundles(BundleTable.Bundles);
I think this is a design issue. As you can see below you can organize your .net application in different layers:
Source: Microsoft
There are some key principles (Separation of concerns, DRY, etc) that Microsoft strongly encourages through the .net platform and I believe will find good use in your project.
Based on what you describe a simple approach is to keep in one project -same for all clients- your business layer (including the Services or the Data layer - even with different connection strings for each project) and create separate projects for the Presentation layer.
You may find more information from Scott, CodeProject, or more traditional methods (BTW this is a great book).

Where do I store services in Symfony2

I'm building an app in Symfony2 that receives a HTML string via an API, does some work on it (think of something like the Tidy library, only with a different purpose) and then returns the fixed HTML.
The stuff that does all the work is mostly written in services, because they don't need to return a Response object.
Where do I store those services? I'm putting them in bundles, but there's no obvious place to store them. I understand that they can be stored anywhere, but I'm wondering what the default convention is.
If that code doesn't have to be re-usable outside of Symfony2 projects, you can just put it into your bundle.
I'd go for something like:
Acme\HtmlCleanerBundle\Cleaner\SimpleCleaner.php
Since it is a bundle, you can extract it to a separate package and re-use it for other Symfony2 projects.
If you want the code to be completely re-usable and standalone, I'd suggest you extract it to a separate library. You can still have dependencies on individual components (shameless plug: you could manage those dependencies through composer, which will be used by Symfony 2.1).
If you decide to go down that path, the bundle simply integrates the library into Symfony2 by providing DI container configuration for it.

Headache designing Symfony2 bundles organization

I'm developing a SaaS where tenants are both real ones and admins (us). So "fornt-end" and "back-end" are the same. Anyway, according to many other questions bundles are a way to structure your project in reusable way.
I really don't think that our bundles are going to be reused, but i still need a way to split the project into bundles to quickly find files we want to work on. Application should:
CRUD for customers - tenants should be able to manage their
customers/partnerships
CRUD for customers tags and keywords (a way to categorize their customers)
CRUD for broadcast notifications sent by us (a messaging system)
CRUD for tenants - we should be able to manage our tenants
So, how can organize my bundles? Could be:
CoreBundle: only Doctrine2 models
ResourcesBundle: templates, js, css, images
SystemUserBundle: manage tenants and customers CRUD
MessagingBundle: message system
How this design can be improved?
According to the Symfony2 documentation:
In Symfony2, a bundle is like a plugin, except that all of the code in
your application will live inside a bundle. A bundle is nothing more
than a directory that houses everything related to a specific feature,
including PHP classes, configuration, and even stylesheets and
Javascript files (see The Bundle System).
Personally, following this description, I would set up the SystemUserBundle to contain the Doctrine2 model and templates/js/css/images that specifically relate to managing customers, rather than splitting them out into CoreBundle and ResourceBundle. However, splitting your app into SystemUserBundle and MessagingBundle sounds like a reasonable approach.
I like to think of it this way - does the bundle encapsulate some behaviour that I might need or want to plugin to a future Symfony project(s) I am involved in. Customer Management, for example, is something that might apply to any app and be re-used across projects (indeed, this is why the extensible FOSUserBundle exists).
I don't think the Symfony2 docs go into sufficient detail on bundles (yet!) but in case you haven't found all the relevant sections these are the ones I'm aware of:
Symfony 2 Page creation
Symfony 2 The Bundle System
Symfony 2 Bundles best practices

An exact description of a Symfony Bundle in a complex web application

I'm new to version 2 of the Symfony framework. I made some projects with v1 but now trying to get my head around the new version and it's features.
I read over the concept of Bundles but it's purpose is not yet very clear to me.
Say you have a big web application, a CRM for example. How would the bundles look like?
Would it be NewsletterBundle (for sending newsletters), ContactManagementBundle (for managing contacts), UserBundle (for editing users and their permissions).
Or would it be less cut-up like, EmailBundle (for handling the entire email traffic), CRMBundle (for putting in all your CRM code), PermissionsBundle, ApiBundle.
I like to think of it like this: a bundle should represent a specific feature or set of like features for a project.
Your first example is a better use of bundles than your second example, because the purpose of each bundle is more defined. While it's possible to use one CRMBundle for everything, you wouldn't really be taking advantage of Symfony's ability to organize your code. Additionally, if you wanted to port over your Newsletter code to a new project, but not all of the CRM code, you'd have an easier time copying over a NewsletterBundle versus copying over the CRMBundle, and then pruning it.
When thinking about a Symfony2 project, sometimes you want to forget everything you know about symfony 1.x, since they take wildly different approaches to solving many problems. For example, in symfony 1 it was common to build a 'frontend' and 'backend' app for a project, and each app would obviously contain logic specific to those parts of the project. So you might have a Newsletter controller in both the frontend and backend apps. In Symfony2, you're better off using only one Newsletter bundle, but with two controllers (perhaps named 'frontend' and 'backend'). Again, an immediate benefit to this is how reusable your code becomes.

Resources