views:

98

answers:

6

Hello guys

I am developing an application using zend framework. In the application I have to provide a URL for each user like mydomain.com/[username] then public will be able to view his profile. [username] is the username of the particular user

But how can I achieve this ? I think in ZF mydomain.com/username tries to get the controller with name username, but I should show user profiles in this URL and it must goes to the right controller if something else comein like mydomain.com/controller1

Please help

Thanks a lot

A: 

Try using Apache .htaccess mod_rewrite.

4) Rewriting yoursite.com/user.php?username=xyz to yoursite.com/xyz

Have you checked zorpia.com.If you type hxxp://zorpia.com/roshanbh233 in browser you can see my profile over there. If you want to do the same kind of redirection i.e

hxxp://yoursite.com/xyz to hxxp://yoursite.com/user.php?username=xyz then you can add the following code to the .htaccess file.

RewriteEngine On
RewriteRule ^([a-zA-Z0-9_-]+)$ user.php?username=$1
RewriteRule ^([a-zA-Z0-9_-]+)/$ user.php?username=$1

source: http://roshanbh.com.np/2008/03/url-rewriting-examples-htaccess.html

Quang
Is this ZF compatible?
fabrik
I am using ZF :(
john
not sure if it's ZF compatible but, if your server's running Apache... you should be able to add an .htaccess file to the root, and then let Apache do the magic...
Quang
+1  A: 

You will need something similar to the following in your bootstrap

public function _initRouter()
{
     $router = Zend_Controller_Front::getinstance()->getRouter();
     $users = array() // get the usernames from DB or wherever you have them

      // Adds some routes
     foreach($users as $user)
     {
        $router->addRoute($user['name'], new Zend_Controller_Router_Route($user['name'].'/:controller/:action/*', array(
          'module' => 'users', // module name
          'controller' => 'index', // controller name
          'action' => 'profile', // action name
          'username' => $user['name']))); // user name
      }
      return $router;
    }
}
Chellini
A: 

Chellini's answer might work, but if you have 1000 users you are going to add 1000 rules to the router. That and the database access might add to your application's response time.

An alternative is to add a generic route which by default maps to the user action (this is defined first as routes are matched in reverse order). Then add the routes to the controllers you actually have - you are likely to have far fewer controllers than users.

If your application is modular, that reduces the number of rules you have to write even further as you just need to add one rule for a module.

kudzai
+1  A: 

I've seen this asked on the mailing lists as well, so I've put up a blog post with a detailed example of how to achieve this in ZF using a custom route class, see:

http://tfountain.co.uk/blog/2010/9/9/vanity-urls-zend-framework

This might not be the simplest approach, but in my opinion it is the best, as it allows you to setup a username route like any other, and you can still use the standard ZF URL helpers and other routing toys.

The only other option is to extend the standard ZF router and then check for a username route before doing anything else. Something like:

class My_Router extends Zend_Controller_Router_Rewrite
{
    public function route(Zend_Controller_Request_Abstract $request)
    {
        $pathBits = explode('/', $request->getPathInfo());
        if (!empty($pathBits[0])) {
            // check whether $pathBits[0] is a username here
            // with a database lookup, if yes, set params and return
        }

        // fallback on the standard ZF router
        return parent::route($request);
    }
}

You then need to tell the front controller to use your router instead of the default one, so in your bootstrap:

protected function _initRoutes()
{
    Zend_Controller_Front::getInstance()->setRouter(new My_Router());
}

replace 'My' with your application's own namespace.

If you follow this approach you can't use the URL helper for your username routes, and things can become a bit messy if you start needing to add other custom functionality, so go with the custom route class instead.

Tim Fountain
You don't have to extend the router - you can simply create a custom route instead. Posted an answer explaining how.
Adrian Schneider
A custom route is exactly what I suggested. Please see the blog post that I linked. The code sample showing extending the router was just an alternative option, custom route is better (which is why wrote a whole blog post about it).
Tim Fountain
+1  A: 

Seems to me that the difficulty here is that you are using the same url scheme:

http:/example.com/something

to represent two types of actions:

  1. If "something" represents a user name, consider this a request to controller=user, action=viewProfile, param=something.
  2. Otherwise, consider this to be a standard request to the controller SomethingController

This seems a bit odd to me. I'd prefer to put the user requests under a different url scheme, like:

http://example.com/user/bob

where standard routing rules can apply. Want to avoid the risk that a user registers with a name that conflicts with one of your static controllers. Of course, you could maintain a pool of "reserved" user names for your static controllers that would be unavailable for users to choose.

But if is really is the requirement that the same url format must be used for both types of requests, then I would do the following: route all requests to something like TrafficCopController with an action directTrafficAction(). The action could test - probably via db query - if the passed "something" parameter represents a real user. If so, then forward the request to controller=user, action=viewProfile. Otherwise, forward the request to controller=something, action=index.

See what I mean?

David Weinraub
+1  A: 

Create a custom Route (not Router; there is no need to create a custom router!).

Your new route should extend Zend_Controller_Router_Route_Abstract, and override the match method, which takes Zend_Controller_Request_Abstract $request as the first parameter.

In your new match method, simply query your database to see if the custom page, user, etc. exists by comparing against $request->getRequestUri(), and if it does, return the relevant routing information. Example:

return array(
    'module'     => 'default',
    'controller' => 'users',
    'action'     => 'view',
    'user'       => $user
);

On failure (can't find the correct user, or page, etc.), then:

return false

This will scale much better than creating a route for every single user, and doesn't require you to mess around with routing too much. It will still work with the standard router, and you can add it to your routes via application.ini as expected.

Adrian Schneider