diff --git a/.gitignore b/.gitignore index 9f9c3c7..b16b17e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ /.idea /.DS_Store /composer.lock +/build /vendor diff --git a/.travis.yml b/.travis.yml index 0bb31c9..fd4ca46 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,4 +10,8 @@ install: script: - vendor/bin/phpcs -n --standard=PSR12 --ignore=./vendor/ --extensions=php ./ + - mkdir -p build/logs - vendor/bin/phpunit + +after_success: + - travis_retry php vendor/bin/php-coveralls -v diff --git a/README.md b/README.md index 86711b4..a25e8b4 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,9 @@ # html-query + +[![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE) +[![Build Status](https://api.travis-ci.org/xinningsu/html-query.svg?branch=master)](https://travis-ci.org/xinningsu/html-query) +[![Coverage Status](https://coveralls.io/repos/github/xinningsu/html-query/badge.svg?branch=master)](https://coveralls.io/github/xinningsu/html-query) + A jQuery-like html processor written in PHP # Quick Start @@ -35,6 +40,32 @@ echo $hq('.content')->text(); //this is content... ``` +### Set contents +```php + + + Html Query + + +

this is title

+
this is content...
+ + +'; +$hq = HQ::html($html); + +echo $hq('.title')->html('this is new title')->html(); +//this is new title + +echo $hq('.content')->html('this is new content...'); +//this is new content... + +echo $hq('.content')->text('this is new content...')->html(); +//this is new content... +``` + ### Get attributes ```php outerHtml(); # License -MIT +[MIT](./LICENSE) diff --git a/composer.json b/composer.json index e523063..0dabfb4 100644 --- a/composer.json +++ b/composer.json @@ -17,7 +17,8 @@ }, "require-dev": { "phpunit/phpunit": "~7.5", - "squizlabs/php_codesniffer": "3.*" + "squizlabs/php_codesniffer": "3.*", + "php-coveralls/php-coveralls": "^2.1" }, "autoload": { "psr-4": { @@ -29,4 +30,4 @@ "tests/" ] } -} \ No newline at end of file +} diff --git a/phpunit.xml b/phpunit.xml index 89d9a38..94fcfd0 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -14,4 +14,12 @@ ./tests/ + + + + + + ./src + + diff --git a/src/HtmlQuery.php b/src/HtmlQuery.php index 333fccc..2ff54ca 100644 --- a/src/HtmlQuery.php +++ b/src/HtmlQuery.php @@ -434,7 +434,7 @@ public function getVal() return $selected->getAttr('value'); } - $fistChild = $ht->children('option:first-child'); + $fistChild = $ht->xpathFind('child::*[1]'); if ($fistChild->count()) { return $fistChild->getAttr('value'); } @@ -456,7 +456,7 @@ public function setVal(string $value) { return $this->each(function (DOMNode $node) use ($value) { if (!($node instanceof DOMElement)) { - return null; + return; } switch ($node->tagName) { @@ -694,10 +694,10 @@ public function setCss(string $name, ?string $value) $css = Helper::splitCss($style); if (!array_key_exists($name, $css)) { - $keys = array_keys($css); + $allKeys = array_keys($css); $arr = array_combine( - $keys, - array_change_key_case($keys, CASE_LOWER) + $allKeys, + array_map('strtolower', $allKeys) ); $keys = array_keys($arr, strtolower($name)); @@ -733,10 +733,10 @@ public function removeCss(string $name) unset($css[$name]); $removed = true; } else { - $keys = array_keys($css); + $allKeys = array_keys($css); $arr = array_combine( - $keys, - array_change_key_case($keys, CASE_LOWER) + $allKeys, + array_map('strtolower', $allKeys) ); $keys = array_keys($arr, strtolower($name)); diff --git a/src/Selector.php b/src/Selector.php index b62efa0..a38ab60 100644 --- a/src/Selector.php +++ b/src/Selector.php @@ -466,11 +466,7 @@ protected function relationResolve(string $relation, ?string $until = null) */ protected function shouldResolve(Closure $function, $index = 0) { - try { - $reflection = new ReflectionFunction($function); - } catch (ReflectionException $exception) { - return false; - } + $reflection = new ReflectionFunction($function); $parameters = $reflection->getParameters(); if ($parameters && array_key_exists($index, $parameters)) { diff --git a/tests/AttributeTest.php b/tests/AttributeTest.php index 07941e0..9fbb56c 100644 --- a/tests/AttributeTest.php +++ b/tests/AttributeTest.php @@ -65,6 +65,8 @@ public function testAttr() 100, $hq->find('img')->eq(1)->setAttr('width', 100)->attr('width') ); + + $this->assertNull($hq->attr('none')); } public function testRemoveAttr() @@ -152,6 +154,8 @@ public function testHasAttr() $this->assertTrue($hq->find('img')->eq(0)->hasAttr('alt')); $this->assertFalse($hq->find('img')->eq(1)->hasAttr('alt')); + + $this->assertFalse($hq->hasAttr('alt')); } public function testProp() @@ -229,10 +233,15 @@ public function testData() $hq->find('.p-0')->data('id', 2)->outerHtml() ); - $hq->find('.p-0')->data( - 'content', - ['id' => 1, 'tag' => 'dom'] - )->removeData('id'); + $this->assertEquals( + '

