Pages are DataObjects, but you are free to create and manage DataObject independently of this... http://www.silverstripe.org/making-a-crm-with-modeladmin-in-silverstripe-230/
I submitted a tutorial based on this cast and linking ot all resources... on this months ago, but the guys are buys with SS3 I assume... Instead I'll copy it here...
Tutorial 6 - Dataobject Relationship Management
Overview
Until now we have about creating Pages that contain data - editted with the Sitetree and all the relationsships within the Data-Model now with ModelAdmin we will create a powserful inferface to manage non-page easily and quickly.
What are we working towards?
To simulate these relations between objects, we are going to simulate the management via the CMS of the Google Summer Of Code 2007 that SilverStripe was part of.
To do this, we are gonna use the following objects :
Customer : A customer
HostingContract : The hosting contract a Customer has
HostingType : Type of hosting service.
MyCRMAdmin : The Admin section to manage this data.
<?php
class Customer extends Member {
static $db = array(
'CustomerType' => "Enum('Private,Business','Private')"
);
static $has_one = array(
'Avatar' => 'Image',
);
static $has_many = array(
'HostingContracts' => 'HostingContract'
);
static $summary_fields = array(
'FirstName',
'Surname',
'CustomerType'
);
static $searchable_fields = array(
'FirstName',
'Surname',
'HostingContracts.ContractNumber'
);
function getCMSFields() {
$fields = parent::getCMSFields();
$fields->removeByName('Locale');
return $fields;
}
}
<?php
class HostingContract extends DataObject {
static $db = array(
'ContractNumber' => 'Varchar',
'StartDate' => 'Date',
'EndDate' => 'Date'
);
static $has_one = array(
'Customer' => 'Customer',
'HostingType' => 'HostingType',
);
static $summary_fields = array(
'ContractNumber',
'Customer.Name',
'HostingType.Title',
'EndDate',
);
}
<?php
class HostingType extends DataObject {
static $db = array(
'Title' => 'Text',
'Description' => 'Text',
'Price' => 'Float',
);
static $has_many = array(
'HostingContracts' => 'HostingContract',
);
}
<?php
class MyCRMAdmin extends ModelAdmin {
protected static $managed_models = array(
'Customer',
'HostingContract',
'HostingType'
);
static $url_segment = 'mycrm'; // will be linked as /admin/mycrm
static $menu_title = 'My CRM';
}
Don't forget to rebuild the database using *dev/build?flush=1* before you proceed to the next part of this tutorial.
Now that we have created our DataObjects and ModelAdmin let’s see what you get right out of the box...
Go into the CMS, select 'My CRM' and you will see the left area has a tab for each managed_model and the right area is empty.
Create one (or more) of each item and see what silverstripe does straigh out or the box for you.
Note this is unlike the sitetree or widgets where we have to specfiy everything that is to be added, in ModelAdmin we get scaffolded summary fields (what data is shown for each record in the search results), search fields (used to search all records to generate summary results) and the edit forms when you create or edit a dataobject.
cms fileds think "change, not add" (most of the time)
// for customer
function getCMSFields() {
$fields = parent::getCMSFields();
$fields->removeByName('Locale');
$fields->replace - dates
$fields->insert - literal
return $fields;
}
Also each model as an import form that can be used to upload csv data directly into the model
static $model_importers = array();
$summary_fields
//for hosting contract
static $summary_fields = array(
'ContractNumber',
'EndDate'
);
casting gets all nice stuff into the summary...
static $casting = array("PriceText" => "Text");
public function PriceText(){return '£'.number_format($this->Price, 2);}
this auto populates the searchable_fields, but you can specifiy them yourself anyway...
public static $searchable_fields = array(
"Name" => array(
"PartialMatchFilter"
)
);
By default only an Admin can edit ModelAdmin data - so you need to specfiy which members can create/view/edite/delete data.
public function canCreate($member = null) {return false;}
public function canView($member = null) {return false;}
public function canEdit($member = null) {return false;}
public function canDelete($member = null) {return false;}
In the case of any mem ber having permission to edit, just create this...
public function canEdit() {return true;}
This affects how our dataobject appears in has_one DropdownFields and as search results
public static $default_sort = "Title ASC";
link to...
cheat sheet
http://doc.silverstripe.org/old/recipes:cheat_sheet#modeladmin
api
http://api.silverstripe.org/2.4/cms/core/ModelAdmin.html
ingo presentation
http://silverstripe.org/making-a-crm-with-modeladmin-in-silverstripe-230/
docs
http://doc.silverstripe.org/sapphire/en/reference/modeladmin
cheese modeladmin stuff
customadmin
panelmodeladmin
http://www.slideshare.net/marvanni/panelmodeladmin-example
http://www.silverstripe.org/all-other-modules/show/14314
ssbits
http://www.ssbits.com/tutorials/2010/dataobjects-as-pages-part-1-keeping-it-simple/
http://www.ssbits.com/tutorials/2010/dataobjects-as-pages-part-2-using-model-admin-and-url-segments-to-create-a-product-catalogue/
http://www.ssbits.com/tutorials/2011/add-a-duplicate-button-to-model-admin/