You are on page 1of 67

Printing with APEX: PL/PDF

Scott Spendolini
Executive Director, Enkitec

1
About the Presenter
Scott Spendolini
scott.spendolini@enkitec.com
@sspendol

Ex-Oracle Employee of 10 years


Senior Product Manager for Oracle APEX
from 2002 through 2005

Founded Sumner Technologies


in October 2005
Co-Founded Sumneva in January 2010
Joined Enkitec in June 2012
Oracle Ace Director
Author, Expert Oracle Application Express Security
Co-Author, Pro Oracle Application Express
Scott on OTN Forums

2
Agenda
Overview
Installation
Integration
Implementation
Security
Summary

4
OVERVIEW

5
What is PL/PDF?
Third party product designed by Oranext
http://plpdf.com
Provides a set of PL/SQL based APIs that can
generate PDF files from the Oracle database
Easy to securely
integrate with APEX
Can be called from a
Page or Application
Process

6
PL/PDF Features
Robust reporting engine
Charts
Bar, Line & Pie

Barcode Printing
Use Existing PDF files as Templates
TrueType Font Embedding
Encrypted PDF Documents
Native Support for PNG & JPEG images
Other types supported via Oracle InterMedia

7
Licensing
Licensed per instance of Oracle
$600 per instance

Can download a trial for free


5 Page Maximum
Watermark Appears on all pages

No additional hardware is required


PL/PDF installs into the same database as APEX

8
The BLOB!
Result of PL/PDF is nothing more than an Oracle
BLOB
Thus, you can do anything with PL/PDF output
that you can with an Oracle BLOB:
E-Mail it as an attachment
Download it to a browser
Store it in a table
Index it with Oracle Text
Schedule a procedure to
generate and e-mail PDF files

9
Simple Example

plpdf.init;
plpdf.NewPage;
plpdf.SetPrintFont('Arial',NULL,12);
plpdf.PrintCell(50,10,'Hello World');
plpdf.SendDoc(l_blob);

10
Complex Example
eSERT Evaluation Summary Report

11
Layout & Control
All layout is handled via API calls
There is no GUI tool to design a PL/PDF report

Seems limiting, and can be at times


Template feature allows you to use any tool to create the
structure of a document and use PL/PDF APIs only to
populate the data
Also, there are APIs that minimize the amount of code
required when creating reports

12
Extras
In addition to its core APIs, PL/PDF offers a
number of extra features
Templates
Charts
Bar, Line & Pie

Bar Codes
Encryption
OpenOffice Forms
TrueType Font Support

13
Templates
PL/PDF allows you to include a PDF template as a
background for any page
No need to use PL/PDF to create the structure of a
document; focus on filling in the data
Any PDF document can be used
Easy to create PDF documents from Word, Acrobat, etc.

14
Templates

15
Charts
Support for three types of charts
Line
Bar
Pie

16
Charts
sumnevaSERT

Settings Summary 28 out of 37 possible points 75.68%


Session Duration
0% Authentication Scheme: 1
0 out of 2 possible points
Security
60%
6 out of 10 possible points
Application Settings
84.62%
11 out of 13 possible points Session Duration: 2 Security: 4
Authentication Scheme
91.67%
11 out of 12 possible points

Application Settings: 2

Exceptions Awaiting Approval

No Data Found

Stale Exceptions

No Data Found

17
Barcodes
Support for a number of types of barcodes:
Feline Adult 20/22LB Feline Adult 20/22LB Feline Adult 20/22LB Feline Adult 20/22LB
8543 8543 8543 8543

$36.99 $36.99 $36.99 $36.99


101262640 101262640 101262640 101262640

Feline Adult 20/22LB Feline Adult 20/22LB Feline Adult 20/22LB Feline Adult 20/22LB
8543 8543 8543 8543

$36.99 $36.99 $36.99 $36.99


101262640 101262640 101262640 101262640

Feline Adult 20/22LB Feline Adult 20/22LB Feline Adult 20/22LB Feline Adult 20/22LB
8543 8543 8543 8543

