22
33namespace TweakPHP \Client ;
44
5+ use PhpParser \Node \Stmt \Expression ;
56use PhpParser \ParserFactory ;
67use PhpParser \PrettyPrinter \Standard ;
8+ use Psy \CodeCleaner \NoReturnValue ;
79use Psy \Configuration ;
810use Psy \Exception \BreakException ;
911use Psy \Shell ;
1012use Symfony \Component \Console \Output \BufferedOutput ;
1113use Symfony \Component \Console \Output \OutputInterface ;
14+ use Symfony \Component \VarDumper \VarDumper ;
1215use TweakPHP \Client \Database \QueryCollector ;
1316use TweakPHP \Client \Output \StreamingOutput ;
1417use TweakPHP \Client \OutputModifiers \OutputModifier ;
1518
1619class Tinker
1720{
21+ public static bool $ dumpOccurred = false ;
22+
1823 protected OutputInterface $ output ;
1924
2025 protected Shell $ shell ;
2126
27+ protected Configuration $ config ;
28+
2229 protected OutputModifier $ outputModifier ;
2330
2431 public static array $ statements = [];
@@ -29,6 +36,8 @@ public function __construct(OutputModifier $outputModifier, Configuration $confi
2936 {
3037 $ this ->output = new BufferedOutput ;
3138
39+ $ this ->config = $ config ;
40+
3241 $ this ->shell = $ this ->createShell ($ this ->output , $ config );
3342
3443 $ this ->outputModifier = $ outputModifier ;
@@ -38,58 +47,68 @@ public function execute(string $rawPHPCode): array
3847 {
3948 self ::$ statements = [];
4049
41- $ rawPHPCode = $ this ->normalizePHPCode ($ rawPHPCode );
42-
43- $ parserFactory = new ParserFactory ;
44- $ parser = method_exists ($ parserFactory , 'createForHostVersion ' )
45- ? $ parserFactory ->createForHostVersion ()
46- : $ parserFactory ->create (ParserFactory::PREFER_PHP7 );
47- $ prettyPrinter = new Standard ;
48- foreach ($ parser ->parse ($ rawPHPCode ) as $ key => $ stmt ) {
49- $ code = $ prettyPrinter ->prettyPrint ([$ stmt ]);
50- self ::$ current = $ key ;
51- self ::$ statements [] = [
52- 'line ' => $ stmt ->getStartLine (),
53- 'code ' => $ code ,
54- ];
50+ $ this ->registerVarDumperHandler ($ this ->config );
5551
56- QueryCollector::start ();
57- try {
58- $ output = $ this ->doExecute ($ code );
59- } finally {
60- $ queries = QueryCollector::stop ();
61- self ::$ statements [$ key ]['queries ' ] = $ queries ;
52+ try {
53+ $ rawPHPCode = $ this ->normalizePHPCode ($ rawPHPCode );
54+
55+ $ parserFactory = new ParserFactory ;
56+ $ parser = method_exists ($ parserFactory , 'createForHostVersion ' )
57+ ? $ parserFactory ->createForHostVersion ()
58+ : $ parserFactory ->create (ParserFactory::PREFER_PHP7 );
59+ $ prettyPrinter = new Standard ;
60+ foreach ($ parser ->parse ($ rawPHPCode ) as $ key => $ stmt ) {
61+ $ code = $ prettyPrinter ->prettyPrint ([$ stmt ]);
62+ $ executableCode = $ stmt instanceof Expression
63+ ? $ prettyPrinter ->prettyPrintExpr ($ stmt ->expr )
64+ : $ code ;
65+
66+ self ::$ current = $ key ;
67+ self ::$ statements [] = [
68+ 'line ' => $ stmt ->getStartLine (),
69+ 'code ' => $ code ,
70+ ];
71+
72+ QueryCollector::start ();
73+ try {
74+ $ output = $ this ->doExecute ($ executableCode );
75+ } finally {
76+ $ queries = QueryCollector::stop ();
77+ self ::$ statements [$ key ]['queries ' ] = $ queries ;
78+ }
79+
80+ self ::$ statements [$ key ]['output ' ] = $ output ;
81+
82+ $ queryErrors = QueryCollector::errors ();
83+ if ($ queryErrors !== []) {
84+ self ::$ statements [$ key ]['query_errors ' ] = $ queryErrors ;
85+ }
6286 }
6387
64- self ::$ statements [$ key ]['output ' ] = $ output ;
65-
66- $ queryErrors = QueryCollector::errors ();
67- if ($ queryErrors !== []) {
68- self ::$ statements [$ key ]['query_errors ' ] = $ queryErrors ;
88+ $ allQueries = [];
89+ $ allQueryErrors = [];
90+ foreach (self ::$ statements as $ stmt ) {
91+ if (isset ($ stmt ['queries ' ])) {
92+ $ allQueries = array_merge ($ allQueries , $ stmt ['queries ' ]);
93+ }
94+ if (isset ($ stmt ['query_errors ' ])) {
95+ $ allQueryErrors = array_merge ($ allQueryErrors , $ stmt ['query_errors ' ]);
96+ }
6997 }
70- }
7198
72- $ allQueries = [];
73- $ allQueryErrors = [];
74- foreach (self ::$ statements as $ stmt ) {
75- if (isset ($ stmt ['queries ' ])) {
76- $ allQueries = array_merge ($ allQueries , $ stmt ['queries ' ]);
77- }
78- if (isset ($ stmt ['query_errors ' ])) {
79- $ allQueryErrors = array_merge ($ allQueryErrors , $ stmt ['query_errors ' ]);
80- }
81- }
99+ $ result = [
100+ 'output ' => self ::$ statements ,
101+ 'queries ' => $ allQueries ,
102+ ];
82103
83- $ result = [
84- 'output ' => self ::$ statements ,
85- 'queries ' => $ allQueries ,
86- ];
104+ if ($ allQueryErrors !== []) {
105+ $ result ['query_errors ' ] = $ allQueryErrors ;
106+ }
87107
88- if ($ allQueryErrors !== []) {
89- $ result ['query_errors ' ] = $ allQueryErrors ;
108+ return $ result ;
109+ } finally {
110+ $ this ->restoreVarDumperHandler ();
90111 }
91-
92- return $ result ;
93112 }
94113
95114 /**
@@ -99,35 +118,45 @@ public function executeStreaming(string $rawPHPCode, callable $onEvent): void
99118 {
100119 self ::$ statements = [];
101120
102- $ rawPHPCode = $ this ->normalizePHPCode ($ rawPHPCode );
103-
104- $ parserFactory = new ParserFactory ;
105- $ parser = method_exists ($ parserFactory , 'createForHostVersion ' )
106- ? $ parserFactory ->createForHostVersion ()
107- : $ parserFactory ->create (ParserFactory::PREFER_PHP7 );
108- $ prettyPrinter = new Standard ;
109-
110- foreach ($ parser ->parse ($ rawPHPCode ) as $ key => $ stmt ) {
111- $ code = $ prettyPrinter ->prettyPrint ([$ stmt ]);
112- self ::$ current = $ key ;
113- self ::$ statements [] = [
114- 'line ' => $ stmt ->getStartLine (),
115- 'code ' => $ code ,
116- ];
117-
118- $ onEvent ([
119- 'type ' => 'statement.started ' ,
120- 'index ' => $ key ,
121- 'line ' => $ stmt ->getStartLine (),
122- 'code ' => $ code ,
123- ]);
121+ $ this ->registerVarDumperHandler ($ this ->config );
124122
125- if (! $ this ->executeStreamingStatement ($ code , $ key , $ onEvent )) {
126- return ;
123+ try {
124+ $ rawPHPCode = $ this ->normalizePHPCode ($ rawPHPCode );
125+
126+ $ parserFactory = new ParserFactory ;
127+ $ parser = method_exists ($ parserFactory , 'createForHostVersion ' )
128+ ? $ parserFactory ->createForHostVersion ()
129+ : $ parserFactory ->create (ParserFactory::PREFER_PHP7 );
130+ $ prettyPrinter = new Standard ;
131+
132+ foreach ($ parser ->parse ($ rawPHPCode ) as $ key => $ stmt ) {
133+ $ code = $ prettyPrinter ->prettyPrint ([$ stmt ]);
134+ $ executableCode = $ stmt instanceof Expression
135+ ? $ prettyPrinter ->prettyPrintExpr ($ stmt ->expr )
136+ : $ code ;
137+
138+ self ::$ current = $ key ;
139+ self ::$ statements [] = [
140+ 'line ' => $ stmt ->getStartLine (),
141+ 'code ' => $ code ,
142+ ];
143+
144+ $ onEvent ([
145+ 'type ' => 'statement.started ' ,
146+ 'index ' => $ key ,
147+ 'line ' => $ stmt ->getStartLine (),
148+ 'code ' => $ code ,
149+ ]);
150+
151+ if (! $ this ->executeStreamingStatement ($ executableCode , $ key , $ onEvent )) {
152+ return ;
153+ }
127154 }
128- }
129155
130- $ onEvent (['type ' => 'completed ' ]);
156+ $ onEvent (['type ' => 'completed ' ]);
157+ } finally {
158+ $ this ->restoreVarDumperHandler ();
159+ }
131160 }
132161
133162 protected function executeStreamingStatement (string $ code , int $ key , callable $ onEvent ): bool
@@ -197,19 +226,30 @@ protected function executeStreamingStatement(string $code, int $key, callable $o
197226
198227 protected function doExecute (string $ code ): string
199228 {
229+ self ::$ dumpOccurred = false ;
200230 $ this ->output = new BufferedOutput ;
201231 $ this ->shell ->setOutput ($ this ->output );
202- $ this ->shell ->execute ($ code , true );
203- $ result = $ this ->outputModifier ->modify ($ this ->cleanOutput ($ this ->output ->fetch ()));
232+ $ return = $ this ->shell ->execute ($ code , true );
233+ $ output = $ this ->outputModifier ->modify ($ this ->cleanOutput ($ this ->output ->fetch ()));
234+
235+ if (! self ::$ dumpOccurred && $ return !== null && ! ($ return instanceof NoReturnValue)) {
236+ $ presented = $ this ->config ->getPresenter ()->present ($ return );
237+ if ($ output !== '' ) {
238+ $ output .= \PHP_EOL .$ presented ;
239+ } else {
240+ $ output = $ presented ;
241+ }
242+ }
204243
205- return trim ($ result );
244+ return trim ($ output );
206245 }
207246
208247 /**
209248 * @param callable(array): void $onEvent
210249 */
211250 protected function doExecuteStreaming (string $ code , int $ index , callable $ onEvent ): void
212251 {
252+ self ::$ dumpOccurred = false ;
213253 $ this ->output = new StreamingOutput (function (string $ chunk ) use ($ index , $ onEvent ): void {
214254 if ($ chunk === '' ) {
215255 return ;
@@ -222,7 +262,18 @@ protected function doExecuteStreaming(string $code, int $index, callable $onEven
222262 ]);
223263 });
224264 $ this ->shell ->setOutput ($ this ->output );
225- $ this ->shell ->execute ($ code , true );
265+ $ return = $ this ->shell ->execute ($ code , true );
266+
267+ if (! self ::$ dumpOccurred && $ return !== null && ! ($ return instanceof NoReturnValue)) {
268+ $ output = $ this ->config ->getPresenter ()->present ($ return );
269+ if ($ output !== '' ) {
270+ $ onEvent ([
271+ 'type ' => 'output ' ,
272+ 'index ' => $ index ,
273+ 'data ' => $ output ,
274+ ]);
275+ }
276+ }
226277 }
227278
228279 protected function createShell (OutputInterface $ output , Configuration $ config ): Shell
@@ -252,6 +303,30 @@ protected function normalizePHPCode(string $rawPHPCode): string
252303 return $ rawPHPCode ;
253304 }
254305
306+ protected function registerVarDumperHandler (Configuration $ config ): void
307+ {
308+ if (! class_exists (VarDumper::class)) {
309+ return ;
310+ }
311+
312+ VarDumper::setHandler (function ($ var ) use ($ config ) {
313+ self ::$ dumpOccurred = true ;
314+ $ output = $ config ->getPresenter ()->present ($ var );
315+ $ this ->output ->write ($ output , true );
316+
317+ return $ output ;
318+ });
319+ }
320+
321+ protected function restoreVarDumperHandler (): void
322+ {
323+ if (! class_exists (VarDumper::class)) {
324+ return ;
325+ }
326+
327+ VarDumper::setHandler (null );
328+ }
329+
255330 public function getShell (): Shell
256331 {
257332 return $ this ->shell ;
0 commit comments