Статьи

IronMQ и Laravel: реализация

Добро пожаловать обратно в серии IronMQ и Laravel — это вторая и последняя часть, в которой мы завершаем работу над нашим веб-приложением с поддержкой фоновых заданий.

Уже есть несколько учебных пособий, связанных с очередями — например: http://vimeo.com/64703617, где Тейлор учит вас, как записывать в файл с использованием очередей. В этом уроке мы попробуем что-то другое.

Мы job_id таблицу заданий, в которой есть job_id и статус задания. Когда вы помещаете задание в очередь, состояние задания будет поставлено в очередь, а когда мы получим задание, мы установим состояние на выполнение . Соответственно, после его завершения мы отметим его как завершенный .

Позже мы изменим размеры изображений.

Таблица рабочих мест

Шаг 1

Давайте создадим таблицу вакансий:

 php artisan migrate:make create_jobs_table 

Перейдите в app/database/migrations/xxxxx_create_jobs_table.php и добавьте следующее (этот код извлечен из app/database/migrations/xxxxx_create_jobs_table.php , поэтому отредактируйте файл соответствующим образом):

 public function up() { Schema::create('jobs', function($table) { $table->increments('id'); $table->string('job_id'); $table->enum('status', array('queued', 'running','finished'))->default('queued'); $table->timestamps(); }); } public function down() { Schema::drop('jobs'); } 

Здесь мы создали таблицу со столбцами job_id , status и timestamps . Запустите php artisan migrate чтобы создать таблицу.

Шаг 2

Создайте файл job.php в app/models со следующим содержимым:

 <?php class Job extends Eloquent { protected $table = 'jobs'; protected $fillable = array('job_id', 'status'); } 

Создайте JobController с помощью следующей команды:

 php artisan controller:make JobController 

и добавьте следующее в файл app/routes.php :

 Route::resource('job','JobController'); 

Перейти к JobController заполнить индексный метод.

 public function index() { $jobs = Job::all(); return View::make('job.index')->with('jobs',$jobs); } 

Прежде чем идти вперед, нам нужно настроить наши взгляды. Во-первых, давайте создадим views/master.blade.php который будет служить шаблоном.

 <!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Laravel PHP Framework</title> <link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css"> </head> <body> <div class="container"> <div class="row"> <div class="col-md-12 well"> Let's Learn Queues </div> @yield('content') </div> </div> </body> </html> 

Давайте рассмотрим нашу работу. Поместите следующий контент в app/views/job/index.blade.php

 @extends('master') @section('content') <div class="col-md-12"> <table class="table"> <thead> <tr> <th>#</th> <th>Job ID</th> <th>Status</th> </tr> </thead> <tbody> @foreach($jobs as $job) <tr> <td>{{ $job->id }}</td> <td>{{ $job->job_id }}</td> <td>{{ $job->status }}</td> </tr> @endforeach </tbody> </table> </div> @stop 

Поскольку у нас сейчас нет работы, мы ничего не увидим, если перейдем по http://localhost:8000/job .

Теперь давайте создадим новое задание (где мы записываем строку в файл), а затем обновим статус задания до «выполнено».

 public function create() { $job_id = Queue::push('JobController@run',array('string' => 'Hello World ')); Job::create(array('job_id' => $job_id)); return Redirect::route('job.index'); } 

