Jump to content

Using an array() from Within a Private Function Within a Class


Go to solution Solved by requinix,

Recommended Posts

Hi,

 

I've inherited some code on a system from another person. I'll be the first to admit that I'm not a PHP pro, I am self taught, and use it sparingly for personal projects mainly. So this is a bit beyond my skill level, and I was hoping for some advice:

 

The system is a glorified calendar, with a lot of our own data being slapped on top of it and presented nicely. The issue I have thoguh is that due to the way the calendar is generated, I cant make the height of the days move dynamically based on what content gets dropped into each day on the calendar. If one day is busy and has 8 events drop into it, they will overflow the days cell.

 

I wanted to adjust the height of ALL cells on a month view calendar to the heighest required height of all cells in that view.

 

What I was going to do, is +1 to a coutner for every event (or block) that is generated for each day (days are looped through a private function), and commit that number to an array. At the end fo the loop (after all days ahve been counted and have a value in the array), I was going to use max() on the array, pull the largest number, calculate the days cell hiehgt from that and apply it via CSS at page level.

 

I've summarised the code in effect here (psuedo code, not real PHP):

class Calendar {

    public $heights;

    private fucntion dayLoop($cellNumber) {
        $heights = []; //array
        $block_count = 0; //counter
        while(mysqlrowdata) {
            [code for mysql operations]
            $block_count++; //increment the count 
        }
    $day_height = ($block_count * 16) + 18; //do some math specific to my application
    $this->heights[] = $day_height; //commit calc'd value to array
    //array_push($heights, $day_height); //this was a previosu attempt, i dont think i should use array_push here..??
    }
}

That function, and others is called from the front end pages to generate the calendar. If I do a:

var_dump($heights);

after it on that page, all I get returned on screen is "Array ( )"

 

I tried changing the private function to a public one, but this did not affect the outcome. Anyone have any ideas on what I'm doing wrong? Is my logic sound? Can I commit values to an array inside a loop in a public OR private function and then reference that array outside of the loop? I defined $heights as public in the class too, but that didnt change the outcome either.

 

Thanks.

There are some syntax issues with the code that are probably causing the problem, but let's step back a second first.

 

What's the HTML and CSS for the calendar as it is? If we can do everything on the client side (ie, with HTML and CSS) then you don't have to touch PHP. It's also very likely the best method anyways.

There are some syntax issues with the code that are probably causing the problem, but let's step back a second first.

 

What's the HTML and CSS for the calendar as it is? If we can do everything on the client side (ie, with HTML and CSS) then you don't have to touch PHP. It's also very likely the best method anyways.

 

Hi, thanks for the reply. The CSS/HTML of the calendar gets a little in depth. I'll try and explain it best I can without overloading you with useless information.

 

The page is a month view calendar, and looks like this:

 

rota-calendar1.PNG

 

You can see for example, the bottom line of day cells are full, if another event were to occur, or more staff had holidays booked, the content would overflow the day container.

 

The overall calendar structure looks like this:

<div id="calendar">                   //parent container
  <div class="box"></div>             //top nav bar to change month
  <div class="box-content">           //container for calendar day cells
     <ul class="label">               //UL with LI's for each heading mon/tues/weds/thurs/fri/sat/sun
        <li>Mon</li>
        ...
     </ul>
     <ul class="dates">              //UL with LI's for each day "cell"
        <li id="li-2017-09-01">...</li>
        ...
     </ul>
  </div>
</div>

Applicable CSS for the above:

#calendar {
    margin: 0px auto;
    padding: 0px;
    width: 994px;
    font-family: Helvetica, "Times New Roman", Times, serif;
}
#calendar div.box {
    position: relative;
    top: 0px;
    left: 0px;
    width: 100%;
    height: 40px;
    background-color: #404f5a;
}
#calendar div.box-content {
    border: 1px solid #787878;
    border-top: none;
}
#calendar ul.label {
    float: left;
    margin: 0px;
    padding: 0px;
    margin-top: 5px;
    margin-left: 5px;
}
#calendar ul.label li {
    margin: 0px;
    padding: 0px;
    margin-right: 5px;
    float: left;
    list-style-type: none;
    width: 136px;
    height: 40px;
    line-height: 40px;
    vertical-align: middle;
    text-align: center;
    color: #000;
    font-size: 15px;
    background-color: transparent;
}

Now to drill down further, the structure of inside of one of those day cell <li>'s looks like this (this is the 29th, for reference):

<ul class="dates">                                //UL with LI's for each day "cell"
   <li id="li-2017-09-29">
      <div style="height:100%;position:relative;">
         <div class="day">
            <span class="day-number">2017-09-29</span>
            <div class="DB 0800" id="shift">DB - 0800</div>
            <div class="LG 0800" id="shift">LG - 0800</div>
            <div class="JZ 0900" id="shift">JZ - 0900</div>
            <div class="JC 1430" id="shift">JC - 1430</div>
            <div class="NS 0800" id="shift">NS - 0800</div>
        
         <div class="dayflag_day">
            <span class="day-number">2017-09-29</span>
            <div id="dayflag" class="14 2017-09-29">MP - MSIgnite (US)</div>
         </div>

         <div class="oncallday">
            <span class="day-number">2017-09-29</span>
            <div class="oncall 27 NS" id="ocshift">NS - ON CALL</div>
         </div>
         </div>
      </div>
   </li>
