Laravel 5: Migration-Route - Artisan::call('migrate', array('--force' => true)) stops - php

I have an migration-route in my application, the current output is:
init migrate:install...done migrate:install
init with tables migrations...
Now it stops. But the output should continue. Heres the route:
Route::get('/migrate', function () {
try {
try {
echo '<br>init migrate:install...';
Artisan::call('migrate:install');
echo 'done migrate:install';
} catch (Exception $e) {
echo 'allready installed';
}
echo '<br>init with tables migrations...';
Artisan::call('migrate', array('--force' => true)); // here it stops via browser
echo 'done with migrations';
echo '<br>clear view cache...';
$cachedViewsDirectory = app('path.storage').'/framework/views/';
if ($handle = opendir($cachedViewsDirectory)) {
while (false !== ($entry = readdir($handle))) {
if(strstr($entry, '.')) continue;
#unlink($cachedViewsDirectory . $entry);
}
closedir($handle);
}
echo 'all view cache cleared';
return redirect()->route('backend::dashboard');
} catch (Exception $e) {
Response::make($e->getMessage(), 500);
}
});
While accessing the Shell and run the migration it will work:
-bash-4.2$ /opt/plesk/php/5.6/bin/php artisan migrate
**************************************
* Application In Production! *
**************************************
Do you really wish to run this command? (yes/no) [no]:
> yes
Migrated: 2016_08_23_194102_import_old_data
Migrated: 2016_08_25_080129_import_old_adresses
Migrated: 2016_08_25_080801_import_oldname_to_accountholder
Why it doesn't work from route?
UPDATE
The Apache Log shows "GET /migrate HTTP/1.0" with return state 200, so its HTTP OK.
Also in Browser DEV tools no errors.
UPDATE 2
Also laravel.log is empty. No new entry during call to migration-route.

post the error, open dev tools > network tab, or apache error logs

OK I got it run.
Original migration (wich may would been usefull if I idiot had posted it)
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
// Load data to be imported.
$oldOrders = json_decode(File::get('storage/olddata.json'), TRUE);
// Update.
foreach ($oldOrders as $rawOrder) {
/* #var \App\Order $order */
$order = \App\Order::find(intval($rawOrder['id']));
// Check whether order is payed.
if ($order->isPayed() === FALSE && floatval($rawOrder["payedAmount"]) != 0) {
/* #var \App\Payment $payment */
$payment = new \App\Payment();
$payment->order_id = $order->id;
$payment->amount = $rawOrder["payedAmount"];
$payment->method = $rawOrder["paymentMethod"];
$payment->save();
}
}
}
And the migration now
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
// Load data to be imported.
$oldOrders = json_decode(File::get(base_path('storage/olddata.json')), TRUE);
// Update.
foreach ($oldOrders as $rawOrder) {
/* #var \App\Order $order */
$order = \App\Order::find(intval($rawOrder['id']));
// Check whether order is payed.
if ($order->isPayed() === FALSE && floatval($rawOrder["payedAmount"]) != 0) {
/* #var \App\Payment $payment */
$payment = new \App\Payment();
$payment->order_id = $order->id;
$payment->amount = $rawOrder["payedAmount"];
$payment->method = $rawOrder["paymentMethod"];
$payment->save();
}
}
}
On local environment I migrated from shell. The startpoint there is /. But with the route the startpoint seems to be something else and File::get threw an Exception. But (whyever) it never got logged. I added try{}catch(\Exception $e){} around the migration and saw the error.

Related

how to use apache kafka consumer in laravel