Обратите внимание, что выше мы поместили метод run в очередь с некоторыми данными. Поэтому нам нужно создать метод run в JobController.

 public function run($job,$data) { $job_id = $job->getJobId(); // Get job id $ejob = Job::where('job_id',$job_id)->first(); // Find the job in database $ejob->status = 'running'; //Set job status to running $ejob->save(); File::append('public/queue.txt',$data['string'].$job_id.PHP_EOL); //Add content to file $ejob->status = 'finished'; //Set job status to finished $ejob->save(); return true; } 

На данный момент вы можете проверить это. Давайте попробуем использовать URL, сгенерированный ngrok. Обратите внимание, что ваш URL будет отличаться от моего.

  1. Перейдите на http://953ffbb.ngrok.com (должно работать)
  2. В Iron MQ Dashboard -> Project -> Queues -> Your Queue -> Push Queues: вы должны увидеть http://953ffbb.ngrok.com/queue/receive под подписчиками.
  3. Перейдите по адресу http://953ffbb.ngrok.com/job : там должен отображаться список рабочих мест (возможно, рабочих мест нет, поскольку мы их не создавали).
  4. Создать работу: http://953ffbb.ngrok.com/job/create . Это создаст работу и вернется на http://953ffbb.ngrok.com/job, где вы увидите свою работу с job_id и статусом «в очереди».
  5. Обновите страницу: http://953ffbb.ngrok.com/job, и вы увидите, что статус изменен на «закончен», и найдите файл public/queue.txt с некоторым текстом.

Это оно! Мы поместили работу в очередь, Айрон отправил ее подписчику, и мы завершили нашу работу (записали данные в файл и изменили статус).


Изменить размер фотографий

Давайте загрузим фотографии и изменим их размер с помощью Intervention.

Сделайте PhotoController для обработки операций с фотографиями:

 php artisan controller:make PhotoController 

Добавить маршрут для фотографий в app / rout.php

 Route::resource('photo','PhotoController'); 

Составим таблицу для фотографий:

 php artisan migrate:make create_photos_table 

Откройте файл app/database/migrations/xxxxxx_create_photos_table.php и следующий контент:

 public function up() { Schema::create('photos', function($table) { $table->increments('id'); $table->string('path'); $table->timestamps(); }); } public function down() { Schema::drop('photos'); } 

А затем запустите php artisan migrate чтобы создать таблицу.

Давайте создадим модель для фотографий в app/models/photo.php

 <?php class Photo extends Eloquent { protected $table = 'photos'; protected $fillable = array('path'); } 

Добавьте метод индекса в PhotoController

 public function index() { $photos = Photo::all(); return View::make('photo.index')->with('photos',$photos); } 

Добавьте индекс просмотра фотографий в app/views/photo/index.blade.php

 @extends('master') @section('content') <div class="col-md-12"> <h2>Photos</h2> <a href="{{ route('photo.create') }}" class="btn btn-primary">Upload New Photo</a> <br><br> <table class="table"> <thead> <tr> <th>#</th> <th>Path</th> </tr> </thead> <tbody> @foreach($photos as $photo) <tr> <td>{{ $photo->id }}</td> <td>{{ $photo->path }}</td> <td> <a href="{{ route('photo.edit', $photo->id) }}" class="btn btn-primary btn-xs"> Resize </a> </td> </tr> @endforeach </tbody> </table> </div> @stop 

Теперь вы можете посетить: http: // localhost: 8000 / photo и проверить страницу (но фотографий не будет)

Нам нужна страница для загрузки фотографий, поэтому давайте сделаем просмотр и подключим несколько методов для достижения этой цели.

Поместите этот контент в app/views/photo/create.blade.php

 @extends('master') @section('content') <div class="col-md-12"> <h2>Upload New Photo</h2> {{ Form::open(array('route' => array('photo.store'),'files' => true)) }} <div class="form-group"> {{ Form::file('photo') }} </div> {{ Form::submit('Upload',array('class' => 'btn btn-blue btn-primary')) }} {{ Form::close() }} </div> @stop 

Внесите изменения в app/controllers/PhotoController.php

 public function create() { return View::make('photo.create'); } public function store() { $file = Input::file('photo'); // Get the file $extension = $file->getClientOriginalExtension(); //Get the extension $filename = time().'.'.$extension; //Prepare filename $upload_success = $file->move('public/uploads', $filename); //Move file Photo::create(array('path' => 'uploads/'.$filename )); //Store info in DB return Redirect::route('photo.index'); } 

Перейдите по http://localhost:8000/photo нажмите «Загрузить новое фото» и загрузите фотографию. Вы можете перейти к public/uploads и найти свою фотографию. В то же время вы можете найти список фотографий вместе с кнопкой изменения размера. Теперь нам нужна форма, где мы можем указать ширину и высоту для изменения размера.

Поместите этот контент в app/views/photo/edit.blade.php

 @extends('master') @section('content') <div class="col-md-12"> <h2>Resize Photo</h2> {{ Form::open(array('route' => array('photo.update',$photo->id), 'method' => 'PUT')) }} <div class="form-group"> {{ Form::label('width', 'Width') }} {{ Form::text('width') }} </div> <div class="form-group"> {{ Form::label('height', 'Height') }} {{ Form::text('height') }} </div> {{ Form::submit('Submit',array('class' => 'btn btn-blue btn-primary')) }} {{ Form::close() }} </div> @stop 

Следующие три метода будут выполнять нашу работу по изменению размера изображений:

      public   function  edit ( $id ) 
     { $photo =   Photo :: find ( $id ); 

         return   View :: make ( 'photo.edit' )-> with ( 'photo' ,  $photo ); 
     } 

     public   function  update ( $id ) 
     { $data [ 'photo_id' ]   =  $id ; $data [ 'width' ]   =   Input :: get ( 'width' ); $data [ 'height' ]   =   Input :: get ( 'height' ); $job_id =   Queue :: push ( 'PhotoController@resize' ,  $data );   //Put a job in queue to resize 

         Job :: create ( array ( 'job_id'   =>  $job_id )); 

         return   Redirect :: route ( 'photo.index' ); 
     } 

     public   function  resize ( $job ,  $data ) 
     { $job_id =  $job -> getJobId ();   // Get job id $ejob =   Job :: where ( 'job_id' ,  $job_id )-> first ();   // Find the job in database $ejob -> status =   'running' ;   //Set job status to running $ejob -> save (); $photo =   Photo :: find ( $data [ 'photo_id' ]); $filename =  $data [ 'width' ]   .   '_'   .  $data [ 'height' ]   .   '_'   .  basename ( $photo -> path ); 

         Image :: open ( 'public/'   .  $photo -> path ) 
             -> resize ( $data [ 'width' ],  $data [ 'height' ],   true ) 
             -> save ( 'public/uploads/'   .  $filename ); 

         Photo :: create ( array ( 'path'   =>   'uploads/'   .  $filename )); $ejob -> status =   'finished' ;   //Set job status to finished $ejob -> save (); 

         return   true ; 
     } 

Теперь, если вы нажмете на изменить размер и отправите форму, работа будет поставлена ​​в очередь. Если вы обновите страницу с фотографиями, вы найдете новое фото.

Вывод

В этой серии статей мы реализовали IronMQ с Laravel, чтобы добавить возможности обработки фонового изображения в наше веб-приложение. Видишь как все было просто? У тебя были проблемы? Хочу увидеть больше? Дайте нам знать!