error when i run php artisan migrate command on line 51 - php

When I run the php artisan migrate command in terminal I'm left with this.
ParseError
syntax error, unexpected ')'
at C:\laragon\www\testnum2\vendor\laravel\framework\src\Illuminate\Bus\BusServiceProvider.php:51
47▕ return new DatabaseBatchRepository(
48▕ $app->make(BatchFactory::class),
49▕ $app->make('db')->connection(config('queue.batching.database')),
50▕ config('queue.batching.table', 'job_batches'),
➜ 51▕ );
52▕ });
53▕ }
54▕
55▕ /**
1 C:\laragon\www\testnum2\vendor\composer\ClassLoader.php:322
Composer\Autoload\includeFile("C:\laragon\www\testnum2\vendor\composer/../laravel/framework/src/Illuminate/Bus/BusServiceProvider.php")
2 [internal]:0
Composer\Autoload\ClassLoader::loadClass("Illuminate\Bus\BusServiceProvider")
PS C:\laragon\www\testnum2>
I'm not quite sure what is causing but this is the code for that file thats causing the error.
<?php
namespace Illuminate\Bus;
use Illuminate\Contracts\Bus\Dispatcher as DispatcherContract;
use Illuminate\Contracts\Bus\QueueingDispatcher as QueueingDispatcherContract;
use Illuminate\Contracts\Queue\Factory as QueueFactoryContract;
use Illuminate\Contracts\Support\DeferrableProvider;
use Illuminate\Support\ServiceProvider;
class BusServiceProvider extends ServiceProvider implements DeferrableProvider
{
/**
* Register the service provider.
*
* #return void
*/
public function register()
{
$this->app->singleton(Dispatcher::class, function ($app) {
return new Dispatcher($app, function ($connection = null) use ($app) {
return $app[QueueFactoryContract::class]->connection($connection);
});
});
$this->registerBatchServices();
$this->app->alias(
Dispatcher::class, DispatcherContract::class
);
$this->app->alias(
Dispatcher::class, QueueingDispatcherContract::class
);
}
/**
* Register the batch handling services.
*
* #return void
*/
protected function registerBatchServices()
{
$this->app->singleton(BatchRepository::class, DatabaseBatchRepository::class);
$this->app->singleton(DatabaseBatchRepository::class, function ($app) {
return new DatabaseBatchRepository(
$app->make(BatchFactory::class),
$app->make('db')->connection(config('queue.batching.database')),
config('queue.batching.table', 'job_batches'),
);
});
}
/**
* Get the services provided by the provider.
*
* #return array
*/
public function provides()
{
return [
Dispatcher::class,
DispatcherContract::class,
QueueingDispatcherContract::class,
BatchRepository::class,
];
}
}
I hope that this is enough to get help.
I wanna also mention that I've used php artisan migrate before and recently I had to upgrade some things like composer and phpmyadmin

The problem is that the PHP version you're using ( below 7.3 ) does not support trailing comma in function calls.
Please read this: Trailing Commas are allowed in Calls
Solution is to switch to > PHP 7.3

Well my problem was my PHP being <7.3
But when I simply checked it in phpinfo file it showed up as 7.4.11.
#lagbox helped me by saying : "there are different versions on your system, and the CLI and the webserver can have different configurations"
To be honest I wasn't sure exactly what to do from that but I decided to just delete PHP 7.2 from my PATH.
My hope was that it would then recognize I was using 7.4 and to my suprise it did.
Also I'm sure there are more effective ways of doing this but that was the way I chose.

Related

Implement locking for all commands in my Symfony app