I am trying to use apache kafka consumer and producer with in laravel framework
i create console command and execute php artisan command with nohup in production to be run until exeption happen. is there any best way to use real time consume and pruduce and prevent message loss
and if i kill command with kill pid messages will be loss ?
class JsonKafka extends Command
{
private $topic;
private $producer;
/**
* The name and signature of the console command.
*
* #var string
*/
protected $signature = 'kafka:up';
/**
* The console command description.
*
* #var string
*/
protected $description = 'kafka';
/**
* Create a new command instance.
*
* #return void
*/
public function __construct()
{
parent::__construct();
$conf = new \RdKafka\Conf();
$conf->set('metadata.broker.list', '0.0.0.0:29092');
//$conf->set('enable.idempotence', 'true');
$this->producer = new \RdKafka\Producer($conf);
$this->topic = $this->producer->newTopic('test_php');
}
/**
* Execute the console command.
*
* #return int
*/
public function handle()
{
//consume
$conf = new \RdKafka\Conf();
// Set a rebalance callback to log partition assignments (optional)
$conf->setRebalanceCb(function (\RdKafka\KafkaConsumer $kafka, $err, array $partitions = null) {
switch ($err) {
case RD_KAFKA_RESP_ERR__ASSIGN_PARTITIONS:
echo "Assign: ";
var_dump($partitions);
$kafka->assign($partitions);
break;
case RD_KAFKA_RESP_ERR__REVOKE_PARTITIONS:
echo "Revoke: ";
var_dump($partitions);
$kafka->assign(NULL);
break;
default:
throw new \Exception($err);
}
});
// Configure the group.id. All consumer with the same group.id will consume
// different partitions.
$conf->set('group.id', 'service');
// Initial list of Kafka brokers
$conf->set('metadata.broker.list', '0.0.0.0:29092');
// Set where to start consuming messages when there is no initial offset in
// offset store or the desired offset is out of range.
// 'earliest': start from the beginning
$conf->set('auto.offset.reset', 'earliest');
$consumer = new \RdKafka\KafkaConsumer($conf);
// Subscribe to topic 'messages'
$consumer->subscribe(['messages']);
echo "Waiting for partition assignment... (make take some time when\n";
echo "quickly re-joining the group after leaving it.)\n";
while (true) {
$message = $consumer->consume(120 * 1000);
switch ($message->err) {
case RD_KAFKA_RESP_ERR_NO_ERROR:
Service::getInstance()->main(json_decode($message->payload, true))
break;
case RD_KAFKA_RESP_ERR__PARTITION_EOF:
echo "No more messages; will wait for more\n";
break;
case RD_KAFKA_RESP_ERR__TIMED_OUT:
echo "Timed out\n";
break;
default:
throw new \Exception($message->errstr(), $message->err);
}
}
}
private function produce(string $key,array $message)
{
$this->topic->produce(RD_KAFKA_PARTITION_UA, 0, json_encode($message), $key);
$this->producer->poll(0);
for ($flushRetries = 0; $flushRetries < 10; $flushRetries++) {
$result = $this->producer->flush(10000);
if (RD_KAFKA_RESP_ERR_NO_ERROR === $result) {
echo 'produced' . PHP_EOL;
break;
}
}
if (RD_KAFKA_RESP_ERR_NO_ERROR !== $result) {
throw new \RuntimeException('Was unable to flush, messages might be lost!');
}
}

How to use Redis cache in Laravel?

It's my first time to use Laravel and Redis. I understand how to get, set, etc of Redis on Terminal. But no idea how to apply Redis on Laravel application.
I have application that saves participant's information in DB with MVC pattern. and I'd like to change it to use Redis cache to make it faster(and for practice). What do I have to do? Could you explain it with code?
This is ParticipantController. 'edit' function send user to edit page, and user edit the information and push 'save', it activate 'update' function. store/updateUserInput functions are just saving data to DB nothing else.
/**
* Show the form for editing the specified participant.
*
* #param int $id
* #return View
*/
public function edit(int $id): View
{
$participant = Participant::find($id);
if(empty($participant)){
return view('errors.404');
}
return view('participants.edit', ['participant'=>$participant]);
}
/**
* Update the specified participant in storage.
*
* #param ParticipantValidation $request
* #return RedirectResponse
*/
public function update(ParticipantValidation $request): RedirectResponse
{
$participant = Participant::find($request->id);
if(empty($participant)){
return view('errors.404');
}
$detail = $request->all();
Participant::updateUserInput($detail);
return redirect()->route('participants.create', $detail['event_id'])->with('success', 'Updated!');
}
+plus I tried this code on top of 'Controller' to use sth like $redis->set('message', 'Hello world'); but there's error that they cannot find 'Predis/Autoload.php'
require 'Predis/Autoload.php';
PredisAutoloader::register();
try {
$redis = new PredisClient();
}
catch (Exception $e) {
die($e->getMessage());
}
You can use the Cache facade
In your .env file, you must add CACHE_DRIVER=redis
Then whenever you want to get an instance of Participant:
$participant = null;
$key ="Participant".$id;
if(Cache::has($key)//get participant from cache
$participant = Cache::get($key);
else{//get participant and cache for 3 minutes
$participant = Participant::find($id);
$seconds = 180;
Cache::set($key, $participant, $seconds);
}

Laravel5: How to disable default scheduler message if no command is ready to run

When using the Laravel5 scheduler:
* * * * * cd /path-to-your-project && php artisan schedule:run >> /dev/null 2>&1
We receive the following default output if no command is ready to run:
# No scheduled commands are ready to run.
How to disable this default Laravel5 message? We don't want to have an output if there is no command ready to run. The best would be, when we were able to configure that message and return code on our self.
You can create a new command in app/Console/Commands similar to below, which extends the default schedule:run command.
It overrides the handle method while leaving everything else as-is to avoid having Laravel output the "No scheduled commands are ready to run." line when it didn't do anything.
By using a different name there's no need to worry about conflicts, and you can still run the original php artisan schedule:run command at any time if you so desire.
<?php
namespace App\Console\Commands
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Console\Scheduling\ScheduleRunCommand;
class RunTasks extends ScheduleRunCommand
{
/**
* The console command name.
*
* #var string
*/
protected $name = 'run:tasks';
/**
* The console command description.
*
* #var string
*/
protected $description = 'Custom task runner with no default output';
/**
* Create a new command instance.
*
* #param \Illuminate\Console\Scheduling\Schedule $schedule
* #return void
*/
public function __construct(Schedule $schedule)
{
parent::__construct($schedule);
}
/**
* Execute the console command.
*
* #return void
*/
public function handle()
{
foreach ($this->schedule->dueEvents($this->laravel) as $event) {
if (! $event->filtersPass($this->laravel)) {
continue;
}
if ($event->onOneServer) {
$this->runSingleServerEvent($event);
} else {
$this->runEvent($event);
}
$this->eventsRan = true;
}
if (! $this->eventsRan) {
// Laravel would output the default text here. You can remove
// this if statement entirely if you don't want output.
//
// Alternatively, define some custom output with:
// $this->info("My custom 'nothing ran' message");
}
}
}
Verify that Laravel sees your new command:
php artisan | grep run:tasks
Finally update your cron to run the new command:
* * * * * cd /path-to-your-project && php artisan run:tasks >> /dev/null 2>&1
As I mentioned in the comments I see two possibilities
You can filter the output by removing what you don't want
* * * * * cd /path-to-your-project && php artisan schedule:run | awk '{ if (/No scheduled commands are ready to run./ && !seen) { seen = 1 } else print }'
Or you can override with your own command:
$ php artisan make:command ScheduleRunCommand
By making your own command (mostly copy/past from ScheduleRunCommand) or extending the ScheduleRunCommand as #dave-s proposed
And if you want to still run php artisan schedule:run with your new command,
you need to register it in a service provider
$this->app->extend('schedule.run', function () {
return new \App\Console\Commands\ScheduleRunCommand;
});
If you look at the code for Laravel at https://github.com/laravel/framework/blob/78505345f2a34b865a980cefbd103d8eb839eedf/src/Illuminate/Console/Scheduling/ScheduleRunCommand.php#L82
public function handle()
{
foreach ($this->schedule->dueEvents($this->laravel) as $event) {
if (! $event->filtersPass($this->laravel)) {
continue;
}
if ($event->onOneServer) {
$this->runSingleServerEvent($event);
} else {
$this->runEvent($event);
}
$this->eventsRan = true;
}
if (! $this->eventsRan) {
$this->info('No scheduled commands are ready to run.');
}
}
You see that it's handled via $this->info handler.
The info handler is defined in Command.php Which calls the line method, which calls the output handler which is defined in the run command
So in essence to be able to intercept this you should be able to override the OutputStyle which is based on the symfonystyle by binding your own output handler before running the commands in the file you call in your cron job.
The best working scenario I can think of is by using an OutputFormatter where you simply return null when the string matches your target string.
$this->output->setFormatter( new MyCatchemAllFormatter() );
And in the class you would define something along the lines of:
use Symfony\Component\Console\Formatter\OutputFormatter;
class MyCatchemAllFormatter extends OutputFormatter
{
public function formatAndWrap(string $message, int $width)
{
if($message != 'No scheduled commands are ready to run.') {
return parent::formatAndWrap($message, $width);
}
return null;
}
}
I understand that my solution is DIRTY and I'll get downvotes by most of SO users, but it's quick to do without registering additional service providers, modifying classes and etc.
I've checked sources and found this at line 81 of ScheduleRunCommand which is
public function handle()
{
foreach ($this->schedule->dueEvents($this->laravel) as $event) {
if (! $event->filtersPass($this->laravel)) {
continue;
}
if ($event->onOneServer) {
$this->runSingleServerEvent($event);
} else {
$this->runEvent($event);
}
$this->eventsRan = true;
}
if (! $this->eventsRan) { // L81
$this->info('No scheduled commands are ready to run.'); // L82
}
}
The quickest way to "cheat" with it is to copy that class to app/Console/ScheduleRunCommand.php and copy that file to original source path every-time when composer dump-autoload called.
1) Copy original file to app/Console folder:
cp vendor/laravel/framework/src/Illuminate/Console/Scheduling/ScheduleRunCommand.php patch/ScheduleRunCommand.php app/Console/ScheduleRunCommand.php
2) add such line in composer.json scripts:post-autoload-dump section:
cp app/Console/ScheduleRunCommand.php vendor/laravel/framework/src/Illuminate/Console/Scheduling/ScheduleRunCommand.php
3) modify Your message in app/Console/ScheduleRunCommand.php (L82):
if (! $this->eventsRan) {
$this->info('NOTHING');
}
4) run: composer dump
and result:

