Philipp Hoffmann

my octopress blog.

Your PHP Array Indices Getting Messed Up When Unsetting Values?

| Comments

Thats because in PHP arrays are internally handled like hashes. Let me give you an example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<?php
// Lets assumme we have an array of numbers
$numbers = array(1, 2, 3, 4, 5);

// Which we are going to inspect
var_dump($numbers);

// Output is
/*
array(4) {
 [0] => int(1)
 [1] => int(2)
 [2] => int(3)
 [3] => int(4)
 [4] => int(5)
}
*/

// And we are going to unset the 3rd element
unset($numbers[2]);

// Lets inspect again
var_dump($numbers);

// Output is
/*
array(4) {
 [0] => int(1)
 [1] => int(2)
 [3] => int(4)
 [4] => int(5)
}
*/
?>

As you can see all other indices dont get touched, we now have four elements and the last index (or better key) is still 4.

So far so good, but how do we fix this. Well, there are two options. You can re-index the array after unsetting a value using array_values or, even better, use array_splice to delete a value off an array (yes, this is similar to the splice function in Javascript).

Let me show you the first option using array_values and the example from above:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?php
// Again, an array of 5 numbers
$numbers = array(1, 2, 3, 4, 5);

// Unsetting the 3rd element
unset($numbers[2]);

// And re-indexing the array
$numbers = array_values($numbers);

// Inspecting the array
var_dump($numbers);

// And there you go
/*
array(4) {
 [0] => int(1)
 [1] => int(2)
 [2] => int(4)
 [3] => int(5)
}
*/
?>

Great, 3rd index got unset, last index is now 3. Second option, using array_splice only takes one line to delete the element:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php
// 5 numbers
$numbers = array(1, 2, 3, 4, 5);

// Unsetting 1 element at index 2 (3rd element of course)
array_splice($numbers, 2, 1);

// Inspecting the array again
var_dump($numbers);

// Yay
/*
array(4) {
 [0] => int(1)
 [1] => int(2)
 [2] => int(4)
 [3] => int(5)
}
*/
?>

Good, we deleted the third element, last index is 3, good job :–)

Symfony 2 - Get the CSRF-Token of a Form in a Twig Template

| Comments

You probably already know that you can get the value of each widget of a form using

1
form.vars.value.{widget_name}

in your Twig template (where {widget_name} is the name of the widget you are trying to get the value of). However, when trying to get the CSRF-Token this way, you will get an error that the variable _token does not exist. To access the CSRF-Token of a Symfony 2 form in Twig you have to use

1
form._token.vars.value

This way you can use it in JavaScripts for example (I actually used it to dynamically build post-delete-buttons).

Using Java Static Nested Helper Classes

| Comments

Helper classes are classes that summarize methods you need throughout your project that don’t actually provide any business logic. Since these methods usually don’t depend on any object they are implemented as static methods like this:

1
2
3
4
5
public class ProjectHelpers {
  public static String hashPassword(String password) {
    // do some kind of hashing
  }
}

This static helper method can be used anywhere in your project by a static call like this:

1
String myHashedPassword = ProjectHelpers.hashPassword(myPassword);

This is pretty simple but also very useful. However, sometimes your “helper-logic” is a bit more complex and you would wrap it into a separate class. You can then still use the idea of helpers and nest a separate class into your helper class like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class ProjectHelpers {
  public static class StringAnalyzer {
    private analyzeString;

    public StringAnalyzer(String analyzeString) {
      this.analyzeString = analyzeString;
    }
    public int countVocals() {
      // count vocals
    }
    public int countConsonants {
      // count consonants
    }
  }
}

The class StringAnalyzer is called a “static nested class” or “static inner class”. To use this class, just use it like any other class but remember that it is a static member, so you have to use it like this:

1
ProjectHelpers.StringAnalyzer myAnalyzer = new ProjectHelpers.StringAnalyzer();

This is a great way to separate small helper methods and classes from your business logic into helper classes. Declaring the members being static, no instantiation of the helper class is necessary, it just acts like a repository for all the little helpers you need throughout your project. Simple, useful and clean.

A Bulletproof Pattern for Creating Doctrine Subqueries of Any Complexity

| Comments

Doctrine subqueries can be very frustrating. They sometimes work but as soon as you reach a certain complexity level, Doctrine just can’t handle things anymore. I will show you how to write subqueries in Doctrine which you can nest in as many levels as you want without Doctrine complaining about it and still using the DQL (Doctrine Query Language).

