How to properly add external php files in Laravel 5 - laravel-5

I have a small websockets chat written, the php part is just 2 files, server.php and Chat.php, they are both inside a bin folder and depend on ratchet and some other libraries which I downloaded to the laravel installation via composer.
server.php
require __DIR__.'/../vendor/autoload.php';
require 'Chat.php';
use Ratchet\Server\IoServer;
use Ratchet\http\HttpServer;
use Ratchet\WebSocket\WsServer;
$server = IoServer::factory(new HttpServer(new WsServer(new Chat)), 8080);
$server->run();
Chat.php
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
class Chat implements MessageComponentInterface {
protected $clients;
function __construct() {
$this->clients = new \SplObjectStorage;
}
public function onOpen(ConnectionInterface $conn)
{
$this->clients->attach($conn);
}
public function onMessage(ConnectionInterface $conn, $msg)
{
foreach ($this->clients as $client)
{
if ($client !== $conn ) {
$client->send($msg);
}
}
}
public function onClose(ConnectionInterface $conn)
{
$this->clients->detach($conn);
}
public function onError(ConnectionInterface $conn, \Exception $e)
{
echo 'the following error occured: ' . $e->getMessage();
$conn->close();
}
}
Now, I have that bin folder inside the laravel root, and so I am able to start the server since the server.php is looking for dependencies in vendor one level up, but what I wanna do is use all the laravel goodies within these files, especially within Chat.php.
So now for example if I write use DB in Chat.php it gives an error (which I understand, it has no way of knowing laravel), so my question is how do I include this bin folder and its files so that I can use all the laravel goodies within them?