How to make a 'npm run build' from a symfony project

I currently have a symfony project that uses Foundation for Emails to create responsive emails.
The Foundation framework uses the command 'npm run build' to tranform files. I tried doing a service parse my content using the Process class but I must be using it wrong as it does not execute 'npm run build'. Here is my faulty code :
<?php
/**
* Created by PhpStorm.
* User: jeremie
* Date: 28/12/17
* Time: 16:59
*/
namespace Acme\Open4XMLParserBundle\Services;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Process\Process;
/**
* #todo : code this
*/
class FoundationParser
{
protected $foundationLocation;
protected $process;
/**
* FoundationParser constructor.
* #param $foundationLocation
*/
public function __construct($foundationLocation)
{
$this->foundationLocation = $foundationLocation;
$this->process = new Process('npm run build', $this->foundationLocation);
}
/**
* Run npm run build if needed
*/
public function initFoundation()
{
//make sure that 'npm run build' is running and execute it if not
if (!$this->process->isRunning()) {
$this->process->start();
}
}
public function saveFoundationContent($foundationContent, $filename)
{
//save the file in foundation/src/pages
$fileSystem = new Filesystem();
$fileLocation = $this->foundationLocation . '/src/pages/' . $filename;
if (!$fileSystem->exists($fileLocation)) {
$fileSystem->dumpFile($fileLocation, $foundationContent);
$fileSystem->chmod($fileLocation, 0664);
}
}
public function retrieveValidHtml($fileName)
{
$fileLocation = $this->foundationLocation . '/dist/' . $fileName;
while (true) {
try {
$result = file_get_contents($fileLocation);
if ($result !== false){
return $result;
}
} catch (\Exception $e) {
}
}
}
}
And I use my service like this :
$foundationParser = $this->container->get('open4xmlparser.foundationparser');
$foundationParser->initFoundation();
$foundationParser->saveFoundationContent($foundationContent, 'test.html');
$response = new Response($foundationParser->retrieveValidHtml('test.html'));
$response->headers->set('Content-Type', 'text/html');
$response->send();
And it tells me that 'test.html' does not exist. Any idea on how to do what I want?
What I finally decided to do is a Symfony command that launch my program in an infinite loop(it is never supposed to stop). Instead of using a service I executed 'npm run build' directly in the while loop.
protected function execute(InputInterface $input, OutputInterface $output)
{
$output->writeln([
'',
'Running program',
'===============',
''
]);
$runBuild = new Process('npm run build', $this->getContainer()->getParameter('foundation_location'));
while (true) {
if (!$runBuild->isRunning()){
$output->writeln([
'',
'Executing npm run build',
''
]);
$runBuild->start();
}
}
}
You seem to have different paths in the saveFoundationContent and retrieveValidHtml for the target file.
// saveFoundationContent()
$fileLocation = $this->foundationLocation . '/src/pages/' . $filename;
// retrieveValidHtml()
$fileLocation = $this->foundationLocation . '/dist/' . $fileName;
Obviously, retrieveValidHtml() cannot find the file in the location.
Tip: Store the subdirectory path as a class variable (or constant):
class FoundationParser
{
private $subdir = "/dist/"; // or "/src/pages/";
…
public function retrieveValidHtml($fileName)
{
$fileLocation = sprintf("%s%s%s", $this->foundationLocation, $this->subdir, $fileName);
…
}
}