$36.99 $36.99 $36.99 $36.99


101262640 101262640 101262640 101262640

Feline Adult 20/22LB Feline Adult 20/22LB Feline Adult 20/22LB Feline Adult 20/22LB
8543 8543 8543 8543

$36.99 $36.99 $36.99 $36.99


101262640 101262640 101262640 101262640

18
Feline Adult 20/22LB Feline Adult 20/22LB Feline Adult 20/22LB Feline Adult 20/22LB
8543 8543 8543 8543
Other Features
Ability to encrypt PDF files
Support for OpenOffice PDF Forms
LZW compression
TrueType Font Support

19
Sweet Spots
PL/PDF is the best solution when:
The core report definition does not change often
End Users do not need to create one-off reports
You have an abundance of PL/SQL resources and little
money

20
INSTALLATION

21
Installation Options
PL/PDF is installed by running a series of SQL
scripts
Can use to install on any target OS
Need to be able to connect to the target database via
SQL*Net

Some additional features may need to be


manually installed
Charts, Bar Codes, etc.

Installation should take about 15 minutes

22
Where to Put It
Since PL/PDF is a set of PL/SQL objects, youll
need to select a schema to put it in
Typically use PLPDF, but can name the schema anything

Best to use its own schema and then create


grants & synonyms to access from other schemas
Youll need to do this manually
Start with just PLPDF & PLPDF_TYPE; synonyms for other
objects can be added as needed

23
INTEGRATION

24
APEX Integration
Once installed and the corresponding grants are
created to your parse as schema, there is
NOTHING ADDITIONAL TO CONFIGURE in order to
integrate PL/PDF with APEX
PL/PDF - like APEX - is PL/SQL
Thus, as long as your parse-as schema can access the
PL/PDF objects, thats all youll need
Seriously.

Theres nothing else to configure.

Try it. Youll see.

25
APEX Integration
PL/PDF must be called as part of the Page
Rendering process in APEX
And it must occur before anything else

Best Practice:
Create an On Load PL/SQL Process that calls PL/PDF
Set the Condition to Request = Expression 1
Add a button/link to that page which sets the Request to
trigger the PL/PDF call

26
PL/SQL Package
Its best to put the logic for a PL/PDF report into
a PL/SQL package
Centralized
Can re-use common functions
More performant
Easier to work with

Be sure pass in parameters when possible so that


a single package may be called from multiple
pages or even outside of APEX

27
PL/SQL Process
A simple PL/SQL Process should be created to
call the report package
Must be set to fire Before Header and be the first
process executed
Must be condition to only execute when Request = PRINT
Can be an Application Process

PL/SQL Code:
plpdf_print.print
(
p_order_id => :P29_ORDER_ID
);

28
Button
A button can be used to trigger our PDF report
Redirects to the page where the process is located
Passes in PRINT to the Request value

29
Column Link
A Column Link can also be used to print a report
Redirects to the page where the process is located
Passes in PRINT to the Request value
Sets the value of the APEX Item which is passed to the
package

30
APEX INTEGRATION
D E M O N S T R A T I O N

31
IMPLEMENTATION

32
Goal
To produce a Sales Receipt for an order
generated in the Sample Database Application
Receipt will encompass a master-detail report
Single row from the header

Variable number of rows from the detail

Should look professional and include a logo

33
Report Types
PL/PDF can produce two types of reports
Row/Column
Produce rows & columns of data based on a SQL query

Forms
Fill in the data for a form, such as a Tax Form or Job Application

Its important to determine which type is needed


for a specific requirement up front
OK to use both in a single report, if needed

34
Our Example

Form Report
Based on a single
row of data
across one or
more tables

Row/Column Report
Based on a SQL
Query returning
multiple rows of
data

35
Where to Start?
PL/PDF can utilize a PDF
document as a template
Simplifies code greatly, as Eugene Bradley
Schoephoester Road
10/1/13 000003

only the data needs to be


Windsor Locks, CT 06906

