for (i = 10; i < 259 ; i = i + 100) {
jg_doc.setColor("#"+genHex());
jg_doc.drawRect(300-i,300-i,i*2,i*2)
jg_doc.drawString("Some Text",300-i,300-i);
}
jg_doc.paint(); // draws, in this case, directly into the document
}
ASPs can do it, JSPs can do it, but PHP doesn't, and has no plans to any
time in the future.
For this application, it means that every single user is going to have to
grab hold of a copy of the database schema every time they start their
session. When we reach the point of tens of thousands of hits per second, we
are going to need far more power in the database than would otherwise be the
case. As it happens, this particular application is designed such that users
of a particular size are going to be happy to pay for their own, uncontended
database instance, and no single company is ever going to grow to a size
where they would need anything more.
It is the principle which counts, though.
You could simply write stuff to disk, and put up with the performance
overhead, but then you might as well use a federated or replicated MySQL
instance. A better solution is to use Memcached. It is a highly scaleable
cacheing tool with a handy PHP interface called Memcache. Install the
package, start the daemon, and throw objects at it. For private objects, use
a name prepended to the session id. For public objects like the schema, just
use a common name. Although it isn't a straightforward install, we
essentially have application scope objects.
To use the memcache interface, I would need to rewrite some code. The code
is going to first check for object existence in memcache, then read from DB
and put into memcache if it isn't already there. I probably wouldn't
normally use the options, but it is possible to put objects into memcache
with a limited time, and to restrict the memory usage of the daemon.
Not something I need to worry about yet (the apps are lightning-fast), but
good to know there's a solution when I need one.
My view on this is that there is pretty much only MySQL. It is free, fast,
scalable, widely used and easy to find support for. Beyond MySQL, there is
Oracle which isn't free, but is more scalable for certain types of
application. Importantly, if it is being used in a site with expertise in
some other database, MySQL really can be left alone, and it will work away
happily without needing maintenance.
Of course MySQL won't be free forever now that Sun own it, and upgrades are
likely to be sporadic with the best features being a cost option.
MySQL also has two distinct php interfaces. MySQLI, and the older MySQL. The
uptake of MySQLI has been relatively poor even though it has been out for a
few years, possibly because there isn't currently an implementation for a
persistent connection.
As a consequence of all this, there are a few design philosophies:
- All database connections are controlled through a single include.php, the
class needs to be extended in order to be used.
- All SQL outside the class needs to be ANSI-99.
- Accomodating a new database should only need a quick whip through the
parent class. An hour or so's work.
- I am using MySQLI as an interface, although it should be a simple matter
to revert to MySQL, or indeed implement memcache within the parent if
necessary.
...job done, and I am not giong to even bother with the complexities of user
configured database connections. In practise, the configuration of DB
connections gives rise to at least 50% of all installation problems anyway.
The program emails PDFs, or prints from emails, allows for the entry of notes against both the line or header, maintains details of GST numbers etc.
I'm now at the stage where I can go in one of two directions. Either :
- I expand functionality to allow for multi-currency, variable GST rates, complex formatting against notes and optional quote layouts etc.
- I expand breadth to encompass invoicing, ordering, stock control, credit control etc.
Every step in additional functionality is also a direction toward complexity, so I'm going to head down the latter of the two options above.
With an architecture painfully assembled around the quotes, adding new form types should be straightforward. We'll see, as I start on sales orders.
Example of PDF attached.
The previous post brings me on to the general area of printing.
To print a document which has just been created
For example a delivery note. Typically, this can be done via a browser as suggested in the previous post. It isn't possible to override the local user's browser setting, however they can change their own settings so that page headers are not printing, shading and images are printed, and even that they are not prompted for permission to print.
To print a batch, or print on someone else's printer
For example a batch of customer statements, or a batch of customer invoices, 100 sites worth of P&Ls etc. The print run might take a long time to prepare, which would result in a browser timeout. In this context, we are not going to be printing via the user's browser.
As long as the browser is CSS2.1 compliant (IE7 and Chrome are fine), it is possible to have a web page looking quite differently when printed from the way it appears on screen.
Doing this is fairly simple - each CSS element can be enclosed in a media envelope to determine how the html is interpreted when printed, or on screen.
So for example we have:
@media screen {
.bt {
background: transparent url('button.gif') scroll top right;
font: normal 12px arial, sans-serif;
height: 24px;
margin-right: 6px;
text-decoration: none;
top-border:none;
bottom-border:none;
}
}
@media print {
.bt {display: none;}
}
<input name=sub class=bt type=submit value='Click to Continue'>
In the above, buttons aren't printed, but are shown on screen. The principle is ideal for web pages with drop down menus which are usually meaningless when printed. To convert any existing CSS, simply enclose it in @media screen brackets, then create a new @media print section for each css indicator.
For print-only html pages, the reverse can be done. i.e. the page is not visible to the user unless they print it.
It took some time to find CSS which rendered properly in cross-browser and pdf scenearios, and I've arrived at the source below.
<html>
<head>
<style>
td.c1 {font-family:Helvetica;font-size:50px;font-weight:bolder;color:#c0c0c0;}
td.c2 {font-family:Helvetica;font-size:13px;}
td.c3 {font-family:Helvetica;font-size:12px;}
td.c4 {font-family:Helvetica;font-size:12px;border-bottom:solid 1px gray; border-left:solid 1px gray; }
td.c5 {font-family:Helvetica;font-size:12px;border-bottom:solid 1px gray; border-right:solid 1px gray; border-left:solid 1px gray}
th.h1 {font-family:Helvetica;font-size:12px;border-bottom:solid 1px gray; border-left:solid 1px gray; border-top:solid 1px gray}
th.h2 {font-family:Helvetica;font-size:12px;border-bottom:solid 1px gray; border-left:solid 1px gray; border-right:solid 1px gray; border-top:solid 1px gray}
table {margin-left:50px;margin-top:10px;margin-right:10px;}
</style>
</head>
<body>
<table width=90%>
<tr><td width=15%>
<img src="coldhot2.jpg" width=100px>
</td>
<td class=c2 valign=top><b>PickMaster</b><br>
37 Isobel Road<br>
Greenhithe<br>
Auckland<br>
0632
</td>
<td valign=top align=right class=c1>
Invoice
</td>
</tr>
</table>
<table width=90%>
<tr>
<td width=50%></td>
<td valign=top align=right class=c3>Invoice Number</td>
<td valign=top class=c3>10302</td>
</tr>
<tr>
<td width=50%></td>
<td valign=top align=right class=c3>Tax Date</td>
<td valign=top class=c3>12 Dec 2009</td>
</tr>
<tr>
<td width=50%></td>
<td valign=top align=right class=c3>Order Number</td>
<td valign=top class=c3>Customer Order Number Goes Here</td>
</tr>
</table>
<br>
<br>
<table width=60%>
<tr>
<td class=c3 width=30%>Customer Addy<br>
Address Line 1<br>
Address Line 2<br>
Address Line 3<br>
Post Code
</td>
<td class=c3 width=30%>Customer Addy<br>
Address Line 1<br>
Address Line 2<br>
Address Line 3<br>
Post Code
</td>
</tr>
</table>
<br>
<br>
<table width=90% style=" border: 0pt none black;" cellspacing=0; >
<tr>
<th valign=top class=h1 align=left width=15%>Code</th>
<th valign=top class=h1 align=left width=60%>Description</th>
<th valign=top class=h1 align=right width=15%>Qty</th>
<th valign=top class=h2 align=right width=10%>Price</th>
</tr>
<tr>
<td valign=top class=c4>ActualCode</td>
<td valign=top class=c4>Full Textual Description Description</td>
<td valign=top class=c4 align=right>14</td>
<td valign=top class=c5 align=right>23.00</td>
</tr>
<tr>
<td valign=top class=c4>ActualCode</td>
<td valign=top class=c4>Full Textual Description Description</td>
<td valign=top class=c4 align=right>14</td>
<td valign=top class=c5 align=right>23.00</td>
</tr>
<tr>
<td></td>
<td></td>
<td align=right valign=top class=c4>Total</td>
<td valign=top class=c5 align=right>23.00</td>
</tr>
<tr>
<td></td>
<td></td>
<td align=right valign=top class=c4>GST</td>
<td valign=top class=c5 align=right>2.30</td>
</tr>
<tr>
<td></td>
<td></td>
<td align=right valign=top class=c4>Total</td>
<td valign=top class=c5 align=right>25.00</td>
</tr>
</table>
</body> </html>
I also went through all of the searching algorithms.
When the user of a web site clicks on the submit button, the page is wrapped up and sent to the web server for processing. Depending on the speed of the connection and the web server, the user may click submit twice.
When this happens, the web server will receive exactly the same page twice, and will need to decide what to do. Depending on the complexity of the server-side application, you may need to cater for many different situations in a complex application.
It is much simpler to reduce the number of duplicated submissions (many users still think double-clicking is the right thing to do!), and to generate a general error. So how do you prevent form resubmission?
Answer : like this:
