6

I am new to Symfony and am not sure how to best structure my web project. The solution must accommodate 3 use cases:

  1. Public access to www.mydomain.com for general use
  2. Member only access to member.mydomain.com
  3. Administrator access to admin.mydomain.com

All three virtual hosts point to the Symfony /web directory

Questions:

Is this 3 separate applications in my Symfony project (e.g. "frontend", "backend" and "admin" or "public", "member", "admin")?

  • Is this a good approach if there is to be some duplicate code (e.g. generating a member list would be common across all 3 applications, but presented differently)?
  • How would I route to the various applications based on the subdomain when a user accesses *.mydomain.com? Where in Symfony should this routing logic be placed?

Or, is this one application with modules for each of the above use cases?

EDIT: I do not have access to httpd.conf in apache to specify a default page for virtual hosts. I can only specify a directory for each subdomain using the hostin provider's cPanel.

James
  • 4,117
  • 2
  • 18
  • 13

3 Answers3

7

This is hard to say without knowing the actual responsibilities of each domain/app/whatever. This is something you have to answer based on the requirements of your project... there is no single strategy one can recommend for every use case.

With that said I think at most you have the makings of two applications - One would serve as frontend and also include the "members" functionality. The reson i think these tow ar probably a sinlge app is because youll want to generate links to one from the other (which is incredibly hard to do if they are seperate applications) - ie. EVERYONE has access to the homepage and say the FAQ, but only members have access to Downloads or something, but still they are the same site.

The other app would be for the backend and hold the admin functionality. Regardless of how many apps you can share the same web dir sinmply make a symlink and then point apache appropriately for example:

cd htdocs
ln -s SF_ROOT_DIR/web frontend
ln -s SF_ROOT_DIR/web backend

Now you can point your cpanel set to htdocs/frontend for domain.com and members.domain.com and point admin.domain.com to htdocs/backend.

Then you could change your .htaccess to look something like this:

Options +FollowSymLinks +ExecCGI

<IfModule mod_rewrite.c>
  RewriteEngine On

  # we check if the .html version is here (caching)
  RewriteRule ^$ index.html [QSA]
  RewriteRule ^([^.]+)$ $1.html [QSA]
  RewriteCond %{REQUEST_FILENAME} !-f

  # no, so we redirect to our front web controller

  # if subdomain is admin.* then use backend.php application
  RewriteCond %{SERVER_NAME} ^admin\..*$
  RewriteRule ^(.*)$ backend.php [QSA,L]

  # not admin so we use the frontend app
  RewriteRule ^(.*)$ index.php [QSA,L]

</IfModule>

This way you should be able to use no_script_name with both apps.

Another way to do the same thing would be to modify your index.php to something like the following:

require_once(dirname(__FILE__).'/../config/ProjectConfiguration.class.php');

if(0 === strpos($_SERVER['SERVER_NAME'], 'admin'){
  $app = 'backend';
}
else
{
  $app = 'frontend';
}


$configuration = ProjectConfiguration::getApplicationConfiguration($app, 'prod', false);
sfContext::createInstance($configuration)->dispatch();

You can modify the app name detection however you like but you get the idea.

With both of the approaches you can do some basic determination based on subdomain, and you can apply this strategy regardless of the number of apps we are talking about whther you only use my recommended 2 or if you use 3.

The alterantive is to make one homegenous application. Assuming each of applications is really just one facet of the overall application i like to go this route. However, I would consider members, non-members, and admin too broad a definition for modules.

If you did it that way you could potentially end up with an insane amount of actions in the controllers. Instead i would make seperate modules for actual concerns. Additionally theres no real reason to use subdomains here - its much easier to just use a segment of the url (ie. /admin or /members) to use specific modules.

For example lets take users... Typically theres going to be an admin area so we can use the admin generator for that functionality and call the module UserAdmin or something similar. Then for the userland stuff we might just have the module User which would handle public profile viewing and listing, profile editing by users and all that stuff. Then for actual login we might have the module UserAuth which strictly handles stuff like login/logout and forgotten password requests and what not. You can route any url to any one of these modules, so your routing might look something like this:

user_login:
  url: /login
  params: {module: UserAuth, action: login}

user_logout:
  url: /logout
  params: {module: UserAuth, action: logout}

user_password:
  url: /forgot-password
  params: {module: UserAuth, action: recoverPassword}

user_reset:
  url: /password/reset/:token
  params: {module: UserAuth, action: resetPassword}

user_profile:
  url: /members/:username
  params: {module: user, action: showProfile}

user_index:
  url: /members
  params: {module: User, action: index}

user_default:
  url: /members/:action
  params: {module: User}

admin_user:
  class:   sfDoctrineRouteCollection
  options:
    Module: UserAdmin
    model: User
    prefix_path: /admin/user

The last step in doing things this way is to make sure you secure the appropriate modules and actions with the proper credential requirements in security.yml and that you also assign credentials appropriately.

prodigitalson
  • 60,050
  • 10
  • 100
  • 114
  • Thank you so much!! You are a prince a among men :) Exactly the information I was looking for, really appreciate the detail. It is a requirement to have the subdomains, so I think I will explore your first two options. Still have much to learn about security. My application GUI is done mostly in ExtJS, so many of the convenience features of Symfony are not going to be leveraged, like admin generation, but it's nice to learn about it. – James Jan 16 '11 at 09:03
