Skip to content

Commit 6eaeb10

Browse files
committed
Reworked number targeting at Util;
Added a changelog; Chnaged the PHAR stub to not fail when reading the hash fails.
1 parent c7b00b5 commit 6eaeb10

File tree

4 files changed

+118
-64
lines changed

4 files changed

+118
-64
lines changed

RELEASE-1.0.0b4

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
Brand new way of manipulating data, and listen...
2+
3+
* A new Util class that abstracts away tons of fancy features, including:
4+
- CRUD operations
5+
- Support of targeting and finding entries by numbers, just like from terminal
6+
- Executing scripts (with the ability to pass typed parameters ala SQL prepared statements)
7+
- Putting and getting files out of RouterOS.
8+
* Client::loop() and Client::completeRequest() no longer fail if there's no reply within "default_socket_timeout" seconds. This means you can now use the "listen" command without also setting up something else to keep the connection busy.
9+
* Client::loop() now accepts timeouts modeled after stream_select()'s, as opposed to a single float value. As before, the default is "no time limit", but is now specified with NULL instead of 0.
10+
* Chnaged the PHAR stub to not fail when reading the hash fails.
11+
* Doc and CS fixes.

src/PEAR2/Net/RouterOS/Util.php

Lines changed: 60 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,6 @@
2020
*/
2121
namespace PEAR2\Net\RouterOS;
2222

23-
/**
24-
* Used as a holder for the entry cache.
25-
*/
26-
use SplFixedArray;
27-
2823
/**
2924
* Values at {@link Util::exec()} can be casted from this type.
3025
*/
@@ -60,7 +55,7 @@ class Util
6055
protected $menu = '/';
6156

