Unificar arquivos PDF usando o PDF Lib no lightning web component
- 24 minutos para leitura
Fala pessoal, tudo bem ? Estou por aqui de novo, focado em escrever mais sobre todo o ecosistema de desenvolvimento em Salesforce.
Dessa vez, irei falar como podemos unificar alguns arquivos PDF usando uma biblioteca externa no lightning web component.
Pois bem, devo considerar que tu já sabes carregar um arquivo externo no lightning web component, mas caso tu não saibas ainda, tu podes ir para o post que eu falo sobre Carregar scripts e folhas de estilos CSS.
1. Criando a classe controller no apex para obter os arquivos em base64 e reber depois estes arquivos unificados e salvar os mesmo no contentVersion.
Aqui devemos nos atentar ao método getAllFilesByAccount,ele é responsável por trazer todos os arquivos do tipo PDF que está vinculado ao id de uma conta que é passado como parâmetro.
Extraímos o Blob do ContentVersion no campo VersionData e códificamos usando o método base64Encode e então adicionamos em uma lista de string para retornar para o front-end.
“Se tu queres saber mais sobre o os métodos base64Encode e base64Decode, tu podes acessar a documentação oficial da Salesforce aqui.”
2. Criando o componente mergePDFExample
No componente iremos importar nosso método getAllFilesByAccount da classe apex, assim como a biblioteca pdflib que irá nos auxiliar na unifiação dos arquivos.
Criei a função create() que será chamada no html através de um botão.
Antes de tudo iremos recuperar todos os arquivos codificados em getAllFilesByAccount({accountId: this.recordId}).
Após isso, iremos criar uma instancia da biblioteca em PDFLib.PDFDocument.create()
A biblioteca precisa que os arquivos estejam em um array na base de 8bits. É o que fazemos na liha Uint8Array.from(atob(file), (c) => c.charCodeAt(0))
Em seguida usamos a função load do PDFlib caso queira saber mais sobre a biblioteca você pode acessar a documentação oficial e ir até Embed PDF Pages
Fazemos uma copia da página usando a função copyPages e em seguida adicionamos essa página usando a função addPage.
Ao final do loop for, chamamos a função save().
3.Preparando o arquivo para carregar no Salesforce.
A função prepareToUploadFile() recebe o arquivo Serializado em bytes (um Uint8Array) que retorna da função save().
Transformamos esses arquivos no tipo blob na linha
let pdfBlob = new Blob([pdfFiles], { type: “application/pdf” })
A constante MAX_FILE_SIZE determina o tamanho máximo que este arquivo poderá conter, passamos o valor 4718592 em bytes, isso dá um pouco mais que 4MB. O Salesforce tem um tamanho para uso de String, mais para frente irei falar sobre este assunto, enquanto isso, vamos continuar com a leitura do código. Se esse tamanho for atingido mostrare-mos uma mensagem do tipo toast ao usuário, caso contrário seguiremos com o código. A funçao readUploadedFileAndReturnBase64 recebe esse nosso novo tipo de variável blob.
Nele, básicamente fazemos uso do objeto FileReader disponível em browsers que permite trabalhar com conteúdos de arquivos. Utilizamos a propriedade onload, para manipular o aquivo, quando esse arquivo está pronto, nós pegamos o seu conteúdo e estraímos apenas a base64 dele, retornando este na função.
Criamos uma nova função denominada fileUpload na qual recebe nosso blob e o conteúdo em base64. Essa função é responsável por passar o ínicio e o fim do indice da nossa base64. A Constante CHUNK_SIZE diz, qual será o tamanho do pedaço deste aquivo será inserido no Salesforce por vez.
Por fim, a função fileUploadInChunks é a responsável chamar a classe controller e passar em pedaços do arquivo até o fim. A linha abaixo é que de fato chama a controller, passando os parametros necessários
Neste momento é feito a inserção do primeiro pedaço (chunk) e com isso, é retornado um Id de um registro do ContentVersion como resposta. Esse resultado passamos na variável contentVersionId, em seguida calculamos novamente o novo posicionamento dos indices startPosition = endPositionendPosition = Math.min(fileContents.length, startPosition + CHUNK_SIZE) E então verificamos se ainda tem mais pedaços a serem inseridos, e então chamamos a mesma função this.fileUploadInChunks novamente até finalizar o processo.
Inserindo e atualizando em pedaços (chunk) os arquivos na classe controller do apex.
O método fileUploadInChunks é o que sempre será chamado pelo front-end, nele verificamos se o Id do contentVersion (fileId) já existe. Se não existir chamamos o método saveFile e fazemos a inserção do contentVersion no banco e retornamos o Id criado. Como o front-end passa em pedaços(chunk) o arquivo, na próxima chamada o Id existirá, e então chamamos o método appendToFile, ele é responsável por recuperar no banco o pedaço (chunk) que inserimos e então somar mais o outro pedaço que estamos recebendo do front-end e atualizamos este registro no banco novamente.
Lembra que disse que comentária sobre o tamanho do arquivo ? pois bem, na linha String existingBody = EncodingUtil.base64Encode(contentVersionResult.VersionData); Recuperamos o pedaço já salvo do arquivo que está salvo no tipo Blob no campo VersionData do objeto ContentVersion e codificamos ele usando base64Encode, este retorna uma string e salvamos na variável existingBody a String possui um tamanho máximo de 6000000, caso isso seja atingido o Salesforce lançará o erro: [String length exceeds maximum: 6000000] por está razão é necessário limitar o tamanho do arquivo lá no front-end, pois um arquivo decodificado gera uma string muito grande.
O processo se repete até finalizar .
Abaixo está todo o código do classe controller do apex chamada MergePDFFileController
E também abaixo o código completo do componente chamado MergePDFExample
Eu sei que esse post ficou um pouco extenso, mas era necessário explicar algumas coisas minimas que está ocorrendo no código. Mas e ai me conta? tu já implementou algo parecido com isto ? ou está passando por isso agora e espero que este conteúdo realmente te ajude. Eu passei por alguns dias tentando fazer isso dá muito certo, e claro pesquisei muito pela internet e esse conteúdo tem referências do post do Kapil Batra.
Essa é uma solução que tem um limite da criação do arquivo, porém, há outra solução para aumentar esse limite trabalhando com a API de inserção do ContentVersion. Me conta aqui se tu queres que eu escreva sobre isso também em um outro post.
Mais uma vez, muito obrigado por passar por aqui, e até o próximo post.