1

I think you should separate your applications in public, member and admin. The routing would be done by apache: you can use 3 document roots pointing to separate folders. Mutualizing your code can be done through the use of plugins. You can override a plugin's code : for a specific application if you need to. If the public and member access have very many things in common, you could consider using the same application for both accesses.

greg0ire
  • 22,714
  • 16
  • 72
  • 101
  • Thanks @greg0ire. What directory under the symfony project would apache be pointing to for each subdomain? Symfony creates a /web directory that an application uses for picking up assets referenced in the layout/templates (.js, .css, etc) and it's at the root level of the project, not under /apps, so I'm still confused about how the project structure should look like. A directory listing would be very helpful. – James Jan 15 '11 at 23:42
  • I would say : /web/backend and ((/web/public and /web/member) or /web/frontend/) But since symfony is very flexible, this may not be the only way to go. – greg0ire Jan 16 '11 at 12:00
  • @greg0ire: i actually tried directory nesting like that on a recent project and i couldnt get it to work out properly. The problem is when you do that you cant use a global asset directories without symlinking them into those folders. Normally this is an acceptable solution but the site in question was running on CloudSites where symlinks arent supported. Instead i ended up using rewrite vodoo similar to what i posted above to simulate those url paths. – prodigitalson Jan 17 '11 at 22:49
  • @prodigitalson: you can also achieve global asset through another domain, it is like using a CDN and incresases performance. – greg0ire Jan 18 '11 at 08:43
  • @greg: veryt tru but that wasnt an option in my case...but the pproject im speaking was sort of clusterf*** on numerous deployment levels. CloudSites is not a happy place to host a symfony app... especially when its not your Rackspace account haha. – prodigitalson Jan 18 '11 at 09:39
  • @prodigitalson: Indeed, it is better to have full permissions on a server if you want a sf app on it... but sometimes you don't have the choice... too bad :( – greg0ire Jan 18 '11 at 09:46
1

I would use two symfony applications. One for the public & members and then a separate for the admin functions. Unless the app is very complex and hard to maintain, it's simple to setup the security so that only members can view restricted content.

Assuming you're on a virtual dedicated or similar, setting up the subdomains is all done in Apache. If not, and you're using a shared host, then I believe it will be very difficult to setup symfony to work with subdomains.

Patrick
  • 3,142
  • 4
  • 31
  • 46
  • What directories under the symfony root would the apache virtual hosts point to? Also, if all virtual hosts pointed to the single /web directory, could I add some logic to index.php to load the appropriate ProjectConfiguration based on the domain name? – James Jan 16 '11 at 01:10
  • you would point all the virtual hosts to the same folder (i.e.- `%symfony_root%/web`) but the `DirectoryIndex` would set the appropriate controller file. the 'main' app would be `index.php`, the admin app would be (for instance, app name is backend) `backend.php` – Patrick Jan 16 '11 at 01:17
  • Ah...thanks but unfortunately the hosting provider does not provide access to the httpd.conf to set up apache like that; i can only point a subdomain to a directory.. Could I simply parse the request for subdomain in index.php and then load the appropriate $configuration? Upvoted for one possible solution, thanks – James Jan 16 '11 at 01:25
  • I believe that would work, although it's not a very used option, so might have some strange bugs – Patrick Jan 16 '11 at 01:31