Jump to content

Barand

Moderators
  • Posts

    24,420
  • Joined

  • Last visited

  • Days Won

    805

Posts posted by Barand

  1. I've cleaned it up, provided the missing function definition and added something that prints,  but it's only a guess at what you really want.

    function __($text)
    {
        return $text;               // or whatever else it is suppoesed to do
    
    } 
    
                                   
    // Parent
    
    class Default_Fields {
        
        protected $_fields = [];
    
        public function fields() 
        {
    
            $this->_fields = array(
                               array(
                                        'name'        => 'text_one',
                                        'label'       => __('Text One'),
                                        'type'        => 'text',
                                    )
                            );    
        }
    
        public function showFields()
        {
            echo 'Output from class: ' . get_class($this);
            echo '<pre>', print_r($this->_fields, 1), '</pre><hr>';
        }
    }
    
    
    // Child 
    
    class More_Fields extends Default_Fields {
    
        public function fields() {
    
            parent::fields();                                                       // call default
            $this->_fields[] = array(                                               // add extra field
                                        'name'        => 'text_two',
                                        'label'       => __('Text Two'),
                                        'type'        => 'text',
                                );    
        }
    
    }
    
    $old = new Default_Fields();
    $old->fields();
    $old->showFields();
    
    $new = new More_Fields;
    $new->fields();
    $new->showFields();

     

  2. The $freqs array contains the counts for P1, P2 , P3 for each digit...

    $freqs = Array
    (
        [0] => Array                          # digit "0"
            (
                [0] => 4                      # P1
                [1] => 7                      # P2
                [2] => 1                      # P3
            )
    
        [1] => Array
            (
                [0] => 3
                [1] => 2
                [2] => 6
            )
    
        [2] => Array
            (
                [0] => 4
                [1] => 4
                [2] => 6
            )
    

    which, coincidentally, is the same structure as the output table. You now loop through the array and for each digit (row) loop through its array (positions columns) and build the table.

    //
    //  create frequncy table and calc digit totals
    //
        $totals =  array_fill_keys(range(0,9), []);
        $tdata = '';
        foreach ($freqs as $n => $occs) {
            $tdata .= "<tr><td><b>$n</b></td>";
            foreach ($occs as $o) {
                $tdata .= "<td>$o</td>";
            }
            $total = array_sum($occs);
            $totals[$n] = [$n,$total];
            
            $tdata .= "<td>=</td><td><b>$total</b></td></tr>\n";
        }

    My complete solution...

    <?php
    
    //
    //  Get the input string of comma-separated numbers
    //  explode into an array and trim off any spaces
    //    
        $input_str = "572, 545, 884, 123, 802, 337, 879, 307, 759, 227, 211, 002, 968, 532, 459, 895, 681, 967, 580, 399, 664, 077, 307, 227, 461, 594, 645, 859, 484, 827, 618, 675, 302, 246, 007, 842, 471, 006, 161, 171";
        $input_arr = array_map('trim', explode(',', $input_str));
    //    
    //  now split each number into a 3-element array
    //  and store in $input
    //
        foreach ($input_arr as $n) {
            $input[] = str_split($n, 1);
        }
    
    //
    //  create output table to display the input numbers
    //  in rows of 10 numbers 
    //
        $inputdata = '';
        $chunks = array_chunk($input_arr, 10);
        foreach ($chunks as $nums) {
            $inputdata .= "<tr>";
            foreach ($nums as $num) {
                $inputdata .= "<td>$num</td>";
            }
            $inputdata .= "</tr>\n";
        }
    
    //
    //  get the counts in each position
    //
        $freqs =  array_fill_keys(range(0,9), [0,0,0]);
    
        for ($pos=0; $pos<3; $pos++) {
            $digits = array_column($input, $pos);
            $occurs = array_count_values($digits);
            foreach ($occurs as $n => $tot) {
                $freqs[$n][$pos] += $tot;
            }
        }
        
    //
    //  create frequncy table and calc digit totals
    //
        $totals =  array_fill_keys(range(0,9), []);
        $tdata = '';
        foreach ($freqs as $n => $occs) {
            $tdata .= "<tr><td><b>$n</b></td>";
            foreach ($occs as $o) {
                $tdata .= "<td>$o</td>";
            }
            $total = array_sum($occs);
            $totals[$n] = [$n,$total];
            
            $tdata .= "<td>=</td><td><b>$total</b></td><td>" . bar($total, 30) . "</td></tr>\n";
        }
    
    //
    //  put digits in frequncy order (highest to lowest)
    //
        uasort ($totals, function($a, $b) {
                            $x = $b[1] <=> $a[1];
                            if ($x == 0) 
                                return $a[0] <=> $b[0];
                            return $x;
                        });
        $freqorder = '<b>' . join('</b> &ndash; <b>', array_keys($totals)) . "</b>" ;
    
    /**
    * draw bar representing number of occurences
    * 
    * @param int $val
    * @param int $max
    */
        function bar($val, $max)
        {
            $wid = 200;
            $ht  = 15;
            $svg = "<svg width='$wid' height='$ht'>
                    <rect x='0' y='0' width='$wid' height='$ht' stroke='#CCC' fill='none'/>
                    ";
            $pix = $wid/$max;
            $w = $val * $pix;
            $svg .= "<rect x='0' y='0' width='$w' height='$ht' fill='#396' stroke='#CCC' />\n";
            $svg .= "</svg>\n";
            return $svg;
        }
    
    ?>
    <!DOCTYPE html>
    <html>
    <head>
    <meta http-equiv="content-language" content="en">
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <meta name="generator" content="PhpED 18.0 (Build 18044, 64bit)">
    <title>Number frequencies</title>
    <meta name="creation-date" content="09/29/2019">
    <style type="text/css">
        table { border-collapse: collapse; font-family: verdana, sans-serif; font-size: 10pt; }
        th    { background-color: #396; color: #FFF; padding: 8px; font-variant: small-caps;}
        td    { text-align: center; padding: 4px 8px; }
        #league, #inputs { padding: 16px; background-color: #FCF8E8; font-size: 12pt; border: 1px solid gray; display: inline-block; }
    </style>
    </head>
    <body>
        <h3>Input</h3>
        <div id="inputs">
            <table>
                <?=$inputdata?>
            </table>
        </div>
        <h3>Digit Frequencies</h3>
        <table border="1">
            <tr><th>Digit</th><th>P1</th><th>P2</th><th>P3</th><th>&nbsp;</th><th>Digit<br>Totals</th></tr>
            <?=$tdata?>
        </table>
        <br>
        <h3>Digit Frequency League</h3>
        <div id="league">
            <?=$freqorder?>
        </div>
    </body>
    </html>

    • Like 1
  3. Like this...

    //
    //  Get the input string of comma-separated numbers
    //  explode into an array and trim off any spaces
    //    
        $input_str = "572, 545, 884, 123, 802, 337, 879, 307, 759, 227, 211, 002, 968, 532, 459, 895, 681, 967, 580, 399, 664, 077, 307, 227, 461, 594, 645, 859, 484, 827, 618, 675, 302, 246, 007, 842, 471, 006, 161, 171";
        $input_arr = array_map('trim', explode(',', $input_str));
    //    
    //  now split each number into a 3-element array
    //  and store in $input
    //
        foreach ($input_arr as $n) {
            $input[] = str_split($n, 1);
        }
    

    Now you have a processable array. You now need an array ($freqs)  which contains, for each digit 0-9, an array the counts of that digits in P1, P2 and P3...

    //
    //  get the counts in each position
    //
        $freqs =  array_fill_keys(range(0,9), [0,0,0]);
    
        for ($pos=0; $pos<3; $pos++) {
            $digits = array_column($input, $pos);
            $occurs = array_count_values($digits);
            foreach ($occurs as $n => $tot) {
                $freqs[$n][$pos] += $tot;
            }
        }
    

    You now have all the data that you want to output in your table in the $freqs array.

    From that input data you should be able to end up with something like this...

    image.png.ee3aad500134f34a4ae94971645262fa.png

  4. 1 hour ago, haymanpl said:

    Runs because i tested it

    Then how about posting the code that "works" because that code above contains syntax errors and undefined function calls.

     

    22 hours ago, haymanpl said:

    There's no errors but the additional code is not printing.

    There is no code there to print anything (except throw error messages of course)

  5. Regarding your current code

    It is going to throw warning notices when the dgits do not appear in the array eg

    Notice: Undefined offset: 0 
    Notice: Undefined offset: 4 
    Notice: Undefined offset: 6 
    Notice: Undefined offset: 7 
    Notice: Undefined offset: 8

    It is repetetive. The advantage of arrays is they can be used in loops, so your code can be replaced by

    $arr = array('9','2','3','2','1','5');
    
    $result = array_count_values($arr);
    
    echo "DIGIT FREQUENCY RESULTS ..<br><br>";
    for ($d=0; $d<10; $d++) {
        echo "{$d}s : " . ($result[$d] ?? 0) . '<br>';
    }

     

  6. I'd store the input as arrays of 3 digits instead of 3-digit numbers.

    $input = [];
    for ($i=0; $i<5; $i++) {
        $input[] = str_split(sprintf('%03d',mt_rand(1,999)), 1); 
    }

    Giving...

    $input Array
    (
        [0] => Array
            (
                [0] => 8
                [1] => 5
                [2] => 2
            )
    
        [1] => Array
            (
                [0] => 3
                [1] => 6
                [2] => 3
            )
    
        [2] => Array
            (
                [0] => 4
                [1] => 1
                [2] => 1
            )
    
        [3] => Array
            (
                [0] => 1
                [1] => 5
                [2] => 6
            )
    
        [4] => Array
            (
                [0] => 7
                [1] => 8
                [2] => 2
            )
    
    )

    Then, if you want, you can get the individual positions for counting by using array_column()

    $p1 = array_column($input, 0);
    $p2 = array_column($input, 1);
    $p3 = array_column($input, 2);

    E.G...

    $p1 Array
    (
        [0] => 8
        [1] => 3
        [2] => 4
        [3] => 1
        [4] => 7
    )

     

  7. 55 minutes ago, Barand said:

    Because I preferred to pass the parameters in an array when executing instead.

    Binding is useful when you want to process records in a loop. Bind the variables first then, in the loop, update the values and execute. EG

    $data = [    [ 1, 'Curly'],
                 [ 2, 'Larry'],  
                 [ 3, 'Mo']  
            ];
          
    $stmt = $db->prepare("INSERT INTO testuser (id, username) VALUES (:id, :user)");
    $stmt->bindParam(':id', $id, PDO::PARAM_INT);
    $stmt->bindParam(':user', $username, PDO::PARAM_STR);
    
    foreach ($data as $user) {
        list($id, $username) = $user;
        $stmt->execute();
    }
    

    EDIT:

    But, with PDO, there is the alternative that I used before EG

    $data = [    [ 1, 'Curly'],
                 [ 2, 'Larry'],  
                 [ 3, 'Mo']  
            ];
          
    $stmt = $db->prepare("INSERT INTO testuser (id, username) VALUES (?, ?)");
    
    foreach ($data as $user) {
        $stmt->execute($user);
    }

    where the values are passed as an array when executing.

    • Thanks 1
  8. The number value of the string "1,000" is 1. (ie anything befor the first non-numeric character.)

    Do all your maths on unformatted numbers and only format imediately prior to output.

    $value = 1000;
    $multiplier = 1.02;
    
    for ($i = 1; $i <= 10; $i++) {
          $value *= $multiplier;
          echo  number_format($value, 2) . '<br>';
    }

     

  9. Sample query I forgot to add to my last post...

    SELECT r.rid
         , r.role_name
         , p.page_id
         , p.page
         , CASE WHEN ra.page IS NULL THEN ''
                ELSE 'Y'
           END as checked
    FROM role r 
            CROSS JOIN
         pages p 
            LEFT JOIN 
         role_access ra ON r.rid = ra.role
                        AND p.page_id = ra.page
    ORDER BY r.rid, p.page_id;
    
    +-----+-----------+---------+--------------+---------+
    | rid | role_name | page_id | page         | checked |
    +-----+-----------+---------+--------------+---------+
    |   1 | Admin     |       1 | Registration | Y       |
    |   1 | Admin     |       2 | List         | Y       |
    |   1 | Admin     |       3 | Edit         | Y       |
    |   1 | Admin     |       4 | Export       | Y       |
    |   1 | Admin     |       5 | MRD          | Y       |
    |   2 | Others    |       1 | Registration |         |
    |   2 | Others    |       2 | List         | Y       |
    |   2 | Others    |       3 | Edit         |         |
    |   2 | Others    |       4 | Export       | Y       |
    |   2 | Others    |       5 | MRD          | Y       |
    +-----+-----------+---------+--------------+---------+

     

  10. The answer is "normalize".

    Don't store comma-separated lists (especially when the list items are ids). The role_access table should be

    CREATE TABLE `role_access` (
      `id` int(10) NOT NULL PRIMARY KEY,
      `page` int NOT NULL,
      `role` int(7) NOT NULL
    ) ENGINE=MyISAM DEFAULT CHARSET=latin1;
    
    INSERT INTO `role_access` (`id`, `page`, `role`) VALUES
    (1,1,1),
    (2,2,1),
    (3,3,1),
    (4,4,1),
    (5,5,1),
    (6,2,2),
    (7,4,2),
    (8,5,2);

    Now you can join to the page table to get the page name

    image.png.43fbb3d592dcf95c9bf0f920501af80a.png

    • Thanks 1
  11. Another option is to display, for each frame, all the referenced banners. For example if you have banner_frames table thus

    +----+-----------+----------+
    | id | banner_id | frame_id |
    +----+-----------+----------+
    |  1 |         1 |        1 |
    |  2 |         2 |        1 |
    |  3 |         2 |        3 |
    |  4 |         3 |        3 |
    |  5 |         1 |        4 |
    |  6 |         2 |        4 |
    |  7 |         3 |        4 |
    +----+-----------+----------+

    then the output would look like

    image.thumb.png.f57b5eb985201692a39ab739e95c9701.png

    CODE:

    <?php
    include 'db_inc.php';
    $db = pdoConnect('chibi');
    
    //
    //  Get the banner data
    //
    $res = $db->query("SELECT id
                            , title
                       FROM banners
                       ORDER BY id
                      ");
    $banner_data = $res->fetchAll();
    $banner_count = count($banner_data);
    $banner_heads = '<th>' . join('</th><th>', array_column($banner_data,'title')) . '</th>';
    $banner_template = array_fill_keys(array_column($banner_data, 'id'), '');
    //
    //  Get frame-banner data
    //      store in array
    //
    $res = $db->query("SELECT f.id as fid
                            , f.title
                            , b.id as bid
                            , CASE WHEN bf.banner_id IS NULL THEN ''
                                   ELSE 'Y'
                              END as checked
                       FROM frames f
                              CROSS JOIN
                            banners b
                              LEFT JOIN 
                            banner_frame bf ON f.id = bf.frame_id 
                                            AND b.id = bf.banner_id
                       ORDER BY f.id, b.id                 
                      ");
    $data = [];
    foreach ($res as $r) {
        if (!isset($data[$r['fid']])) {
            $data[$r['fid']] = [ 'title' => $r['title'],
                                 'banners' => $banner_template
                               ];
        }
        $data[$r['fid']]['banners'][$r['bid']] = $r['checked'];
    }
    
    ?>
    <!DOCTYPE html >
    <html>
       <head>
           <meta http-equiv="content-language" content="en">
           <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
           <link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css">
          <title>Banner Frames</title>
       </head>
       <body>
       <header class="w3-container w3-blue">
           <h1>Banner Frames</h1>
       </header>
       <div class="w3-container w3-margin w3-padding">
           <table class="w3-table w3-bordered">
               <tr class="w3-brown">
                   <th rowspan="2">Frame ID</th>
                   <th rowspan="2">Title</th>
                   <th colspan="<?=$banner_count?>">Banners</th>
               </tr>
               <tr class="w3-brown">
                   <?=$banner_heads?>
               </tr>
               
               <?php
                   // output the data array as table rows
                   foreach ($data as $fid => $fdata) {
                       echo "<tr><td>$fid</td><td>{$fdata['title']}</td>";
                       foreach ($fdata['banners'] as $bid => $chkd) {
                           $checked = $chkd=='Y' ? 'checked' : '';
                           echo "<td><input type=\"checkbox\" name=\"banner[$fid][]\" value=\"$bid\" $checked></td>";
                       }
                       echo "</tr>\n";
                   }
               ?>
           </table>
       </div>
       </body>
    
    </html>
    

     

  12. In that case you need to specify the banner you are looking for in the LEFT JOIN's ON clause

    EG (looking for banner #2)

    SELECT DISTINCT
           f.id as frameId
         , f.title as frameTitle
         , bf.banner_id
    FROM frames f
    LEFT JOIN banner_frame bf ON bf.frame_id = f.id
                              AND bf.banner_id = 2
    ORDER BY f.id;
    +---------+------------+-----------+
    | frameId | frameTitle | banner_id |
    +---------+------------+-----------+
    |       1 | Frame 1    |         2 |
    |       2 | Frame 2    |      NULL |
    |       3 | Frame 3    |      NULL |
    |       4 | Frame 4    |      NULL |
    |       5 | Frame 5    |         2 |
    +---------+------------+-----------+

     

    • Great Answer 1
  13. 4 hours ago, Chibi said:

    The purpose of the query is to list all the frames from the frames table and then only put a check next to those that
    is linked to the banner table through the pivot table.

    I used

    COUNT(DISTINCT bf.banner_id) as banner_table

    so that it would be non-zero if the frame were linked to any banners. You are trying to match that that count value against a $banner_id (???).

    Does that mean you want to show as checked those frames that are link to s specific banner and not just any banner? If so the query will be different.

  14. Something like this?

    mysql> SELECT f.id as frameId
        ->      , f.title as frameTitle
        ->      , COUNT(DISTINCT bf.banner_id) as banner_tot
        -> FROM frames f
        -> LEFT JOIN banner_frame bf ON bf.frame_id = f.id
        -> GROUP BY f.id;
    +---------+------------+------------+
    | frameId | frameTitle | banner_tot |
    +---------+------------+------------+
    |       1 | Frame 1    |          2 |
    |       2 | Frame 2    |          0 |
    |       3 | Frame 3    |          0 |
    |       4 | Frame 4    |          0 |
    |       5 | Frame 5    |          1 |
    +---------+------------+------------+

     

  15. With the provided data your query gives

    mysql> SELECT frames.id as frameId, frames.title as frameTitle, banners.id as banner_id
        -> FROM frames
        -> LEFT JOIN banner_frame ON banner_frame.frame_id = frames.id
        -> LEFT JOIN banners ON banners.id = banner_frame.banner_id
        -> ORDER BY frames.id;
    +---------+------------+-----------+
    | frameId | frameTitle | banner_id |
    +---------+------------+-----------+
    |       1 | Frame 1    |         1 |
    |       1 | Frame 1    |      NULL |
    |       2 | Frame 2    |      NULL |
    |       3 | Frame 3    |      NULL |
    |       4 | Frame 4    |      NULL |
    |       5 | Frame 5    |      NULL |
    +---------+------------+-----------+

    Beacause you have "... FROM frames LEFT JOIN ..." you get every frames record even if there is no matching data in the other tables.

    You get 2 rows for Frame 1 because there are 2 matching records for frame 1 in "banner_frame" table

    57 minutes ago, Chibi said:

       id  |   banner_id   |   frame_id
        1   |       1       |       1
        2   |       2       |       1
        2   |       2       |       5

    So the question is "What is the purpose of the query?"

  16. This was my rearrangement of your code

    <?php
    const KM2MILES = 0.62;
    
    $Distances = array(
            "Berlin" => array(
                "Berlin" => 0,
                "Moscow" =>1607.99,
                "Paris" => 876.96,
                "Prague" => 280.34,
                "Rome" => 1181.67
            ),
            "Moscow" => array(
                "Berlin" => 1607.99,
                "Moscow" => 0,
                "Paris" => 2484.92,
                "Prague" => 1664.04,
                "Rome" => 2374.26
            ),
            "Paris" => array(
                "Berlin" => 876.96,
                "Moscow" => 641.31,
                "Paris" => 0,
                "Prague" => 885.38,
                "Rome" => 1105.76
            ),
            "Prague" => array(
                "Berlin" => 280.34,
                "Moscow" => 1664.04,
                "Paris" => 885.38,
                "Prague" => 0,
                "Rome" => 922
            ),
            "Rome" => array(
                "Berlin" => 1181.67,
                "Moscow" => 2374.26,
                "Paris" => 1105.76,
                "Prague" => 922,
                "Rome" => 0
            )
        );
    
    /**
    * convert Km to miles
    *     
    * @param float $km     distance in Kilometers
    * @return string miles
    */
            function toMiles($km)
            {
                return number_format($km * KM2MILES, 2);
            }
    
    /**
    * create list of city options
    * 
    * @param array $Distances    distances array
    * @param string $current     currently selected city
    * @return string list of options
    */
            function cityOptions($Distances, $current)
            {
                $opts = "<option value=''> - Select city -</option>";
                foreach (array_keys($Distances) as $city) {
                    $sel = $city == $current ? 'selected' : '';
                    $opts .= "<option $sel> $city</option>";
                }
                return $opts;
            }
    
    //
    //   Initialise output variables
    //
    $StartIndex = "";
    $EndIndex = "";
    $kms = 0;;
    
    //
    //  Was form data posted?
    //    
    if ($_SERVER['REQUEST_METHOD']=='POST') {
    
        $StartIndex = $_POST['Start'] ?? '';
        $EndIndex = $_POST['End'] ?? '';
        $kms = $Distances[$StartIndex][$EndIndex] ?? 0;;
        
    }
    ?>
     <!DOCTYPE html >
     <html>
        <head>
            <meta http-equiv="content-language" content="en">
            <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
            <title>European Travel</title>
        </head>
        <body>
           <form action="" method="post">
            <p>Starting City:
            <select name="Start">
                <?=cityOptions($Distances, $StartIndex)?>
            </select></p>
            <p>Ending City:
            <select name="End">
                <?=cityOptions($Distances, $EndIndex)?>
            </select></p>
            <p><input type="submit" name="btnSubmit"
                value="Calculate Distance" /></p>
            </form>
            <br><br>
            Distance <br><?=$kms?> Km
            <br><?=toMiles($kms)?> Miles    
        </body>
    
    </html>

     

  17. Just about all of your code is misplaced.

    • The PHP code should be first. (except for output which should be in the html/body section
    • Your <form> should be in the html/body section.
    • Your <options>..</options>s should be between the <select>..</select> tags

    plus your course material appears to be many years out of date.

    • Thanks 1
  18. P.S.

    If you want to show the nurse allotment even when there are no patients on the allocated ward...

    image.png.8cd3e97f9db837dd0ce51bc390433b11.png

    ... then you will need LEFT JOINS thus

    $stmt = $db->prepare("SELECT   sdate
                                 , DATE_FORMAT(sdate, 'Week %v %W %d/%m/%Y') as fdate
                                 , wa.shift
                                 , w.ward_name
                                 , a.bed
                                 , a.patient_id
                                 , p.patient_name
                            FROM ward_allotment wa
                                 INNER JOIN
                                 ward w ON wa.ward = w.wid
                                 LEFT JOIN
                                 admission a ON wa.ward = a.ward
                                             AND wa.sdate BETWEEN a.from_date AND a.discharge_date
                                 LEFT JOIN 
                                 patient p ON a.patient_id = p.patient_id
                            WHERE wa.nurse = ?
                                 AND sdate BETWEEN CURDATE() - interval 30 day AND CURDATE() + INTERVAL 6 DAY
                            ORDER BY sdate, shift, ward_name, a.bed, a.patient_id
                            ");

     

×
×
  • 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.