[Dbix-class] many_to_many data access

Patrick Meidl patrick at pantheon.at
Thu Jul 12 07:48:44 GMT 2012


On Wed, Jul 11 2012, Robyn Jonahs <learn.catalyst at gmail.com> wrote:

> I was trying to get some many_to_many data into a FormFU select
> element but I am having trouble. I think that it is time to ask the
> pros for help.
> 
> I was staying similar to the online tutorial. In my add and edit sub
> routines, I have the following code (similar to the online tutorial)
> 
>         # Stores
>         my @store_objs = $c->model("DB::Store")->all();
>         my @stores;
>         foreach (sort {$a->store cmp $b->store} @store_objs) {
>         #  push(@stores, [$_->id, $_->store]);
>           push(@stores, [$_->id, $_->full_address, $_->store]);
>         }
>         my $select3 = $form->get_element({name => 'stores'});
>         $select3->options(\@stores);
> 
> So I want to get a list of all the values in a table called stores and
> stick them into a select element in FormFU. I can do this fine. What I
> wanted to do was to give it the full address of the store bringing in
> the state, city and country from many_to_many relationships with these
> tables.  I was able to do this in another test application but the
> relationships were has_many not many_to_many. I am stumped on how to
> do this.
> 
> The store model is simple
> 
> __PACKAGE__->add_columns(
>   "id",
>   { data_type => "integer", is_auto_increment => 1, is_nullable => 0 },
>   "store",
>   { data_type => "varchar", is_nullable => 0, size => 255 },
>   "notes",
>   { data_type => "varchar", is_nullable => 1, size => 255 },
> );
> 
> and it contains
> 
> __PACKAGE__->has_many(
>   "store_cities",
>   "ProductTracker::Schema::Result::StoreCity",
>   { "foreign.store_id" => "self.id" },
>   { cascade_copy => 0, cascade_delete => 0 },
> );
>  ...
> 
> __PACKAGE__->many_to_many("cities", "store_cities", "city");
> 
> And I tried to do this...
> #
> # Row-level helper methods
> #
> =head2 full_address experimental
> 
>   Get the city, state and country that correspond to a specific Store ID
> 
> =cut
> sub full_address {
>     my ($self) = @_;
> 
>     my $cities = $self->store_cities;
>     return $self->store . ' ' . $cities->city->city;
> 
> #    return $self->store . ' ' . $self->city->city . ', ' .
> $self->states->abb . ' ' . $self->countries->abb;
> }

there are several errors in this method.

first, to get the cities associated to the store, use the many_to_many
relationship you defined; if you have such a relationship, you usually
never use the bridging table (store_cities in your example) directly.

second, since you are dealing with a many_to_many, there might be
multiple cities associated to a store, you have have to deal with this.
so your code should look something like this:

--8<---------------------------------------------------------------

sub full_address {
  my ($self) = @_;

  my $result = $self->store;

  my @cities = $self->cities;
  foreach my $city (@cities) {
    $result .= sprintf(' | %s, %s %s', $city->city,
      $self->states->abb, $self->countries->abb);
  }
  
  return $result;
}

--8<---------------------------------------------------------------

not sure about the calls to states and countries, you didn't include
the code what these methods return; look like many_to_many to me too, or
rather belongs_to relations on City? so I'm speculating that your code
will look like

    $result .= sprintf(' | %s, %s %s', $city->city,
      $city->state->abb, $city->country->abb);
  
HTH

    patrick

-- 
Patrick Meidl ........................ patrick at pantheon.at
Vienna, Austria ...................... http://gplus.to/pmeidl




More information about the DBIx-Class mailing list