Value setted to null on flush doctrine

I've got a problem with my code. I am just trying to insert a simple set of data to my db, but doctrine insert my attribute (telVerifCode) as NULL.
I've dumped my data and figured out, that attribute (telVerifCode) has some value in it, but after I flush it is set to NULL.
This is my controller:
$user = $this->getUser();
if ($user->getTel() != $tel || $user->getTelCode() != $telCode) {
try {
$code = $this->sendTelehopneCode($user);
} catch (\Exception $e) {
//.......
}
// update user phone verifcation fields //
$user->setTelVerifCode($code);
$user->setLastTelVerificationCodeDate(new \DateTime());
$em->persist($user);
$em->flush();
}
My ORM Mapping:
/**
* #var string
*
* #ORM\Column(name="tel_verification_code", type="string", length=255, nullable=true)
*/
protected $telVerifCode;
/**
* #var \DateTime
*
* #ORM\Column(name="last_tel_verification_code_date", type="date", nullable=true)
*/
protected $lastTelVerificationCodeDate;
sendTelehopneCode function :
private function sendTelehopneCode($user)
{
$code = strval(rand(100000, 999999));
$tel = $user->getTelCode() . $user->getTel();
$msg = 'code:' . $code;
$twilio = $this->get('twilio.api');
try {
$message = $twilio->account->messages->sendMessage(
"+14*******", // Verified Outgoing Caller ID or Twilio number
$tel, // The phone number you wish to send a message to
$msg
);
} catch (\Services_Twilio_RestException $e) {
throw $e;
}
return $code;
}
Try clearing your doctrine caches, the code looks fine and cannot be the issue.
./bin/console doctrine:cache:clear-metadata
./bin/console doctrine:cache:clear-query
./bin/console doctrine:cache:clear-result
I solved the problem, I made a listener On preUpdate one that puts the value null, I completely forgotten it :(
Maybe your problem is due to a typo in your setter.
Are you sure your setter setTelVerifCode looks exactly like this?
public function setTelVerifCode($code)
{
$this->telVerifCode = $code;
}

Categories