...

Hi! I’m Starx

experienced Software Developer. And this is my blog
Start Reading About me
Blog Page
April 7, 2012

How can I decouple $_POST/$_GET handling code from html forms/urls? (PHP-OOP)

Question by Jonathan

In a class I have a handling method which performs actions based on what post/get variables are available. Here is a simplified example:

public function handleAll(array $vars) {
    if (isset($vars['var1'])) {
        $this->doThisAction($vars['var1']);
    } else if (isset($vars['var2'])) {
        $this->doAnotherAction($vars['var2']);
    }
}

So at runtime the method could be called like this $handler->handleAll($_POST).
The problem is that the variables stored in the $vars array must be named “var1” & “var2” etc. This means that the handling code is coupled with the names of html form elements or get variables in urls (or indeed the keys of any array passed in).

Allowing an array of any variables to be injected makes the method flexible which is necessary as it is also polymorphic. Classes inherit this method and use it to call it’s own actions. A result of this is that it is not obvious from the outside what the handling method requires for it to function. This means that the implementation must be examined to find out what it does (unless I copy the code into the phpdoc which would be silly).

I’m not sure how to get around this. Having enormous if/case statements all exposed on index pages (from multiple classes like these) makes for extremely messy code so it is preferable to have all this encapsulated within a method. Also, it makes sense to have it as a method of the class responsible for calling the actions that manipulate it’s own state (responsibility driven design). I thought about having each variable as a parameter for the method but for some classes the parameter list would be quite large. Also it would mean that many handleAll() methods of different classes cannot be called automatically as all parameters would need to be explicitly injected for each call, removing the polymorphic aspect.

To sum up I need to keep the method polymorphic but I need some way of decoupling the handling code from user input from html forms or urls. In doing this perhaps there is a way of separating the interface from the implementation too. I’m surprised I can’t find any solutions to this already, it seems like it would be a common problem.

Answer by Jani Hartikainen

I’m not sure if what you describe can even be avoided.

If you have code which requires specific arguments to it – be it in the form of an array containing certain values or whatever else – that function will always depend on the arguments being populated correctly.

If I have function foo($a, $b, $c), I will always have to fill the parameters. If they come from POST, then I would need to take them from POST. The same goes even if the function took an array('a' => ..., 'b' => ..., 'c' => ...) instead.

However, if you wanted to decouple your forms from the parameter list, you could use a simple function to transform the POST array into the format expected by one of your handler functions. I do not really see any reason for this though, since why add the extra complexity if you don’t have to?

If you wish to better define what kind of array your handler requires, you could consider having it require an object instead. This approach is sometimes called a parameter object.

The benefits of using a parameter object is that you can easily set up required parameters in the constructor, and use setters for optional ones. Anyone who uses your code can just look at your object’s interface to see what values are required.

If the values your handlers use are actually related to each other, I would consider creating an actual business logic type object. Create it using the data from POST, and move the code which processes the values into a method in the object.

Answer by Starx

Decoupling and automating handling methods, can be painful methods to narrow down too. But there is not so many options, other than, create handlers for eveything. However, I would you like add something. Allow defaults and support variation

function handlePOST() {    }
function handleGET()  {    }
function handleArr()  {    }

Now, these function can hold the variations of the function on their behalf.

Inside however, they is not better way other than to code all the handlers. But switch is shorten them and use separate function for the handling.

switch($_POST['var1']) {
    case "value1": callPostValue1(); break;
    default: callPostDefaultHandler(); break;
}
Read more

jquery run functions

Question by user1022585

I have a function in jquery:

