I'm working on a project with vapor and I'm trying to make a function who edit an item with multiples pictures and I don't know how to make it properly for making update the pictures.
Currently, my func is really really lengthy (200 lines :o and I want to add others pictures) and I didn't how to do more properly.
Thanks you for any help :)
''''
func editItemPostHandler(_ req: Request) throws
-> EventLoopFuture<Response> {
let updateData =
try req.content.decode(CreateItemFormData.self)
return Item
.find(req.parameters.get("itemID"), on: req.db)
.unwrap(or: Abort(.notFound)).flatMap { item in
// 3
item.title = updateData.title
item.price = updateData.price
item.description = updateData.description
item.condition = updateData.condition
item.weight = updateData.weight
item.$category.id = updateData.categoryID
item.$size.id = updateData.sizeID
item.$genderCollection.id = updateData.collectionGenderID
item.$brand.id = updateData.brandID
if !updateData.picture.isEmpty && !updateData.frontPicture.isEmpty {
let imageName = "\(UUID()).jpg"
let NewPath =
req.application.directory.workingDirectory +
imageFolder + imageName
let frontPictureImageName = "\(UUID()).jpg"
let frontPictureNewPath =
req.application.directory.workingDirectory +
imageFolder + frontPictureImageName
return req.fileio
.writeFile(.init(data: updateData.picture), at: NewPath)
.flatMap {
return req.fileio
.writeFile(.init(data: updateData.frontPicture), at: frontPictureNewPath)
.flatMap {
return Item
.find(req.parameters.get("itemID"), on: req.db)
.unwrap(or: Abort(.notFound)).flatMapThrowing
{ item in
let filename = item.pictures
// 3 3. Construct the path of the picture.
let oldPicturePath = req.application.directory
.workingDirectory + imageFolder + filename
let frontPicturefilename = item.frontPicture
// 3 3. Construct the path of the picture.
let oldFrontPicturePath = req.application.directory
.workingDirectory + imageFolder + frontPicturefilename
do {
try FileManager.default.removeItem(atPath: oldPicturePath)
try FileManager.default.removeItem(atPath: oldFrontPicturePath)
}
item.pictures = imageName
item.frontPicture = frontPictureImageName
return item
}
.flatMap {
(item: Item) -> EventLoopFuture<Response> in
guard let id = item.id else {
let error = Abort(.internalServerError)
return req.eventLoop.future(error: error)
}
// 5
let redirect = req.redirect(to: "/items/\(id)")
return item.save(on: req.db).transform(to: redirect)
}
}
}
}
else if !updateData.picture.isEmpty {
let imageName = "\(UUID()).jpg"
let NewPath =
req.application.directory.workingDirectory +
imageFolder + imageName
return req.fileio
.writeFile(.init(data: updateData.picture), at: NewPath)
.flatMap {
return Item
.find(req.parameters.get("itemID"), on: req.db)
.unwrap(or: Abort(.notFound)).flatMapThrowing
{ item in
let filename = item.pictures
let oldPicturePath = req.application.directory
.workingDirectory + imageFolder + filename
do {
try FileManager.default.removeItem(atPath: oldPicturePath)
}
item.pictures = imageName
return item
}
.flatMap {
(item: Item) -> EventLoopFuture<Response> in
guard let id = item.id else {
let error = Abort(.internalServerError)
return req.eventLoop.future(error: error)
}
// 5
let redirect = req.redirect(to: "/items/\(id)")
return item.save(on: req.db).transform(to: redirect)
}
}
}
else if !updateData.frontPicture.isEmpty {
let frontPictureImageName = "\(UUID()).jpg"
let frontPictureNewPath =
req.application.directory.workingDirectory +
imageFolder + frontPictureImageName
return req.fileio
.writeFile(.init(data: updateData.frontPicture), at: frontPictureNewPath)
.flatMap {
return Item
.find(req.parameters.get("itemID"), on: req.db)
.unwrap(or: Abort(.notFound)).flatMapThrowing
{ item in
let frontPicturefilename = item.frontPicture
// 3 3. Construct the path of the picture.
let oldFrontPicturePath = req.application.directory
.workingDirectory + imageFolder + frontPicturefilename
do {
try FileManager.default.removeItem(atPath: oldFrontPicturePath)
}
item.frontPicture = frontPictureImageName
return item
}
.flatMap {
(item: Item) -> EventLoopFuture<Response> in
guard let id = item.id else {
let error = Abort(.internalServerError)
return req.eventLoop.future(error: error)
}
let redirect = req.redirect(to: "/items/\(id)")
return item.save(on: req.db).transform(to: redirect)
}
}
}
else {
guard let id = item.id else {
let error = Abort(.internalServerError)
return req.eventLoop.future(error: error)
}
let redirect = req.redirect(to: "/items/\(id)")
return item.save(on: req.db).transform(to: redirect)
}
}
}
'''
Thanks you for your help.
Emmanuel
Update,
I found a tricky strategy but it's allow me to have a less longer code :
When I edit an item, firstly I give the name of the former image path to the new image path. If there is a new image (so the data of the image is not empty) I'll change the name of this path. After that, I'll try to push the data with fileIO.writeFile. If there is not data, nothing is write and the path of the image stay the same. If there is data, it will write the data, and after it will delete the old picture with : try FileManager.default.removeItem(atPath: oldPicturePath)
'''
func editItemPostHandler(_ req: Request) throws
-> EventLoopFuture<Response> {
let updateData =
try req.content.decode(CreateItemFormData.self)
return Item
.find(req.parameters.get("itemID"), on: req.db)
.unwrap(or: Abort(.notFound)).flatMap { item in
item.title = updateData.title
item.price = updateData.price
item.description = updateData.description
item.condition = updateData.condition
item.weight = updateData.weight
item.$category.id = updateData.categoryID
item.$size.id = updateData.sizeID
item.$genderCollection.id = updateData.collectionGenderID
item.$brand.id = updateData.brandID
// 1. give the former name of itemPicture to imageName
var imageName = item.pictures
// 2. if updateData.picture isn't empty, give a new name the image name
if !updateData.picture.isEmpty {
imageName = "\(UUID()).jpg"
}
// create a path with the name of the image
let NewPath =
req.application.directory.workingDirectory +
imageFolder + imageName
// same logic for the second picture
var frontPictureImageName = item.frontPicture
if !updateData.frontPicture.isEmpty {
frontPictureImageName = "\(UUID()).jpg"
}
let frontPictureNewPath =
req.application.directory.workingDirectory +
imageFolder + frontPictureImageName
// try to write the file with the data (if it's empty, nothing is write but the logic continue.
return req.fileio
.writeFile(.init(data: updateData.picture), at: NewPath)
.flatMap {
// same for the second picture
return req.fileio
.writeFile(.init(data: updateData.frontPicture), at: frontPictureNewPath)
.flatMap {
return Item
.find(req.parameters.get("itemID"), on: req.db)
.unwrap(or: Abort(.notFound)).flatMapThrowing
{ item in
let filename = item.pictures
// Construct the path with the old picture name.
let oldPicturePath = req.application.directory
.workingDirectory + imageFolder + filename
let frontPicturefilename = item.frontPicture
// 3 3. Construct the path of the picture.
let oldFrontPicturePath = req.application.directory
.workingDirectory + imageFolder + frontPicturefilename
do {
// if the data isn't empty delete the former picture file
if !updateData.picture.isEmpty {
try FileManager.default.removeItem(atPath: oldPicturePath)
}
// same for the second picture
if !updateData.frontPicture.isEmpty {
try FileManager.default.removeItem(atPath: oldFrontPicturePath)
}
}
item.pictures = imageName
item.frontPicture = frontPictureImageName
return item
}
.flatMap {
(item: Item) -> EventLoopFuture<Response> in
guard let id = item.id else {
let error = Abort(.internalServerError)
return req.eventLoop.future(error: error)
}
// save the new item
let redirect = req.redirect(to: "/items/\(id)")
return item.save(on: req.db).transform(to: redirect)
}
}
}
}
}
'''
It's tricky but it allow to have less code than before and be able to add more picture to my item struct
Here's my item struct :
'''
struct CreateItemFormData: Content {
let collectionGenderID: UUID
let categoryID: UUID
let sizeID : UUID
let brandID : UUID
let title: String
let price: String
let description: String
let condition: String
let weight: String
var picture: Data
var frontPicture: Data
}
'''
Thanks you, and if you have better solution, it's always welcome. :)
Have a good day, Emmanuel