test

', + $hq->find('.p-0')->data(['name' => 'test'])->outerHtml() + ); + + $hq->find('.p-0') + ->data('content', ['id' => 1, 'tag' => 'dom']) + ->removeData('id') + ->removeData('name'); $this->assertEquals( '

test

', @@ -350,6 +359,11 @@ public function testRemoveClass() '

test

', $hq->find('p')->removeClass()->outerHtml() ); + + $this->assertEquals( + '

test

', + $hq->find('p')->removeClass('test')->outerHtml() + ); } public function testToggleClass() @@ -395,6 +409,11 @@ public function testToggleClass() '

test

', $hq->find('p')->toggleClass(null, false)->outerHtml() ); + + $this->assertEquals( + '

test

', + $hq->find('p')->toggleClass('foo')->outerHtml() + ); } public function testCss() @@ -477,5 +496,22 @@ public function testCss() ', $hq->outerHtml() ); + + $this->assertNull($hq->find('.content')->css('none')); + + $hq->find('img')->eq(0)->css('WIDTH', '100px'); + $this->assertEquals('100px', $hq->find('img')->eq(0)->css('width')); + + $hq->find('img')->eq(0)->css('width', '99px'); + $this->assertEquals( + '', + $hq->find('img')->eq(0)->outerHtml() + ); + + $hq->find('img')->eq(0)->removeCss('WIDTH'); + $this->assertEquals( + '', + $hq->find('img')->eq(0)->outerHtml() + ); } } diff --git a/tests/ContentTest.php b/tests/ContentTest.php index 9c0a3c8..76428bd 100644 --- a/tests/ContentTest.php +++ b/tests/ContentTest.php @@ -53,6 +53,28 @@ public function testVal() ->val("It's really good.") ->val() ); + + $hq->find('option')->removeAttr('selected'); + $this->assertEquals( + '1', + $hq->find("select[name='type']")->val() + ); + + $hq->val('test'); + $this->assertNull($hq->val()); + $this->assertNull($hq->find('form')->val()); + + $html = ' +
+ +
+ '; + $hq = HQ::html($html); + $this->assertNull($hq->find("select[name='type']")->val()); + + $hq->find("select[name='type']")->val(2); + $this->assertNull($hq->find("select[name='type']")->val()); } public function testHtml() diff --git a/tests/ExampleTest.php b/tests/ExampleTest.php index 83bfcc9..e6d1f22 100644 --- a/tests/ExampleTest.php +++ b/tests/ExampleTest.php @@ -5,7 +5,7 @@ class ExampleTest extends TestCase { - public function testExample1() + public function testGetContents() { $html = ' @@ -38,7 +38,37 @@ public function testExample1() ); } - public function testExample2() + public function testSetContents() + { + $html = ' + + + Html Query + + +

this is title

+
this is content...
+ + + '; + $hq = HQ::html($html); + + $this->assertEquals( + 'this is new title', + $hq('.title')->html('this is new title')->html() + ); + $this->assertEquals( + 'this is new content...', + $hq('.content')->html('this is new content...')->html() + ); + + $this->assertEquals( + 'this is new content...', + $hq('.content')->text('this is new content...')->html() + ); + } + + public function testGetAttributes() { $html = '
@@ -75,7 +105,7 @@ public function testExample2() ); } - public function testExample3() + public function testChangeAttributes() { $html = '
@@ -136,7 +166,7 @@ public function testExample3() ); } - public function testExample4() + public function testChangeStructure() { $html = '
diff --git a/tests/NodeTest.php b/tests/NodeTest.php index ad0d8c4..bf1d0c3 100644 --- a/tests/NodeTest.php +++ b/tests/NodeTest.php @@ -1,7 +1,7 @@ find('.image')->html() ); + $exception = null; + try { + $hq->find('p.foo')->wrap( + 'no html tag' + ); + } catch (Exception $exception) { + } + $this->assertInstanceOf(Exception::class, $exception); + $this->assertEquals( + 'Invalid wrap html format.', + $exception->getMessage() + ); $html = '
@@ -111,6 +123,19 @@ public function testWrapInner() ->html() ); + $exception = null; + try { + $hq->find('img')->wrapInner( + 'no html tag' + ); + } catch (Exception $exception) { + } + $this->assertInstanceOf(Exception::class, $exception); + $this->assertEquals( + 'Invalid wrap html format.', + $exception->getMessage() + ); + $html = '

