logo
Ask your Symfony questions! Pay money and get answers fast! (more info)

Warning: Please do not give out any FTP or ssh credentials to anyone, unless you trust them completely. Giving out login details is dangerous.

If the asker does not get an answer then they have 10 days to request a refund.

$4
Saving drops the relations that are not in the list

Hello!

First of all, sorry for my English. I'm a beginner in Sf, so...

I create a Customer Relationship Management System (as a beginner :D) and I have a problem with relations. There are companies and users in this system.

Some companies have a special flag, they are providers! It means, they can provide some services to 'plain' companies. Therefore I created a many-many relation between companies. In this case when i open the page of a company, I can see a company checkbox list, where I can check off which company is a provider for this company. I made a trick to remove non-provider companies from the list:

$choices = User::getProviders();
$this->widgetSchema['company_list'] = new sfWidgetFormChoice(array('choices' => $choices));


It works perfectly, only providers are shown in the list. BUT! User::getProviders() only returns with those providers where the user and the provider have a relation! It's a but difficult to understand so here is an example:

SUPERADMIN
When superadmin opens the page of XY company, User::getProviders() returns with ALL THE PROVIDERS:
PROV1
PROV2
PROV3
Superadmin check them off, so all three providers are checked.

USER
When a plain user opens the page of XY company, User::getProviders() returns with only one provider:
PROV1
It is checked, because superadmin checked it off. If now user click on save, PROV2, PROV3 relations will be deleted in the background.

How can I solve this? Every user should be able to modify only those relations that are shown in the list. If User::getProviders() doesn't return with PROV2, PROV3, the system shouldn't deal with them.

Thank you so much in advance!

This question has been answered.

saki | 07/28/10 at 5:10am Edit


(8) Responses

See a threaded view of answers?

Warning: Please do not give out any FTP or ssh credentials to anyone, unless you trust them completely. Giving out login details is dangerous.

  • avatar
    Last edited:
    07/28/10
    8:48am
    Ben says:

    I have no idea what you mean.

  • avatar
    Last edited:
    07/28/10
    11:42am
    Tomasz I says:

    So if for user B you give only some list of relations, SYmfony should work only on them. Please provide a schema and a Form code

  • avatar
    Last edited:
    07/28/10
    2:57pm
    Damian Martinelli says:

    Before save the form, you have to get all the previous company assigned that the logged user has not access, and add these companies manually to the checked ones.

  • avatar
    Last edited:
    07/29/10
    3:03am
    Loban Rahman says:

    Your attached image explained nicely what you are trying to do. Company has a many-to-many relation with it self. But instead of showing the entire list of companies to every user, some users get a limited list. However, you don't want the relations between unshown companies to be removed.

    The reason this is happening is because of how symfony forms automatically handle many-to-many relations. When you have a widget for many-to-many relations, processing the form follows the following steps:

    (1) Remove all relations
    (2) Add back in those relations that have been selected
    (3) Save

    That's why, if you show only companies 3, 4, and 5, then any relation with 2 will be removed, if it had existed.

    What you need to do is customize this code. Open your base form file and look for the doSave() function.


    protected function doSave($con = null)
    {
    $this->saveUsersList($con);
    parent::doSave($con);
    }

    public function saveUsersList($con = null)
    {
    if (!$this->isValid())
    {
    throw $this->getErrorSchema();
    }

    if (!isset($this->widgetSchema['users_list']))
    {
    // somebody has unset this widget
    return;
    }

    if (null === $con)
    {
    $con = $this->getConnection();
    }

    $existing = $this->object->Users->getPrimaryKeys();
    $values = $this->getValue('users_list');
    if (!is_array($values))
    {
    $values = array();
    }

    $unlink = array_diff($existing, $values);
    if (count($unlink))
    {
    $this->object->unlink('Users', array_values($unlink));
    }

    $link = array_diff($values, $existing);
    if (count($link))
    {
    $this->object->link('Users', array_values($link));
    }
    }


    You'll notice that the doSave method calls a separate saveXXXList() method for every many-to-many widget in that form. And the structure of this method is always around the same as what you see above. Check out the end code. It's getting an array_diff of the exising list and the new list, and unlinking and linking the appropriate relations.

    You need to override this function with one that does the exact same thing, but does NOT unlink relations that are not being shown.

    Previous versions of this answer: 07/28/10 at 4:26pm

  • avatar
    Last edited:
    07/28/10
    10:01am
    saki says:

    Okay, I try to explain shortly:

    There is a modell (company) with a many-many relation to itself. This relation is shown in the forms as a checkbox list. OK. There are two users, A and B. When A logged in, he must be able to see all companies in the checkbox list. However B has a lower permission, so B should be able to see only few companies in the list. So I want to hide/remove some options from the checkbox list when B looks the page. Unfortunately, symfony will delete the relations that are not shown in the list. I attached a picture, perhaps it helps you to understand my problem.

    Thank you so much!

    attachment image expert uploaded image

  • avatar
    Last edited:
    07/28/10
    10:05am
    Ben says:

    sounds like you need to have two sets of relationships, one for permissions and one for whatever you need to represent with your check boxes - if you post your schema.yml file, it might make it easier to understand what you are saying.

  • avatar
    Last edited:
    07/28/10
    10:50am
    saki says:

    Yes, but the relations are OK. These relations are not as simple as modell-modell!

    Company:
    ...
    relations:
    providers:
    class: Company
    local: id
    foreign: provider_id
    refClass: LinkCompanyProvider

    So this works. Now I want to remove items from the checkbox list, but not for all users. If I delete items, after saving the form the relations will be deleted by symfony. How can I save the form and keep the existing relations?

    Thx!

  • avatar
    Last edited:
    07/28/10
    4:34pm
    Loban Rahman says:

    Suppose u have $shownValues, which is an array of id's that are being shown. So the following:


    $unlink = array_diff($existing, $values);


    should be changed to


    $unlink = array_intersect($shownValues, array_diff($existing, $values));


    That way, the list of id's to unlink is restricted to those that are being shown.

This question has expired.





Current status of this question: Completed



Warning: Please do not give out any FTP or ssh credentials to anyone, unless you trust them completely. Giving out login details is dangerous.

If the asker does not get an answer then they have 10 days to request a refund.