質問

I have this relationship in my SS3 project:

  • Restaurant many_many Cuisine
  • Cuisine many_many SubCuisine

Seems simple enough but I can't seem to find any way to administer it. Tried GridField and Listbox. Is this a limitation of SilverStripe perhaps?

Thanks for any leads! Wilson

役に立ちましたか?

解決

After our conversation on IRC we came up with the following alternative solution, which I will post here for the record.

This solution is quiet similar to the original answer, with the difference, that there is an additional object that handles the relation between Restaurant and Cuisine.

File: Restaurant.php

/**
 * @method ManyManyList RestaurantCuisines
 */
class Restaurant extends Page {
    private static $many_many = array(
        'RestaurantCuisines' => 'RestaurantCuisine',
    );

    /**
     * @return FieldList
     */
    public function getCMSFields() {
        $return = parent::getCMSFields();
        $return->addFieldToTab('Root', Tab::create('Cuisines', 'The Cuisines'));
        $return->addFieldToTab(
            'Root.Cuisines',
            GridField::create(
                'RestaurantCuisines',
                'The Cuisines this Restaurant offers',
                $this->RestaurantCuisines(),
                GridFieldConfig_RecordEditor::create()
            )
        );
        return $return;
    }
}

class Restaurant_Controller extends Page_Controller {
}

File: RestaurantCuisine.php

/**
 * @property int CuisineID
 * @method Cuisine Cuisine
 * @method ManyManyList SubCuisines
 */
class RestaurantCuisine extends DataObject {
    private static $has_one = array(
        'Cuisine' => 'Cuisine',
    );
    private static $many_many = array(
        'SubCuisines' => 'SubCuisine',
    );
    private static $summary_fields = array(
        'getTitle' => 'Title'
    );
    public function getCMSFields() {
        if ($this->isInDB()) {
            $grid = GridField::create(
                'SubCuisines',
                'The Sub Cuisines of this Cuisines',
                $this->SubCuisines(),
                GridFieldConfig_RelationEditor::create()
            );
        } else {
            // because this record is not saved to the DB yet, we have no ID, without ID there can be no many_many relation
            $grid = ReadonlyField::create('SubCuisines', '', 'Sub Cuisines can be added after creating');
        }
        return FieldList::create(array(
            DropdownField::create('CuisineID', 'Select a Cuisine', Cuisine::get()->map()),
            $grid
        ));
    }
    /**
     * overwrite getTitle and return title of Cuisine to have a nice text to display instead of the ID when displaying the save message
     */
    public function getTitle() {
        return $this->Cuisine() && $this->Cuisine()->exists() ? $this->Cuisine()->Title : parent::getTitle();
    }
}

File: Cuisine.php

/**
 * @property string Title
 */
class Cuisine extends DataObject {
    private static $db = array(
        'Title' => 'Varchar(255)',
    );

    /**
     * @return FieldList
     */
    public function getCMSFields() {
        return FieldList::create(array(
            TextField::create('Title', 'Name of Cuisine'),
        ));
    }
}

File: SubCuisine.php

/**
 * @property string Title
 */
class SubCuisine extends DataObject {
    private static $db = array(
        'Title' => 'Varchar(255)',
    );

    /**
     * @return FieldList
     */
    public function getCMSFields() {
        return FieldList::create(array(
            TextField::create('Title', 'Name of Cuisine'),
        ));
    }
}

他のヒント

GridField is the perfect tool to manage this kind of data structure, I do it on a daily bases.

Because of your topic I feel the need to also mention this: it doesn't join here (ok, yes the ORM does joins, but not Restaurant & Cuisine & SubCuisine).
What the below example will do:

  • on a single Restaurant it will display a list (GridField) of Cuisines, where you can create new ones or attach existing ones.
  • on a single Cuisine it will display a list (GridField) of SubCuisines, where you can create new ones or attach existing ones.

(I am assuming that Restaurant is a Page, but it works just as well if its a normal DataObject)


File Restaurant.php:

/**
 * @method ManyManyList Cuisines
 */
class Restaurant extends Page {
    private static $many_many = array(
        'Cuisines' => 'Cuisine',
    );

    /**
     * @return FieldList
     */
    public function getCMSFields() {
        $return = parent::getCMSFields();
        $return->addFieldToTab('Root', Tab::create('Cuisines', 'The Cuisines'));
        $return->addFieldToTab(
            'Root.Cuisines',
            GridField::create(
                'Cuisines',
                'The Cuisines this Restaurant offers',
                $this->Cuisines(),
                GridFieldConfig_RelationEditor::create()
            )
        );
        return $return;
    }
}

class Restaurant_Controller extends Page_Controller {
}

File Cuisine.php:

/**
 * @property string Title
 * @method ManyManyList SubCuisines
 */
class Cuisine extends DataObject {
    private static $db = array(
        'Title' => 'Varchar(255)',
    );
    private static $many_many = array(
        'SubCuisines' => 'SubCuisine',
    );

    /**
     * @return FieldList
     */
    public function getCMSFields() {
        if ($this->isInDB()) {
            $grid = GridField::create(
                'SubCuisines',
                'The Sub Cuisines of this Cuisines',
                $this->SubCuisines(),
                GridFieldConfig_RelationEditor::create()
            );
        } else {
            // because this record is not saved to the DB yet, we have no ID, without ID there can be no many_many relation
            $grid = ReadonlyField::create('SubCuisines', '', 'Sub Cuisines can be added after creating');
        }
        return FieldList::create(array(
            TextField::create('Title', 'Name of Cuisine'),
            $grid,
        ));
    }
}

File SubCuisine.php:

/**
 * @property string Title
 */
class SubCuisine extends DataObject {
    private static $db = array(
        'Title' => 'Varchar(255)',
    );

    /**
     * @return FieldList
     */
    public function getCMSFields() {
        return FieldList::create(array(
            TextField::create('Title', 'Name of Cuisine'),
        ));
    }
}

File Restaurant.ss (template):

<h1>Restaurant: $Title</h1>
<% if $Cuisines %>
    <h2>Cuisines</h2>
    <ol>
        <% loop $Cuisines %>
            <li>
                <h3>$Title</h3>
                <% if $SubCuisines %>
                    <h4>Sub Cuisines:</h4>
                    <ul>
                        <% loop $SubCuisines %>
                            <li>
                                <h5>$Title</h5>
                            </li>
                        <% end_loop %>
                    </ul>
                <% end_if %>
            </li>
        <% end_loop %>
    </ol>
<% end_if %>
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top