Author: Thomas Su @@ -302,6 +327,21 @@ public function testUnwrapSelf() '', trim($hq->find('div.image')->html()) ); + + $html = ' +

    +
  • PHP
  • +
+ '; + $hq = HQ::html($html); + $hq->unwrapSelf(); + // won't unwrap if no parent node + $this->assertHtmlEquals( + '
    +
  • PHP
  • +
', + $hq->outerHtml() + ); } public function testBefore() @@ -909,6 +949,17 @@ public function testPrepend() ', $hq->outerHtml() ); + + $html = '
    '; + $hq = HQ::html($html); + $hq->find('ul')->prepend('
  • js
  • '); + $this->assertHtmlEquals( + ' +
      +
    • js
    • +
    ', + $hq->find('ul')->outerHtml() + ); } public function testPrependTo() @@ -1066,6 +1117,21 @@ public function testReplaceWith()
  • html
  • ', $hq->find('.ul')->html() ); + + $html = ' +
      +
    • PHP
    • +
    + '; + $hq = HQ::html($html); + $hq->replaceWith('
    • dom
    '); + // won't replace if no parent node + $this->assertHtmlEquals( + '
      +
    • PHP
    • +
    ', + $hq->outerHtml() + ); } public function testReplaceAll() diff --git a/tests/ResolverTest.php b/tests/ResolverTest.php index ec0cc06..b206f9b 100644 --- a/tests/ResolverTest.php +++ b/tests/ResolverTest.php @@ -80,6 +80,11 @@ public function testXpathQuery() ); $this->assertEquals([], $nodes); + $this->assertEquals( + [], + $this->protectMethod($hq, 'xpathQuery')('^&9*') + ); + $nodes = $this->protectMethod($hq, 'xpathQuery')( Helper::toXpath('#foo p') ); diff --git a/tests/SelectionTest.php b/tests/SelectionTest.php index c1665d7..c962d60 100644 --- a/tests/SelectionTest.php +++ b/tests/SelectionTest.php @@ -1,7 +1,7 @@ assertCount(3, $images); $this->assertEquals('1.png', $images->last()->attr('src')); + + $exception = null; + try { + $images[] = 'incorrect content'; + } catch (Exception $exception) { + } + $this->assertInstanceOf(Exception::class, $exception); + $this->assertEquals( + 'Expect an instance of DOMNode, string given.', + $exception->getMessage() + ); } public function testIterator() diff --git a/tests/SelectorTest.php b/tests/SelectorTest.php index 6d70d7d..31dc443 100644 --- a/tests/SelectorTest.php +++ b/tests/SelectorTest.php @@ -863,6 +863,7 @@ public function testIs() $this->assertFalse($hq->find('img')->eq(1)->is('.foo')); $this->assertFalse($hq->find('img')->slice(1)->is('.foo')); + $this->assertFalse($hq->find('.null')->slice(1)->is('.foo')); } public function testInvoke()