Notice that this post refers to Doctrine Version 1.2. Version 2 of Doctrine is already released but many developers still use symfony 1.3/1.4 which ships with Doctrine 1.2.

A lot of people suggest embedding subqueries into the where() function of Doctrine but this will only work until a certain level. At some point Doctrine gets confused parsing the subqueries. This results in queries that are not completely parsed and thus throw errors when executed. The solution is to explicitly tell Doctrine about the subquery. I am going to use an example query which is short enough to understand the solution pattern. Lets say I have two tables, one table for movies and and one for movies I already saw. In my query I want to check if the movie “Prometheus” (in a Movie-Table) is one of the movies I already saw (by checking if the name exists in a SeenMovie-Table). Lets have a look at the sample query:

1
2
3
4
5
6
7
// nest subquery into the where condition
$q = Doctrine_Query::create()
  ->from('Movie m')
  ->where('name = ?', 'Prometheus')
  ->where('EXISTS (SELECT * FROM SeenMovie sm WHERE m.name=sm.name)')
  ->execute()
;

We have a simple select with a nested subselect in the where condition. I know that this is not very complex and Doctrine can surely handle this. But it is easier to understand the principle using this simple example (and I like the movie “Prometheus” :-P). You can then easily use the pattern on more complex queries. So here is how to tell Doctrine about the nested subquery:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// build root query
$query = Doctrine_Query::create()
  ->from('Movie m')
  ->where('name = ?', 'Prometheus')
;

// build subquery
$subquery = $query->createSubquery()
  ->from('SeenMovie sm')
  ->where('m.name = sm.name')
;

// nest subquery and execute
$query->where('EXISTS (' . $subquery->getDql() . ')')->execute();

What I did is, I created the subquery separately from the main query by using $query->createSubquery(). A new subquery is created and linked to the main query. This replaces Doctrine_Query::create() when creating regular queries. Everything after $query->createSubquery() is exactly the same as if you were writing a regular query. So you can write your subquery just like any other query. You can even nest another subquery by continuing the pattern. Then you call $subquery->getDql() to let Doctrine “render” the subquery. After that you can embed it into the main query and execute it. The result is the same as before but you excplicitely told Doctrine about the subquery. This helped me in a much more complex situation and I’m sure it will help you too :–)

Browsers Automatically Submit Single Input Field Forms on Enter (and How to Fix That)

| Comments

Normally browsers will not submit forms when the enter key is pressed. You have to implement this kind of feature via JavaScript (and you probably did already at some point). However if your form only has ONE single input field most browsers will submit the form when the enter key is pressed. You don’t even need a submit button for this to happen. This is deeply rooted in the HTML 2.0 specification (you can read about this here). I guess it is supposed to be some kind of feature. I found it very frustrating because I didn’t want my form to be submitted when the enter key is press and I tried everything to prevent this from happening, from unbinding the key events to blocking the event from bubbling up. Nothing helped. It took me quiet a while until I figured out that this is because my form only has one input field. Apparently, there is only one way to solve this problem. Right, you guessed it, add another input field and hide it via CSS:

1
2
3
4
<form action="/search.php" method="get">
  <input type="text" name="keyword" />
  <input type="text" name="formsubmitfix" style="display: none;" />
</form>

This will make it work. But you end up with a messy url when submitting the form: /search.php?keyword=test&formsubmitfix;=. This is not a very satisfying solution. Making the input a hidden field will not work either:

1
2
3
4
<form action="/search.php" method="get">
  <input type="text" name="keyword" />
  <input type="hidden" name="formsubmitfix" />
</form>

Despite the fact that the resulting URL is still messy, it also doesnt prevent the form from being submitted when the enter key is pressed. What does help is the following:

1
2
3
4
<form action="/search.php" method="get">
  <input type="text" name="keyword" />
  <input type="text" style="display: none;" />
</form>

Hide the input field via CSS and don’t give it a name. This way the browser recognizes multiple input fields but the resulting URL does not contain the input field we added to fix the problem, voilá: /search.php?keyword=test Exactly what we wanted :–)

How to Discard the Query String in a RewriteRule (Apache, Mod_rewrite)

| Comments

