Добро пожаловать обратно в серии 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 будет отличаться от моего.
- Перейдите на http://953ffbb.ngrok.com (должно работать)
- В Iron MQ Dashboard -> Project -> Queues -> Your Queue -> Push Queues: вы должны увидеть http://953ffbb.ngrok.com/queue/receive под подписчиками.
- Перейдите по адресу http://953ffbb.ngrok.com/job : там должен отображаться список рабочих мест (возможно, рабочих мест нет, поскольку мы их не создавали).
- Создать работу: http://953ffbb.ngrok.com/job/create . Это создаст работу и вернется на http://953ffbb.ngrok.com/job, где вы увидите свою работу с job_id и статусом «в очереди».
- Обновите страницу: 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, чтобы добавить возможности обработки фонового изображения в наше веб-приложение. Видишь как все было просто? У тебя были проблемы? Хочу увидеть больше? Дайте нам знать!