6257
/**
63-
* @var SplFixedArray An array with the numbers of entries in the current menu as
58+
* @var array An array with the numbers of entries in the current menu as
6459
* keys, and the corresponding IDs as values.
6560
*/
6661
protected $idCache = null;
@@ -260,9 +255,15 @@ public function exec(
260255
* number. If you're using both Util's methods and other means (e.g.
261256
* {@link Client} or {@link Util::exec()}) to add/move/remove entries, the
262257
* cache may end up being out of date. By calling this method right before
263-
* targeting an entry with a number, you can ensure number accuracy. Note
264-
* that Util's add(), move() and remove() methods automatically clear the
265-
* cache. A change in the menu also clears the cache.
258+
* targeting an entry with a number, you can ensure number accuracy.
259+
*
260+
* Note that Util's {@link move()} and {@link remove()} methods
261+
* automatically clear the cache before returning, while {@link add()} adds
262+
* the new entry's ID to the cache as the next number. A change in the menu
263+
* also clears the cache.
264+
*
265+
* Note also that the cache is being rebuilt unconditionally every time you
266+
* use {@link find()} with a callback.
266267
*
267268
* @return $this The Util object itself.
268269
*/
@@ -295,8 +296,16 @@ public function clearIdCache()
295296
public function find()
296297
{
297298
if (func_num_args() === 0) {
298-
$this->refreshIdCache();
299-
return implode(',', $this->idCache->toArray());
299+
if (null === $this->idCache) {
300+
$idCache = array();
301+
foreach ($this->client->sendSync(
302+
new Request($this->menu . '/print .proplist=.id')
303+
)->getAllOfType(Response::TYPE_DATA) as $response) {
304+
$idCache[] = $response->getArgument('.id');
305+
}
306+
$this->idCache = $idCache;
307+
}
308+
return implode(',', $this->idCache);
300309
}
301310
$idList = '';
302311
foreach (func_get_args() as $criteria) {
@@ -307,21 +316,28 @@ public function find()
307316
$idList .= $response->getArgument('.id') . ',';
308317
}
309318
} elseif (is_callable($criteria)) {
319+
$idCache = array();
310320
foreach ($this->client->sendSync(
311321
new Request($this->menu . '/print')
312322
) as $response) {
313323
if ($criteria($response)) {
314324
$idList .= $response->getArgument('.id') . ',';
315325
}
326+
$idCache[] = $response->getArgument('.id');
316327
}
328+
$this->idCache = $idCache;
317329
} else {
318-
$this->refreshIdCache();
330+
$this->find();
319331
if (is_int($criteria)) {
320-
$idList = $this->idCache[$criteria] . ',';
332+
if (isset($this->idCache[$criteria])) {
333+
$idList = $this->idCache[$criteria] . ',';
334+
}
321335
} else {
322336
$criteria = (string)$criteria;
323337
if ($criteria === (string)(int)$criteria) {
324-
$idList .= $this->idCache[(int)$criteria] . ',';
338+
if (isset($this->idCache[(int)$criteria])) {
339+
$idList .= $this->idCache[(int)$criteria] . ',';
340+
}
325341
} elseif (false === strpos($criteria, ',')) {
326342
$idList .= $criteria . ',';
327343
} else {
@@ -361,7 +377,7 @@ public function find()
361377
public function get($number, $value_name)
362378
{
363379
if (is_int($number) || ((string)$number === (string)(int)$number)) {
364-
$this->refreshIdCache();
380+
$this->find();
365381
if (isset($this->idCache[(int)$number])) {
366382
$number = $this->idCache[(int)$number];
367383
} else {
@@ -513,11 +529,13 @@ public function add(array $values)
513529
foreach ($values as $name => $value) {
514530
$addRequest->setArgument($name, $value);
515531
}
516-
$idList .= $this->client->sendSync($addRequest)->getArgument('ret')
517-
. ',';
532+
$id = $this->client->sendSync($addRequest)->getArgument('ret');
533+
if (null !== $this->idCache) {
534+
$this->idCache[] = $id;
535+
}
536+
$idList .= $id . ',';
518537
$addRequest->removeAllArguments();
519538
}
520-
$this->clearIdCache();
521539
return rtrim($idList, ',');
522540
}
523541

@@ -555,6 +573,14 @@ public function move($numbers, $destination)
555573
/**
556574
* Puts a file on RouterOS's file system.
557575
*
576+
* Puts a file on RouterOS's file system, regardless of the current menu.
577+
* Note that this is a VERY VERY VERY time consuming method - it takes a
578+
* minimum of a little over 4 seconds, most of which are in sleep. It waits
579+
* 2 seconds after a file is first created (required to actually start
580+
* writing to the file), and another 2 seconds after its contents is written
581+
* (performed in order to verify success afterwards). If you want an
582+
* efficient way of transferring files, use (T)FTP.
583+
*
558584
* @param string $filename The filename to write data in.
559585
* @param string $data The data the file is going to have.
560586
* @param bool $overwrite Whether to overwrite the file if it exists.
@@ -606,29 +632,19 @@ public function filePutContents($filename, $data, $overwrite = false)
606632
public function fileGetContents($filename, $tmpScriptName = null)
607633
{
608634
$checkRequest = new Request(
609-
'/file print',
635+
'/file/print',
610636
Query::where('name', $filename)
611637
);
612638
if (1 === count($this->client->sendSync($checkRequest))) {
613639
return false;
614640
}
615-
$name = $this->_exec(
641+
$contents = $this->_exec(
616642
'/system script set $"_" source=[/file get $filename contents]',
617643
array('filename' => $filename),
618644
null,
619645
$tmpScriptName,
620646
true
621647
);
622-
$printRequest = new Request(
623-
'/system script print .proplist=source',
624-
Query::where('name', $name)
625-
);
626-
$contents = $this->client->sendSync(
627-
$printRequest
628-
)->getArgument('source');
629-
$removeRequest = new Request('/system script remove');
630-
$removeRequest->setArgument('numbers', $name);
631-
$this->client->sendSync($removeRequest);
632648
return $contents;
633649
}
634650

@@ -653,31 +669,11 @@ protected function doBulk($what, array $args = array())
653669
return $this->client->sendSync($bulkRequest);
654670
}
655671

656-
/**
657-
* Refresh the id cache, if needed.
658-
*
659-
* @return void
660-
*/
661-
protected function refreshIdCache()
662-
{
663-
if (null === $this->idCache) {
664-
$idCache = array();
665-
foreach ($this->client->sendSync(
666-
new Request($this->menu . '/print .proplist=.id')
667-
)->getAllOfType(Response::TYPE_DATA) as $response) {
668-
$id = $response->getArgument('.id');
669-
$idCache[hexdec(substr($id, 1))] = $id;
670-
}
671-
ksort($idCache, SORT_NUMERIC);
672-
$this->idCache = SplFixedArray::fromArray(array_values($idCache));
673-
}
674-
}
675-
676672
/**
677673
* Executes a RouterOS script.
678674
*
679-
* Same as the public equivalent, with the addition of allowing you not to
680-
* remove the script after you're done.
675+
* Same as the public equivalent, with the addition of allowing you to get
676+
* the contents of the script post execution, instead of removing it.
681677
*
682678
* @param string $source A script to execute.
683679
* @param array $params An array of local variables to make available in
@@ -694,7 +690,7 @@ protected function refreshIdCache()
694690
* "/system script" under a random name (prefixed with the computer's
695691
* name), and is removed after execution. To eliminate any possibility
696692
* of name clashes, you can specify your own name.
697-
* @param bool $keep Whether to keep the script after execution.
693+
* @param bool $get Whether to keep the script after execution.
698694
*
699695
* @return ResponseCollection|string If the script was not added
700696
* successfully before execution, the ResponseCollection from the add
@@ -706,7 +702,7 @@ private function _exec(
706702
array $params = array(),
707703
$policy = null,
708704
$name = null,
709-
$keep = false
705+
$get = false
710706
) {
711707
$request = new Request('/system/script/add');
712708
if (null === $name) {
@@ -733,13 +729,17 @@ private function _exec(
733729
$request->setArgument('number', $name);
734730
$result = $this->client->sendSync($request);
735731

736-
if ($keep) {
737-
return $name;
738-
} else {
739-
$request = new Request('/system/script/remove');
740-
$request->setArgument('numbers', $name);
741-
$this->client->sendSync($request);
732+
if ($get) {
733+
$result = $this->client->sendSync(
734+
new Request(
735+
'/system/script/print .proplist="source"',
736+
Query::where('name', $name)
737+
)
738+
)->getArgument('source');
742739
}
740+
$request = new Request('/system/script/remove');
741+
$request->setArgument('numbers', $name);
742+
$this->client->sendSync($request);
743743
}
744744

745745
return $result;

stub.php

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,29 @@
2929
exit(1);
3030
}
3131

32-
if (!in_array('phar', $missing_extensions)) {
33-
$phar = new Phar(__FILE__);
34-
$sig = $phar->getSignature();
35-
echo "{$sig['hash_type']} hash: {$sig['hash']}\n\n";
32+
if (extension_loaded('phar')) {
33+
try {
34+
$phar = new Phar(__FILE__);
35+
$sig = $phar->getSignature();
36+
echo "{$sig['hash_type']} hash: {$sig['hash']}\n\n";
37+
} catch(Exception $e) {
38+
echo <<<HEREDOC
39+
The PHAR extension is available, but was unable to read this PHAR file's hash.
40+
Regardless, you should not be having any trouble using the package by directly
41+
including the archive.
42+
43+
Exception details:
44+
HEREDOC
45+
. $e . "\n\n";
46+
}
47+
} else {
48+
echo <<<HEREDOC
49+
If you wish to use this package directly from this archive, you need to install
50+
and enable the PHAR extension. Otherwise, you must instead extract this archive,
51+
and include the autoloader.
52+
53+
54+
HEREDOC;
3655
}
3756

3857
if (function_exists('stream_socket_client')) {

tests/UtilStateAlteringFeaturesTest.php

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,30 @@ public function testAdd()
6363
$this->assertSame($beforeCount, $postCount);
6464
}
6565

66+
/**
67+
* @depends testAdd
68+
*
69+
* @return void
70+
*/
71+
public function testAddToCache()
72+
{
73+
$this->util->changeMenu('/queue/simple');
74+
$beforeCount = substr_count($this->util->find(), ',');
75+
$this->assertRegExp(
76+
'/^' . self::REGEX_ID . '$/',
77+
$id = $this->util->add(array('name' => TEST_QUEUE_NAME))
78+
);
79+
$afterCount = substr_count($this->util->find(), ',');
80+
$this->assertSame(1 + $beforeCount, $afterCount);
81+
82+
$removeRequest = new Request('/queue/simple/remove');
83+
$removeRequest->setArgument('numbers', $id);
84+
$this->client->sendSync($removeRequest);
85+
86+
$postCount = substr_count($this->util->clearIdCache()->find(), ',');
87+
$this->assertSame($beforeCount, $postCount);
88+
}
89+
6690
/**
6791
* @depends testAdd
6892
*

0 commit comments

Comments
 (0)