symfony/event-dispatcher not receiving first dispatch - php

I'm using the symfony/event-dispatcher component and am trying to get a 'hello world' thing to work, I think.
My application (not symfony2) runs bootstrap.php then MVC's its way to some file I named composer.php.
bootstrap.php (the necessary parts)
<?php
require __DIR__ . '/vendor/autoload.php';
use Events\MsgEvent;
use Symfony\Component\EventDispatcher\EventDispatcher;
$dispatcher = new EventDispatcher();
if ($user_id) {
$dispatcher->dispatch('msg_event', new MsgEvent("I'm logged in as: " . $user['username']));
}
composer.php
<?php
use Events\MsgEvent;
$dispatcher->addListener('msg_event', function (MsgEvent $event) {
echo $event->getMsg();
});
$dispatcher->dispatch('msg_event', new MsgEvent("I got called from composer.php"));
On the route for my composer.php page I get to see 'called from composer', but my 'logged in as' message doesn't appear. When I output it's return, I can see it has succesfully created the event.
I have a feeling the problem is that the listener is defined after the first dispatch and somehow this does not get stored in the dispatcher. But I'm not sure.
What am I not seeing here?

You are dispatching the event before registering a listener. Since bootstrap.php is included before composer.php, the first event will fire with no listeners attached to it.

Related

Composer Autoload only finding classes in root-level directories