I followed this guide: https://symfony.com/doc/current/console/lockable_trait.html and implemented the command lock feature for my one of my commands to see how it works. It worked as described and then I was going to implement it for all of my commands. But the issue is that I have about 50 commands and:
I do not want spent time adding the necessary code to each command
I want to have the centralized management of commands locking. I mean, adding extra option to regular commands so that they will be used by my future management center. For now I will need a pretty simple option protected function isLocked() for a regular command which will help me to manage if a command should have lockable feature.
So, I went to the source of \Symfony\Component\Console\Command\LockableTrait and after some time created the following listener to the event console.command:
use Symfony\Component\Console\Event\ConsoleCommandEvent;
use Symfony\Component\Console\Exception\LogicException;
use Symfony\Component\Lock\Lock;
use Symfony\Component\Lock\LockFactory;
use Symfony\Component\Lock\LockInterface;
use Symfony\Component\Lock\Store\FlockStore;
use Symfony\Component\Lock\Store\SemaphoreStore;
class LockCommandsListener
{
/**
* #var array<string, Lock>
*/
private $commandLocks = [];
private static function init()
{
if (!class_exists(SemaphoreStore::class)) {
throw new LogicException('To enable the locking feature you must install the symfony/lock component.');
}
}
public function onConsoleCommand(ConsoleCommandEvent $event)
{
static::init();
$name = $event->getCommand()->getName();
$this->ensureLockNotPlaced($name);
$lock = $this->createLock($name);
$this->commandLocks[$name] = $lock;
if (!$lock->acquire()) {
$this->disableCommand($event, $name);
}
}
private function disableCommand(ConsoleCommandEvent $event, string $name)
{
unset($this->commandLocks[$name]);
$event->getOutput()->writeln('The command ' . $name . ' is already running');
$event->disableCommand();
$event->getCommand()->setCode()
}
private function createLock(string $name): LockInterface
{
if (SemaphoreStore::isSupported()) {
$store = new SemaphoreStore();
} else {
$store = new FlockStore();
}
return (new LockFactory($store))->createLock($name);
}
private function ensureLockNotPlaced(string $name)
{
if (isset($this->commandLocks[$name])) {
throw new LogicException('A lock is already in place.');
}
}
}
I made some tests and it kind of worked. But I am not sure this is the right way of doing things.
Another problem is that I can not find the proper exit code when I disabled a command. Should I just disable it? But it seems that exit code would be a great feature here. Specially when it comes to this listener testing (PHPUnit testing).
And I also have with testing itself. How can I run commands in parallel in my test class. For now I have this:
class LockCommandTest extends CommandTest
{
public function testOneCommandCanBeRun()
{
$commandTester = new ApplicationTester($this->application);
$commandTester->run([
'command' => 'app:dummy-command'
]);
$output = $commandTester->getDisplay();
dd($output);
}
}
It will allow only to run my commands one by one. But I would like to run them both so after running the first one, the second will fail (with some exit code).
As for me the best way to make background task is doing it via supervisor, create config file, like:
[program:your_service]
command=/usr/local/bin/php /srv/www/bin/console <your:app:command>
priority=1
numprocs=1
# Each 5 min.
startsecs=300
autostart=true
autorestart=true
process_name=%(program_name)s_%(process_num)02d
user=root
this is the best way to be sure that your command will be ran only in one process

php app / console stops working

After a slight modification of my units, I wanted the update with a simple php app/console doctrine: update --force. But no action executed and in addition no response. I then did a php app/check.php meaning me no problems (Your system is ready to run Symfony2 projects). I do not understand and it doesn't provide an error. Here's what I've done:
Command: ********: ***** ProjetSymphony $ php app / console***
Answer (none): ******* **** $ ProjetSymphony***
If someone has an idea.
Screen :
Try with:
php app/console doctrine:schema:update --force
Maybe it's only a syntaxis error.
Also, if anyone tries to run php app/console in a newer symfony version (for example symfony 3.0), you will get an error: no file found because the file was moved to 'bin' folder. Now to run from the console, you have to use php bin/console instead. Just in case this change confused anyone who started to learn symfony and updated to 3.0.
I finally found my mistake. I had a command file that prevented the execution of my order (CreateUserCommand.php)
If someone wants to explain to me why this cosait file an error during the execution of my order ...
Here is the file :
<?php
namespace FP\UserBundle\Command;
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use FOS\UserBundle\Model\User;
use FOS\UserBundle\Command\CreateUserCommand as BaseCommand;
class CreateUserCommand extends BaseCommand
{
/**
* #see Command
*/
protected function configure()
{
exit;
echo "tes";
parent::configure();
$this
->setName('fp:user:create')
->getDefinition()->addArguments(array(
new InputArgument('age', InputArgument::REQUIRED, 'The age')
))
;
}
/**
* #see Command
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
exit;
echo "tes";
$username = $input->getArgument('username');
$email = $input->getArgument('email');
$password = $input->getArgument('password');
$age = $input->getArgument('age');
$inactive = $input->getOption('inactive');
$superadmin = $input->getOption('super-admin');
$manipulator = $this->getContainer()->get('fos_user.util.user_manipulator');
$manipulator->setAge($age);
$manipulator->create($username, $password, $email, !$inactive, $superadmin);
$output->writeln(sprintf('Created user <comment>%s</comment>', $username));
}
/**
* #see Command
*/
protected function interact(InputInterface $input, OutputInterface $output)
{
exit;
echo "tes";
parent::interact($input, $output);
if (!$input->getArgument('age')) {
$age = $this->getHelper('dialog')->askAndValidate(
$output,
'Please choose a age:',
function($age) {
if (empty($age)) {
throw new \Exception('Lastname can not be empty');
}
return $age;
}
);
$input->setArgument('age', $age);
}
}
}

