1

A dispatch table (or dispatch method) is both a table (model) and a router/controller.

Imagine a tabbed navigation where there may be 30 tabs for various end users. Each tab is essentially a page that has its own controller and views. In my case, a dispatch table contains keys for the tabs and then data for each tab (path, displayName, visibility, etc).

my $tabs = {
  Home => {
    action => \&HomeController::dashboard,
    displayName => ‘Home’,
    ...
  },
  About => {
    action => \&AboutController::info,
    displayName => ‘About Us’,
    ...
  },
  ...
};

Initially I had a TabController and TabView. Inside the controller was a dispatch table; however it didn’t seem to fall in accordance with MVC. It seemed fine when there was only 3 tabs, but different when it grew, especially as it required security trimming or filtering the views.

It made sense to move it to the model since it was being treated more as a data table. However, because it’s Perl (and a dispatch table) all the corresponding packages must also be loaded. So this TabModel is loading many controllers (and in some cases views). I don’t particularly like to load/reference any controllers in the model, so loading multi feels even worse.

Is there a best practice or example for this scenario?


Addendum

In an attempt to provide something a little more tangible. I'm going to attempt to frame this around a makeshift web application. This is only a conceptual example, not fully-working and missing a lot; but hopefully should add a little more description and context. It has the following, directory structure:

index.pl -- entrance
Controllers/
  -- Dashboard.pm
  -- Home.pm
  -- About.pm
Models/
  -- Tabs.pm
  -- Users.pm
Views/
  -- Dashboard.pm
  -- Home.pm
  -- About.pm
  -- Error.pm

I won't break out index.pl, but it essentially parses parameters and directs to the DashboardController::dashboard.

DashboardController

package Controllers::Dashboard;

sub dashboard{
   my $users = Models::Users::get_all();           # Users Model
   my $tabs = Models::Tabs::get_permitted(         # Tabs Model
     $users->{CURRENT_USER}{permissions}
   );
   print Views::Page::render($users,$tabs);        # Page View
}

AboutController

package Controllers::About;

sub info {
  # No models necessary
  print Views::About::render();
}

TabsModel

package Models::Tabs;

use Controllers::Home;
use Controllers::About;

sub get_all {
  my $tabs =  {
    Home => {
      action => \&Controllers::Dashboard::dashboard,
      displayName => ‘Home’,
      ...
    },
    About => {
      action => \&Controllers::About::info,
      displayName => ‘About Us’,
      ...
    },
    ...
  };

  return $tabs;
}

sub get_permitted {
  my $user_permissions = shift;
  my $tabs = get_all();
  if (defined $user_permissions){
    foreach my $tab (keys %$tabs){
      delete $tabs->{$tab} unless $user_permissions->{"can_access_$tab"};
    }
  } 
}

DashboardView

package Views::Dashboard;

sub render {
  my ($users,$tabs) = @_;


  my $html_tabs = '<ul>';
  foreach my $tab (values %$tabs){
    $html_tabs .= "$tab->{displayName}";
  }
  $html_tabs .= '</ul>;

  my $html = <<"END";

  $html_tabs 
  <!-- dashboard content -->

END

  return $html;
}
TylerH
  • 20,799
  • 66
  • 75
  • 101
vol7ron
  • 40,809
  • 21
  • 119
  • 172
  • 2
    Can you extract a minimal running example with a handful of tabs? I have a hard time grokking the vague description. – daxim Oct 08 '19 at 13:08
  • 1
    @daxim As mentioned in my previous comment, I understand this may be difficult to conceptualize for some, though it is a conceptual question. It would be too big an effort to include a full minimal running example, but hopefully the addendum helps to illustrate the scenario more clearly. Does this update help? – vol7ron Oct 08 '19 at 13:57
  • I think it hinders my question because it distracts from the original question, which is about a dispatch table that might reference multiple controllers and needing to require those perl packages because the dispatch table stores references to the subroutines. – vol7ron Oct 08 '19 at 14:22

1 Answers1

0

ancient question, but it popped up in the feed today

I think there's something wonky in the way you've categorized things. Models are typically sources of data and don't really care what you do with them or how you display them. However, you've pushed some of the view (presentation) into the model. To me, that Tabs.pm looks like it should be part of some view.

And, because a dispatch table is a table doesn't mean it's a source of data. It's a particular technique to solve a problem that's not related to the particular data or the particular view. If you did the same task without the dispatch table, you wouldn't suddenly move that responsibility into another part of MVC.

brian d foy
  • 129,424
  • 31
  • 207
  • 592
  • Thank you, Brian. I also didn't see this answer until I searched over a year later :) ***"Models are typically sources of data and don't really care what you do with them or how you display them."*** I think that's conceptually true. My experience has revealed that Models contain the business rules, perform filtering and security for security trimming. They also present data from the source in some default way; for example, text casing, or a person's name might be "Last, First" instead of "First Last" -- some measure of presentation. – vol7ron Aug 01 '22 at 18:11
  • I think this project shifted to Rails, but I'm still curious about the Perl implementation using a dispatch table. The idea is to have 100 tabs stored in a db table (UI-managed) w/ corresponding access controls to roles/privileges. How those "tabs" are presented (a vertical menu, navigation bar, mobile view, etc) would be managed by the Controller/View, but the model would retrieve which tabs to display based on the user's role. This one would be a controller of controllers. – vol7ron Aug 01 '22 at 18:20
  • ***"If you did the same task without the dispatch table, you wouldn't suddenly move that responsibility into another part of MVC."*** Agreed. I think I moved it into the model because it was acting as a meta table. It's been a while, but I think I was trying to recreate Rails/Rack in perl. – vol7ron Aug 01 '22 at 18:23