I am currently working on building an API in the Slim framework, and having a bit of trouble with it not finding classes that should be getting autoloaded.
Folder structure
database
- db_connection.php
<?php
namespace Database;
class DBConnection {}
...
public
- index.php
src
- middlewares
-- authentication_middleware.php
<?php
namespace Middleware;
class AuthenticationMiddleware {}
...
- routes
-- different routes for tickets, projects, notifications etc.
- utils
-- data_convertor.php
<?php
namespace Utils;
class DataConvertor {}
...
And here is my composer.json:
{
"autoload": {
"psr-4": {
"Database\\": "./database",
"Middleware\\": "./src/middlewares",
"Utils\\": "./src/utils"
}
},
"require": {
// Dependencies
}
}
Now if I go into my projects.php file in src/routes and use Database\DBConnection, then do $db_connection = new DBConnection(); further down, all is well, my database connects and the app returns a response. However, now that I have attempted to create these other namespaces, Middleware and Utils, I am suddenly getting "Uncaught Error: Class "Middleware\AuthenticationMiddleware" not found". It is in Slim 4 so here is what it ultimately looks like:
<?php
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Database\DBConnection;
use Middleware\AuthenticationMiddleware;
$app->group('/projects', function($app) {
$app->get('', function(Request $request, Response $response, Array $args) {
try {
$db_connection = new DBConnection();
// The rest of the code
return $response->withStatus($status);
});
})->add(new AuthenticationMiddleware()); // Here is where the "error" is generated.
What on Earth could I be doing wrong? I have gone with the theory that Middleware might be a protected word so changed it to something else, to no avail, and even ended up renaming Middleware to MW and AuthenticationMiddleware to AM to eliminate any chance of mispelling, again to no avail. Between every step I have also been running composer update and even composer dumpautoload && composer update to try and get it working.
As the title may suggest, the one thing the non-loading ones have in common, and separate from the loading one, is that database is a top-level directory and the others aren't. But surely as long as the path is correct in composer.json that shouldn't matter?
Further to this, a bit more Googling before posting has led me to look at vendor/composer/autoload_psr4.php and sure enough, it returns the below:
return array(
'Utils\\' => array($baseDir . '/src/utils'),
'Middleware\\' => array($baseDir . '/src/middlewares'),
'Database\\' => array($baseDir . '/database'),
// Plenty of auto-generated ones with plenty of slashes in the directory paths
)
Thanks to the comments on my question I now know that the issue was that the class name e.g. AuthenticationMiddleware didn't match the filename, in this case authentication_middleware.php, changing that by renaming the files has fixed the issue. Weird that the database connection was still working despite that - but hey, it now all works so I'm good!

TypeRocket: php script stops running when function is called via Controller

I'm trying to utilize FirePHP in typerocket but I'm having trouble when I try to use its API in a Controller.
I have the the following routes (in routes.php):
tr_route()->get()->match('/exp-get/')->do('experiment#Customer');
tr_route()->get()->match('/exp-get2/')->do(function() {
require_once TR_PATH . '/vendor/firephp/firephp-core/lib/FirePHPCore/fb.php';
echo 'before';
fb('Hello World!', FirePHP::INFO);
echo 'after';
});
the CustomerController contains:
public function experiment() {
require_once TR_PATH . '/vendor/firephp/firephp-core/lib/FirePHPCore/fb.php';
echo 'before';
fb('Hello World!', FirePHP::INFO);
echo 'after';
}
Now, when I call https://dummy-domain.org/exp-get2/ everything runs as expected, but however, when I call https://dummy-domain.org/exp-get/ only 'before' is echoed (or printed) but not the rest! Unfortunately no errors are logged even though I've configured php logging. What might be the reason for this and why isn't the error logged if there is any error?
Additionally, I'm having the issue that I need to explicitly require_once fb.php although FirePHP should be autoloaded, as outside of the do related functions I can use the FirePHP API without having to do this! Isn't the autoload working here?
Note: I'm using the lastest TypeRocket version.
By further debugging I noticed that the php engine was complaining about that aFirePHP class was not found which is used inside the fb function. As a result I just had to put this statement on top of the class which contains that experiment method:
use \FirePHP;
those require_once TR_PATH . '/vendor/firephp/firephp-core/lib/FirePHPCore/fb.php'; lines are unnecessary since the autoloader handels that stuff already.
This answer led me to the right direction.

Laravel small standalone one-off script without artisan command?

I need to check something small in Laravel, so I just want to make a small script to check it.
I know that I can do it with
php artisan make:console ...
But It will add a file to the App/Console/Command, and I will need to update app/Console/Kernel.php. It means that I will have do commit it to source control, which is really not needed.
Is there a way to have a standalone laravel script which will give me access to the Laravel Components?
I am using Laravel 5.2, (make:command doesn't exists, only make:console)
Just an example for what I tried:
<?php
use App\User;
use DB;
require __DIR__.'/../vendor/autoload.php';
require __DIR__.'/..//bootstrap/app.php';
echo "hello world\n";
$res=User::where('id',5)->first();
echo "end!\n";
?>
But I am getting an error:
PHP Fatal error: Uncaught Error: Call to a member function connection() on null in /var/www/html/dpriceit/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php:3314
Stack trace:
#0 /var/www/html/dpriceit/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php(3280): Illuminate\Database\Eloquent\Model::resolveConnection(NULL)
#1 /var/www/html/dpriceit/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php(1880): Illuminate\Database\Eloquent\Model->getConnection()
#2 /var/www/html/dpriceit/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php(1853): Illuminate\Database\Eloquent\Model->newBaseQueryBuilder()
#3 /var/www/html/dpriceit/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php(1823): Illuminate\Database\Eloquent\Model->newQueryWithoutScopes()
#4 /var/www/html/dpriceit/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php(3524): Illuminate\Database\Eloquent\Model->newQuery()
UPDATE
I tried creating a console command
php artisan make:console MyTempTest
But when I do php artisan list I don't see its signature in the list of available commands.
To fix the error you're getting, boot up the application's kernel and handle the response like so
app\script.php
<?php
use App\User;
require __DIR__.'/../vendor/autoload.php';
$app = require_once __DIR__.'/../bootstrap/app.php';
$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);
$response = $kernel->handle(
$request = Illuminate\Http\Request::capture()
);
echo "hello world\n";
$res = User::find(5)->name;
var_dump($res);
echo "end!\n";
Then from a terminal, run php app/script.php
Result:
~/Sites/laravel (master ✗) ✹ ★ ᐅ php app/script.php
hello world
string(11) "Khalid Bins"
end!
When I want to try/test something in Laravel, I usually do one of three things:
If the "something" I want to try is a simple one-liner I use Tinker: artisan tinker. This gives you the fully booted Laravel Framework, ready to use any class or function you want. This is usually my go-to when I want to: Test a global helper function I just created; Create a model using a factory, to check if my factory is setup correctly; Check if my $casts array on a model is setup the right way;
Another scenario might involve a bit more code, maybe a few lines to retrieve some data from the database, mutate it and show it on a page. For this you can simply create a closure based route in the file routes/web.php:
Route::get('test-url', function () {
$user = User::where('email', 'user#example.com')->first();
$user->makeAdmin()->save();
// I can see on the page if the attributes have been changed, as a result of the makeAdmin() call.
return $user->getAttributes();
});
The same is possible for console routes. Add a structure like this in your routes/console.php file:
Artisan::command('test:functionality', function () {
$instance = new BusinessLogic();
$result = $instance->someVeryInterestingMethod();
dump($result);
});
You can then call this function from the command line with php artisan test:functionality. You can, of course, call the command whatever you like.
Then the last scenario; when I want to try something new (like a new package, library, plugin) and it will be more than a few lines of code. I create a new test class with php artisan make:test ThrowawayTest (or another randomly chosen name). I can then add a few lines of code and run it with PHPUnit. I have set my editor to launch the test that my cursor is on with the key-combination CTRL-T so that I can re-run it quickly when some code changed.
This means I can let some code stay in its function, and write a new function to elaborate on the things I just learned about the new package. When I am finished I can either leave the code and commit it to the repository, so that I can check the code later on when I need to use some of it again for production code. I can also throw away the test file if it seems like I won't need the code for reference in the future.
This last solution also gives me the added benefit of being able to use assert statements from PHPUnit.
Hope this gives you some insight on the different possibilities with the Laravel Framework when it comes to trying or testing out new stuff.

How to avoid outside of request scope exception in silex application?

After restructuring my silex1.2 application, I am now getting hit by:
exception 'RuntimeException' with message 'Accessed request service
outside of request scope. Try moving that call to a before handler or
controller.' in
../vendor/silex/silex/src/Silex/Application.php:150
I used to setup the appilcation's config this way:
$app = new Silex\Application();
$app->register(new ServiceControllerServiceProvider());
$app->register(new ConfigServiceProvider($configFile));
$fileFinder = new \Symfony\Component\Finder\Finder();
foreach ($fileFinder->in($configPath . 'country') as $file) {
/* #var SplFileInfo $file */
$app->register(new ConfigServiceProvider($file->getRealPath()));
}
I now wanted to replace the foreach loop by injecting a specific value which I get from the user's request. So I wanted to access $request->query->get('country'); yet I cannot since app['request'] is out of scope at that point.
I don't understand the error message, as in:
When and why are request objects out of scope in silex?
How am I supposed to move the call before handler and controllers when it is the very first thing I do on setting up my application?
Basically, I want to access request data early on on in order to get one value. How can I achieve that in order to bootstrap application accordingly?
You try to use Request before it is initialized, before $app->run().
You can manually initialize Request:
$app = new \Silex\Application();
$app['request'] = \Symfony\Component\HttpFoundation\Request::createFromGlobals();
.....
$app->run($app['request']);
or make lazy loading in service providers:
$app['object1'] = $app->share(function ($app) {
return new Object1($app['request']->query->get('country'));
});
...
and somewhere in controller get these variable as $app['object1']

Path issue with autoload function to get files for use in Ajax

So my project uses an MVC framework and I have a page with an Ajax script I run to get content from the server. When the PHP script is called in the Ajax script, I want to access the classes already in my library for use in the PHP script. To do this, I use what I call an ajaxBootstrap to call the appropriate function that then instantiates the objects needed for that specific Ajax script.
To load those classes from my library I have an autoload function in my ajaxBootstrap so I don't need to use a bunch of require and include statements. My problem is those files aren't being loaded due to a path issue with the autoload function. When I use a require statement with the same path, the classes load with no problems, its only when I try to load them using the autoload function that I get an 500 internal server error.
Here is my ajaxBootstrap file:
// This file routes Ajax requests made in JS files and instantiates a specific object to carry out the actions needed for that particular Ajax operation
// Autoload any classes that are required
function autoLoad($classToLoad)
{
if(file_exists('../library/' . $classToLoad . 'class.php')) // File in the library folder
{
require('../library/' . $classToLoad . '.class.php');
}
else if(file_exists('../../app/models/' . $classToLoad . 'class.php')) // File in the models folder
{
require('../../app/models/' . $classToLoad . '.class.php');
}
}
spl_autoload_register('autoLoad');
// Determine which function to call based on the url that's listed in the Ajax request
switch($_GET['action'])
{
case 'pageOne':
pageOne();
break;
case 'pageTwo':
pageTwo();
break;
}
function pageOne()
{
$test = new Test();
$test->funcThatReturnStuff();
}
function pageTwo()
{
$test2 = new Test2();
$test2->funcThatReturnStuff();
}
Like I mentioned eariler, if I use a require statement such as:
require('../library/Test.class.php');
$test = new Test();
$test->funcThatReturnStuff();
The class loads and works just fine. But using the same path in the autoloader function throws an error. The really odd thing is if I put an else if statement in the autoloader that loads a class from the folder where my ajaxBootstrap is it also works fine too...
I know I could just use the require statements and be done with the problem but I want to be able to scale the project and not need to use loads of require statements in the future. BTW, I use '../' to get from where my ajaxBootstrap file is to my other folders.
Also, to add to my previous post, I've tried replacing the ../ with absolute paths using define('ROOT', dirname(__FILE__) . '/') and also define('ROOT', $_SERVER['DOCUMENT_ROOT'] . '/path/to/folder/') neither of which worked and still gave me the internal server error in Firebug. In addition, I haven't received any errors in my error log either.
Nevermind... Even after staring at my code for the past few hours I somehow missed the missing period in two of my file paths. I hate coding sometimes... Thank you to anyone who took time to read this.

Categories