Laravel multi tenant migrate

Wondering if anyone knows how or of a package that allows migrations to be done on multiple databases without having the additional connection in the config file. Currently I have two different connections, one for the default and another for the tenants. The tenant connection has the credentials input, but it doesn't have the database name since each tenant will have a different database name. Problem is when I'm doing the initial setup and need the migrations to be run it will do it for the default or the tenant(if I edit the file to include the database name). I had found a package that would do it but it is not currently compatible with laravel 5. Obviously if I have to do it manually it can be done. It would just be a pain. Thanks in advance for suggestions.
Looking through the tenancy related questions here, I stumbled upon your open one.
What I've done is override the default MigrateCommand provided by Laravel and add the --tenant option. This will allow me to migrate one, more or all tenants. You can check the implementation out at my repository. Knowing the code of conduct here, I'll also add an example implementation:
<?php
namespace Hyn\MultiTenant\Commands\Migrate;
use Hyn\MultiTenant\Traits\TenantDatabaseCommandTrait;
use Illuminate\Database\Migrations\Migrator;
use PDOException;
class MigrateCommand extends \Illuminate\Database\Console\Migrations\MigrateCommand
{
use TenantDatabaseCommandTrait;
/**
* MigrateCommand constructor.
*
* #param Migrator $migrator
*/
public function __construct(Migrator $migrator)
{
parent::__construct($migrator);
$this->website = app('Hyn\MultiTenant\Contracts\WebsiteRepositoryContract');
}
public function fire()
{
// fallback to default behaviour if we're not talking about multi tenancy
if (! $this->option('tenant')) {
$this->info('No running tenancy migration, falling back on native laravel migrate command due to missing tenant option.');
return parent::fire();
}
if (! $this->option('force') && ! $this->confirmToProceed()) {
$this->error('Stopped no confirmation and not forced.');
return;
}
$websites = $this->getWebsitesFromOption();
// forces database to tenant
if (! $this->option('database')) {
$this->input->setOption('database', 'tenant');
}
foreach ($websites as $website) {
$this->info("Migrating for {$website->id}: {$website->present()->name}");
$website->database->setCurrent();
$this->prepareDatabase($website->database->name);
// The pretend option can be used for "simulating" the migration and grabbing
// the SQL queries that would fire if the migration were to be run against
// a database for real, which is helpful for double checking migrations.
$pretend = $this->input->getOption('pretend');
// Next, we will check to see if a path option has been defined. If it has
// we will use the path relative to the root of this installation folder
// so that migrations may be run for any path within the applications.
if (! is_null($path = $this->input->getOption('path'))) {
$path = $this->laravel->basePath().'/'.$path;
} else {
$path = $this->getMigrationPath();
}
try {
$this->migrator->run($path, $pretend);
} catch (PDOException $e) {
if (str_contains($e->getMessage(), ['Base table or view already exists'])) {
$this->comment("Migration failed for existing table; probably a system migration: {$e->getMessage()}");
continue;
}
}
// Once the migrator has run we will grab the note output and send it out to
// the console screen, since the migrator itself functions without having
// any instances of the OutputInterface contract passed into the class.
foreach ($this->migrator->getNotes() as $note) {
$this->output->writeln($note);
}
}
// Finally, if the "seed" option has been given, we will re-run the database
// seed task to re-populate the database, which is convenient when adding
// a migration and a seed at the same time, as it is only this command.
if ($this->input->getOption('seed')) {
$this->call('db:seed', ['--force' => true, '--tenant' => $this->option('tenant')]);
}
}
/**
* Prepare the migration database for running.
*
* #return void
*/
protected function prepareDatabase($connection = null)
{
if (! $connection) {
$connection = $this->option('database');
}
$this->migrator->setConnection($connection);
if (! $this->migrator->repositoryExists()) {
$options = ['--database' => $connection];
$this->call('migrate:install', $options);
}
}
/**
* #return array
*/
protected function getOptions()
{
return array_merge(
parent::getOptions(),
$this->getTenantOption()
);
}
}
If you have any questions to solve this issue, let me know.

