Skip to content

Commit

Permalink
Feature: HtaccessContainer::search now supports multidimensional sear…
Browse files Browse the repository at this point in the history
…ched.

Chore: Extended documentation accordingly
  • Loading branch information
tivie committed Dec 9, 2014
1 parent 4856cd6 commit 083cd3a
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 21 deletions.
22 changes: 13 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ By default, prior to serialization, the Parser rewinds the file pointer to the b
$parser->rewindFile(false);
```

### Extending the Parser
#### Extending the Parser
The Parser class provides API points that developers can override. For more information, you can check the code at https://github.com/tivie/php-htaccess-parser/blob/master/src/Parser.php

-----
Expand All @@ -158,7 +158,7 @@ The Parser class provides API points that developers can override. For more info
The default returned object ([HtaccessContainer][2]) implements [ArrayAccess](http://php.net/manual/en/class.arrayaccess.php), so you can access the definitions as you would with an array. The keys of this array are numeric and ordered by their appearance in the original file.


### Retrieving a Token
#### Retrieving a Token
Since the Parser returns an array or array like object, you can retrieve a specific token by it's index:

```php
Expand All @@ -171,7 +171,13 @@ You can also use the `search` method to find a specific token by its name:
$modRewrite = $htaccess->search('modRewrite');
```

### Modifying a Token
You can constrain the search to a specific token type.

```php
$modRewrite = $htaccess->search('modRewrite', Tivie\HtaccessParser\Token\TOKEN_BLOCK);
```

#### Modifying a Token
[**TokenInterface**][1] provides a common API that you can use to manipulate the tokens.

```php
Expand All @@ -180,7 +186,7 @@ $token->setArguments('foo', 'bar', 'baz'); //Changes the Token arguments
```
Keep in mind, however, that with some tokens, an array of arguments doesn't make much sense. For instance, [**Comments Tokens**][5] only expect 1 argument (the actual text of the comment) while [**WhiteLine Tokens**][4] expect none so extra arguments will be **silently ignored**.

### Adding a Token
#### Adding a Token
You can add a token by simply creating and appending it.

```php
Expand All @@ -195,15 +201,15 @@ $newBlock = new Block('modRewrite');
$htaccess->insertAt(4, $newBlock);
```

### Outputting htaccess
In order to output an .htaccess txt file, you can simply cast the [**HtaccessContainer**][2] to string and write the resulting string to a file:
#### Outputting htaccess
In order to output an .htaccess txt file, you can cast the [**HtaccessContainer**][2] to string and write the resulting string to a file:

```php
$output = (string) $htaccess;
file_put_content('.htaccess', $output);
```

You can also use the method `txtSerialize` to control how the output should be:
You can also use the method `txtSerialize` to control how the output should be formatted:

```php
$output = $htaccess->ignoreWhiteLines(true)
Expand All @@ -214,8 +220,6 @@ file_put_content('.htaccess', $output);
NOTE: Keep in mind that ignored elements in the parser won't be available to HtaccessContainer serialize methods.


####

## Contribute
Feel free to contribute by forking or making suggestions.

Expand Down
58 changes: 46 additions & 12 deletions src/HtaccessContainer.php
Original file line number Diff line number Diff line change
Expand Up @@ -124,26 +124,60 @@ public function setIgnoreWhiteLines($ignoreWhiteLines)
}

/**
* Search this object for a Token with a specific name and returns it.
* Search this object for a Token with a specific name and return the first match
*
* @param $name
* @param int $type TOKEN_DIRECTIVE | TOKEN_BLOCK
* @return null|TokenInterface
* @param string $name [required] Name of the token
* @param int $type [optional] TOKEN_DIRECTIVE | TOKEN_BLOCK
* @param bool $deepSearch [optional] If the search should be multidimensional. Default is true
* @return null|TokenInterface Returns the Token or null if none is found
*/
public function search($name, $type = null)
public function search($name, $type = null, $deepSearch = true)
{
if (($index = $this->getIndex($name, $type)) !== null) {
return $this->offsetGet($index);
} else {
return null;
/** @var TokenInterface[] $array */
$array = $this->getArrayCopy();

foreach ($array as $token) {
if ($token->getName() === $name) {
if ($type === null) {
return $token;
}
if ($token->getTokenType() === $type) {
return $token;
}
}
if ($token instanceof Block && $token->hasChildren() && $deepSearch) {
if ($res = $this->deepSearch($token, $name, $type)) {
return $res;
}
}
}
return null;
}

private function deepSearch(Block $parent, $name, $type)
{
foreach ($parent as $token) {
if ($token->getName() === $name) {
if ($type === null) {
return $token;
}
if ($token->getTokenType() === $type) {
return $token;
}
}
if ($token instanceof Block && $token->hasChildren()) {
if ($res = $this->deepSearch($token, $name, $type)) {
return $res;
}
}
}
}

/**
* Search this object for a Token with specific name and returns its index(key)
* Search this object for a Token with specific name and return the index(key) of the first match
*
* @param string $name
* @param int $type
* @param string $name [required] Name of the token
* @param int $type [optional] TOKEN_DIRECTIVE | TOKEN_BLOCK
* @return int|null Returns the index or null if Token is not found
*/
public function getIndex($name, $type = null)
Expand Down
42 changes: 42 additions & 0 deletions tests/HtaccessContainerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,48 @@ public function testOffsetSet3()
$this->testClass['foo'] = $this->createTokenMock();
}

/**
* @covers \Tivie\HtaccessParser\HtaccessContainer::search
*/
public function testSearch()
{
$this->testClass[] = $this->createTokenMock();
$this->testClass[] = $this->createTokenMock();

$mock = $this->getMockBuilder('\Tivie\HtaccessParser\Token\Block')
->setMethods(['getName', 'getTokenType', 'hasChildren'])
->getMock();

$mock->expects($this->any())
->method('getName')
->will($this->returnValue('fooBlock'));

$mock->expects($this->any())
->method('getTokenType')
->will($this->returnValue(TOKEN_BLOCK));

$mock->expects($this->any())
->method('hasChildren')
->will($this->returnValue(TRUE));

$mockChild = $this->getMockBuilder('\Tivie\HtaccessParser\Token\Directive')
->setMethods(['getName', 'getTokenType'])
->getMock();

$mockChild->expects($this->any())
->method('getName')
->will($this->returnValue('fooDirective'));

$mock[] = $this->testClass[] = $this->createTokenMock();
$mock[] = $this->testClass[] = $this->createTokenMock();
$mock[] = $mockChild;

$this->testClass[] = $mock;

self::assertSame($mock, $this->testClass->search('fooBlock', TOKEN_BLOCK, true), "Search method failed to return the correct token");
self::assertSame($mockChild, $this->testClass->search('fooDirective', null, true), "Search method failed to return the correct token");
}

/**
* @covers \Tivie\HtaccessParser\HtaccessContainer::slice
*/
Expand Down

0 comments on commit 083cd3a

Please sign in to comment.