Skip to main content

This site requires you to update your browser. Your browsing experience maybe affected by not having the most up to date version.

Data Model Questions

Looping many to many in the controller


5 Posts   509 Views


16 January 2013 at 9:48pm Community Member, 9 Posts

Hi guys,

I'm sure this is a very simple task but I'm just not sure on the syntax.

Basically I have a Job dataobject that has the usual fields like Title, Description, etc, but it also has a many to many relationship with Locations as each job can have multiple locations assigned.

So Job is (some code stripped out for clarity):

class Job extends DataObject {
   static $db = array(
      'JobID' => "Int",
      'Title' => "Varchar(255)",
      'ShortDescription' => "Text",
      'Description' => 'HTMLText'

   public static $many_many = array(
      'Categories' => 'Category',
      'SubCategories' => 'SubCategory',
      'Locations' => 'Location',
      'JobTypes' => 'JobType'
public function getLongTitle() {
$data = $this->Title . '  |  ';

return $data;

And location is (again missing code for clarity):

class Location extends DataObject {
   static $db = array(
      'Title' => "Varchar(255)"
   public static $many_many = array(
      'Jobs' => 'Job'

In my template I have a small block that shows the latest 5 jobs using this bit of code in the pages class.

   function LatestVacancies() {
      return DataObject::get('Job','','ID DESC','','5');   

Which is fine when I was only showing the title.

What I need to do now however is show the locations after the job title. I know I could use another control block in the template to loop through the locations, but I only have a limited width of space so I want to use the ".LimitCharacters(35)".

So what I want to do is return a long title from the php to the template which will be a single string in the format <job title> | <location1>, <location2>, etc...

This way I will be able to use the LimitCharacters on that entire string as some job title's are really short the 35 character cut off will be part way through one of the locations, and some are long so it cuts off part way through the job title.

So I might end up with:
Assessor | Perth, Sydney
Senior Quality Controller | Sydn ...
Group Facilities and Capital Works ...

I started to make a getLongTitle() function in the Job DataObject which works fine (as I use other bits from the Job DataObject in the template) but I just don't know how to access the Locations array from the job and build that string.

Like I said, this should be easy, I'm just not used to PHP or Silver Stripe.

Hopefully someone can fix that one function up for me!



21 January 2013 at 8:14pm Community Member, 9 Posts


I would have thought this was about 2 lines of code... I just don't have any of my developers available to help me as I have them all on different projects so I'm trying to do this bit myself.

Please help! :)


23 January 2013 at 2:37am Community Member, 3 Posts

firstly you must used in Job Class or in Location Class for a many_many relationship the array

$belongs_many_many = array();

And then you can use in your template

<% control LatestVacancies %>
<% if Locations %>
<% control Locations %>
<% end_control %>
<% end_if %>
<% end_control %>

This is only theory and i have not try this ;)



24 January 2013 at 8:38pm (Last edited: 24 January 2013 10:12pm), Forum Moderator, 5511 Posts

As mentioned in the original post, should be in PHP

public function getLongTitle() {
$title = $this->Title . implode(", ", $this->Locations()->column('Title'));

return substr($title, 0, 50);

The implode trick should work, if not you can do the longer - foreach($this->Locations() as $location) .... and append the locations there.

The other thing I would do is add LongTitle to your $casting array to ensure the field is escaped in templates (


24 January 2013 at 8:46pm Community Member, 9 Posts

Thanks Willr.

That was more what I was after. I was sure I could do it with a foreach loop I just wasn't sure on the syntax.

I'll give the implode trick a bash first.