How to get the Mink Selenium 2 Driver to wait for the page to load with Behat

I am in the process of upgrading from the Behat 2.x series to the Behat 3.x series. In the prior version I could load the Selenium 1 driver, which attached to PhantomJS to execute tests. When I did this I was able to hook into a function called waitForPageToLoad().
This function was provided by php-selenium (from Alexandre Salomé). It hooked into selenium and called a driver action by the same name. This worked perfectly for ensuring that Selenium waited for a page to load. At least until a timeout was reached. It made tests to go much faster.
The problem is that the Selenium 1 driver is not compatible with Behat 3.x. It looks like it has been all but abandoned and I don't see that functionality in the Selenium 2 driver for Mink.
Does anyone know of a way to make this work with Behat 3.x and Selenium 2?
Using Selenium (or any other driver for that matter), I've never had to worry about whether the page has loaded or not, with one exception: if the page finishes loading, then loads more content via AJAX.
To handle this, you can use a spin function as documented in the Behat Manual.
http://docs.behat.org/en/v2.5/cookbook/using_spin_functions.html
The benefits of this are:
It doesn't need you to use the selenium driver (for example, you could use PhantomJS if you want speed over looks).
It won't break if you stop using jQuery and switch to something else (such as Angular's $httpProvider)
I wouldn't use theirs though, the back trace is broken and who want's to wait a second between checks anyway. :)
Try this:
Assuming you are using the Mink Context (thanks Mick), you can simply check the page every second or so until the desired
text has either appeared or dissapeared, or a given timeout has expired in which case we'd assume a fail.
/**
* #When I wait for :text to appear
* #Then I should see :text appear
* #param $text
* #throws \Exception
*/
public function iWaitForTextToAppear($text)
{
$this->spin(function(FeatureContext $context) use ($text) {
try {
$context->assertPageContainsText($text);
return true;
}
catch(ResponseTextException $e) {
// NOOP
}
return false;
});
}
/**
* #When I wait for :text to disappear
* #Then I should see :text disappear
* #param $text
* #throws \Exception
*/
public function iWaitForTextToDisappear($text)
{
$this->spin(function(FeatureContext $context) use ($text) {
try {
$context->assertPageContainsText($text);
}
catch(ResponseTextException $e) {
return true;
}
return false;
});
}
/**
* Based on Behat's own example
* #see http://docs.behat.org/en/v2.5/cookbook/using_spin_functions.html#adding-a-timeout
* #param $lambda
* #param int $wait
* #throws \Exception
*/
public function spin($lambda, $wait = 60)
{
$time = time();
$stopTime = $time + $wait;
while (time() < $stopTime)
{
try {
if ($lambda($this)) {
return;
}
} catch (\Exception $e) {
// do nothing
}
usleep(250000);
}
throw new \Exception("Spin function timed out after {$wait} seconds");
}
Selenium2 now has the wait($timeout, $condition) function.
You can use it like:
/**
* #Then /^I wait for the ajax response$/
*/
public function iWaitForTheAjaxResponse()
{
$this->getSession()->wait(5000, '(0 === jQuery.active)');
}
Other conditions that you could test for are:
the appearance of a certain element on the page
the DOM to finish loading
The reason for the change is outlined on the selenium website documentation
In order to help someone else, I added this method in FeatureContext.php :
/**
* #Then I wait :sec
*/
public function wait($sec)
{
sleep($sec);
}
And it's working
Will
/**
* #Then /^I wait for the ajax response$/
*/
public function iWaitForTheAjaxResponse()
{
$this->getSession()->wait(5000, '(0 === jQuery.active)');
}
it's working