</ul>

Applicable CSS for the above:

div#calendar ul.dates {
    float: left;
    margin: 0px;
    padding: 0px;
    margin-left: 5px;
    margin-bottom: 5px;
}
div#calendar ul.dates li {
    margin: 0px;
    padding: 2px;
    margin-right: 5px;
    margin-top: 5px;
    float: left;
    list-style-type: none;
    width: 136px;
    height: 130px;
    background-color: #DDD;
    color: #000;
    text-align: left;
    font-weight: bold;
}
.day {
    height: 100%;
    position: relative;
}
#shift.DB {                                                   //(along with many other shit.* declarations)
    background-color: #9acbcb;
    margin-bottom: 2px;
    font-weight: normal;
    padding-left: 2px;
}
#dayflag {
    background-color: #fb8500;
    margin-bottom: 2px;
    padding-left: 2px;
    font-weight: bold;
    color: #f9ff00;
}
.oncall {
    background-color: #802f35;
    margin-bottom: 2px;
    font-weight: bold;
    padding-left: 2px;
    color: white;
    position: absolute;
    bottom: 12px;
    width: 100%;
}

If I can fix it in CSS alone then I'd be eternally happy. Just to clarify, all of the data in the second code block there, within the dates UL, is generated by PHP pulling different record types from a MySQL backend. I can show you that code also if needed, its a little clusterfuck-ey though.

height: 130px; /* div#calendar ul.dates li */
Increasing that number should increase the height of all the boxes. It's not automatic sizing but it's an easy change.

 

You can still do it according to content, but that's going to take quite a bit of effort and experimentation.

a) If you do it programmatically you'll need to figure the height on a per-row basis, or else one box in a row will be taller than the others. It may also simply look bad to have each row at different heights.

b) I'm pretty sure doing it automatically in CSS will require redoing the layout - the LIs are using float now and I don't think that will work for resizing elements vertically. The main problem is setting heights: most techniques need a container element with a known/fixed height to work with. I do believe it's possible without but that's more into the tricky CSS stuff I'm not familiar with.

height: 130px; /* div#calendar ul.dates li */
Increasing that number should increase the height of all the boxes. It's not automatic sizing but it's an easy change.

 

You can still do it according to content, but that's going to take quite a bit of effort and experimentation.

a) If you do it programmatically you'll need to figure the height on a per-row basis, or else one box in a row will be taller than the others. It may also simply look bad to have each row at different heights.

b) I'm pretty sure doing it automatically in CSS will require redoing the layout - the LIs are using float now and I don't think that will work for resizing elements vertically. The main problem is setting heights: most techniques need a container element with a known/fixed height to work with. I do believe it's possible without but that's more into the tricky CSS stuff I'm not familiar with.

 

Hi Requinix,

 

Thanks again for the reply. That height value is what I've manually adjusted up til now to globally make all day cells larger to fit the ever growing number of events per day. But its not sustainable when I have users complaining they cant see something they've added.

 

You mention programatically. That is the solution I was going for originally, to work out what day has the largest height requirement, then set all other say cells on that view (month) to that height.

 

This is waht my psuedo code from my first post was doing within that function. Define an array, start a counter, increase the counter for ever event (or block) that is returned, do some math on the counter value to work out the cell height, add that height into the array, repeat for all days. Then I was planning to max() that arrray, pull the largest number, and set the cell heights to that.

 

But it doesnt work. My array always seems to return emtpy.

Edited by dragon2309
  • Solution

class Calendar {

    public $heights;

    private function dayLoop($cellNumber) {
        $heights = []; //array
        $block_count = 0; //counter
        while(mysqlrowdata) {
            // code for mysql operations
            $block_count++; //increment the count 
        }
    $day_height = ($block_count * 16) + 18; //do some math specific to my application
    $this->heights[] = $day_height; //commit calc'd value to array
    //array_push($heights, $day_height); //this was a previosu attempt, i dont think i should use array_push here..??
    }
}
You're mixing $heights and $this->heights.

 

You don't need the local $heights variable. Make $this->heights start as an empty array

public $heights = [];
then append to it in the method

$this->heights[] = $block_count;
Don't do the math there: the calendar should not have to care about how the calendar is displayed and should only focus on the data itself.

 

