Skip to content

Commit da52ad5

Browse files
committed
Merge branch 'release/0.6.33'
2 parents 9e409c2 + 4621c62 commit da52ad5

File tree

16 files changed

+380
-28
lines changed

16 files changed

+380
-28
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@ public_html/
99
build/
1010
.phpunit.result.cache
1111
/examples/test.log
12+
/examples/bad/test.log

.version.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@
22
"strategy": "semver",
33
"major": 0,
44
"minor": 6,
5-
"patch": 32,
5+
"patch": 33,
66
"build": 0
77
}

composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@
1616
"neuron-php/application": "0.6.*",
1717
"neuron-php/routing": "^0.6.8",
1818
"symfony/yaml": "^6.4",
19-
"league/commonmark": "^2.6"
19+
"league/commonmark": "^2.6",
20+
"mikey179/vfsstream": "^1.6"
2021
},
2122
"require-dev": {
2223
"phpunit/phpunit": "9.*",

examples/bad/config.yaml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
logging:
2+
destination: \Neuron\Log\Destination\File
3+
format: \Neuron\Log\Format\PlainText
4+
file: test.log
5+
level: debug
6+
7+
views:
8+
path: views
9+
10+
system:
11+
timezone: US/Eastern
12+
base_path: examples/bad
13+

examples/bad/config/routes.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
invalid_yaml:
2+
key1: value1
3+
key2: val

examples/config/config.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,4 @@ views:
1010
system:
1111
timezone: US/Eastern
1212
base_path: examples
13+
routes_path: examples/config

examples/config/routes.yaml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,29 @@ routes:
44
method: POST
55
controller: App\Controllers\AuthController@login
66
request: login
7+
78
test:
89
route: /test
910
method: POST
1011
controller: Mvc\TestController@test
1112
request: test
13+
14+
put:
15+
route: /test_put
16+
method: PUT
17+
controller: Mvc\TestController@test
18+
19+
delete:
20+
route: /test_delete
21+
method: DELETE
22+
controller: Mvc\TestController@test
23+
1224
no_request:
1325
route: /no_request
1426
method: GET
1527
controller: Mvc\TestController@no_request
28+
29+
bad_request:
30+
route: /bad_request
31+
method: GET
32+
controller: Mvc\TestController@bad_request

src/Mvc/Application.php

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use Neuron\Core\Exceptions\BadRequestMethod;
88
use Neuron\Core\Exceptions\MissingMethod;
99
use Neuron\Core\Exceptions\NotFound;
10+
use Neuron\Core\Exceptions\Validation;
1011
use Neuron\Data\Setting\Source\ISettingSource;
1112
use Neuron\Log\Log;
1213
use Neuron\Mvc\Controllers\Factory;
@@ -28,6 +29,8 @@ class Application extends Base
2829
private string $_RoutesPath;
2930
private Router $_Router;
3031
private array $_Requests = [];
32+
private bool $_CaptureOutput = false;
33+
private ?string $_Output = '';
3134

3235
/**
3336
* Application constructor.
@@ -43,7 +46,7 @@ public function __construct( string $Version, ?ISettingSource $Source = null )
4346

4447
Registry::getInstance()->set( 'BasePath', $this->getBasePath() );
4548

46-
$RoutesPath = $this->getSetting( 'routes_path', 'paths' );
49+
$RoutesPath = $this->getSetting( 'routes_path', 'system' );
4750
if( $RoutesPath )
4851
{
4952
$this->setRoutesPath( $RoutesPath );
@@ -53,6 +56,32 @@ public function __construct( string $Version, ?ISettingSource $Source = null )
5356
$this->loadRoutes();
5457
}
5558

59+
/**
60+
* @param bool $CaptureOutput
61+
* @return $this
62+
*/
63+
public function setCaptureOutput( bool $CaptureOutput ): Application
64+
{
65+
$this->_CaptureOutput = $CaptureOutput;
66+
return $this;
67+
}
68+
69+
/**
70+
* @return bool
71+
*/
72+
public function getCaptureOutput(): bool
73+
{
74+
return $this->_CaptureOutput;
75+
}
76+
77+
/**
78+
* @return string
79+
*/
80+
public function getOutput(): ?string
81+
{
82+
return $this->_Output;
83+
}
84+
5685
/**
5786
* @return string
5887
*/
@@ -191,7 +220,16 @@ protected function onStart(): bool
191220
*/
192221
protected function onRun() : void
193222
{
194-
echo $this->_Router->run( $this->getParameters() );
223+
$Output = $this->_Router->run( $this->getParameters() );
224+
225+
if( !$this->_CaptureOutput )
226+
{
227+
echo $Output;
228+
}
229+
else
230+
{
231+
$this->_Output = $Output;
232+
}
195233
}
196234

197235
/**
@@ -270,7 +308,7 @@ protected function loadRoutes(): void
270308
catch( ParseException $exception )
271309
{
272310
Log::error( "Failed to load routes: ".$exception->getMessage() );
273-
return;
311+
throw new Validation( $exception->getMessage(), [] );
274312
}
275313

276314
foreach( $Data[ 'routes' ] as $Route )

src/Mvc/Views/Markdown.php

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
1010
use League\CommonMark\Extension\Footnote\FootnoteExtension;
1111
use League\CommonMark\MarkdownConverter;
12+
use Neuron\Core\Exceptions\NotFound;
1213
use Neuron\Patterns\Registry;
1314

1415
/**
@@ -36,11 +37,13 @@ public function render( array $Data ): string
3637
$Path = "$BasePath/resources/views";
3738
}
3839

39-
$View = "$Path/{$this->getController()}/{$this->getPage()}.md";
40+
$cwd = getcwd();
41+
$ControllerPath = "$Path/{$this->getController()}";
42+
$View = $this->findMarkdownFile( $ControllerPath, $this->getPage() );
4043

41-
if( !file_exists( $View ) )
44+
if( !$View )
4245
{
43-
throw new NotFound( "View notfound: $View" );
46+
throw new NotFound( "View notfound: {$this->getPage()}.md in $ControllerPath" );
4447
}
4548

4649
extract( $Data );
@@ -62,6 +65,48 @@ public function render( array $Data ): string
6265
return $Page;
6366
}
6467

68+
/**
69+
* Find markdown file in controller directory or nested subdirectories
70+
*
71+
* @param string $BasePath
72+
* @param string $PageName
73+
* @return string|null
74+
*/
75+
protected function findMarkdownFile( string $BasePath, string $PageName ): ?string
76+
{
77+
if( !is_dir( $BasePath ) )
78+
{
79+
return null;
80+
}
81+
82+
// First check direct path
83+
$DirectPath = "$BasePath/$PageName.md";
84+
if( file_exists( $DirectPath ) )
85+
{
86+
return $DirectPath;
87+
}
88+
89+
// Search recursively in subdirectories
90+
$Iterator = new \RecursiveIteratorIterator(
91+
new \RecursiveDirectoryIterator( $BasePath, \RecursiveDirectoryIterator::SKIP_DOTS ),
92+
\RecursiveIteratorIterator::SELF_FIRST
93+
);
94+
95+
foreach( $Iterator as $File )
96+
{
97+
if( $File->isFile() && $File->getExtension() === 'md' )
98+
{
99+
$FileName = $File->getBasename( '.md' );
100+
if( $FileName === $PageName )
101+
{
102+
return $File->getPathname();
103+
}
104+
}
105+
}
106+
107+
return null;
108+
}
109+
65110
/**
66111
* @return MarkdownConverter
67112
*/

tests/Mvc/ApplicationTest.php

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use Neuron\Application\CrossCutting\Event;
66
use Neuron\Core\Exceptions\BadRequestMethod;
7+
use Neuron\Core\Exceptions\MissingMethod;
78
use Neuron\Core\Exceptions\NotFound;
89
use Neuron\Data\Setting\Source\Yaml;
910
use Neuron\Mvc\Application;
@@ -277,4 +278,112 @@ public function testControllerNoRequest()
277278

278279
$this->assertTrue( $ControllerState );
279280
}
281+
282+
public function testCaptureOutput()
283+
{
284+
$this->App->setCaptureOutput( true );
285+
286+
$this->assertTrue( $this->App->getCaptureOutput() );
287+
288+
$this->App->setRegistryObject( 'Requests.Path', $this->App->getBasePath().'/config/requests' );
289+
290+
$this->App->run(
291+
[
292+
"type" => "GET",
293+
"route" => "/test"
294+
]
295+
);
296+
297+
$Output = $this->App->getOutput();
298+
299+
$this->assertStringContainsString(
300+
"<html>",
301+
$Output
302+
);
303+
304+
$this->assertStringContainsString(
305+
"Resource Not Found",
306+
$Output
307+
);
308+
309+
$this->assertStringContainsString(
310+
"does not exist",
311+
$Output
312+
);
313+
314+
global $ControllerState;
315+
316+
if( $ControllerState )
317+
return;
318+
319+
throw new \Exception( "Controller state is not false." );
320+
321+
}
322+
323+
/**
324+
* @throws \Exception
325+
*/
326+
public function testPut()
327+
{
328+
$this->App->run(
329+
[
330+
"type" => "PUT",
331+
"route" => "/test_put"
332+
]
333+
);
334+
335+
global $ControllerState;
336+
$this->assertTrue( $ControllerState );
337+
}
338+
339+
/**
340+
* @throws \Exception
341+
*/
342+
public function testDelete()
343+
{
344+
$this->App->run(
345+
[
346+
"type" => "DELETE",
347+
"route" => "/test_delete"
348+
]
349+
);
350+
351+
global $ControllerState;
352+
$this->assertTrue( $ControllerState );
353+
}
354+
355+
public function testRoutesPath()
356+
{
357+
$this->App->setRoutesPath( 'test');
358+
$this->assertEquals(
359+
"test",
360+
$this->App->getRoutesPath()
361+
);
362+
}
363+
364+
public function testBadRoutes()
365+
{
366+
$this->expectException( \Neuron\Core\Exceptions\Validation::class );
367+
$Ini = new Yaml( './examples/bad/config.yaml' );
368+
$App = new Application( "1.0.0", $Ini );
369+
}
370+
371+
public function testGetRequest()
372+
{
373+
$Request = $this->App->getRequest("" );
374+
375+
$this->assertNull( $Request );
376+
}
377+
378+
public function testMissingControllerMethod()
379+
{
380+
$this->App->run(
381+
[
382+
"type" => "GET",
383+
"route" => "/bad_request"
384+
]
385+
);
386+
387+
$this->assertTrue( $this->App->getCrashed() );
388+
}
280389
}

0 commit comments

Comments
 (0)