printed via the APIs 12345 Check

00001 Business Shirt 1 $50 $50


00003 Trousers 2 $100 $200

$250

36
The ABCs of the APIs
PL/PDF is nothing more than a set of PL/SQL APIs
Like any other API set, theres a learning curve

Most APIs have default values on most


parameters
Thus you only need to pass values to those you wish to set
Use param => value notation for best results

Refer to the documentation for full details

37
Where to Start
Like any other problem, it all starts with the data
Analyze the data required and determine the best way to get what you
need

Create views where it makes sense to simplify SQL statements in APEX


or PL/SQL

DEMO_ORDERS

DEMO_ORDER_ITEMS

DEMO_CUSTOMERS

38
DEMO_ORDERS
Since well need to reference a row of
DEMO_ORDERS, it can be created as a ROWTYPE
variable and referenced throughout in the
PL/PDF APIs

DECLARE
l_order_t demo_orders%ROWTYPE;
BEGIN

-- Get the Order Row


SELECT * INTO l_order_t
FROM demo_orders
WHERE order_id = p_order_id;

39
init
Called once to initialize PL/PDF
Parameters:
p_orientation
p_unit
p_format

40
newPage
Creates a new page
Called anytime a new page is needed
PL/PDF will automatically create a new page when
needed if data overflows the current page

Parameters:
p_orientation

41
Initializing PL/PDF
-- Get the Template
SELECT blob_content INTO l_template_pdf
FROM wwv_flow_files
WHERE filename = 'sales_receipt.pdf';

l_template :=
plpdf_parser.getTemplate(l_template_pdf,1);

-- Initialize PL/PDF
plpdf.init(p_format => 'letter');
l_template_id := plpdf.InsTemplate(l_template);

-- Create a new page


plpdf.NewPage;

-- Place the template on the page


plpdf.useTemplate(l_template_id);
42
setCurrentXY
Sets the position of the cursor
Parameters:
p_x
p_y

Similar:
setCurrentX
setCurrentY

43
setPrintFont
Sets the font family and style used for text
Parameters:
p_family
p_style
p_size

44
printCell
Prints a line of text on the page
Parameters:
p_w p_align

p_h p_fill

p_txt p_link

p_border p_clipping

p_ln

45
lineBreak
Places the cursor on the next line
Parameters:
p_h

46
Printing Customer Details
plpdf.SetPrintFont(
p_family => 'Courier', p_size => 10);
plpdf.setCurrentXY(11,60);

-- Customer Details
FOR x IN
(SELECT * FROM demo_customers
WHERE customer_id = l_order_t.customer_id)
LOOP
plpdf.printCell(70, 10, x.cust_first_name
|| ' ' || x.cust_last_name, NULL, NULL, 'L');
plpdf.LineBreak(4);
plpdf.setCurrentX(11);
plpdf.printCell(70, 10, x.cust_street_address1,
NULL, NULL, 'L');

47
Printing Customer Details
plpdf.LineBreak(4);
plpdf.setCurrentX(11);
IF x.cust_street_address2 IS NOT NULL THEN
plpdf.printCell(70,10,
x.cust_street_address2, NULL, NULL, 'L');
plpdf.LineBreak(4);
plpdf.setCurrentX(11);
END IF;
plpdf.printCell(70, 10, x.cust_city || ','
|| x.cust_state || ' '
|| x.cust_postal_code, NULL, NULL, 'L');
END LOOP;

48
Other Details
-- Date and Order Number
plpdf.setCurrentXY(152,60);
plpdf.printCell(26, 10,
TO_CHAR(l_order_t.order_timestamp,
'DD-MON-YYYY'),NULL,NULL,'C');
plpdf.printCell(30,10,'0000'
|| p_order_id,NULL,NULL,'C');

-- Payment Method
plpdf.setCurrentXY(10,95);
plpdf.printCell(28,10,'n/a' ,NULL,NULL,'C');
plpdf.printCell(28,10,'Credit',NULL,NULL,'C');

