Strutturare la logica del codice per gli eventi sul controller laravel
Il codice seguente memorizzerà un'immagine base64 su un altro sito Web e creerà un evento per visualizzare l'immagine su una pagina Vue in tempo reale . Funziona bene e tutto.
La mia domanda è: è un buon modo per farlo o c'è un modo migliore per strutturare il codice? Ho pensato di collocare la logica in un ascoltatore ma non mi sembra che debba usarne una. Per le code, le aggiungerò in seguito.
Controller
public function store(Request $request) { $base64 = $request->image; $image = str_replace('data:image/png;base64,', '', $base64); $imageName = 'draw'.time().'.png';
$response = $this->guzzleClient()->post(config('archiving.api_postBase64_file'),
[
'multipart' => [
[
'name' => 'file',
'contents' => $image ], [ 'name' => 'file_name', 'contents' => $imageName
],
[
'name' => 'file_folder',
'contents' => 'drawings'
],
],
]
);
if($response->getStatusCode() >= 500){ return response($response->getBody(), $response->getStatusCode()); }else{ $drawing = Drawing::create([
'user_id'=>Auth::id(),
'file_name'=>$imageName, ]); event(new NewDrawing($drawing));
return response('Drawing created!',200);
}
}
Evento NewDrawing
class NewDrawing implements ShouldBroadcastNow
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $drawing; public function __construct(Drawing $drawing)
{
$this->drawing = $drawing;
}
public function broadcastOn()
{
return new Channel('channel-drawing');
}
}
Frontend (Vue)
<script>
export default {
data(){
return{
images:'',
}
},
methods:{
listen() {
Echo.channel('channel-drawing')
.listen('NewDrawing', res => {
this.images.push(res.drawing);
})
}
},
mounted() {
this.listen()
}
}
</script>
Risposte
Sono principalmente un ragazzo di back-end che si fa strada nel codice del front-end. Ecco il mio consiglio:
Mantenere il codice del controller il più vicino possibile alla gestione della sola risposta. Delegare la creazione di oggetti alle proprie classi. Pensa alla S in SOLID - Responsabilità Unica.
public function store(Request $request) { $image = new ImageMeta($base64); $archiver = new ImageArchiver($image); $response = $archiver->post(); if($response->getStatusCode() >= 500){ return response($response->getBody(), $response->getStatusCode()); }else{ $drawing = Drawing::create([ 'user_id'=>Auth::id(), 'file_name'=>$imageName, ]); //There's a few different ways to look at this which might be part of a larger conversation, // so I won't touch this part yet. But is this something specific to drawings? Or is the broadcast // of model creation something that will happen for lots of different models? Regardless, I would // change the name from NewDrawing to something like DrawingCreationBroadcast, or something like that // NewDrawing gets confusing since its too close to new Drawing(); event(new NewDrawing($drawing)); return response('Drawing created!',200); } }
Classe ImageMeta
/** For all classes assume property declarations, and getters are included.
* Lean toward immutable classes where possible, so don't include setters
* unless it becomes necessary. Code re-use != object instance re-use.
**/
class ImageMeta {
public function __construct($base64) {
$this->image = str_replace('data:image/png;base64,', '', $base64);
$this->imageName = 'draw'.time().'.png';
}
}
ImageArchiver classe
class ImageArchiver {
private $config;
public function __construct(ImageMeta $image) { $this->image = $image; $this->makeConfig();
}
private function makeConfig() {
$this->config = [ 'multipart' => [ [ 'name' => 'file', 'contents' => $image->getImage()
],
[
'name' => 'file_name',
'contents' => $imageName->getName() ], [ 'name' => 'file_folder', 'contents' => 'drawings' ], ], ] } //use type hinting here. Off the top of my head I don't know the parent class of guzzleClient public function archive($guzzleClient) {
return $guzzleClient->post($this->config);
}
}
In questa presentazione sulla pulizia del codice Rafael Dohms parla di molti modi per mantenere il codice snello, come evitare la else
parola chiave. ( vedi le diapositive qui ).
È saggio evitare la else
parola chiave, specialmente quando non è necessaria, ad esempio quando un blocco precedente contiene return
un'istruzione:
if($response->getStatusCode() >= 500){ return response($response->getBody(), $response->getStatusCode()); }else{ $drawing = Drawing::create([ 'user_id'=>Auth::id(), 'file_name'=>$imageName, ]); event(new NewDrawing($drawing)); return response('Drawing created!',200); }
Nel codice Frontend, sembra che images
sia impostato su una stringa vuota:
data(){ return{ images:'', } },
Tuttavia, nel callback di ascolto viene utilizzato come un array:
Echo.channel('channel-drawing') .listen('NewDrawing', res => { this.images.push(res.drawing); })
Dovrebbe essere inizializzato come un array in data()
.
Il metodo viene listen()
chiamato in un punto diverso dal mounted()
callback? In caso contrario, potrebbe essere più semplice spostare il codice da quel metodo nel mounted()
callback.