#laravel #laravel-5
#laravel #laravel-5
Вопрос:
У меня есть метод в моем контроллере, который в основном просто сохраняет форму в базе данных. Моя форма очень большая, и в ней более 30-40 полей. Итак, мне нужно сохранить эту информацию в разных 3 таблицах по условию.
Например :
foreach($request->all() as $answer):
if($answer->employeeType === 1){
//store data to type_one_table
} else if($answer->employeeType === 2){
//store data to type_two_table
} else if($answer->employeeType === 3){
//store data to type_two_table
} else {
//store data to some_other_table
}
endforeach;
Итак, я думал использовать какой-нибудь пользовательский, StoreInterface
который будет иметь некоторый store
метод.
и извлечь приведенную выше логику в ее собственную реализацию.
И затем в моем конструкторе Controllers получите этот экземпляр интерфейса.
Но как я могу вызвать, что implementation
мне нужно для конкретного условия.
Могу ли я сделать это с помощью контроллера?
Или я должен использовать другую стратегию в этом случае.
пожалуйста, направьте меня.
Спасибо.
Ответ №1:
У вас может быть общий интерфейс, подобный этому:
interface EmployeeStoreContract
{
public function saveAnswer();
}
Затем реализуйте это для всех различных способов сохранения ответа, например:
class FirstTypeEmployee implements EmployeeStoreContract
{
public function saveAnswer()
{
// do something
}
}
И в вашем контроллере, чтобы выяснить, как сохранить данные запроса:
public function store()
{
$employeeTypesMap = [
1 => 'FirstTypeEmployee',
2 => 'SecondTypeEmployee',
3 => 'ThirdTypeEmployee',
];
foreach ($request->all() as $answer) {
$employeeType = $answer->employeeType;
if (!array_key_exists($employeeType, $employeeTypesMap)) {
throw new InvalidArgumentException('Answer type is not available.');
}
$employeeStrategyClass = "App\Service\Employee\{$employeeTypesMap[$employeeType]}";
$employeeStrategyObject = new $employeeStrategyClass;
$employeeStrategyObject->saveAnswer($answer);
}
}
Пожалуйста, обратите внимание, что пространство имен, в котором у вас есть эти классы AppServiceEmployee
, может быть любым, что вы хотите. Также не стесняйтесь создавать абстрактный класс или признак для повторного использования некоторой функциональности каждого класса employee.
Комментарии:
1. Спасибо за ответ. не могли бы вы, пожалуйста, объяснить последние 3 строки? откуда
new $strategyClass;
взялось? и почему `$employeeStrategyObject` это существует, если мы не используем его здесь.2. @TrueCode, да, моя ошибка, извините. Итак, по сути, вы создаете экземпляр класса в зависимости от типа ответа и вызываете
saveAnswer()
объект.3. я немного новичок в ООП, но у меня возник вопрос в этом конкретном примере, имеет ли смысл иметь
EmployeeStoreContract
? Здесь в основном мы просто переключаемся между 3 классами.4. Конечно, интерфейс
EmployeeStoreContract
заключается в том, чтобы просто убедиться, что все классы employee, формирующие$employeeTypesMap
массив, имеютsaveAnswer()
метод, так что здесь на самом деле ничего особенного. Вы можете сделать то же самое следующим образомif (method_exists($employeeStrategyObject, 'saveAnswer')) {...}
.5. Спасибо. Понятно. просто интересно, как мы можем сделать это больше
INTERFACE WAY
и получить выгоду от полиморфизма? Я имею в виду, что в этом случае мы могли бы использоватьabstract class
, если мы хотим убедиться, что метод должен быть реализован.
Ответ №2:
Может быть много подходов.
Я предложу 2 способа, которые я бы лично использовал:
1) Создайте специальные модели eloquent, по одной для каждого случая.
Например:
if($answer->employeeType === 1){
EmployeeOne::create($answer);
}
И ваша красноречивая модель может выглядеть следующим образом:
<?php
namespace AppModels;
use IlluminateDatabaseEloquentModel;
use DB;
class EmployeeOne extends Model
{
protected $table = 'type_one_table';
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
// your db field names
];
/**
* The attributes that should be hidden for arrays.
*
* @var array
*/
protected $hidden = [
];
public $timestamps = false;
}
Убедитесь, что ключи массива, которые вы передаете функции create, должны соответствовать полям вашей базы данных. Я только что привел вам пример первого if
, чтобы вы могли использовать его здесь.
2) Другим подходом было бы создать модель, которая принимает в качестве параметра имя таблицы. Итак, на основе вашего if
вы собираетесь передать имя таблицы, которое хотите вставить, и данные, которые должны быть вставлены.
if($answer->employeeType === 1){
$this->myModel->insertData($answer,'type_one_table');
}
И в вашей модели у вас будет что-то вроде:
public function insertData($answer,$table){
$query = DB::table($table)->insertGetId($answer); // returns the id of the new record
return $query;
}
Итак, в каждом if-else
заявлении вы просто меняете имя таблицы, передаваемое вашей функции model, и все.
Комментарии:
1. Спасибо за ответ. Но мои ключи массива более сложны и содержат вложенные данные, которые я буду хранить как json. также необходимо отфильтровать и удалить некоторые входные данные.. Таким образом, логика (код) будет больше… поэтому я не хочу помещать всю логику в свой контроллер. Какой другой подход я могу использовать?