Those two changes are more or less what you already had. You were seeing an empty array because of that line you had commented out, and/or because the $heights in the method is not the same $heights you were dumping (I can't tell from what you posted).

 

After the calendar is set up you can get the heights, find the maximum, and do the math:

$calendar = // set up calendar
$maxheight = max($calendar->heights) * 16 + 18; // math
Is that in pixels? Use it inline with each
  • , which is where the cell height is managed.

    <li id="li-2017-09-29" style="height:<?=$maxheight?>px;">
    • Like 1

    Can you adjust the HTML? Because (as requinix pointed out) you've got some syntax and structural issues. First, you've got multiple elements with the same ID value, which you shouldn't. Also, you're creating an unordered list per day, then jamming all the daily records as divs into the one list item in those lists - while not wrong, it is a bit strange.

     

    At any rate, I think you're better off tackling your problem with CSS than with PHP - this is a display issue at heart, so fix it in the display. Look into flexbox CSS - it's widely supported these days so you shouldn't have a problem there. I knocked this together in a couple minutes as an example (note that I updated some of the markup, so you may have to take that into account if you can't modify that).

    HTML:

    <div id="calendar">
    	<div class="week">
    		<ul class="day" style="background-color:red;">
    			<li id="li-2017-09-26" class="day-number">2017-09-26</li>
    			<li id="DB-0800" class="shift">DB - 0800</li>
    			<li>MP - MSIgnote (US)</li>
    			<li class="oncallday" id="ocshift1">NS - ON CALL</li>
    		</ul>
    		<ul class="day" style="background-color: yellow;">
    			<li id="li-2017-09-27" class="day-number">2017-09-27</li>
    			<li>MP - MSIgnote (US)</li>
    			<li class="oncallday" id="ocshift2">NS - ON CALL</li>
    		</ul>
    		<ul class="day" style="background-color: gray;">
    			<li id="li-2017-09-28" class="day-number">2017-09-28</li>
    			<li id="DB-08001" class="shift">DB - 0800</li>
    			<li id="LG-08001" class="shift">LG - 0800</li>
    			<li id="JZ-09001" class="shift">JZ - 0900</li>
    			<li id="JC-14301" class="shift">JC - 1430</li>
    			<li id="makingitup" class="shift">MO' DATA</li>
    			<li id="makingitup2" class="shift">MO' DATA</li>
    			<li id="makingitup3" class="shift">MO' DATA</li>
    			<li id="makingitup4" class="shift">MO' DATA</li>
    			<li id="NS-08001" class="shift">NS - 0800</li>
    			<li>MP - MSIgnote (US)</li>
    			<li class="oncallday" id="ocshift3">NS - ON CALL</li>
    		</ul>
    		<ul class="day" style="background-color: blue;">
    			<li id="li-2017-09-29" class="day-number">2017-09-29</li>
    			<li id="DB-08002" class="shift">DB - 0800</li>
    			<li id="JZ-09002" class="shift">JZ - 0900</li>
    			<li id="NS-08002" class="shift">NS - 0800</li>
    			<li>MP - MSIgnote (US)</li>
    			<li class="oncallday" id="ocshift4">NS - ON CALL</li>
    		</ul>
    	</div>
    </div>
    

    CSS:

    ul{
    	list-style: none;
    }
    #calendar{
    	display: flex;
    	flex-direction: column;
    	justify-content: flex-start;
    }
    .week{
    	display: flex;
    	flex-direction: row;
    	justify-content: center;
    	flex-wrap: nowrap;
    }
    .day{
    	display: flex;
    	flex-direction: column;
    	justify-content: flex-start;
    }
    .oncallday{
        margin-top: auto;
    }
    
    class Calendar {
    
        public $heights;
    
        private function dayLoop($cellNumber) {
            $heights = []; //array
            $block_count = 0; //counter
            while(mysqlrowdata) {
                // code for mysql operations
                $block_count++; //increment the count 
            }
        $day_height = ($block_count * 16) + 18; //do some math specific to my application
        $this->heights[] = $day_height; //commit calc'd value to array
        //array_push($heights, $day_height); //this was a previosu attempt, i dont think i should use array_push here..??
        }
    }
    
    You're mixing $heights and $this->heights.

     

    You don't need the local $heights variable. Make $this->heights start as an empty array

    public $heights = [];
    then append to it in the method

    $this->heights[] = $block_count;
    Don't do the math there: the calendar should not have to care about how the calendar is displayed and should only focus on the data itself.

     

    Those two changes are more or less what you already had. You were seeing an empty array because of that line you had commented out, and/or because the $heights in the method is not the same $heights you were dumping (I can't tell from what you posted).

     

    After the calendar is set up you can get the heights, find the maximum, and do the math:

    $calendar = // set up calendar
    $maxheight = max($calendar->heights) * 16 + 18; // math
    Is that in pixels? Use it inline with each <li>, which is where the cell height is managed.

    <li id="li-2017-09-29" style="height:<?=$maxheight?>px;">

     

    That is absolutely perfect and works a charm. Thank you so much. I realise my failure as well, thanks to your explanations. I failed at almsot every point there, by addressing the wrong thing at various points. I didnt realise that the heights array would be referenced via the class when called with max() externally for example.

     

    Thanks again, it works a dream.

    This thread is more than a year old. Please don't revive it unless you have something important to add.

    Join the conversation

    You can post now and register later. If you have an account, sign in now to post with your account.

    Guest
    Reply to this topic...

    ×   Pasted as rich text.   Restore formatting

      Only 75 emoji are allowed.

    ×   Your link has been automatically embedded.   Display as a link instead

    ×   Your previous content has been restored.   Clear editor

    ×   You cannot paste images directly. Upload or insert images from URL.

    ×
    ×
    • Create New...

    Important Information

    We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.