1

Although the code in question is PHP, I need a second look, a general algorithm, pseudocode or something similar as a solution.

I have a collection of objects ($events) with properties:

  • event_name
  • date_from
  • date_to

I have a table with weekdays:

         Mon   Tue   Wed   Thu   Fri   Sat   Sun  
Starts    *     *     *     *     *     *     *
Ends      *     *     *     *     *     *     *

Same table in HTML:

<table>
      <thead>
        <tr>
          <th></th>
          <th>Mon</th>
          <th>Tue</th>
          <th>Wed</th>
          <th>Thu</th>
          <th>Fri</th>
          <th>Sat</th>
          <th>Sun</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td><strong>Starts</strong></td>
          <td>*</td>
          <td>*</td>
          <td>*</td>
          <td>*</td>
          <td>*</td>
          <td>*</td>
          <td>*</td>
        </tr>
        <tr>
          <td><strong>Ends</strong></td>
          <td>*</td>
          <td>*</td>
          <td>*</td>
          <td>*</td>
          <td>*</td>
          <td>*</td>
          <td>*</td>
        </tr>
      </tbody>
    </table>

Asterisk is just a placeholder and it isn't relevant.

I would like to display event_name under e.g. Wednesday if the event starts or ends on Wednesday. Of course, if it starts on Wednesday (date_from is a Wednesday), I would like it in the Starts row under Wed, and if it ends on Wednesday (date_to is a Wednesday), I would like it in the Ends row under Wed.

I have a working solution, but it's so bad that I have second thoughts of even writing it here :)

The solution was to take that HTML and put in each <td>*</td> instead of asterisk these lines of PHP (example for Monday's <td>):

<td>
  foreach($events as $event) {
    if($event->date_to == $week_start) { //Monday is start of the week
      echo $event->name;
    }
  }
</td>

For Tuesday's <td>, it would be something like:

<td>
  foreach($events as $event) {
    if($event->date_to == $week_start + 1) {  //Tuesday is start of the week + 1 day
      echo $event->name;
    }
  }
</td>

...and so on, but 14 of these foreach's and if's for each day times two rows is probably as stupid as it gets :). Of course, for Ends row I compare date_to property to the day in question.

Does anyone have a conceptual answer? How to aproach this problem in a better way?

P.S. I'm working in Laravel, PHP MVC framework, so I'm building a collection in a controller and passing it on to the view. Dates are Carbon instances, which is a PHP API extension for DateTime so various handy methods for determining days are available (addDay(), startOfWeek(), etc.). The HTML in question can be changed, as can be the structure of $events collection, if necessary.

Thank you in advance for your ideas.

EDIT: Bonus points for putting comma after each event_name except last, in a table cell (<td>).

TommyZG
  • 500
  • 3
  • 13
  • Why are you not using blade template engine? – Enrico Feb 27 '16 at 14:52
  • Address each "*" with a div/id and set the values all at once from an OnLoad fn or some AJAX. (No - it's not quite what you are asking for but it might get you started) – ethrbunny Feb 27 '16 at 16:06
  • @Enrico - I am, but I removed it here to keep it as conceptual as possible. @ foreach and @ if are used. Do you have any other idea that would use some Blade's option that I might not know about? – TommyZG Feb 27 '16 at 16:51
  • @ethrbunny - Thank you for your comment, I will think about it. The table is already loading via AJAX, but in it's entirety. – TommyZG Feb 27 '16 at 16:53
  • Well I'm not exactly blade's expert, as i work with twig and erb, but I'm sure you can approach things differently, which can also be done with pure php. What I'd do is Dinamically create the table with a loop and inside the td use the conditions you need. This will compile to your same solution, but the source will be and easier to mantain. Sorry if This is not very clear -i'm using a phone-, I will try and post a solution as soon as i'm back to my computer. – Enrico Feb 27 '16 at 18:29
  • I guess what I meant was get all the values via AJAX and then loop through and set the appropriate values for each DIV (day of the week + start/stop). You just need to label each DOTW with the appropriate ID tag. – ethrbunny Feb 28 '16 at 01:25

1 Answers1

0

1) php template language only solution

twig:

{% set days = ["monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"] %}