Removing the query string in a rewrite rule of Apache’s module mod_rewrite is a bit tricky. Let’s say you want to redirect the url http://www.example.com?query=test to http://www.example.com/noqueries in Apache with mod_rewrite enabled. Rewriting the URL is no problem but Apache always appends the original query string (?query=test) to the resulting URL which we don’t want in this example. If you’re using Apache 2.4 or later you can use the QSD option (qsdiscard) to remove the query string like this:

1
2
RewriteCond %{QUERY_STRING} ^query=test$
RewriteRule ^/$ /noqueries [QSD,R=301,L]

However if you’re using an earlier version of Apache (like 2.2) this solution won’t work. We have to use a little trick to make this happen:

1
2
RewriteCond %{QUERY_STRING} ^query=test$
RewriteRule ^/$ /noqueries? [R=301,L]

Notice that instead of setting the QSD option we added the question mark to the result URL. This generates the URL we wished for (http://www.example.com/noqueries) adding a new (empty) query string. The original query string is completely discarded. Have fun url-rewriting ;–)

Flexible Domain Mapping to Symfony Apps

| Comments

Here is a quick tip for your symfony 1.3/1.4 project (this probably works with other versions as well) hosted on an Apache webserver: So you fleshed out your symfony project and you ended up with several apps, all being available under their controller name frontend.php, anotherfrontend.php etc. For your routing (and maybe SEO purposes) its a bit unsatisfying that only one app in the project can be available without adressing its front controller (using the no_script_name setting in settings.yml). However, if you do have multiple domains, you can map each domain to a symfony app in your project very flexibly by modifying .htaccess in your symfony web folder. The stock file should look like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Options +FollowSymLinks +ExecCGI

<IfModule mod_rewrite.c>
RewriteEngine On

# uncomment the following line, if you are having trouble
# getting no_script_name to work
#RewriteBase /

# we skip all files with .something
#RewriteCond %{REQUEST_URI} \..+$
#RewriteCond %{REQUEST_URI} !\.html$
#RewriteRule .* - [L]

# we check if the .html version is here (caching)
RewriteRule ^$ index.html [QSA]
RewriteRule ^([^.]+)$ $1.html [QSA]
RewriteCond %{REQUEST_FILENAME} !-f

# no, so we redirect to our front web controller
RewriteRule ^(.*)$ index.php [QSA,L]
</IfModule>

For each domain you want to redirect to another app you then insert the following lines into the rewrite rules:

1
2
RewriteCond %{HTTP_HOST} ^(www\.)?example.com$
RewriteRule ^$ exampleapp.php [L]

This will redirect the domain www.anotherdomain.com to the app controller exampleapp.php. Of course these are just examples. You need to modify this for your issues. You could, for instance use regular expressions to cover multiple domains or you could redirect the domain to a certain route instead to the front controller. You can also use this pattern for further domain routings by just inserting more of these rules. Your final result look something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Options +FollowSymLinks +ExecCGI

<IfModule mod_rewrite.c>
RewriteEngine On

# uncomment the following line, if you are having trouble
# getting no_script_name to work
#RewriteBase /

RewriteCond %{HTTP_HOST} ^(www\.)?example.com$
RewriteRule ^$ exampleapp.php [L]

# we skip all files with .something
#RewriteCond %{REQUEST_URI} \..+$
#RewriteCond %{REQUEST_URI} !\.html$
#RewriteRule .* - [L]

# we check if the .html version is here (caching)
RewriteRule ^$ index.html [QSA]
RewriteRule ^([^.]+)$ $1.html [QSA]
RewriteCond %{REQUEST_FILENAME} !-f

# no, so we redirect to our front web controller
RewriteRule ^(.*)$ index.php [QSA,L]
</IfModule>

This is my solution for routing multiple domains to symfony apps, I hope you like it :–)

How to View Any Git Repository File Without Checking It Out

| Comments

Here is how to have a quick look into any file in your git repository without checking it out or overwriting your working copy.

1
git show master:path/to/file/file.xml

This will show file.xml of the master branch. Git will echo the contents of the file to the standard output. So to actually save a temporary copy of the file for inspection you can just redirect the output into a new file:

1
git show test:path/to/file/file.xml > temp_file.xml

or pipe it into your favorite editor like this

1
git show test:path/to/file/file.xml | vim -

You can even look into files in the origin repository:

1
git show origin:path/to/file/file.xml

There is a lot more you can do with git show like showing diffs. Check out git help show for more information.