You do not need to manually load vendor/autoload.php because laravel does that for you.
First you have to create folder inside your YourLaravelRoot/app dir(Let's name that as Services). Then move chat.php into that, rename it to ChatService.php(Change class name also to ChatService) or any appropriate name(reccomanded to ends with xxxxService so it's easier to identify) and namespace it as namespace App\Services;(Assumming that your app name is App).Namespacing correctly is important otherwise you have to manually loads it throught composer.json .Then create a artisan command and move content of server.php into handle method inside command(Let's name it ServerCommand.php). Add use App\Services\ChatService as Chat;. Register the command in Kernal.php on app/console That's it. Now you should be able to access any laravel facade inside ChatService
Summary:
YourLaravelProject
-app
--Console
Kernal.php
<?php
namespace App\Console;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
class Kernel extends ConsoleKernel
{
/**
* The Artisan commands provided by your application.
*
* #var array
*/
protected $commands = [
Commands\ServerCommand::class,
];
/**
* Define the application's command schedule.
*
* #param \Illuminate\Console\Scheduling\Schedule $schedule
* #return void
*/
protected function schedule(Schedule $schedule)
{
// $schedule->command('inspire')
// ->hourly();
}
}
---Commands
----ServerCommand.php
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Ratchet\Server\IoServer;
use Ratchet\Http\HttpServer;
use Ratchet\WebSocket\WsServer;
use App\Services\ChatService as Chat;
class ServerCommand extends Command
{
/**
* The name and signature of the console command.
*
* #var string
*/
protected $signature = 'server:run';
/**
* The console command description.
*
* #var string
*/
protected $description = 'Command description';
/**
* Create a new command instance.
*
* #return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* #return mixed
*/
public function handle()
{
$server = IoServer::factory(new HttpServer(new WsServer(new Chat)), 8080);
$server->run();
}
}
--Services
---ChatService.php
<?php
namespace App\Services;
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
/**
*
*/
class ChatService implements MessageComponentInterface {
{
protected $clients;
function __construct() {
$this->clients = new \SplObjectStorage;
}
public function onOpen(ConnectionInterface $conn)
{
$this->clients->attach($conn);
}
public function onMessage(ConnectionInterface $conn, $msg)
{
foreach ($this->clients as $client)
{
if ($client !== $conn ) {
$client->send($msg);
}
}
}
public function onClose(ConnectionInterface $conn)
{
$this->clients->detach($conn);
}
public function onError(ConnectionInterface $conn, \Exception $e)
{
echo 'the following error occured: ' . $e->getMessage();
$conn->close();
}
}
Execute command php artisan server:run

Related

Mail Not working in laravel console command within handle function

I'm developing a new Laravel application. When I'm using mail to send messages via laravel schedule command, I'm getting the following error:
Swift_TransportException with message 'Process could not be started
[The system cannot find the path specified. ]
This is my Command file.
EmailReminder.php
<?php
namespace App\Console\Commands;
use App\ScheduleMeeting;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Mail;
use Modules\User\Emails\MentorEmailReminder;
class EmailReminder extends Command
{
/**
* The name and signature of the console command.
*
* #var string
*/
protected $signature = 'reminder:emails';
/**
* The console command description.
*
* #var string
*/
protected $description = 'Send email notification to user about reminders.';
/**
* Create a new command instance.
*
* #return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* #return int
*/
public function handle()
{
$date = now()->tz('Asia/Singapore')->addDay(); // Current date is added one day
$newDate = $date->format('Y-m-d g:i A');
$tomorrow_meetings = ScheduleMeeting::where('start_time','=', $newDate)
->where('status',1)
->where('meeting_type',0)
->get();
$data = [];
foreach($tomorrow_meetings as $meeting){
$data[$meeting->mentor_id][] = $meeting->toArray();
}
foreach($data as $mentorId => $reminders){
$this->sendEmailToUser($mentorId, $reminders);
}
}
private function sendEmailToUser($mentorId, $reminders){
$user = \App\User::find($mentorId);
Mail::to($user)->send(new MentorEmailReminder($reminders));
}
}
This is my email file.
MentorEmailReminder.php
<?php
namespace Modules\User\Emails;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
class MentorEmailReminder extends Mailable
{
use Queueable, SerializesModels;
public $reminders;
public function __construct($reminders)
{
$this->reminders = $reminders;
}
public function build()
{
$subject = 'Reminder: Mentoring Session with';
return $this->from(setting_item("email_from_address"), 'Uplyrn')->subject($subject)->view('User::emails.mentor-email-reminder')->with([
'reminders' => $this->reminders,
]);
}
}
This is .env file.
MAIL_DRIVER=sendmail
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null

Laravel Service won't register

Followed every step from laravel 9 manual, and my service will not register consistently. Don't quite know why but it suddenly breaks and I receive a Target class [thumbnail] does not existerror out of nowhere.
Setup
Service:
namespace App\Services;
use Illuminate\Support\Facades\Storage;
use Intervention\Image\Facades\Image;
class ThumbnailService
{
public function storeThumbnail($userId, $file, $scale) {
$thumbnail_image = Image::make($file);
$orig_width = $thumbnail_image->width();
$orig_height = $thumbnail_image->height();
$thumbnail_image->resize($orig_width * $scale, $orig_height * $scale);
$thumb_stream = $thumbnail_image->stream();
$thumb_path = env('MIX_AWS_IMAGES_DIRECTORY') . '/'. $userId . '/thumbnails';
$thumb_file = $thumb_path . '/' . 'thumb_1_4_' . $file->getClientOriginalName();
Storage::disk('s3')->put($thumb_file, $thumb_stream->__toString());
return $thumb_file;
}
}
Provider:
namespace App\Providers;
use App\Services\ThumbnailService;
use Illuminate\Contracts\Support\DeferrableProvider;
use Illuminate\Support\ServiceProvider;
class ThumbnailServiceProvider extends ServiceProvider implements DeferrableProvider
{
/**
* Register services.
*
* #return void
*/
public function register()
{
$this->app->singleton('thumbnail', function() {
return new ThumbnailService();
});
}
/**
* Bootstrap services.
*
* #return void
*/
public function boot()
{
}
public function provides()
{
return [ThumbnailService::class];
}
}
Facade:
namespace App\Facades;
use Illuminate\Support\Facades\Facade;
class Thumbnail extends Facade
{
protected static function getFacadeAccessor() {
return 'thumbnail';
}
}
obviously, I did register in app.php in the providers array. But if I inspect the bindings, there is no service... Any help? This is the second time this happened and earlier, I got away with dumping autoload and config:clear and it is currently under my sail dev environment. I don't want this to happen in prod. So help would be appreciated.

Call to a member function expectsOutput() on integer when testing artisan console command

I have a very simple example to show the problem:
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
class VendorCounts extends Command
{
/**
* The name and signature of the console command.
*
* #var string
*/
protected $signature = 'vendor:counts
{year : The year of vendor counts}';
/**
* The console command description.
*
* #var string
*/
protected $description = 'Runs vendor counts';
/**
* Create a new command instance.
*
* #return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* #return mixed
*/
public function handle()
{
$this->info('Starting Vendor Counts');
}
}
<?php
namespace Tests\Feature\Console\Vendor;
use Tests\TestCase;
class VendorCountsTest extends TestCase {
public function testVendorCounts()
{
$this->artisan('vendor:counts', ['year' => 2019])
->expectsOutput('Starting Vendor Counts')
->assertExitCode(0);
}
}
I get the following error:
1) Tests\Feature\Console\Vendor\VendorCountsTest::testVendorCounts
Error: Call to a member function expectsOutput() on integer
/Users/albertski/Sites/vrs/tests/Feature/Console/Vendor/VendorCountsTest.php:12
I know the command definitely runs because if I put a dump statement in it shows the debug output.
I am using Laravel 6.3. Is there a different way to test this?
The problem I was using was that TestCase was using Laravel\BrowserKitTesting\TestCase as BaseTestCase. I ended up creating another Base just for console commands.
<?php
namespace Tests;
use Illuminate\Foundation\Testing\TestCase as BaseTestCase;
abstract class ConsoleTestCase extends BaseTestCase
{
use CreatesApplication;
}
Can you add this to your VendorCountsTest class:
public $mockConsoleOutput = true;
This is set by a trait but just making sure something hasn't changed the value. When $mockConsoleOutput is false it will directly run the artisan commmand. When it is true it will wrap it in a PendingCommand object that has those methods you are trying to call.
I had an issue where the use of expectedOutput() on my Artisan class would fail all the time, which turned out to be because I had used exit() and/or die() in a method, which really did not work well with phpunit test methods.
So if you want to stop processing the "script" at some point, just use an empty return and not exit() or die() if you want to utilize the built-in ->artisan() testing in Laravel.
Working example:
<?php
// app/Console/Commands/FooCommand.php
public function handle()
{
$file = $this->argument('file');
if (! file_exists($file)) {
$this->line('Error! File does not exist!');
return;
}
}
// tests/Feature/FooCommandTest.php
public function testFoo() {
$this->artisan('foo', ['file' => 'foo.txt'])->expectsOutput('Something');
}
Non-working example:
<?php
// app/Console/Commands/FooCommand.php
public function handle()
{
$file = $this->argument('file');
if (! file_exists($file)) {
$this->line('Error! File does not exist!');
exit;
}
}
// tests/Feature/FooCommandTest.php
public function testFoo() {
$this->artisan('foo', ['file' => 'foo.txt'])->expectsOutput('Something');
}

Laravel authentication without global scope

In my Laravel app users can disable (not delete) their account to disappear from the website. However, if they try to login again their account should be activated automatically and they should log in successfully.
This is done with "active" column in the users table and a global scope in User model:
protected static function boot() {
parent::boot();
static::addGlobalScope('active', function(Builder $builder) {
$builder->where('active', 1);
});
}
The problem now is that those inactive accounts can't log in again, since AuthController does not find them (out of scope).
What I need to achieve:
Make AuthController ignore global scope "active".
If username and password are correct then change the "active" column value to "1".
The idea I have now is to locate the user using withoutGlobalScope, validate the password manually, change column "active" to 1, and then proceed the regular login.
In my AuthController in postLogin method:
$user = User::withoutGlobalScope('active')
->where('username', $request->username)
->first();
if($user != null) {
if (Hash::check($request->username, $user->password))
{
// Set active column to 1
}
}
return $this->login($request);
So the question is how to make AuthController ignore global scope without altering Laravel main code, so it will remain with update?
Thanks.
Create a class GlobalUserProvider that extends EloquentUserProvider like below
class GlobalUserProvider extends EloquentUserProvider {
public function createModel() {
$model = parent::createModel();
return $model->withoutGlobalScope('active');
}
}
Register your new user provider in AuthServiceProvider:
Auth::provider('globalUserProvider', function ($app, array $config) {
return new GlobalUserProvider($this->app->make('hash'), $config['model']);
});
Finally you should change your user provider driver to globalUserProvider in auth.php config file.
'providers' => [
'users' => [
'driver' => 'globalUserProvider',
'model' => App\Models\User::class
]
]
protected static function boot()
{
parent::boot();
if (\Auth::check()) {
static::addGlobalScope('active', function(Builder $builder) {
$builder->where('active', 1);
});
}
}
Please try this for login issue, You can activate after login using withoutGlobalScopes().
#Sasan's answer is working great in Laravel 5.3, but not working in 5.4 - createModel() is expecting a Model but gets a Builder object, so when EloquentUserProvider calls $model->getAuthIdentifierName() an exception is thrown:
BadMethodCallException: Call to undefined method Illuminate\Database\Query\Builder::getAuthIdentifierName() in /var/www/vendor/laravel/framework/src/Illuminate/Database/Query/Builder.php:2445
Instead, follow the same approach but override more functions so that the right object is returned from createModel().
getQuery() returns the builder without the global scope, which is used by the other two functions.
class GlobalUserProvider extends EloquentUserProvider
{
/**
* Get query builder for the model
*
* #return \Illuminate\Database\Eloquent\Builder
*/
private function getQuery()
{
$model = $this->createModel();
return $model->withoutGlobalScope('active');
}
/**
* Retrieve a user by their unique identifier.
*
* #param mixed $identifier
* #return \Illuminate\Contracts\Auth\Authenticatable|null
*/
public function retrieveById($identifier)
{
$model = $this->createModel();
return $this->getQuery()
->where($model->getAuthIdentifierName(), $identifier)
->first();
}
/**
* Retrieve a user by their unique identifier and "remember me" token.
*
* #param mixed $identifier
* #param string $token
* #return \Illuminate\Contracts\Auth\Authenticatable|null
*/
public function retrieveByToken($identifier, $token)
{
$model = $this->createModel();
return $this->getQuery()
->where($model->getAuthIdentifierName(), $identifier)
->where($model->getRememberTokenName(), $token)
->first();
}
}
Sasan Farrokh has a right answer. The only thing not to rewrite createModel but newModelQuery and this will work
protected function newModelQuery($model = null)
{
$modelQuery = parent::newModelQuery();
return $modelQuery->withoutGlobalScope('active');
}
Extend the AuthController with the code you used in your OP. That should work.
public function postLogin(Request $request)
{
$user = User::withoutGlobalScope('active')
->where('username', $request->username)
->first();
if($user != null){
if (Hash::check($request->password, $user->password)){
$user->active = 1;
$user->save();
}
}
return $this->login($request);
}
I resolved it by creating the new package.
mpyw/scoped-auth: Apply specific scope for user authentication.
Run composer require mpyw/scoped-auth and modify your User model like this:
<?php
namespace App;
use Illuminate\Auth\Authenticatable;
use Illuminate\Contracts\Auth\Authenticatable as UserContract;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Mpyw\ScopedAuth\AuthScopable;
class User extends Model implements UserContract, AuthScopable
{
use Authenticatable;
public function scopeForAuthentication(Builder $query): Builder
{
return $query->withoutGlobalScope('active');
}
}
You can also easily pick Illuminate\Auth\Events\Login to activate User on your Listener.
<?php
namespace App\Providers;
use Illuminate\Support\Facades\Event;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
class EventServiceProvider extends ServiceProvider
{
/**
* The event listener mappings for the application.
*
* #var array
*/
protected $listen = [
\Illuminate\Auth\Events\Login::class => [
\App\Listeners\ActivateUser::class,
],
];
/**
* Register any events for your application.
*
* #return void
*/
public function boot()
{
parent::boot();
//
}
}
 
<?php
namespace App\Listeners;
use Illuminate\Auth\Events\Login;
class ActivateUser
{
/**
* Handle the event.
*
* #param Illuminate\Auth\Events\Login $event
* #return void
*/
public function handle(Login $event)
{
$event->user->fill('active', 1)->save();
}
}
 
I had to use
->withoutGlobalScopes() instead
in order for it to work

Laravel 5 Command and Handler issue

I am working one of my project with laravel 5. During the implementation i got struct with one issue which is related to command and handler.
I used artisan command to generate command
php artisan make:command TestCommand --handler
I generated command at app/commands folder "TestCommand.php"
<?php
namespace App\Commands;
use App\Commands\Command;
class TestCommand extends Command
{
public $id;
public $name;
public function __construct($id, $name)
{
$this->id = $id;
$this->name = $name;
}
}
Also my TestCommandHandler.php looks like this
<?php
namespace App\Handlers\Commands;
use App\Commands\TestCommand;
use Illuminate\Queue\InteractsWithQueue;
class TestCommandHandler
{
/**
* Create the command handler.
*
* #return void
*/
public function __construct()
{
//
}
/**
* Handle the command.
*
* #param TestCommand $command
* #return void
*/
public function handle(TestCommand $command)
{
dd($command);
}
}
Whenever dispatch this command from controller it shows following issue
InvalidArgumentException in Dispatcher.php line 335:
No handler registered for command [App\Commands\TestCommand]
Please, Anybody help me to solve this problem. Thank you
By default Laravel 5.1.x does not included BusServiceProvider. So we should create BusServiceProvider.php under provider folder and include that in to config/app.php.
BusServiceProvider.php
<?php namespace App\Providers;
use Illuminate\Bus\Dispatcher;
use Illuminate\Support\ServiceProvider;
class BusServiceProvider extends ServiceProvider {
/**
* Bootstrap any application services.
*
* #param \Illuminate\Bus\Dispatcher $dispatcher
* #return void
*/
public function boot(Dispatcher $dispatcher)
{
$dispatcher->mapUsing(function($command)
{
return Dispatcher::simpleMapping(
$command, 'App\Commands', 'App\Handlers\Commands'
);
});
}
/**
* Register any application services.
*
* #return void
*/
public function register()
{
//
}
}
config/app.php
'providers' => [
App\Providers\BusServiceProvider::class
]
So it may help others. Thank you

Resources