views:

42

answers:

2

Hi all.

I know it might seam slightly strange to user the admin generator.yml in the frontend but every page is either a list or an edit page and it's definitely the easiest things to do.

After struggling with writing a log in module i have installed sfDoctrineGuardPlugin and used the relations to link them to my main user table. Everything in the database relies on this one table, and the data has been building up on the current live site for little over 8 months now and i need to keep it.

My current problem is that once someone logs in and it stores there ID in the guard system, i need all the pages to filter all results by it, including lists, and edits.

Is there a simple method of doing this or do i need to use the table_method for every list?

The only problem with the above is that the ID appears in the address and i need it to make sure people can not view data that that shouldn't.

Also, and this is likely to change soon, at the moment the tables are MyISAM for the use of better auto increment, can have it increment by user so each person starts at one. However it appears to not do foreign keys so when i write the code to convert it to INNOBDB the ID in the address becomes inven more important for people not to be able to change.

Owner:
  columns:
    id: { type: integer(4), primary: true, autoincrement: true }
    slname: { type: string(64), notnull: true }
    uuid: { type: string(36), notnull: true }
    e_mail: { type: string(64) }
    user: { type: string(16) }
    pass: { type: string(40), notnull: true }
    subscription: { type: integer(4), default: '0', notnull: true }
    registered: { type: integer(1), default: '0', notnull: true }
  relations:
    Subscription:  { local: subscription, foreign: id }
    User: { class: sfGuardUser, foreign: id, local: id, type: one, onDelete: cascade, foreignType: one, foreignAlias: Owner }

Once the plug in works properly i am planning on removing the password from the above table and using the default one and forcing everyone to make new passes.

EDIT:

Thank Ben i have the template working i think. It's adding in the column anyway to the database.

 class Doctrine_Template_Owned extends Doctrine_Template
{
    protected $_options = array(
        'name'          =>  'owner_id',
        'type'          =>  'integer',
        'length'        =>  11,
        'options'       =>  array(
            'default' => 0,
            'notnull' => true
        )
    );

    public function setTableDefinition()
    {
        $this->hasColumn($this->_options['name'], $this->_options['type'], $this->_options['length'], $this->_options['options']);
        $this->addListener(new Doctrine_Template_Listener_Owned($this->_options));
    }
}

However the listener doesn't seam to be getting called.

class Doctrine_Template_Listener_Owned extends Doctrine_Record_Listener
    {
        protected $_options = array();

        public function __construct(array $options)
        {
            $this->_options = $options;
        }

        public function preDqlSelect(Doctrine_Event $event)
        {
            $params = $event->getParams();
            $field = $params['alias'] . '.' . $this->_options['name'];
            $query = $event->getQuery();

            if (( ! $query->isSubquery() || ($query->isSubquery() && $query->contains(' ' . $params['alias'] . ' '))) && ! $query->contains($field)) {
                $query->addPendingJoinCondition(
                    $params['alias'], $field . ' = ' . sfContext::getInstance()->getUser()->getGuardUser()->getId()
                    );
            }
        }
    }

The code for the listener is that of soft delete with the timetable and boolean check removed. The line doesn't seam to appear in the dev bar though.

A: 

Just change the functions in the actions.class.php file. For example, the listSuccess function could be changed to filter the results where ID = USERID

Jon
Would that still take the default filters into account?
Kye
It should. Let me know if it doesnt ;)
Jon
Only problem is, There is currently no listSuccess as it's using the yaml file. How would i write one that gets the query it is about to perform to add the addWhere('user_id = ?',$userID);
Kye
this way will be a lot of work, as unless you want to leave it that you can edit the id in the url, it needs applying to edit/delete etc as well as just list.
benlumley
A: 

If you need to do this application wide, I would use a doctrine behaviour, rather than doing it at action level.

Take a look at how the SoftDelete behaviour works (its two files, a template and a listener, in lib/vendor/symfony/lib/plugins/sfDoctrinePlugin/lib/vendor/Doctrine/Template, and the Listener subfolder within that) - you should be able to adapt it to always add a user_id = x clause instead of what it does at present, and then add it to your schema.yml for relevant classes.

Then you need to get the user_id to doctrine. You can add a method called "configureDoctrine" to config/ProjectConfiguration.class.php, which will get called if it exists by doctrine. Not sure where is best within doctrine to pass it to, but you should pass the user id for the current user to doctrine within this method - sfContext::getInstance()->getUser()->getGuardUser()->getId() to get it. The behaviour should then pull the value from here. If nothing else, a static property on the listener or template classes should work.

You could make the behaviour pick the user id up directly by calling sfContext::getInstance from the template, but not advised as it creates extra links between doctrine/symfony, which is against the whole dependency injection/no global state ethos of symfony, and stuff will break sooner or later.

If this won't work for any reason, I'd look instead at over-riding the relevant files from the generator template (at lib/vendor/symfony/plugins/sfDoctrinePlugin/data/generator/sfDoctrineModule/admin/). You can do this by adding any of the files under the projects top level data folder. Or I think admin generated modules also throw events that you might be able to listen to...

In response to comment about it not working, if you've not used any other behaviours that rely on callbacks, make sure your databases.yml has the use_dql_callbacks: true attribute:

all:
  doctrine:
    class: sfDoctrineDatabase
    param:
      dsn:      mysql:host=localhost;dbname=mydb
      username: myuser
      password: mypassword
      attributes:
        use_dql_callbacks: true
benlumley
Thanks Ben. I've added the code I've written to the post. While the template seams to be working and correctly adding the column to the database the listener doesn't.
Kye
see edit re dql_callbacks.
benlumley
Thank you very much Ben. I wouldn't know anything about symfony without your help.
Kye