-- Reset Cursor
plpdf.setCurrentXY(10,114);

49
row_print
ROW_PRINT allows for a lot more flexibility than
QUERY_PRINT
Typically called from inside a loop
FOR X IN (SELECT * FROM ...)
DBMS_SQL

Four different variations are available:


ROW_PRINT through ROW_PRINT4

50
row_print
Sample Parameters
p_data
p_width
p_align
p_style
p_maxline
p_links
p_h
p_fill
p_min_height
p_clipping

51
Order Lines
ROW_PRINT may or may not suffice for what you
need
Often times just looping through a query and printing the
individual columns is just as effective

Take some time to become familiar with it and


what it can and cant do

52
Order Lines
LOOP
plpdf.printCell(29,10,'0000'
|| x.product_id ,NULL,NULL,'C');
plpdf.printCell(84,10,x.product_name,
NULL,NULL,'L');
plpdf.printCell(28,10,x.quantity,
NULL,NULL,'C');
plpdf.printCell(28,10,TO_CHAR(x.list_price,
'FML999G999G999G999G990D00'),
NULL,NULL,'R');
plpdf.printCell(28,10,TO_CHAR(x.list_price *
x.quantity,'FML999G999G999G999G990D00'),
NULL,NULL,'R');
plpdf.LineBreak(4);
END LOOP;

53
sendDoc
Returns the PDF document to a BLOB variable
Parameters:
p_blob

54
Download File API
You can also create a single procedure to handle
file downloads
Pass in the BLOB and filename
All PL/PDF reports can call this procedure

In fact, it is recommended that PL/PDF reports


be based on a package
Reusability
Security

55
Printing the PDF
-- Send the contents of the PDF document to
l_blob and Print it
plpdf.SendDoc(l_blob);

-- Send the PDF document to the browser


owa_util.mime_header('application/pdf', FALSE);
htp.p('Content-Disposition: inline;
filename=' || p_filename || '.pdf') ;
htp.p('Content-Length: '
|| dbms_lob.getlength(l_blob)) ;
owa_util.http_header_close;
wpg_docload.download_file(l_blob);
apex_application.g_unrecoverable_error := TRUE;

56
Table of Contents
PL/PDF allows you to automatically crete a Table
of Contents
You can add bookmarks throughout your application that
link back to the main table of contents
Fully automated; no need to calculate anything

57
SECURITY

58
PL/PDF Security
Since PL/PDF is all PL/SQL, there are no specific
provisions when it comes to security
Any database layer security will work
Secure Views
Label Security
VPD

59
VPD Function
CREATE OR REPLACE FUNCTION plpdf_vpd
(p_schema IN VARCHAR2 DEFAULT NULL,
p_object IN VARCHAR2 DEFAULT NULL)
RETURN VARCHAR2
AS
BEGIN

RETURN q'!user_name = '!' || v('APP_USER')


|| q'!'!';

END;
/

60
Enabling VPD
BEGIN
DBMS_RLS.add_policy
(object_schema => 'PLPDF_OOW',
object_name => 'DEMO_ORDERS',
policy_name => 'DEMO_ORDERS_VPD',
function_schema => 'PLPDF_OOW',
policy_function => 'PLPDF_VPD',
statement_types => 'SELECT');
END;
/

61
Disabling VPD
BEGIN
DBMS_RLS.drop_policy
(object_schema => 'PLPDF_OOW',
object_name => 'DEMO_ORDERS',
policy_name => 'DEMO_ORDERS_VPD');
END;
/

62
VPD & PL/PDF
D E M O N S T R A T I O N

63
SUMMARY

64
PL/PDF Report Card

Installation
A
Integration
A
Implementation
& Ease of Use D
Security
A
Cost
A

65
Summary
PL/PDF provides a robust, cost effective
solution for producing high quality PDF
documents from any APEX application
Not always the right tool for every job; but in many cases,
it works quite well
Low cost and zero footprint means that it should at least
be seriously considered

66
http://www.odtug.com

67

You might also like