Variable number of options for symfony/console component

How would one configure symfony/console to accept a dynamic list of options?
That said - the names for the options aren't known on development step so I need an application to accept everything and expose it using the standard $input->getOption.
Any chance it can be done easily (without hacking the component in million places)?
My attempts included extending the ArgvInput and InputDefinition classes but they failed due to various reasons (they are objective and symfony/console component implementation-specific). Briefly: the former requires parsing to be invoked multiple times; the latter - is instantiated in multiple places so I just couldn't find a proper way to inject it.
You can create your own ArgvInput that will allow all options.
For example you can see the slightly modified version of ArgvInput here
I have only modified lines : 178
And comment out the lines: 188-199
Then pass instance of your version ArgvInput instead of default one to
$input = new AcceptAllArgvInput();
$kernel = new AppKernel($env, $debug);
$application = new Application($kernel);
$application->run($input);
I have accomplished this in the past using the IS_ARRAY option. Would this not work for your instance as well?
->addArgument('routeParams', InputArgument::IS_ARRAY, "Required Placeholders for route");
My use case was a custom URL generator for a special authentication system. I needed a way to generate URLs for testing. Naturally, each route has a different number of required parameters and I wanted to avoid passing the parameters as a CSV string.
Command examples:
Usage: myGenerateToken user route [variables1] ... [variablesN]
php app/console myGenerateToken 1 productHomePage
php app/console myGenerateToken 1 getProduct 1
php app/console myGenerateToken 1 getProductFile 1 changelog
The variables were delivered to the command in the "routeParams" as an array
$params = $input->getArgument('routeParams');
var_dump($params);
array(2) {
[0] =>
string(1) "1"
[1] =>
string(9) "changelog"
}
I noticed that there is also an "Option" version called InputOption::VALUE_IS_ARRAY, but I did not have success getting it to work. The argument version InputArgument::IS_ARRAY seems to behave as an option anyways, as it does not error if no arguments are specified.
EDIT:
The author's question is seeking "How do i define variable command line options at run time" where my answer is "How do you provide multiple values for a pre-defined option/argument"
Here is how to implement this on PHP 7+ using symfony/console ^3.0:
abstract class CommandWithDynamicOptions extends Command {
/** #var array The list of dynamic options passed to the command */
protected $dynamicOptions = [];
/**
* #inheritdoc
*/
protected function configure() {
$this->setName('custom:command');
$this->setDefinition(new class($this->getDefinition(), $this->dynamicOptions) extends InputDefinition {
protected $dynamicOptions = [];
public function __construct(InputDefinition $definition, array &$dynamicOptions) {
parent::__construct();
$this->setArguments($definition->getArguments());
$this->setOptions($definition->getOptions());
$this->dynamicOptions =& $dynamicOptions;
}
public function getOption($name) {
if (!parent::hasOption($name)) {
$this->addOption(new InputOption($name, null, InputOption::VALUE_OPTIONAL));
$this->dynamicOptions[] = $name;
}
return parent::getOption($name);
}
public function hasOption($name) {
return TRUE;
}
});
}
}
Another approach bypassing Symfony validation and reading from argv directly:
class Foo extends Command {
protected function configure() {
$this->ignoreValidationErrors();
}
protected function execute(InputInterface $input, OutputInterface $output): int {
global $argv;
$customOptions = array_filter($argv, static function ($value) {
return is_string($value) && substr($value, 0, 2) === '--';
});
var_dump($customOptions);
}
}
./foo --foo=bar
Result:
array(1) {
[4]=> string(9) "--foo=bar"
}

Categories