$('#map').click(function(e) {
    var posX = $(this).offset().left, posY = $(this).offset().top;
    if (posY < 100) {
       // do this

When the user clicks within that element it will run. But I also want it to run if he presses a cursor key.

Is it possible to do something like:

$('#map').click OR key.press(function(e) {

Basically, can you set more than one event to run that function?
Just learning jquery so go easy on me.

UPDATE

function move(e) {
   var posX = $(this).offset().left, posY = $(this).offset().top;

    if (posX > 75 && posX < 150 && posY < 75) { var go = "N"; }
    if (e.which == 38) { var go = "N"; }

    $.post("inc_map.php", { move: go }, function(data){ 
        var substr = data.split('@'); 
        if (substr[0] != "block") {
            var x1 = substr[0]; var y1 = substr[1];
            x = parseInt(x1) * 32; y = parseInt(y1) * 32;
            $("#mapview").css({ backgroundPosition: -x + "px " + -y + "px" });
                $("#map").html(substr[2]);
                $("#info").html(substr[3]);
                };
            $("#pos").html((x/32) + ', ' + (y/32)); 
        });  

};



$("#map").click(move).keypress(move);

Why doesnt this work? 😮

Answer by Elliot Bonneville

You’d define a function outside of the event handlers, then call it from each handler separately.

function myFunc(e) {
    var posX = $(this).offset().left, posY = $(this).offset().top;
    if (posY < 100) {

    }

    // if e.which equals 38, the up arrow was pressed
    if(e.which == 38) {
        // do nice stuff here
    }

    // the rest of your function here...
}

$("#map").click(myFunc).keypress(myFunc);

Edit: Threw in jQuery function chaining, too.

Aha, okay. I think I found your error. I’ve reformatted your code a bit and neatened it up some. Try this:

function move(e) {
    var posX = $(this).offset().left,
    var posY = $(this).offset().top;

    var go = "";

    if (posX > 75 && posX < 150 && posY < 75) {
        go = "N";
    }

    if (e.which == 38) {
        go = "N";
    }

    $.post("inc_map.php", {
        move: go
    }, function(data) {
        var substr = data.split('@');
        if (substr[0] != "block") {
            var x1 = substr[0];
            var y1 = substr[1];
            x = parseInt(x1) * 32;
            y = parseInt(y1) * 32;
            $("#mapview").css({
                backgroundPosition: -x + "px " + -y + "px"
            });
            $("#map").html(substr[2]);
            $("#info").html(substr[3]);
        };
        $("#pos").html((x / 32) + ', ' + (y / 32));
    });

};

Answer by Starx

Pass a common event handler between clicks and keypresses

For example:

function myFunc(e) {
   //For cursor
   switch(e.charCode) {
      case 37: 
         // Left
      break;
      case 37: 
         // Up
      break;
      case 37: 
         // Right
      break;
      case 37: 
         // Down
      break;
   }
}

$("#map").click(myfunc).keypress(myfunc);
Read more

Grouping a query with php

Question by Tom Hoad

Basic question!

I have 2 tables

PRODUCE

   +-----+--------------+  
   | id  |  fruit_name  |
   +--------------------+
   | 1   |   Apple      |
   | 2   |   Banana     |
   | 3   |   Carrot     |
   +-----+--------------+

VARIETIES

   +-----+---------------+----------------+
   | id  |  fk_fruit_id  |  variety_name  |
   +-----+---------------+----------------+
   | 1   |   1           |    Cox         |
   | 2   |   1           |    Braeburn    |
   | 3   |   2           |    Chester     |
   | 4   |   3           |    Kotaka      |
   | 5   |   3           |    Imperial    |
   | 6   |   3           |    Oneal       |
   +-----+---------------+----------------+

I’d like to output a list of varieties per fruit e.g.

APPLE - Cox, Braeburn

BANANA - Chester

CARROT - Kotaka, Imperial, Oneal

My current code is

$query   = "SELECT * FROM produce, varieties WHERE produce.id = varieties.fk_fruit_id"; 

$result  = mysql_query($query) or die('Error : ' . mysql_error()); 
while ($row     = mysql_fetch_array($result, MYSQL_ASSOC)) { 

$produce_fruit_code   = $row['fruit_code']; 
$variety_name   = $row['variety_name']; 

echo $produce_fruit_code.' - '.$variety_name.'<br/>';

}

which outputs:

Apple - Cox
Apple - Braeburn
Banana - Chester
Carrot - Kotaka
Carrot - Imperial
Carrot - Oneal

Not a million miles away, but still not there. Any help is much appreciated, thanks!

Answer by Nathaniel Ford

This won’t get you all the way, but it will get you most of what you want. There are some edge cases that are problematic.

$query   = "SELECT * FROM produce, varieties WHERE produce.id = varieties.fk_fruit_id"; 
$result  = mysql_query($query) or die('Error : ' . mysql_error()); 

$produce_fruit_code = "";
while ($row     = mysql_fetch_array($result, MYSQL_ASSOC)) { 
  if ($produce_fruit_code != $row['fruit_code'])
  {
    $produce_fruit_code = $row['fruit_code'];
    echo "<br/>".$produce_fruit_code." - ". $row['variety_name'];
  } else {
    echo ", ".$row['variety_name']; 
  }
}

Answer by Starx

You can query this directly

SELECT 
   f.fruitname as fruit, 
   GROUP_CONCAT(distinct v.varietyname separator ',') as variety  
FROM fruit f JOIN varieties v ON produce.id = varieties.fk_fruit_id;
GROUP BY produce.id
Read more
April 6, 2012

What event should I use to hide context menu in jquery?

Question by Frankie

I have a contextmenu that shows on certain elements when you right click. This works no problem.

wrapper.on('contextmenu', 'div.outer', function (e) {        
    context_menu.css({
        left: e.pageX,
        top: e.pageY,
        zIndex: '101'
     }).fadeIn();
     return false;
});

//This does not work correctly
context_menu.mouseout(function (e) {
    $(this).fadeOut();
});

I’m trying to figure out how to hide the menu when the user is not hovered over the menu. Right now as soon as I move the mouse after I right click it fades out.

Answer by Starx

The events, should most probably be mouseleave since its a container.

context_menu.mouseleave(function (e) {
    $(this).fadeOut();
});
Read more

Placing an icon beside the text of an H1 tag by using a span

Question by Only Bolivian Here

Here’s the HTML I’m trying to use:

<h1>Order Not Paid<span class="not-paid"></span></h1>

Of course if there is a better way please say so.

Currently since there is no text inside of the span, it seems the browsers are ignoring this tag. Firebug shows up grayed out when inspecting.

When I place text in the span, the icon shows correctly.

What CSS rule can I apply for this effect? Here’s what I have so far (It’s SASS, but easy to grasp):

h1 {
    font-size: 24px;

    span.not-paid {
        background-image: url('/Public/images/remove.png');
        background-repeat: no-repeat;
    }
}

I’d like the icon to appear where the span is.

Alternatively, is it kosher to do something like this? If so, I can settle with this as it looks good on IE8 and modern browsers.

<h1>Order Not Paid <img src="@Url.Content("~/Public/images/remove.png")" alt="" /></h1>

Answer by Alex

If the icon is small and not reused anywhere else just set it as part of the h1.

HTML:

<h1 class="not-paid">Order Not Paid</h1>

CSS:

h1.not-paid {
  font-size: 24px;
  padding:0 16px 0 0; /* whatever the dimensions the image needs */
  background-image: url('/Public/images/remove.png') no-repeat right center; /* Position left/right/whatever */
}

A little cleaner this way.

Answer by Starx

First, if you are not using sass and less, your stylesheet is wrong. Next, give inner-block to span and the image height and width.

h1 {
    font- size: 24px;
}

h1 span.not-paid {
    width: 50px;
    height: 50px;
    display: inline-block;
    background-image: url('/Public/images/remove.png');
    background-repeat: no-repeat;
}
Read more

using css -top value to move a div position

Question by Diver Dan

Hi I am not sure if this is the right way to do it but I am trying to position a div tag back
over the previous div element
This is what I have working

example

my css that I have used to get this to work looks like

.page-frame {
background-color: #fff;
padding-top: 40px;
position: relative;
top: -35px;
}

so for the top part the div element looks the way I want it to however the bottom on the element hasn’t adjusted for the -35px;

enter image description here

I have tried adding a clear div after the element however that doesnt help. What do I need to change to remove the space between my .page-frame div and the next div?

Answer by ScottS

The use of position: relative only shifts the appearance of the element in the page, but not the actual “space” it takes up on the page. So what you have done made your visual change to show the element 35px higher, but it does not cause other elements to reflow around it. Probably, what you need to add is a margin-bottom: -35px to get the final effect you want.

EDIT: Added better fiddle example to show reflow with margin.

Answer by Starx

Use position: absolute; instead of relative

Read more

mysql how to select the top ten values and store them into vars?

Question by user1200640

How do I select the top ten values (largest) from a column and store them in php variables ?

I tried this but it is not working :

SELECT counter FROM hitscountervote 
WHERE counter = counter 
ORDER BY counter DESC LIMIT 10

Answer by Starx

Not sure of the exact problem but try this. I added quotes and Limits

SELECT counter FROM hitscountervote 
WHERE counter = 'counter' 
ORDER BY counter DESC LIMIT 0,10
Read more

UTF-8 charset issues from MySQL in PHP

Question by Nick

this is really doing my nut…..

all relevant PHP Output scripts set headers (in this case only one file – the main php script):

header("Content-type: text/html; charset=utf-8");

HTML meta is set in head:

<meta http-equiv="Content-Type" content="text/html; charset=utf-8">

all Mysql tables and related columns set to:

utf8_unicode_ci     Unicode (multilingual), case-insensitive

I have been writing a class to do some translation.. when the class writes to a file using fopen, fputs etc everything works great, the correct chars appear in my output files (Which are written as php arrays and saved to the filesystem as .php or .htm files. eval() brings back .htm files correctly, as does just including the .php files when I want to use them. All good.

Prob is when I am trying to create translation entries to my DB. My DB connection class has the following line added directly after the initial connection:

 mysql_query("SET NAMES utf8, character_set_results = 'utf8', character_set_client = 'utf8', character_set_connection = 'utf8', character_set_database = 'utf8', character_set_server = 'utf8'");

instead of seeing the correct chars, i get the usual crud you would expect using the wrong charset in the DB. Eg:

Propriétés

instead of:

propriétés

don’t even get me started on Russian, Japanese, etc chars! But then using UTF8 should not make any single language charset an issue…

What have I missed? I know its not the PHP as the site shows the correct chars from the included translation .php or .htm files, its only when I am dealing with the MySQL DB that I am having these issues. PHPMyAdmin shows the entries with the wrong chars, so I assume its happening when the PHP “writes” to MySQL. Have checked similar questions here on stack, but none of the answers (all of which were taken care of) give me any clues…

Also, anyone have thoughts on speed difference using include $filename vs eval(file_get_contents($filename)).

Answer by Sebastián Grignoli

You say that you are seeing “the usual crud you would expect using the wrong charset”. But that crud is in fact created by using utf8_encode() on an already UTF8 string, so chances are that you are not using the “wrong encoding” anywhere, but exceeding the times you are encoding into UTF8.

You may take a look into a library I made to fix that kind of problems:

http://stackoverflow.com/a/3521340/290221

Answer by Starx

There is a mysql_set_charset('utf8'); in mysql for that. Run the query at the beginning of another query.

Read more

How to check with PHP does a SQL database already have

Question by Dan Horvat

I’ve tried to find the answer to this question but none of the answers fit.

I have two databases, one has 15.000.000 entries and I want to extract the necessary data and store it in a much smaller database with around 33.000 entries. Both databases are open at the same time. Or at least they should be.

While having the big database open and extracting the entries from it, is it possible to check whether the value already exists in a certain table in the smaller database? I just need some generic way which checks that.

In my code I’m first opening both databases (big one is oddsnavi_push, small one is oddsnavi_baby):

$database = "oddsnavi_push";    
$db_handle = mysql_connect($server, $user_name, $password);
$db_found = mysql_select_db($database, $db_handle);
$database_baby = "oddsnavi_baby";
$db_handle_baby = mysql_connect($server, $user_name, $password);
$db_found_baby = mysql_select_db($database_baby, $db_handle_baby);

And then I’m starting to read and calculate data from oddsnavi_push:

$SQL_SELECT_ALL = "...giant query...";
$result_select_all = mysql_query( $SQL_SELECT_ALL );

while($db_field_all = mysql_fetch_assoc( $result_select_all ) ) {
$SQL_INSERT="INSERT INTO oddsnavi_baby.calc (id, one, two) VALUES ('$id', '$one', '$two')";

It works up until that point. It takes the data which was read (id, one, two) and inserts them in proper columns in oddsnavi_baby table named calc. It does that properly when the oddsnavi_baby is completely empty.

However, I need it to only update the database IF an entry (based on whether a certain ‘id’ exists or not) doesn’t exist.

EDIT: I will rephrase my question. From the query results (big database) I’m getting strings, for every row. For example $string. How do I open the second database and check if oddsnavi_baby.calc table has the $string value in column Events?

Answer by barsju

Skip the check and try with just INSERT IGNORE assuming the Id is a unique key.

http://dev.mysql.com/doc/refman/5.5/en/insert.html

Answer by Starx

Why do you really need multiple database? Amount does not matter tables are just fine, no need to split.

//Multiple links to different databases
$dblink1 = mysqli_connect($localhost, $user, $pass, $db1);
$dblink2 = mysqli_connect($localhost, $user, $pass, $db2);


$id = '1'; // Id to check
$query = "SELECT COUNT(*) FROM `table` WHERE id = '1' LIMIT 1";
$result = mysqli_query($dblink1, $query); //query db 1

if(mysql_num_rows($result)) {
    $query = "INSERT INTO `table` VALUES(.....)";
    $result = mysqli_query($dblink1, $query); //query db 2
}
Read more

Change CSS of Dynamic List Item

Question by Andaero

===UPDATE===

If I remove the style="display: none; from the template and apply the below method as recommended below, the empty container fires when you click on any other list item. What else can be done?

I have an ul list that is dynamically created at run time using jQuery and JSON (Using inline HTML is a template). I need the background CSS style to change when a user clicks on a list item (#navItem). I’ve tried everything under the moon that I can think of from inline class to .appentTo(), etc. What I have below works fine for hard-coded elements but Nothing seems to work with dynamically loaded content. Whats even more confusing is that the classes in the elements within the li tag initiate…???

Any help would be appreciated. Below are my code snippets. Thnx.

HTML:

<div id="navScrollContainer" class="navContentPosition">
    <ul id="navContent">
    // Display as 'None' to prevent a empty containter from showing -->
        <li id="navItem" class="ulFx" style="display: none;">//<-THIS NEEDS TO CHANGE ONCLICK!!
            <a class="navA">
            <h1 class="navH1">.</h1>
            <h2 class="navH2">.</h2>
            <p class="navP">.</p>
            <hr class="navHR" />
        </li>
    </ul>
</div>
<script type="text/javascript">
    $('#navScrollContainer').on('click', '.ulFx', function() {
        $(this).addClass("liFx");
    });
</script>

This is the Function that injects the data into the DOM as a list:

function loadNav(url, container, appendE) {
    $.getJSON(url, function(data) {

        $.each(data.items, function() {
            var newItem = $('#' + container).clone();
            // Now fill in the fields with the data
                    newItem.addClass('ulFx');
            newItem.find("h1").text(this.label);
            newItem.find("h2").text(this.title);
            newItem.find("p").text(this.description);
            newItem.find("a").attr("href", this.gotoURL);
            newItem.children().appendTo('#' + appendE);
        });

        $('#navHeaderTitle').text(data.listTitle);
        iniScroll('scrollNav', 'navScrollContainer');
        var target = data.targetKey;
        // transition("#" + pageName, "show");
    });
};

The CSS that need to happen (only on that item) when the user clicks on a Item:

@-webkit-keyframes
liBG {from {
    background-color: transparent
}
50% { background-color: rgba(51,102,255,0.15); }
to {
    background-color: transparent
}
}

.liFx {
    -webkit-animation-name: liBG;
    -webkit-animation-duration: 1s;
    -webkit-animation-fill-mode: forwards;
}

The Class atributes given to the li items:

.navH1 {
    font-size: 18px;
    color: #FFA500;
    text-decoration: underline;
    font-weight: bold;
    margin-top: 8px;
    margin-bottom: 8px;
    margin-left: 15px;
}
.navH2 {
    font-size: 16px;
    color: #999999;
    font-weight: bold;
    margin-top: 5px;
    margin-bottom: 5px;
    margin-left: 25px;
    font-weight: bold;
}
.navP {
    color: #888;
    font-size: 14px;
    text-align: justify;
    margin-top: 5px;
    margin-bottom: 16px;
    margin-left: 25px;
    margin-right: 10px;
}
.navA {
    text-decoration: none;
}
.navHR {
    border: none;
    background-color: #336;
    height: 1px;
}

Answer by Andaero

I added another div and an addClass() method to my function along with Jeff B’s answer above. If the class is hard coded into the tag, it doesnt function.

<ul id="navContent">
    <li id="navItem" style="display: none;">
        <div>//ADDED THIS TAG TO EXCEPT THE CLASS
            <a>
                <h1>.</h1>
                <h2>.</h2>
                <p>.</p>
                <hr/>
            </a>
        </div>
    </li>
</ul>

In my js file:

$.each(data.items, function() {
    var newItem = $('#' + container).clone();
    // Now fill in the fields with the data
    newItem.find("div").addClass("ulFx");//ADDED THIS METHOD
    newItem.find("h1").text(this.label);
    newItem.find("h2").text(this.title);
    newItem.find("p").text(this.description);
    newItem.find("a").attr("href", this.gotoURL);
    newItem.children().appendTo('#' + appendE);
});

Answer by Starx

I am not sure where is the problem, but you are trying to do something as such:

$("#navlink").on('click', function() {
     $("#yourselector").css("backgroundColor", "#ddd"); //change the color
});
Read more
...

Please fill the form - I will response as fast as I can!