{% set event_1 = {"name":"event_1","date_from" : "monday", "date_to" : "monday"} %}
{% set event_2 = {"name":"event_2","date_from" : "friday", "date_to" : "thursday"} %}
{% set event_3 = {"name":"event_3","date_from" : "wednesday", "date_to" : "tuesday"} %}
{% set event_4 = {"name":"event_4","date_from" : "saturday", "date_to" : "monday"} %}
{% set event_5 = {"name":"event_5","date_from" : "sunday", "date_to" : "thursday"} %}

{% set event_list = [event_1, event_2, event_3, event_4, event_5] %}


<div class="container">
    <table class="table table-striped">
        <thead>
        <tr>
            {% for day in days %}
                <th>{{ day }}</th>
            {% endfor %}
        </tr>
        </thead>
        <tbody>
            <tr>
                {% for day in days %}
                    <td>
                        {% for ev in event_list %}
                            {% if ev.date_from == day %}
                                {{ ev.name }}
                            {% endif %}
                        {% endfor %}
                    </td>
                {% endfor %}
            </tr>
            <tr>
                {% for day in days %}
                    <td>
                        {% for ev in event_list %}
                            {% if ev.date_to == day %}
                                {{ ev.name }}
                            {% endif %}
                        {% endfor %}
                    </td>
                {% endfor %}
            </tr>
        </tbody>
    </table>
</div>

2) php template language + jQuery solution

twig

{% set days = ["monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"] %}


<div class="container">
    <table class="table table-striped">
        <thead>
        <tr>
            {% for day in days %}
                <th>{{ day }}</th>
            {% endfor %}
        </tr>
        </thead>
        <tbody>
            <tr id="event_start">
                {% for day in days %}
                    <td name="{{ day }}">
                    </td>
                {% endfor %}
            </tr>
            <tr id="event_end">
                {% for day in days %}
                    <td name="{{ day }}">
                    </td>
                {% endfor %}
            </tr>
        </tbody>
    </table>
</div>

jquery:

<script>
    $(document).ready(function(){

        var event_list = {
            event_1 : {event_name : "event_1", date_from : "monday", date_end : "sunday"},
            event_2 : {event_name : "event_2", date_from : "wednesday", date_end : "tuesday"},
            event_3 : {event_name : "event_3", date_from : "thursday", date_end : "friday"},
            event_4 : {event_name : "event_4", date_from : "saturday", date_end : "saturday"},
            event_5 : {event_name : "event_5", date_from : "friday", date_end : "tuesday"},
            event_6 : {event_name : "event_6", date_from : "monday", date_end : "thursday"}
        };

        var first_row = $("#event_start");
        var second_row = $("#event_end");

        function loop (row, date) {
            row.find("td").each(function(){
                var t = $(this);
                var name = $(this).attr("name");
                $.each( event_list, function( key, value ) {
                    if (value[date] == name) {
                        t.text(value.event_name);
                    }
                });
            });
        }

        loop(first_row, "date_from");
        loop(second_row, "date_end");

    });
</script>
Enrico
  • 408
  • 6
  • 13
  • 1
    Thank you. Yes, Blade has almost completely the same syntax. It is the same solution, it still boils down to 14 `foreach`'s and `if`'s except, as you said, this is easier to maintain. I will wait some more if anyone has a different conceptual approach to avoid having this many loops and conditions. If not, I will mark your answer as most helpful. Thanks. – TommyZG Feb 27 '16 at 20:02
  • Another solution would be to populate the table via ajax. Using DOM methods that can be done with less code – Enrico Feb 28 '16 at 08:01
  • Could that be a viable solution for you? – Enrico Feb 28 '16 at 08:38
  • 1
    In that case, foreach and if would be in the jQuery? Meaning, table would be statically rendered as is, maybe marked with data-attributes for "addressing" cells, and after DOM load jQuery would foreach $events, test which day they belong to and then populate the cells? – TommyZG Feb 28 '16 at 09:16
  • Exactly. that would be no more than a few .each method. Not really sure how many, but surely not more than 2-3 – Enrico Feb 28 '16 at 10:01
  • I added the jQuery + twig solution – Enrico Feb 28 '16 at 16:51
  • 1
    Thank you so much for your effort. In the next version we will implement the jQuery solution, I will sleep better at night knowing there aren't 14 foreach's and if's running all day in that view :) – TommyZG Feb 29 '16 at 00:20