Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Save more on your purchases! discount-offer-chevron-icon
Savings automatically calculated. No voucher code required.
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Events
Videos
Audiobooks
Packt Hub
Free Learning
Arrow right icon
timer SALE ENDS IN
0 Days
:
00 Hours
:
00 Minutes
:
00 Seconds

How-To Tutorials

7018 Articles
article-image-recovery-postgresql-9
Packt
25 Oct 2010
14 min read
Save for later

Recovery in PostgreSQL 9

Packt
25 Oct 2010
14 min read
Recovery of all databases Recovery of a complete database server, including all of its databases, is an important feature. This recipe covers how to do that in the simplest way possible. Getting ready Find a suitable server on which to perform the restore. Before you recover onto a live server, always take another backup. Whatever problem you thought you had could be just about to get worse. How to do it... LOGICAL (from custom dump -F c): Restore of all databases means simply restoring each individual database from each dump you took. Confirm you have the correct backup before you restore: pg_restore --schema-only -v dumpfile | head | grep Started Reload globals from script file as follows: psql -f myglobals.sql Reload all databases. Create the databases using parallel tasks to speed things along. This can be executed remotely without needing to transfer dumpfile between systems. Note that there is a separate dumpfile for each database. pg_restore -d postgres -j 4 dumpfile LOGICAL (from script dump created by pg_dump –F p): As above, though with this command to execute the script. This can be executed remotely without needing to transfer dumpfile between systems. Confirm you have the correct backup before you restore. If the following command returns nothing, then the file is not timestamped, and you'll have to identify it in a different way: head myscriptdump.sql | grep Started Reload globals from script file as follows: psql -f myglobals.sql Reload all scripts like the following: psql -f myscriptdump.sql LOGICAL (from script dump created by pg_dumpall): We need to follow the procedure, which is shown next. Confirm you have the correct backup before you restore. If the following command returns nothing, then the file is not timestamped, and you'll have to identify it in a different way: head myscriptdump.sql | grep Started Find a suitable server, or create a new virtual server. Reload script in full psql -f myscriptdump.sql PHYSICAL: Restore the backup file onto the target server. Extract the backup file into the new data directory. Confirm that you have the correct backup before you restore. $ cat backup_label START WAL LOCATION: 0/12000020 (file 000000010000000000000012) CHECKPOINT LOCATION: 0/12000058 START TIME: 2010-06-03 19:53:23 BST LABEL: standalone Check all file permissions and ownerships are correct and links are valid. That should already be the case if you are using the postgres userid everywhere, which is recommended. Start the server That procedure is so simple. That also helps us understand that we need both a base backup and the appropriate WAL files. If you used other techniques, then we need to step through the tasks to make sure we cover everything required as follows: Shutdown any server running in the data directory. Restore the backup so that any files in the data directory that have matching names are replaced with the version from the backup. (The manual says delete all files and then restore backup—that might be a lot slower than running an rsync between your backup and the destination without the –-update option). Remember that this step can be performed in parallel to speed things up, though it is up to you to script that. Check that all file permissions and ownerships are correct and links are valid. That should already be the case if you are using the postgres userid everywhere, which is recommended. Remove any files in pg_xlog/. Copy in any latest WAL files from a running server, if any. Add in a recovery.conf and set its file permissions correctly also. Start the server. The only part that requires some thought and checking is which parameters you select for the recovery.conf. There's only one that matters here, and that is the restore_command. restore_command tells us how to restore archived WAL files. It needs to be the command that will be executed to bring back WAL files from the archive. If you are forward-thinking, there'll be a README.backup file for you to read to find out how to set the restore_command. If not, then presumably you've got the location of the WAL files you've been saving written down somewhere. Say, for example, that your files are being saved to a directory named /backups/pg/servername/archive, owned by the postgres user. On a remote server named backup1, we would then write this all on one line of the recovery.conf as follows: restore_command = 'scp backup1:/backups/pg/servername/archive/%f %p' How it works... PostgreSQL is designed to require very minimal information to perform a recovery. We try hard to wrap all the details up for you. Logical recovery: Logical recovery executes SQL to re-create the database objects. If performance is an issue, look at the recipe on recovery performance. Physical recovery: Physical recovery re-applies data changes at the block level so tends to be much faster than logical recovery. Physical recovery requires both a base backup and a set of archived WAL files. There is a file named backup_label in the data directory of the base backup. This tells us to retrieve a .backup file from the archive that contains the start and stop WAL locations of the base backup. Recovery then starts to apply changes from the starting WAL location, and must proceed as far as the stop address for the backup to be valid. After recovery completes, the recovery.conf file is renamed to recovery.done to prevent the server from re-entering recovery. The server log records each WAL file restored from the archive, so you can check progress and rate of recovery. You can query the archive to find out the name of the latest archived WAL file to allow you to calculate how many files to go. The restore_command should return 0 if a file has been restored and non-zero for failure cases. Recovery will proceed until there is no next WAL file, so there will eventually be an error recorded in the logs. If you have lost some of the WAL files, or they are damaged, then recovery will stop at that point. No further changes after that will be applied, and you will likely lose those changes; that would be the time to call your support vendor. There's more... You can start and stop the server once recovery has started without any problem. It will not interfere with the recovery. You can connect to the database server while it is recovering and run queries, if that is useful. That is known as Hot Standby mode. Recovery to a point in time If your database suffers a problem at 15:22 p.m. and yet your backup was taken at 04:00 a.m. you're probably hoping there is a way to recover the changes made between those two times. What you need is known as "point-in-time recovery". Regrettably, if you've made a backup with pg_dump at 04:00 a.m. then you won't be able to recover to any other time than 04:00. As a result, the term point-in-time recovery (PITR) has become synonymous with the physical backup and restore technique in PostgreSQL. Getting ready If you have a backup made with pg_dump, then give up all hope of using that as a starting point for a point in time recovery. It's a frequently asked question, but the answer is still "no"; the reason it gets asked is exactly why I'm pleading with you to plan your backups ahead of time. First, you need to decide what the point of time is that to which you would like to recover. If the answer is "as late as possible", then you don't need to do a PITR at all, just recover until end of logs. How to do it... How do you decide to what point to recover? The point where we stop recovery is known as the "recovery target". The most straightforward way is to do this based upon a timestamp. In the recovery.conf, you can add (or uncomment) a line that says the following: recovery_target_time = '2010-06-01 16:59:14.27452+01' or similar. Note that you need to be careful to specify the time zone of the target, so that it matches the time zone of the server that wrote the log. That might differ from the time zone of the current server, so check. After that, you can check progress during a recovery by running queries in Hot Standby mode. How it works... Recovery works by applying individual WAL records. These correspond to individual block changes, so there are many WAL records to each transaction. The final part of any successful transaction is a commit WAL record, though there are abort records as well. Each transaction completion record has a timestamp on it that allows us to decide whether to stop at that point or not. You can also define a recovery target using a transaction id (xid), though finding out which xid to use is somewhat difficult, and you may need to refer to external records if they exist. The recovery target is specified in the recovery.conf and cannot change while the server is running. If you want to change the recovery target, you can shutdown the server, edit the recovery.conf, and then restart the server. Be careful though, if you change the recovery target and recovery is already passed the point, it can lead to errors. If you define a recovery_target_timestamp that has already passed, then recovery will stop almost immediately, though this will be later than the correct stopping point. If you define a recovery_target_xid that has already passed, then recovery will just continue to the end of logs. Restarting recovery from the beginning using a fresh restore of the base backup is always safe. Once a server completes recovery, it will assign a new "timeline". Once a server is fully available, we can write new changes to the database. Those changes might differ from changes we made in a previous "future history" of the database. So we differentiate between alternate futures using different timelines. If we need to go back and run recovery again, we can create a new server history using the original or subsequent timelines. The best way to think about this is that it is exactly like a Sci-Fi novel—you can't change the past but you can return to an earlier time and take a different action instead. But you'll need to be careful not to confuse yourself. There's more... pg_dump cannot be used as a base backup for a PITR. The reason is that a log replay contains the physical changes to data blocks, not logical changes based upon Primary Keys. If you reload a pg_dump the data will likely go back into different data blocks, so the changes wouldn't correctly reference the data. WAL doesn't contain enough information to reconstruct all SQL fully that produced those changes. Later feature additions to PostgreSQL may add the required information to WAL. See also Planned in 9.1 is the ability to pause/resume/stop recovery, and to set recovery targets while the server is up dynamically. This will allow you to use the Hot Standby facility to locate the correct stopping point more easily. You can trick Hot Standby into stopping recovery, which may help. Recovery of a dropped/damaged table You may drop or even damage a table in some way. Tables could be damaged for physical reasons, such as disk corruption, or they could also be damaged by running poorly specified UPDATEs/DELETEs, which update too many rows or overwrite critical data. It's a common request to recover from this situation from a backup. How to do it... The methods differ, depending upon the type of backup you have available. If you have multiple types of backup, you have a choice. LOGICAL (from custom dump -F c): If you've taken a logical backup using pg_dump into a custom file, then you can simply extract the table you want from the dumpfile like the following: pg_restore -t mydroppedtable dumpfile | psql or connect direct to the database using –d. The preceding command tries to re-create the table and then load data into it. Note that pg_restore -t option does not dump out any of the indexes on the table selected. That means we need a slightly more complex procedure than it would first appear, and the procedure needs to vary depending upon whether we are repairing a damaged table or putting back a dropped table. To repair a damaged table we want to replace the data in the table in a single transaction. There isn't a specific option to do this, so we need to do the following: Dump the table to a script file as follows: pg_restore -t mydroppedtable dumpfile > mydroppedtable.sql Edit a script named restore_mydroppedtable.sql with the following code: BEGIN; TRUNCATE mydroppedtable; i mydroppedtable.sql COMMIT; Then, run it using the following: psql -f restore_mydroppedtable.sql If you've dropped a table then you need to: Create a new database in which to work, name it restorework, as follows: CREATE DATABASE restorework; Restore the complete schema to the new database as follows: pg_restore --schema-only -d restorework dumpfile Now, dump just the definitions of the dropped table into a new file, which will contain CREATE TABLE, indexes, other constraints and grants. Note that this database has no data in it, so specifying –-schema-only is optional, as follows: pg_dump -t mydroppedtable --schema-only restorework > mydroppedtable.sql Now, recreate the table on the main database as follows: psql -f mydroppedtable.sql Now, reload just the data into database maindb as follows pg_restore -t mydroppedtable --data-only -d maindb dumpfile If you've got a very large table, then the fourth step can be a problem, because it builds the indexes as well. If you want you can manually edit the script into two pieces, one before the load ("pre-load") and one after the load ("post-load"). There are some ideas for that at the end of the recipe. LOGICAL (from script dump): The easy way to restore a single table from a script is as follows: Find a suitable server, or create a new virtual server. Reload the script in full, as follows: psql -f myscriptdump.sql From the recovered database server, dump the table, its data, and all the definitions of the dropped table into a new file as follows: pg_dump -t mydroppedtable -F c mydatabase > dumpfile Now, recreate the table into the original server and database, using parallel tasks to speed things along. This can be executed remotely without needing to transfer dumpfile between systems. pg_restore -d mydatabase -j 2 dumpfile The only way to extract a single table from a script dump without doing all of the preceding is to write a custom Perl script to read and extract just the parts of the file you want. That can be complicated, because you may need certain SET commands at the top of the file, the table, and data in the middle of the file, and the indexes and constraints on the table are near the end of the file. It's complex; the safe route is the one already mentioned. PHYSICAL: To recover a single table from a physical backup, we need to: Find a suitable server, or create a new virtual server. Recover the database server in full, as described in previous recipes on physical recovery, including all databases and all tables. You may wish to stop at a useful point in time. From the recovered database server, dump the table, its data, and all the definitions of the dropped table into a new file as follows: pg_dump -t mydroppedtable -F c mydatabase > dumpfile Now, recreate the table into the original server and database using parallel tasks to speed things along. This can be executed remotely without needing to transfer dumpfile between systems as follows: pg_restore -d mydatabase -j 2 dumpfile How it works... At present, there's no way to restore a single table from a physical restore in just a single step. See also Splitting a pg_dump into multiple sections, "pre" and "post" was proposed by me for an earlier release of PostgreSQL, though I haven't had time to complete that yet. It's possible to do that using an external utility also; the best script I've seen to split a dump file into two pieces is available at the following website: http://bucardo.org/wiki/split_postgres_dump
Read more
  • 0
  • 0
  • 5403

article-image-unix-monitoring-tool-postgresql
Packt
22 Oct 2010
8 min read
Save for later

UNIX Monitoring Tool for PostgreSQL

Packt
22 Oct 2010
8 min read
PostgreSQL 9.0 High Performance Accelerate your PostgreSQL system Learn the right techniques to obtain optimal PostgreSQL database performance, from initial design to routine maintenance Discover the techniques used to scale successful database installations Avoid the common pitfalls that can slow your system down Filled with advice about what you should be doing; how to build experimental databases to explore performance topics, and then move what you've learned into a production database environment Covers versions 8.1 through 9.0    iostat The data vmstat gives is a total across all devices on the system. If you want totals per disk device instead, you need to use iostat for that. On Linux, iostat defaults to slightly different behavior than vmstat. When it uses "block", it means a 512 byte chunk of data, not the 1024 bytes chunk vmstat uses. You can switch iostat to using kilobytes instead using iostat -k, or you can just divide all the figures by two in order to get them on the same scale. Here's an example of the same data shown both ways: $ iostat Device tps Blk_read/s Blk_wrtn/s Blk_read Blk_wrtn sda1 0.07 3.29 0.24 1579784 115560 $ iostat -k Device tps kB_read/s kB_wrtn/s kB_read kB_wrtn sda1 0.07 1.64 0.12 789892 57780 Since not all UNIX versions will have the kilobyte option available, the examples here all use the default 512 byte blocks, and accordingly halve the block figures to interpret using kilobyte units. You'll likely find that you need to average iostat data over a slightly longer period of time than vmstat data. A single second of vmstat data is a summary of all the disks on the system. A PostgreSQL database goes through several common phases: Just after a checkpoint: heavy full-page writes to WAL, fewer writes to database disks because there are fewer dirty buffer evictions. Between checkpoints: most are an even mix of WAL and database writes. Checkpoint in progress: Small to moderate WAL writes; increasingly heavy database writes as checkpoint data is written and starts flowing to disk. Checkpoint sync phase: Minimal WAL writes because fewer full page writes are likely happening; heavy writes to database disks as all data is flushed out of the OS cache. If you are looking at the vmstat data, or if you don't have the pg_xlog WAL data broken out onto a separate disk, you can't see the balance of the data vs. WAL writes change; you just see a total. But if you're grabbing really short iostat snapshots, you're likely to see writes bounce between the WAL and database disks, with the exact pattern depending on where in the checkpoint cycle you're at. You need to combine a few seconds of data (5 seconds is used for these examples) in order to have both types of writes be usefully averaged out: $ iostat 5 avg-cpu: %user %nice %system %iowait %steal %idle 42.69 0.00 18.07 6.69 0.30 32.25 Device tps Blk_read/s Blk_wrtn/s Blk_read Blk_wrtn sda 0.00 0.00 0.00 0 0 sda1 0.00 0.00 0.00 0 0 sdc 80.80 0.00 1286.40 0 6432 sdc1 80.80 0.00 1286.40 0 6432 sdd 77.80 0.00 1251.20 0 6256 sdd1 77.80 0.00 1251.20 0 6256 sde 69.40 0.00 1086.40 0 5432 sde1 69.40 0.00 1086.40 0 5432 sdf 2348.20 0.00 88262.40 0 441312 sdf1 2348.20 0.00 88262.40 0 441312 md0 311.40 0.00 2491.20 0 12456 Since all of the activity relates to the single partition on these disks, there's a lot of redundant data in here. You should also note that many of the statistics for the software RAID volume used here are not very interesting—you have to look at the underlying physical disk devices instead. If you're using hardware RAID, that particular problem will go away, but you won't have any easy way to get actual disk performance information out of that abstraction layer either; you'll just see the summary for the whole logical RAID device. The following examples eliminate all the redundant lines, and place the md0 array device between its individual components and the device the WAL is on (sdf1), for easier readability. Examples of good performance When busy but not overloaded, iostat data for this system looks like the following: $ iostat 5 avg-cpu: %user %nice %system %iowait %steal %idle 18.54 0.00 9.45 23.49 0.15 48.38 Device tps Blk_read/s Blk_wrtn/s Blk_read Blk_wrtn sdc1 1068.80 0.00 15740.80 0 78704 sdd1 1041.80 0.00 15459.20 0 77296 sde1 1028.00 0.00 15377.60 0 76888 md0 5969.20 0.00 47753.60 0 238768 sdf1 989.00 0.00 40449.60 0 202248 The %iowait figure of 23% is high enough to know the disks are busy, but not completely saturated yet. This is showing 20 MB/s (40449.6 512-byte blocks per second) being written to the WAL and 24 MB/s to the entire database disk array, the latter of which is evenly split as almost 8 MB/s to each of the three drives. Linux also features an extended iostat mode. This produces a large number of derived statistics from the underlying data. Since that's too wide to display here, the first example showing all of the data here has been transposed to swap the row for columns and vice-versa: $ iostat –x 5 sdc1 sdd1 sde1 md0 sdf1 rrqm/s 0 0 0 0 0 wrqm/s 411.8 404.6 396.2 0 3975.4 r/s 0 0 0 0 0 w/s 438.6 442 444.2 2461.4 1229.8 rsec/s 0 0 0 0 0 wsec/s 6956.8 6966.4 6915.2 19691.2 41643.2 avgrq-sz 15.86 15.76 15.57 8 33.86 avgqu-sz 67.36 67.09 62.93 0 0.65 await 158.18 158.85 148.39 0 0.55 svctm 1.2 1.2 1.19 0 0.51 %util 52.8 52.88 53.04 0 63.04 All of the values here with a "q" in them (most of what's listed on the following bulleted line) represent figures related to the read or write queues on these devices. Since the queue size doesn't correspond with any real-world figure you can benchmark the device against, it's hard to do anything with that data. The number of read and write requests is similarly useless in a database context. The following fields of iostat -x data are therefore not that useful here: rrqm/s, wrqm/s, r/s, w/s, avgrq-sz, avgqu-sz Solaris has a similar extended mode available using iostat -xc This next example is similar to the iostat one given previously: $ iostat –x 5 avg-cpu: %user %nice %system %iowait %steal %idle 21.51 0.00 11.08 23.75 0.10 43.56 Device rsec/s wsec/s avgrq-sz avgqu-sz await svctm %util sdc1 0.00 6956.80 15.86 67.36 158.18 1.20 52.80 sdd1 0.00 6966.40 15.76 67.09 158.85 1.20 52.88 sde1 0.00 6915.20 15.57 62.93 148.39 1.19 53.04 md0 0.00 19691.20 8.00 0.00 0.00 0.00 0.00 sdf 0.00 41643.20 33.86 0.65 0.55 0.51 63.04 That's 21 MB/s written to the WAL and 20 MB/s to the database disks, about 7 MB/s to each one. However, recall that the total disk read or write throughput available depends heavily on how random the workload is, which is normally a hard thing to estimate. The %util figure, which is by far the most valuable of the derived figures shown here, gives you a rough idea of that by noting how congested the device is to achieve that throughput. In this next example, there's minimal database I/O and heavy WAL I/O, typical of the period just after a checkpoint: $ iostat –x 5 avg-cpu: %user %nice %system %iowait %steal %idle 49.35 0.00 22.00 3.80 0.25 24.60 Device rsec/s wsec/s avgrq-sz avgqu-sz await svctm %util sdc1 0.00 2649.10 15.01 0.76 4.31 0.06 1.04 sdd1 0.00 2895.01 14.95 0.90 4.64 0.06 1.12 sde1 0.00 2728.94 15.06 0.82 4.51 0.06 1.04 md0 0.00 8273.05 8.00 0.00 0.00 0.00 0.00 sdf1 0.00 103760.48 38.11 0.23 0.09 0.09 23.47 This is happily getting >50 MB/s out of the WAL volume but it's still only busy 23.5% of the time. This suggests writes to it are being cached by the disk controller and written quite efficiently. One of the reasons to break out the WAL onto its own disk is because it makes it so easy to monitor this balance between WAL and database writes, and to determine if the WAL volume (which only gets sequential writes normally) is keeping up. Since there are techniques to accelerate the WAL writes at the expense of something else, such as switching to an unjournaled filesystem, the %util figure can help you determine when the WAL is the system bottleneck and therefore necessary to accelerate that way. A final example of good performance involves the database disks. There are some operations in PostgreSQL that can bypass writing to the WAL. For example, if you start a transaction that creates a new table and does a COPY into it, as long as you don't have PITR archiving turned on that data is not put through the WAL before being written to disk. The idea is that if the server crashes, the whole transaction will be rolled back anyway, which includes deleting the table data; therefore, whether it's consistent or not at the block level doesn't matter. Here is what the database disks are capable of when running such a COPY, which essentially turns into sequential write I/O directly to the database: $ iostat –x 5 avg-cpu: %user %nice %system %iowait %steal %idle 16.39 0.00 6.85 12.84 0.00 63.92 Device rsec/s wsec/s avgrq-sz avgqu-sz await svctm %util sdc1 25.60 58710.40 249.09 27.22 115.43 1.19 28.08 sdd1 24.00 58716.80 249.11 27.76 117.71 1.20 28.24 sde1 1.60 58667.20 250.51 28.31 120.87 1.14 26.80 md0 51.20 176094.40 8.00 0.00 0.00 0.00 0.00 sdf1 0.00 0.00 0.00 0.00 0.00 0.00 0.00 This is over 29 MB/s being written to each database disk, for a total of 88 MB/s to the RAID 0 array, and even that isn't fully utilizing the disks, as shown by the %util at about 28%. Given that this is a four-core server and the COPY is the only process running, a %user of 16 means that about 64% of a single CPU is busy here. The CPU and disks are likely waiting for each other a bit in this situation, and you might have to improve both to significantly speed this up. This example is from a server with a battery-backed RAID controller; without one, it's much easier to run into one of the disk bottlenecks here before the CPU ones. Final iostat hint: on some versions you can switch the output to use megabytes/second as its units, which is often the easiest to read. The following syntax for example, usually makes for a good summary on Linux systems: $ iostat -x -m 5
Read more
  • 0
  • 0
  • 2442

article-image-building-your-first-bean-coldfusion
Packt
22 Oct 2010
10 min read
Save for later

Building Your First Bean in ColdFusion

Packt
22 Oct 2010
10 min read
  Object-Oriented Programming in ColdFusion Break free from procedural programming and learn how to optimize your applications and enhance your skills using objects and design patterns Fast-paced easy-to-follow guide introducing object-oriented programming for ColdFusion developers Enhance your applications by building structured applications utilizing basic design patterns and object-oriented principles Streamline your code base with reusable, modular objects Packed with example code and useful snippets         What is a Bean? Although the terminology evokes the initial reaction of cooking ingredients or a tin of food from a supermarket, the Bean is an incredibly important piece of the object-oriented design pattern. The term 'Bean' originates from the Java programming language, and for those developers out there who enjoy their coffee as much as I do, the thought process behind it will make sense: Java = Coffee = Coffee Bean = Bean. A Bean is basically the building block for your object. Think of it as a blueprint for the information you want each object to hold and contain. In relation to other ColdFusion components, the Bean is a relatively simple CFC that primarily has two roles in life: to store information or a collection of values to return the information or collection of values when required But what is it really? Typically, a ColdFusion bean is a single CFC built to encapsulate and store a single record of data, and not a record-set query result, which would normally hold more than one record. This is not to say that the information within the Bean should only be pulled from one record within a database table, or that the data needs to be only a single string—far from it. You can include information in your Bean from any source at your disposal; however, the Bean can only ever contain one set of information. Your Bean represents a specific entity. This entity could be a person, a car, or a building. Essentially, any 'single' object can be represented by a bean in terms of development. The Bean holds information about the entity it is written for. Imagine we have a Bean to represent a person, and this Bean will hold details on that individual's name, age, hair color, and so on. These details are the properties for the entity, and together they make up the completed Bean for that person. In reality, the idea of the Bean itself is incredibly similar to a structure. You could easily represent the person entity in the form of a structure, as follows: <!---Build an empty structure to emulate a Person entity.---> <cfset stuPerson = { name = '', age = '', hairColor = ''} /> Listing: 3.1 – Creating an entity structure This seems like an entirely feasible way to hold your data, right? To some extent it is. You have a structure, complete with properties for the object/entity, wrapped up into one tidy package. You can easily update the structure to hold the properties for the individual, and retrieve the information for each property, as seen in the following code example: <!---Build an empty structure to emulate a Person entity.---> <cfset stuPerson = { name = '', age = '', hairColor = ''} /> <cfdump var="#stuPerson#" label="Person - empty data" /> <!---Update the structure with data and display the output---> <cfset StructUpdate( stuPerson, 'name', 'Matt Gifford') /> <cfset StructUpdate( stuPerson, 'hairColor', 'Brown') /> <br /> <cfdump var="#stuPerson#" label="Person - data added" /> <br /> <cfoutput> Name: #stuPerson.name#<br /> Hair: #stuPerson.hairColor# </cfoutput> Listing 3.2 – Populating the entity structure Although the structure is an incredibly simple method of retaining and accessing data, particularly when looking at the code, they do not suit the purpose of a blueprint for an entity very well, and as soon as you have populated the structure it is no longer a blueprint, but a specific entity. Imagine that you were reading data from the database and wanted to use the structure for every person who was drawn out from the query. Sure enough, you could create a standard structure that was persistent in the Application scope, for example. You could then loop through the query and populate the structure with the recordset results. For every person object you wanted, you could run ColdFusion's built-in Duplicate() function to create a copy of the original 'base' structure, and apply it to a new variable. Or perhaps, the structure might need to be written again on every page it is required in, or maybe written on a separate .cfm page that is included into the template using cfinclude. Perhaps over time, your application will grow, requirements will change, and extra details will need to be stored. You would then be faced with the task of changing and updating every instance of the structures across your entire application to include additional keys and values, or remove some from the structure. This route could possibly have you searching for code, testing, and debugging at every turn, and would not be the best method to optimize your development time and to enhance the scalability of your application. Taking the time to invest in your code base and development practices from the start will greatly enhance your application, development time, and go some way to reduce unnecessary headaches caused by spaghetti code and lack of structure. The benefit of using beans By creating a Bean for each entity within your application, you have created a specific blueprint for the data we wish to hold for that entity. The rules of encapsulation are adhered to, and nothing is hardcoded into our CFC. We have already seen how our objects are created, and how we can pass variables and data into them, which can be through the init() method during instantiation or perhaps as an argument when calling an included function within the component. Every time you need to use the blueprint for the Person class, you can simply create an instance of the Bean. You instantly have a completely fresh new object ready to populate with specific properties, and you can create a fully populated Person object in just one line of code within your application. The main purpose of a Bean in object-oriented development is to capture and encapsulate a variety of different objects, be they structures, arrays, queries, or strings for example, into one single object, which is the Bean itself. The Bean can then be passed around your application where required, containing all of the included information, instead of the application itself sending the many individual objects around or storing each one in, for example, the Application or Session scope, which could get messy. This creates a nicely packaged container that holds all of the information we need to send and use within our applications, and acts as a much easier way to manage the data we are passing around. If your blueprints need updating, for example more properties need to be added to the objects, you only have one file to modify, the CFC of the Bean itself. This instantly removes the problematic issues of having to search for every instance or every structure for your object throughout your entire code base. A Bean essentially provides you with a consistent and elegant interface, which will help you to organize your data into objects, removing the need to create, persist, and replicate ad-hoc structures. Creating our first Bean Let's look at creating a Bean for use with the projects table in the database. We'll continue with the Person Bean as the primary example, and create the CFC to handle person objects. An introduction to UML Before we start coding the component, let's have a quick look at a visual representation of the object using Unified Modeling Language (UML). UML is a widely-used method to display, share, and reference objects, Classes, workflows, and structures in the world of object-oriented programming, which you will come into contact with during your time with OOP development. The modeling language itself is incredibly detailed and in-depth, and can express such a wide array of details and information. Person object in UML In this example, let's take a look at the basics of UML and the visual representation of the Person component that we will create, which looks like this: At first glances, you can instantly see what variables and functions our component consists of. With most UML objects, it is broken into segments for easier digestion. The actual name of the component is clearly visible within the top section of the diagram. In the second section, we include the variables that will be included within our object. These have a '-' character in front of them, to indicate that these variables are private and are hidden within the component (they are not accessible externally). These variables are followed by the variable type, separated by a colon (':'). This lets you easily see which variable type is expected. In this example, we can see that all of the variables are strings. In the bottom section of the diagram we include the function references, which contain all methods within the component. All of the functions are prefixed with a '+' to indicate that they are publically accessible, and so are available to be called externally from the component itself. For any functions that require parameters, they are included inside the parenthesis. If a function returns a value, the returnType is specified after the ':'. Based upon this UML diagram, let's create the core wrapper for the CFC, and create the constructor method—the init() function. Create a new file called Person.cfc and save this file in the following location within your project folder: com/packtApp/oop/beans. <cfcomponent displayname="Person" output="false" hint="I am the Person Class."> <cfproperty name="firstName" type="string" default="" /> <cfproperty name="lastName" type="string" default="" /> <cfproperty name="gender" type="string" default="" /> <cfproperty name="dateofbirth" type="string" default="" /> <cfproperty name="hairColor" type="string" default="" /> <!--- Pseudo-constructor ---> <cfset variables.instance = { firstName = '', lastName = '', gender= '', dateofbirth = '', hairColor = '' } /> <cffunction name="init" access="public" output="false" returntype="any" hint="I am the constructor method for the Person Class."> <cfargument name="firstName" required="true" type="String" default="" hint="I am the first name." /> <cfargument name="lastName" required="true" type="String" default="" hint="I am the last name." /> <cfargument name="gender" required="true" type="String" default="" hint="I am the gender." /> <cfargument name="dateofbirth" required="true" type="String" default="" hint="I am the date of birth." /> <cfargument name="hairColor" required="true" type="String" default="" hint="I am the hair color." /> <cfreturn this /> </cffunction> </cfcomponent> Listing 3.3 - com/packtApp/oop/beans/Person.cfc Here, we have the init() method for the Person.cfc and the arguments defined for each property within the object. The bean will hold the values of its properties within the variables.instance structure, which we have defined above the init() method as a pseudo-constructor.
Read more
  • 0
  • 0
  • 4789

article-image-creating-customized-dialog-boxes-wix
Packt
22 Oct 2010
5 min read
Save for later

Creating Customized Dialog Boxes with WiX

Packt
22 Oct 2010
5 min read
        Read more about this book       The WiX toolset ships with several User Interface wizards that are ready to use out of the box. We'll briefly discuss each of the available sets and then move on to learning how to create your own from scratch. In this article by Nick Ramirez, author of the book WiX: A Developer's Guide to Windows Installer XML, you'll learn about: Adding dialogs into the InstallUISequence Linking one dialog to another to form a complete wizard Getting basic text and window styling working Including necessary dialogs like those needed to display errors (For more resources on WiX, see here.) WiX standard dialog sets The wizards that come prebuilt with WiX won't fit every need, but they're a good place to get your feet wet. To add any one of them, you first have to add a project reference to WixUIExtension.dll, which can be found in the bin directory of your WiX program files. Adding this reference is sort of like adding a new source file. This one contains dialogs. To use one, you'll need to use a UIRef element to pull the dialog into the scope of your project. For example, this line, anywhere inside the Product element, will add the "Minimal" wizard to your installer: <UIRef Id="WixUI_Minimal" /> It's definitely minimal, containing just one screen. It gives you a license agreement, which you can change by adding a WixVariable element with an Id of WixUILicenseRtf and a Value attribute that points to a Rich Text Format (.rtf) file containing your new license agreement: <WixVariable Id="WixUILicenseRtf" Value="newLicense.rtf" /> You can also override the background image (red wheel on the left, white box on the right) by setting another WixVariable called WixUIDialogBmp to a new image. The dimensions used are 493x312. The other available wizards offer more and we'll cover them in the following sections. WixUI_Advanced The "Advanced" dialog set offers more: It has a screen that lets the user choose to install for just the current user or for all users, another where the end user can change the folder that files are installed to and a screen with a feature tree where features can be turned on or off. As in the following screenshot: You'll need to change your UIRef element to use WixUI_Advanced. This can be done by adding the following line: <UIRef Id="WixUI_Advanced" /> You'll also have to make sure that your install directory has an Id of APPLICATIONFOLDER, as in this example: <Directory Id="TARGETDIR" Name="SourceDir"> <Directory Id="ProgramFilesFolder"> <Directory Id="APPLICATIONFOLDER" Name="My Program" /> </Directory></Directory> Next, set two properties: ApplicationFolderName and WixAppFolder. The first sets the name of the install directory as it will be displayed in the UI. The second sets whether this install should default to being per user or per machine. It can be either WixPerMachineFolder or WixPerUserFolder. <Property Id="ApplicationFolderName" Value="My Program" /><Property Id="WixAppFolder" Value="WixPerMachineFolder" /> This dialog uses a bitmap that the Minimal installer doesn't: the white banner at the top. You can replace it with your own image by setting the WixUIBannerBmp variable. Its dimensions are 493x58. It would look something like this: <WixVariable Id="WixUIBannerBmp" Value="myBanner.bmp" /> WixUI_FeatureTree The WixUI_FeatureTree wizard shows a feature tree like the Advanced wizard, but it doesn't have a dialog that lets the user change the install path. To use it, you only need to set the UIRef to WixUI_FeatureTree, like so: <UIRef Id="WixUI_FeatureTree" /> This would produce a window that would allow you to choose features as show in the following screenshot: Notice that in the image, the Browse button is disabled. If any of your Feature elements have the ConfigurableDirectory attribute set to the Id of a Directory element, then this button will allow you to change where that feature is installed to. The Directory element's Id must be all uppercase. WixUI_InstallDir WixUI_InstallDir shows a dialog where the user can change the installation path. Change the UIRef to WixUI_InstallDir. Like so: <UIRef Id="WixUI_InstallDir" /> Here, the user can chose the installation path. This is seen in the following screenshot: You'll have to set a property called WIXUI_INSTALLDIR to the Id you gave your install directory. So, if your directory structure used INSTALLLDIR for the Id of the main install folder, use that as the value of the property. <Directory Id="TARGETDIR" Name="SourceDir"> <Directory Id="ProgramFilesFolder"> <Directory Id="INSTALLDIR" Name="My Program" /> </Directory></Directory> <Property Id="WIXUI_INSTALLDIR" Value="INSTALLDIR" /> WixUI_Mondo The WixUI_Mondo wizard gives the user the option of installing a "Typical", "Complete" or "Custom" install. Typical sets the INSTALLLEVEL property to 3 while Complete sets it to 1000. You can set the Level attribute of your Feature elements accordingly to include them in one group or the other. Selecting a Custom install will display a feature tree dialog where the user can choose exactly what they want. To use this wizard, change your UIRef element to WixUI_Mondo. <UIRef Id="WixUI_Mondo" /> This would result in a window like the following:
Read more
  • 0
  • 0
  • 9899

article-image-omnigraffle-5-making-your-diagram-look-good
Packt
22 Oct 2010
8 min read
Save for later

OmniGraffle 5: Making your Diagram Look Good

Packt
22 Oct 2010
8 min read
OmniGraffle 5 Diagramming Essentials Create better diagrams with less effort using OmniGraffle Produce high-quality professional-looking diagrams that communicate information much better than words Makes diagramming fun and simple for Macintosh users Master the art of illustrating your ideas with OmniGraffle Learn to draw engaging charts and graphs to grasp your viewers' attention to your presentations A hands-on guide filled with visual step-by-step examples that cover both the basics and the advanced features of OmniGraffle        We will start with a few tips on making your diagrams visually appealing: Colorize gently: Do not flush your diagram full of colors. It is best if you can keep to just a few colors. Use colors that match each other—if you feel that you are not good at choosing colors, you can use the ColorJack and Kuler websites. Use few fonts: Try to use only two different fonts. These fonts should be without serifs, also known as sans serif. The text you are reading right now is a serif font—the titles in this book are written without serifs. Consider your output media: The thickness of lines, the color (or lack there of) fill of shapes, and so on, means different things when used in a screen presentation, on a web page or in a printed report. Symmetry is better than asymmetry: A balanced diagram is a good-looking diagram. However, any educated graphics designer will tell you there is a difference between visual and mathematical symmetry. If you are unsure about this – just do what looks correct. Have one and only one focus point: The focus point is the most important part of the diagram. Use titles, figure captions and legends: A diagram without a title is not telling the reader exactly what they are looking at. The exception to this rule is if the diagram is part of a report or a book. Be liberal with white space: Avoid cramping shapes together, as this will make your diagram look busy and messy. If space permits – use a whole page exclusively for your diagram if needed. Manually adjusting diagram elements So far you have manually moved shapes around your diagram. You have also learned that you can use visual guides in your diagram to align elements. However, for the majority of tasks, you used the Smart Alignment Guides and the Smart Distance Guides found in the Arrange | Guides application menu. Next, you see a shape that is aligned with both the Smart Alignment and Smart Distance guides enabled. The thin blue lines going through My Shape in the previous diagram are a visual indication that the shape is aligned both to the shapes to the left and above. If you have a diagram with a lot of shapes close to each other, the Smart Alignment Guides may not seem so smart anymore. In fact, the guides will not align to whatever shapes you wish they should align to. In these circumstances, using manual guides is the only good solution for very precise shape alignments. The Smart Alignment Guides will appear when you align two or more shapes to each other. Between the shapes you see the visual measurements that appear when the Smart Distance Guides kicks into action. The guide shows that the distances between My Shape and the two other horizontal shapes are equal to each other—creating horizontal symmetry. The same is also true for the vertical distance guide. The Smart Distance Guides appears when you try to distance three or more shapes from each other. Resizing shapes Until now you have resized shapes manually by dragging on the shape's resize handles (the small squares found on each corner and on each edge). If you wanted to make two or more shapes the same size, you've had to do a lot of work manually. Instead of manually working on each shape, you can use the Arrange | Size menu commands . You can also find the same commands using the context sensitive menu that appears if you right click on any shape, or selection of shapes. There are all together five sizing commands available (Make Same Width, Make Same Height, Make Same Size, Make Natural Size, and Size to Fit Image). You can size shapes to the same height, the same width, the same width and height, to their natural size and finally you can resize a shape to fit an imported image. Size to Fit Image Executing this menu command will resize the shape to cover the length and height of an associated image. Make Natural Size A natural sized shape is a shape where the height and the width of the shape are the same. The resizing is done based on the longest length, either vertically or horizontally. If you resize a shape which is wider than it's tall—then the Natural Size is calculated based on the width of the shape. The same applies if the shape is taller than it's wide—the Natural Size, in this case, is based on the height of the shape. The shape is always resized from the center line (either vertically or horizontally). Let's learn by doing. Start with a new canvas – add a rectangle to the canvas, and place a manual guideline through the shape's horizontal center line. After either using the Arrange | Size | Make Natural Size menu command , or right clicking and using the Size | Make Natural Size menu command , the shape is resized into a perfect square where each side has the same length and width. As you can see, the horizontal center is still intact. Making shapes the same size You have at your disposal three resizing commands that can only be used if you have selected more than one shape. The commands are to make the shapes the same width, height, and both width and height at the same time. We cannot stress this enough, but the order in which you select the shapes affects the end result. Start by creating an OmniGraffle document with an ellipse, a rectangle, and a triangle. First select the ellipse and then select the rectangle. Issue the Make Same Width menu command. The result is an oblong the same length as the ellipse. Now – first select the triangle, and then select the rectangle. Issue the Make Same Height menu command. The result is that the rectangle is now the same height as the triangle, as seen in the screenshot below: Let's try to select all the shapes and then use the Make Same Size menu command. You can select all the shapes by using the ⌘+A keyboard shortcut command. If you got the following result, this is because the rectangle and triangle where already selected (remember that the order in which the shapes are selected matters). If you instead had deselected any shapes prior to using the keyboard shortcut, the result would have been as expected because the ellipse was the fi rst shape you drew on the canvas. To complicate matters even further, as you drew the ellipse first, this shape was the top-most shape in your diagram. If you add a new cloud-shape to the right of the triangle, and order this shape to be the uppermost shape using the Front function () on the Canvas toolbar , your diagram should now look as shown next: Now, hit ⌘+A to select all shapes on the canvas, and then issue the Make Same Size menu command. The following screenshot is the resulting diagram: Gridlines So far you have worked without using a visible grid on your canvas. With the aid of the Smart Alignment Guides and the Smart Distance Guides, you have made perfectly aligned and good-looking diagrams. If your diagrams are much like the ones you have created so far, you may never have to use a grid when placing shapes. However, if you are making diagrams, which represent "real life objects" – using a grid is a must. These kinds of diagrams can be anything from a diagram showing the new office layout – to a diagram for showing offi ce visitors where various parts of the building are. Enabling gridlines You turn the visibility of grid lines on or off by using the View | Gridlines menu command. You could also use the ⌘+ keyboard shortcut command. In the previous screenshot, you see the canvas with grid lines. The thick grid lines are called the Major Gridlines, while the thinner lines are called the Minor Steps. Adjusting gridlines You can control the measurement unit in the Major Grid Spacing input field using the Canvas Size Property inspector. The default spacing for the Major Gridlines is 2,54 cm / 1 inch. Between Major Gridlines, there are eight Minor Steps as default. You can adjust the Major Gridlines and the Minor Steps by using the Grid Property inspector found in the Canvas selector.
Read more
  • 0
  • 0
  • 4518

article-image-php-5-social-networking-integrating-media-profile-posts
Packt
22 Oct 2010
13 min read
Save for later

PHP 5 Social Networking: Integrating Media in Profile Posts

Packt
22 Oct 2010
13 min read
Since different status types will use different status tables, we should use a left join to connect the tables, so we can keep just a single query to look up the statuses. It also pulls in the extra information when it is required. Let's get started with extending our profiles and the status stream! Changes to the view Since all of the media types we are going to support require at least one additional database field in a table that extends the statuses table, we are going to need to display any additional fields on the post status form. The standard type of status doesn't require additional fields, and new media types that we haven't discussed, which we may wish to support in the future, may require more than one additional field. To support a varying number of additional fields depending on the type, we could use some JavaScript (in this case, we will use the jQuery framework) to change the form depending on the context of the status. Beneath the main status box, we can add radio buttons for each of the status types, and depending on the one the user selects, the JavaScript can show or hide the additional fields, making the form more relevant. Template Our update status template needs a few changes: We need to set the enctype on the form, so that we can upload files (for posting images) We need radio buttons for the new types of statuses We need additional fields for those statuses The changes are highlighted in the following code segment: <p>Tell your network what you are up to</p> <form action="profile/statuses/{profile_user_id}" method="post" enctype="multipart/form-data"> <textarea id="status" name="status"></textarea> <br /> <input type="radio" name="status_type" id="status_checker_update" class="status_checker" value="update" />Update <input type="radio" name="status_type" id="status_checker_video" class="status_checker" value="video" />Video <input type="radio" name="status_type" id="status_checker_image" class="status_checker" value="image" />Image <input type="radio" name="status_type" id="status_checker_link" class="status_checker" value="link" />Link <br /> <div class="video_input extra_field"> <label for="video_url" class="">YouTube URL</label> <input type="text" id="" name="video_url" class="" /><br /> </div> <div class="image_input extra_field"> <label for="image_file" class="">Upload image</label> <input type="file" id="" name="image_file" class="" /><br /> </div> <div class="link_input extra_field"> <label for="link_url" class="">Link</label> <input type="text" id="" name="link_url" class="" /><br /> <label for="link_description" class="">Description</label> <input type="text" id="" name="link_description" class="" /><br /> </div> <input type="submit" id="updatestatus" name="updatestatus" value="Update" /> </form> These changes also need to be made to the post template, for posting on another user's profile. jQuery to enhance the user experience For accessibility purposes, we need this form to function regardless of whether the user has JavaScript enabled on their browser. To that end, we should use JavaScript to hide the unused form elements. So, even if the user has JavaScript disabled, they can still use all aspects of the form. We can then use JavaScript to enhance the user experience, toggling which aspects of the form are hidden or shown. <script type="text/javascript"> $(function() { First, we hide all of the extended status fields. $('.extra_field').hide(); $("input[name='status_type']").change(function(){ When the user changes the type of status, we hide all of the extended fields. $('.extra_field').hide(); We then show the fields directly related to the status type they have chosen. $('.'+ $("input[name='status_type']:checked").val() + '_input').show(); }); }); </script> View in action If we now take a look at our status updates page for our profile, we have some radio buttons that we can use to toggle elements of the form. Images To process images as a new status type, we will need a new database table and a new model to extend from the main status model. We will also need some new views, and to change the profile and status stream controllers (though we will make those changes after adding the three new status types). Database table The database table for images simply needs two fields:     Field Type Description ID Integer, Primary key To relate to the main statuses table Image Varchar The image filename These two fields will be connected to the statuses table via a left join, to bring in the image filename for statuses that are images. Model The model needs to extend our statuses model, providing setters for any new fields, call the parent constructor, call the parent setTypeReference method to inform that it is an image, call the parent save method to save the status, and then insert a new record into the image status table with the image information. Class, variable, and constructor Firstly, we define the class as an extension of the status class. We then define a variable for the image, and construct the object. The constructor calls the parent setTypeReference method to ensure it generates the correct type ID for an image, and then calls the parent constructor so it too has reference to the registry object. This file is saved as /models/imagestatus.php. <?php /** * Image status object * extends the base status object */ class Imagestatus extends status { private $image; /** * Constructor * @param Registry $registry * @param int $id * @return void */ public function __construct( Registry $registry, $id = 0 ) { $this->registry = $registry; parent::setTypeReference('image'); parent::__construct( $this->registry, $id ); } To call a method from an object's parent class, we use the parent keyword, followed by the scope resolution operator, followed by the method we wish to call. Processing the image upload When dealing with image uploads, resizing, and saving, there are different PHP functions that should be used depending on the type of the image. To make this easier and to provide a centralized place for dealing with image uploads and other image-related tasks, we should create a library file (lib/images/imagemanager. class.php) to make this easier. Let's discuss what an image manager library file should do to make our lives easier: Process uploading of an image from $_POST data Verify the type of file and the file extension Process images from the file system so that we can modify them Display an image to the browser Resize an image Rescale an image by resizing either the x or y co-ordinate, and scaling the other co-ordinate proportionally Get image information such as size and name Save the changes to the image The following is the code required to perform the above-mentioned tasks: <?php /** * Image manager class * @author Michael Peacock */ class Imagemanager { /** * Type of the image */ private $type = ''; /** * Extensions that the user can upload */ private $uploadExtentions = array( 'png', 'jpg', 'jpeg', 'gif' ); /** * Mime types of files the user can upload */ private $uploadTypes = array( 'image/gif', 'image/jpg', 'image/jpeg', 'image/pjpeg', 'image/png' ); /** * The image itself */ private $image; /** * The image name */ private $name; public function __construct(){} We need a method to load a local image, so that we can work with images saved on the servers file system. /** * Load image from local file system * @param String $filepath * @return void */ public function loadFromFile( $filepath ) { Based on the path to the image, we can get information on the image including the type of image (getimagesize gives us an array of information on the image; the second element in the array is the type). $info = getimagesize( $filepath ); $this->type = $info[2]; We can then compare the image type to various PHP constants, and depending on the image type (JPEG, GIF, or PNG) we use the appropriate imagecreatefrom function. if( $this->type == IMAGETYPE_JPEG ) { $this->image = imagecreatefromjpeg($filepath); } elseif( $this->type == IMAGETYPE_GIF ) { $this->image = imagecreatefromgif($filepath); } elseif( $this->type == IMAGETYPE_PNG ) { $this->image = imagecreatefrompng($filepath); } } We require a couple of getter methods to return the height or width of the image. /** * Get the image width * @return int */ public function getWidth() { return imagesx($this->image); } /** * Get the height of the image * @return int */ public function getHeight() { return imagesy($this->image); } We use a simple resize method that resizes the image to the dimensions we request. /** * Resize the image * @param int $x width * @param int $y height * @return void */ public function resize( $x, $y ) { $new = imagecreatetruecolor($x, $y); imagecopyresampled($new, $this->image, 0, 0, 0, 0, $x, $y, $this->getWidth(), $this->getHeight()); $this->image = $new; } Here we use a scaling function that takes a height parameter to resize to and scales the width accordingly. /** * Resize the image, scaling the width, based on a new height * @param int $height * @return void */ public function resizeScaleWidth( $height ) { $width = $this->getWidth() * ( $height / $this->getHeight() ); $this->resize( $width, $height ); } Similar to the above method, this method takes a width parameter, resizes the width, and rescales the height based on the width. /** * Resize the image, scaling the height, based on a new width * @param int $width * @return void */ public function resizeScaleHeight( $width ) { $height = $this->getHeight() * ( $width / $this->getWidth() ); $this->resize( $width, $height ); } The following is another scaling function, this time to rescale the image to a percentage of its current size: /** * Scale an image * @param int $percentage * @return void */ public function scale( $percentage ) { $width = $this->getWidth() * $percentage / 100; $height = $this->getheight() * $percentage / 100; $this->resize( $width, $height ); } To output the image to the browser from PHP, we need to check the type of the image, set the appropriate header based off the type, and then use the appropriate image function to render the image. After calling this method, we need to call exit() to ensure the image is displayed correctly. /** * Display the image to the browser - called before output is sent, exit() should be called straight after. * @return void */ public function display() { if( $this->type == IMAGETYPE_JPEG ) { $type = 'image/jpeg'; } elseif( $this->type == IMAGETYPE_GIF ) { $type = 'image/gif'; } elseif( $this->type == IMAGETYPE_PNG ) { $type = 'image/png'; } header('Content-Type: ' . $type ); if( $this->type == IMAGETYPE_JPEG ) { imagejpeg( $this->image ); } elseif( $this->type == IMAGETYPE_GIF ) { imagegif( $this->image ); } elseif( $this->type == IMAGETYPE_PNG ) { imagepng( $this->image ); } } To load an image from $_POST data, we need to know the post field the image is being sent through, the directory we wish to place the image in, and any additional prefix we may wish to add to the image's name (to prevent conflicts with images with the same name). /** * Load image from postdata * @param String $postfield the field the image was uploaded via * @param String $moveto the location for the upload * @param String $name_prefix a prefix for the filename * @return boolean */ public function loadFromPost( $postfield, $moveto, $name_prefix='' ) { Before doing anything, we should check that the file requested is actually a file that has been uploaded (and that this isn't a malicious user trying to access other files). if( is_uploaded_file( $_FILES[ $postfield ]['tmp_name'] ) ) { $i = strrpos( $_FILES[ $postfield ]['name'], '.'); if (! $i ) { //'no extention'; return false; } else { We then check that the extension of the file is in our allowed extensions array. $l = strlen( $_FILES[ $postfield ]['name'] ) - $i; $ext = strtolower ( substr( $_FILES[ $postfield ]['name'], $i+1, $l ) ); if( in_array( $ext, $this->uploadExtentions ) ) { Next, we check if the file type is an allowed file type. if( in_array( $_FILES[ $postfield ]['type'], $this->uploadTypes ) ) { Then, we move the file, as it has already been uploaded to our server's temp folder, to our own uploads directory and load it into our image manager class for any further processing we wish to make. $name = str_replace( ' ', '', $_FILES[ $postfield ]['name'] ); $this->name = $name_prefix . $name; $path = $moveto . $name_prefix.$name; move_uploaded_file( $_FILES[ $postfield ]['tmp_name'] , $path ); $this->loadFromFile( $path ); return true; } else { // 'invalid type'; return false; } } else { // 'invalid extention'; return false; } } } else { // 'not uploaded file'; return false; } } The following getter method is used to return the name of the image we are working with: /** * Get the image name * @return String */ public function getName() { return $this->name; } Finally, we have our save method, which again must detect the type of image, to work out which function to use. /** * Save changes to an image e.g. after resize * @param String $location location of image * @param String $type type of the image * @param int $quality image quality /100 * @return void */ public function save( $location, $type='', $quality=100 ) { $type = ( $type == '' ) ? $this->type : $type; if( $type == IMAGETYPE_JPEG ) { imagejpeg( $this->image, $location, $quality); } elseif( $type == IMAGETYPE_GIF ) { imagegif( $this->image, $location ); } elseif( $type == IMAGETYPE_PNG ) { imagepng( $this->image, $location ); } } } ?> Using the image manager library to process the file upload Now that we have a simple, centralized way of processing file uploads and resizing them, we can process the image the user is trying to upload as their extended status. /** * Process an image upload and set the image * @param String $postfield the $_POST field the image was uploaded through * @return boolean */ public function processImage( $postfield ) { require_once( FRAMEWORK_PATH . 'lib/images/imagemanager.class.php' ); $im = new Imagemanager(); $prefix = time() . '_'; if( $im->loadFromPost( $postfield, $this->registry- >getSetting('upload_path') . 'statusimages/', $prefix ) ) { $im->resizeScaleWidth( 150 ); $im->save( $this->registry->getSetting('upload_path') . 'statusimages/' . $im->getName() ); $this->image = $im->getName(); return true; } else { return false; } } Saving the status This leaves us with the final method for saving the status. This calls the parent object's save method to create the record in the statuses table. Then it gets the ID, and inserts a new record into the images table with this ID as the ID. /** * Save the image status * @return void */ public function save() { // save the parent object and thus the status table parent::save(); // grab the newly inserted status ID $id = $this->getID(); // insert into the images status table, using the same ID $extended = array(); $extended['id'] = $id; $extended['image'] = $this->image; $this->registry->getObject('db')->insertRecords( 'statuses_images', $extended ); } } ?>
Read more
  • 0
  • 0
  • 4552
Unlock access to the largest independent learning library in Tech for FREE!
Get unlimited access to 7500+ expert-authored eBooks and video courses covering every tech area you can think of.
Renews at €18.99/month. Cancel anytime
article-image-nhibernate-30-using-icriteria-and-paged-queries-data-access-layer
Packt
21 Oct 2010
4 min read
Save for later

NHibernate 3.0: Using ICriteria and Paged Queries in the Data Access Layer

Packt
21 Oct 2010
4 min read
NHibernate 3.0 Cookbook Get solutions to common NHibernate problems to develop high-quality performance-critical data access applications Master the full range of NHibernate features Reduce hours of application development time and get better application architecture and performance Create, maintain, and update your database structure automatically with the help of NHibernate Written and tested for NHibernate 3.0 with input from the development team distilled in to easily accessible concepts and examples Part of Packt's Cookbook series: each recipe is a carefully organized sequence of instructions to complete the task as efficiently as possible Using ICriteria in the data access layer For queries where the criteria are not known in advance, such as a website's advanced product search, ICriteria queries are more appropriate than named HQL queries. This article by Jason Dentler, author of NHibernate 3.0 Cookbook, shows how to use the same DAL infrastructure with ICriteria and QueryOver queries. In an effort to avoid overwhelming the user, and increase application responsiveness, large result sets are commonly broken into smaller pages of results. This article also shows how we can easily add paging to a QueryOver query object in our DAL. Getting ready Complete the previous recipe, Using Named Queries in the data access layer. How to do it... In Eg.Core.Data.Impl.Queries, add a new, empty, public interface named ICriteriaQuery. Add a class named CriteriaQueryBase with the following code: public abstract class CriteriaQueryBase<TResult> : NHibernateQueryBase<TResult>, ICriteriaQuery { public CriteriaQueryBase(ISessionFactory sessionFactory) : base(sessionFactory) { } public override TResult Execute() { var criteria = GetCriteria(); return Transact(() => Execute(criteria)); } protected abstract ICriteria GetCriteria(); protected abstract TResult Execute(ICriteria criteria); } In Eg.Core.Data.Queries, add the following enum: public enum AdvancedProductSearchSort { PriceAsc, PriceDesc, Name } Add a new interface named IAdvancedProductSearch with the following code: public interface IAdvancedProductSearch : IQuery<IEnumerable<Product>> { string Name { get; set; } string Description { get; set; } decimal? MinimumPrice { get; set; } decimal? MaximumPrice { get; set; } AdvancedProductSearchSort Sort { get; set; } } In Eg.Core.Data.Impl.Queries, add the following class: public class AdvancedProductSearch : CriteriaQueryBase<IEnumerable<Product>>, IAdvancedProductSearch { public AdvancedProductSearch(ISessionFactory sessionFactory) : base(sessionFactory) { } public string Name { get; set; } public string Description { get; set; } public decimal? MinimumPrice { get; set; } public decimal? MaximumPrice { get; set; } public AdvancedProductSearchSort Sort { get; set; } protected override ICriteria GetCriteria() { return GetProductQuery().UnderlyingCriteria; } protected override IEnumerable<Product> Execute( ICriteria criteria) { return criteria.List<Product>(); } private IQueryOver GetProductQuery() { var query = session.QueryOver<Product>(); AddProductCriterion(query); return query; } private void AddProductCriterion<T>( IQueryOver<T, T> query) where T : Product { if (!string.IsNullOrEmpty(Name)) query = query.WhereRestrictionOn(p => p.Name) .IsInsensitiveLike(Name, MatchMode.Anywhere); if (!string.IsNullOrEmpty(Description)) query.WhereRestrictionOn(p => p.Description) .IsInsensitiveLike(Description, MatchMode.Anywhere); if (MinimumPrice.HasValue) query.Where(p => p.UnitPrice >= MinimumPrice); if (MaximumPrice.HasValue) query.Where(p => p.UnitPrice <= MaximumPrice); switch (Sort) { case AdvancedProductSearchSort.PriceDesc: query = query.OrderBy(p => p.UnitPrice).Desc; break; case AdvancedProductSearchSort.Name: query = query.OrderBy(p => p.Name).Asc; break; default: query = query.OrderBy(p => p.UnitPrice).Asc; break; } } } How it works... In this recipe, we reuse the same repository and query infrastructure from the Using Named Queries in The Data Access Layer recipe. Our simple base class for ICriteria-based query objects splits query creation from query execution and handles transactions for us automatically. The example query we use is typical for an "advanced product search" use case. When a user fills in a particular field on the UI, the corresponding criterion is included in the query. When the user leaves the field blank, we ignore it. We check each search parameter for data. If the parameter has data, we add the appropriate criterion to the query. Finally, we set the order by clause based on the Sort parameter and return the completed ICriteria query. The query is executed inside a transaction, and the results are returned. There's more... For this type of query, typically, each query parameter would be set to the value of some field on your product search UI. On using this query, your code looks like this: var query = repository.CreateQuery<IAdvancedProductSearch>(); query.Name = searchCriteria.PartialName; query.Description = searchCriteria.PartialDescription; query.MinimumPrice = searchCriteria.MinimumPrice; query.MaximumPrice = searchCriteria.MaximumPrice; query.Sort = searchCriteria.Sort; var results = query.Execute();
Read more
  • 0
  • 0
  • 1943

article-image-adding-event-calendar-your-joomla-site-using-jevents
Packt
21 Oct 2010
2 min read
Save for later

Adding an Event Calendar to your Joomla! Site using JEvents

Packt
21 Oct 2010
2 min read
Getting ready... There are many extensions to add event calendars to Joomla!. However, JEvents is the most feature-rich and popular extension. Download this extension from http://www.jevents.net/jevents-download and install it from the Extensions | Install/Uninstall screen. How to do it... After installing JEvents, follow these steps to add the calendar: From the Joomla! administration panel, select Components | JEvents. This will show you the JEvents:: Control Panel screen. Click on the Manage Categories icon in the Control Panel screen. This will show you the Categories screen, listing all the available categories, if any. Click on the New button in the toolbar. It will show you a form similar to that in the following screenshot: Enter a Title, select the parent category (if any), then select Access Level and Administrator, select Yes in Published field, and type a brief description of the category. From the Event Colour field, choose the color for the events in this category. Then click on the Save icon in the toolbar. Repeat the step to create another category. To go back to the Control Panel page, click on the CPanel icon on the Categories screen. Then click on the Manage Calendars icon in the Control Panel screen. That shows the Calendars screen. Click on the New button. This shows you a form similar to the one in the following screenshot: Type a Unique Identifier (name) for the calendar, select the default category and Access Level, select No for the Is Default field, and click on Create Calendar from Scratch. This creates a new calendar. Go back to the Control Panel page, and click on the Manage Events icon. This will shows you the Events screen. Click on the New button in the toolbar, and you will get the Edit Event screen. On the Edit Event screen, first select a calendar and then type the subject of the event. Then select a category, a color for the event, and the access level. In the Activity field briefly describe the activity, and then fill in the Location, Contact, and Extra Info fields. Then click on the Calendar tab.
Read more
  • 0
  • 0
  • 3265

article-image-blender-25-creating-uv-texture
Packt
21 Oct 2010
4 min read
Save for later

Blender 2.5: creating a UV texture

Packt
21 Oct 2010
4 min read
Before we can create a custom UV texture, we need to export our current UV map from Blender to a file that an image manipulation program, such as GIMP or Photoshop, can read. Exporting our UV map If we have GIMP downloaded, we can export our UV map from Blender to a format that GIMP can read. To do this, make sure we can view our UV map in the Image Editor. Then, go to UVs | Export UV Layout. Then save the file in a folder you can easily get to, naming it UV_layout or whatever you like. (Move the mouse over the image to enlarge.) Now it's time to open GIMP! Downloading GIMP Before we begin, we need to first get an image manipulation program. If you don't have one of the high-end programs, such as Photoshop, there still is hope. There's a wonderful free (and open source) program called GIMP, which parallels Photoshop in functionality. For the sake of creating our textures, we will be using GIMP, but feel free to use whatever you are personally most comfortable with. To download GIMP, visit the program's website at http://www.gimp.org and download the right version for your operating system. Mac Users will need to install X11 so GIMP will run. Consult your Mac OS installation guide for instructions on how to install. Windows users, you will need to install the GTK+ Runtime Environment to run GIMP—the download installer should warn you about this during installation. To install GTK+, visit http://www.gtk.org. Hello GIMP! When we open GIMP for the first time, we should have a 3-window layout, similar to the following screen: Create a new document by selecting File | New. You can also use the Ctrl+N keyboard shortcut. This should bring up a dialog box with a list of settings we can use to customize our new document. Because Blender exported our UV map as an SVG file, we can choose any size image we want, because we can scale the image to fit our document. SVG stands for Scalable Vector Graphic. Vector graphics are images defined by mathematically calculated paths, allowing them to be scaled infinitely without the pixilation caused when raster images are enlarged beyond a certain point. Change the Width and Height attributes to 2000 each. This will create a texture image 2000 pixels wide by 2000 pixels high. Click on OK to create our new document. Getting reference images Before we can create a UV texture for our wine bottle, which will primarily define the bottle's label, we need to know what is typically on a wine bottle's label. If you search the web for any wine bottle, you'll get a pretty good idea of what a wine bottle label looks like. However, for our purposes, we're going to use the following image: Notice how there's typically the name of the wine company, the type of wine, and the year it was made. We're going to use all of these in our own wine bottle label. Importing our UV map A nice thing about GIMP is that we can import images as layers into our current file. We're going to do just this with our UV map. Go to File | Open as Layers... to bring up the file selection dialog box. Navigate to the UV map we saved earlier and open it. Another dialog box will pop up—we can use this to tell GIMP how we want our SVG to appear in our document. Change the Width and Height attributes to match our working document—2000px by 2000px. Click on OK to confirm. Not every file type will bring up this dialog box—it's specific to SVG files only. We should now see our UV map in the document as a new layer. Before we continue, we should change the background color of our texture. Our label is going to be white, so we are going to need to distinguish our label from the rest of the wine bottle's material. With our background layer selected, fill the layer with a black color using the Fill tool. Next, we can create the background color of the label. Create a new layer by clicking on the New Layer button. Name it label_background. Using the Marquee Selection tool, make a selection similar to the following image: Fill it, using the Fill tool, with white. This will be the background for our label—everything else we add with be made in relation to this layer. Keep the UV map layer on top as often as possible. This will help us keep a clear view of where our graphics are in relation to our UV map at all times.
Read more
  • 0
  • 0
  • 24529

article-image-microsoft-wcf-security
Packt
21 Oct 2010
5 min read
Save for later

Microsoft WCF Security

Packt
21 Oct 2010
5 min read
Security is a big topic in distributed communication applications. When the client consumers call a service operation through an intranet or the Internet, it is necessary to consider how we will secure the communication between the two sides, or how we can make sure that we are talking to the correct service or the correct client consumers. WCF provides a lot of built-in features for developers to address all these kinds of problems in service application development. The most commonly used WCF security features include authentication, authorization, and message protection (signing and encrypting). In this article, we will use 5 recipes to demonstrate some useful security scenarios in WCF service development. These recipes will focus on various authentication use cases, including Windows authentication, username authentication, and so on. Setting up ad hoc Windows authentication over plain HTTP WCF supports various authentication types and Windows authentication is a common authentication method used in existing distributed communication components on the Windows platform. A very common use case is to enable Windows authentication at transport layer without an additional secure connection like SSL (just like what the traditional ASMX Web Service uses). In this recipe, we will demonstrate how to apply Windows authentication for a WCF service endpoint using plain HTTP as the transport protocol, without additional security. How to do it... Make the service endpoint use BasicHttpBinding. The first thing to do is choose BasicHttpBinding as the binding type of our WCF service endpoint. Also, in the binding configuration, we need to specify the security mode as TransportCredentialOnly and clientCredentialType as Windows. The following screenshot shows the app.config section of our sample service endpoint. Adjust the Windows authentication settings in IIS server. For a WCF service, if we use IIS as the hosting environment, we also need to apply proper configuration on the application virtual directory in which we will deploy the service endpoints. For our ad hoc Windows authentication service, it is necessary to turn on the Windows authentication and disable anonymous access on the IIS virtual directory so that the Windows authentication on the WCF endpoint can work correctly. All these configurations can be done through the IIS virtual directory settings in the management console. The following screenshot shows the configuration manager UI of IIS 7. How it works... After the service endpoint has been properly configured as ad hoc Windows authentication mode, the client consumer can use the generated proxy class or ChannelFactory to invoke the target service operations. Also, either the service proxy or ChannelFactory provides the ClientCredential property for the caller to supply their Windows credentials (see the following code snippet): static void CallService() { TestProxy.Service1Client client = new TestProxy.Service1Client(); client.ClientCredentials.Windows.ClientCredential = System.Net.CredentialCache.DefaultNetworkCredentials; Console.WriteLine( client.GetData(11)); } Getting an authenticated client identity in a service operation WCF provides various built-in authentication methods either at the transport layer or at the message layer. The client consumer can use a WCF service proxy or ChannelFactory to supply certain client credentials to the service. The following MSDN reference lists all the built-in credential types supported by WCF: Selecting a Credential Type http://msdn.microsoft.com/en-us/library/ms733836.aspx After the service request passes authentication, a valid identity will be associated with each service-operation execution context and the service operation code can retrieve the identity information within the operation context. This recipe will show you how to programmatically retrieve the client authenticated identity information in service operation code. How to do it... WCF runtime provides an OperationContext object associated with each request processing so that the developers can access some operation/request context-specific data from it. For example, we can access and manipulate SOAP headers or other underlying transport protocol properties through OperationContext. For operation authentication, the authenticated identity is also accessible through OperationContext, and the minor difference is that we need to get the identity by a ServiceSecurityContext member of the OperationContext object. The ServiceSecurityContext type contains several member properties, which represent security information transferred from the client side. Name Description Anonymous Returns an instance of the ServiceSecurityContext class that contains an empty collection of claims, identities, and other context data usually used to represent an anonymous party. AuthorizationContext Gets the authorization information for an instance of this class. The AuthorizationContext contains a collection of ClaimSet that the application can interrogate, and retrieve the information of the party. AuthorizationPolicies Gets the collection of policies associated with an instance of this class. Current Gets the current ServiceSecurityContext. IsAnonymous Gets a value that indicates whether the current client has provided credentials to the service. PrimaryIdentity Gets the primary identity associated with the current setting. WindowsIdentity Gets the Windows identity of the current setting. The WindowsIdentity and PrimaryIdentity properties are the corresponding members which contain the authentication identity information of the client service caller. We can inspect the identity details such as identity name or authentication type from the two properties. The following screenshot shows the code for obtaining main authentication identity information from the PrimaryIdentity property. Likewise, we can use the Windows Identity property to get the Windows security identity associated with the current operation call (as shown in the following screenshot):
Read more
  • 0
  • 0
  • 2531
article-image-all-new-october-open-source-books-packt
Packt
21 Oct 2010
1 min read
Save for later

All New October Open Source Books from Packt

Packt
21 Oct 2010
1 min read
  PostgreSQL 9.0 High Performance Accelerate your PostgreSQL system. Click for more information PHP 5 Social Networking Create a powerful and dynamic Social Networking website in PHP by building a flexible framework. Click for more information Learning Ext JS 3.2 Build dynamic, desktop-style user interfaces for your data-driven web applications using Ext JS. Click for more information Joomla! 1.5 Top Extensions Cookbook Over 80 great recipes for taking control of Joomla! Extensions. Click for more information jQuery Plugin Development Beginner's Guide Build powerful, interactive plugins to implement jQuery in the best way possible. Click for more information NHibernate 3.0 Cookbook Get solutions to common NHibernate problems to develop high-quality performance-critical data access applications. Click for more information Mastering phpMyAdmin 3.3.x for Effective MySQL Management A complete guide to get started with phpMyAdmin 3.3 and master its features. Click for more information WiX: A Developer's Guide to Windows Installer XML Create a hassle-free installer for your Windows software using WiX. Click for more information  
Read more
  • 0
  • 0
  • 1135

article-image-oracle-business-intelligence-drilling-data-and-down
Packt
21 Oct 2010
5 min read
Save for later

Oracle Business Intelligence: Drilling Data Up and Down

Packt
21 Oct 2010
5 min read
What is data drilling? In terms of Oracle Discoverer, drilling is a technique that enables you to quickly navigate through worksheet data, finding the answers to the questions facing your business. As mentioned, depending on your needs, you can use drilling to view the data you're working with in deeper detail or, in contrast, drill it up to a higher level. The drilling to detail technique enables you to look at the values making up a particular summary value. Also, you can drill to related items, adding related information that is not currently included in the worksheet. So, Discoverer supports a set of drilling tools, including the following: Drilling up and down Drilling to a related item Drilling to detail Drilling out The following sections cover the above tools in detail, providing examples on how you might use them. Drilling to a related item Let's begin with a discussion on how to drill to a related item, adding the detailed information for a certain item. As usual, this is best understood by example. Suppose you want to drill from the Maya Silver item, which can be found on the left axis of the worksheet, to the Orddate:Day item. Here are the steps to follow: Let's first create a copy of the worksheet to work with in this example. To do this, move to the worksheet discussed in the preceding example and select the Edit | Duplicate Worksheet | As Crosstab menu of Discoverer. In the Duplicate as Crosstab dialog, just click OK. As a result a copied worksheet should appear in the workbook. On the worksheet, right-click the Maya Silver item and select Drill… in the pop-up menu: As a result, the Drill dialog should appear. In the Drill dialog, select Drill to a Related Item in the Where do you want to drill to? select box and then choose the Orddate:Day item, as shown in the following screenshot: Then, click OK to close the dialog and rearrange the data on the worksheet. The reorganized worksheet should now look like the following one: As you can see, this shows the Maya Silver item broken down into day sales per product. Now suppose you want to see a more detailed view of the Maya Silver item and break it out further into product category. Right-click the Maya Silver item and select Drill… in the pop-up menu. In the Drill dialog, select Drill to a Related Item in the Where do you want to drill to? select box and then choose the Category item. Next, click OK.The resulting worksheet should look now like this: As you can see, the result of the drilling operations you just performed is that you can see the dollar amount for Maya Silver detailed by category, by day, by product. You may be asking yourself if it's possible to change the order in which the Maya Silver record is detailed. Say, you want to see it detailed in the following order: by day, by category, and finally by product. The answer is sure. On the left axis of the worksheet, drag the Orddate:Day item (the third from the left) to the second position within the same left axis, just before the Category item, as shown in the following screenshot: As a result, you should see that the data on the worksheet has been rearranged as shown in the following screenshot: Having just a few rows in the underlying tables, as we have here, is OK for demonstration purposes, since it results in compact screenshots. To see more meaningful figures on the worksheet though, you might insert more rows into the orderitems, orders, and products underlying tables. Once you're done with it, you can click the Refresh button on the Discoverer toolbar to see an updated worksheet. Select the File | Save menu option of Discoverer to save the worksheet discussed here. Drilling up and down As the name implies, drilling down is a technique you can use to float down a drill hierarchy to see data in more detail. And drilling up is the reverse operation, which you can use to slide up a drill hierarchy to see consolidated data. But what is a drill hierarchy? Working with drill hierarchies A drill hierarchy represents a set of items related to each other according to the foreign key relationships in the underlying tables. If a worksheet item is associated with a drill hierarchy, you can look at that hierarchy by clicking the drill icon located at the left of the heading of the worksheet item. Suppose you want to look at the hierarchy associated with the Orddate item located on our worksheet at the top axis. To do this, click the Orddate drill icon. As a result, you should see the menu shown in the following screeenshot: As you can see, you can drill up here from Orddate to Year, Quarter, or Month. The next screenshot illustrates what you would have if you chose Month. It's important to note that you may have more than one hierarchy associated with a worksheet item. In this case, you can move on to the hierarchy you want to use through the All Hierarchies option on the drill menu.
Read more
  • 0
  • 0
  • 4424

article-image-nhibernate-30-using-linq-specifications-data-access-layer
Packt
21 Oct 2010
4 min read
Save for later

NHibernate 3.0: Using LINQ Specifications in the data access layer

Packt
21 Oct 2010
4 min read
  NHibernate 3.0 Cookbook Get solutions to common NHibernate problems to develop high-quality performance-critical data access applications Master the full range of NHibernate features Reduce hours of application development time and get better application architecture and performance Create, maintain, and update your database structure automatically with the help of NHibernate Written and tested for NHibernate 3.0 with input from the development team distilled in to easily accessible concepts and examples Part of Packt's Cookbook series: each recipe is a carefully organized sequence of instructions to complete the task as efficiently as possible         Read more about this book       (For more resources on NHibernate, see here.) Getting ready Download the LinqSpecs library from http://linqspecs.codeplex.com. Copy LinqSpecs.dll from the Downloads folder to your solution's libs folder. Complete the Setting up an NHibernate Repository recipe. How to do it... In Eg.Core.Data and Eg.Core.Data.Impl, add a reference to LinqSpecs.dll. Add these two methods to the IRepository interface. IEnumerable<T> FindAll(Specification<T> specification);T FindOne(Specification<T> specification); Add the following three methods to NHibernateRepository: public IEnumerable<T> FindAll(Specification<T> specification){ var query = GetQuery(specification); return Transact(() => query.ToList());}public T FindOne(Specification<T> specification){ var query = GetQuery(specification); return Transact(() => query.SingleOrDefault());}private IQueryable<T> GetQuery( Specification<T> specification){ return session.Query<T>() .Where(specification.IsSatisfiedBy());} Add the following specification to Eg.Core.Data.Queries: public class MoviesDirectedBy : Specification<Movie>{ private readonly string _director; public MoviesDirectedBy(string director) { _director = director; } public override Expression<Func<Movie, bool>> IsSatisfiedBy() { return m => m.Director == _director; }} Add another specification to Eg.Core.Data.Queries, using the following code: public class MoviesStarring : Specification<Movie>{ private readonly string _actor; public MoviesStarring(string actor) { _actor = actor; } public override Expression<Func<Movie, bool>> IsSatisfiedBy() { return m => m.Actors.Any(a => a.Actor == _actor); }} How it works... The specification pattern allows us to separate the process of selecting objects from the concern of which objects to select. The repository handles selecting objects, while the specification objects are concerned only with the objects that satisfy their requirements. In our specification objects, the IsSatisfiedBy method of the specification objects returns a LINQ expression to determine which objects to select. In the repository, we get an IQueryable from the session, pass this LINQ expression to the Where method, and execute the LINQ query. Only the objects that satisfy the specification will be returned. For a detailed explanation of the specification pattern, check out http://martinfowler.com/apsupp/spec.pdf. There's more... To use our new specifications with the repository, use the following code: var movies = repository.FindAll( new MoviesDirectedBy("Stephen Spielberg")); Specification composition We can also combine specifications to build more complex queries. For example, the following code will find all movies directed by Steven Speilberg starring Harrison Ford: var movies = repository.FindAll( new MoviesDirectedBy("Steven Spielberg") & new MoviesStarring("Harrison Ford")); This may result in expression trees that NHibernate is unable to parse. Be sure to test each combination. Summary In this article we covered: Using LINQ Specifications in the data access layer Further resources on this subject: NHibernate 3.0: Working with the Data Access Layer NHibernate 3.0: Using Named Queries in the Data Access Layer NHibernate 3.0: Using ICriteria and Paged Queries in the data access layer NHibernate 3.0: Testing Using NHibernate Profiler and SQLite Using the Fluent NHibernate Persistence Tester and the Ghostbusters Test
Read more
  • 0
  • 0
  • 3645
article-image-showing-your-google-calendar-your-joomla-site-using-gcalendar
Packt
21 Oct 2010
3 min read
Save for later

Showing your Google calendar on your Joomla! site using GCalendar

Packt
21 Oct 2010
3 min read
To use a Google calendar with GCalendar, you must make the Google Calendar publicly available. To do so, select the Make this calendar public checkbox on the Share this calendar tab on the Settings screen. Getting ready... The GCalendar extension allows you to display your Google calendar inside the Joomla! site. Visit http://g4j.laoneo.net/content/extensions/download/cat_view/20-joomla-15x/21-gcalendar.html and download the latest version of the GCalendar suite. Once downloaded, extract the ZIP package and you will get an installation file for one component, three modules, and two plugins. Install these from the Extensions | Install/Uninstall screen. How to do it... After installation, follow these steps: From the Joomla! administration panel, select Components | GCalendar. This shows you the Google calendar manager screen. Click on the Tools link of the Google calendar manager screen, and then click on the System check link. This checks the system requirements and connectivity with Google and shows you the results. Resolve any issue raised by a system check. Then click on the GCalendars link, followed by clicking on Please login to connect to Google data. You will see the Google authorization page. Click on the Grant access button on the Google accounts page. You will see the list of calendars under Google Calendar. If you are not logged in to Google already, the Google Login page will be shown. Enter the username and password for your Google account (or create one if you don't have an account) and click on the Sign In button. Select the calendars you want to use on your Joomla! site, and click on the Add button in the toolbar. The calendars are added and you will see them in the list. Now select Menus | Main Menu, and click on the New button on the Menu Item Manager: [mainmenu] screen. This will show you the Menu Item: [New] screen. Select Internal Link | GCalendar | GCalendar. It will show the Menu Item: [New] screen, as shown in the following screenshot: Type a Title for the menu, and select Yes in the Published field. From the Parameters (Basic) section, select a calendar, select the default view, the day the week starts on, and then the date format. You can also add text to display before and after the calendar. Then click on the Save button in the toolbar. Preview the site's frontend and click on the menu item. This shows the Google calendar. As you see, you can change the view of the calendar by clicking on any of the view icons shown above the calendar. You can also go to a specific date or month. Summary Google Calendar is gaining popularity. If you are a user of Google Calendar, you already know how flexible it is. In this article, you saw how to display your Google calendar on your Joomla! site. In the next article we will add a Booking System for Events. Further resources on this subject: Adding an Event Calendar to your Joomla! Site using JEvents Joomla! 1.5 Top Extensions: Adding a Booking System for Events Joomla! 1.5 Top Extensions for Using Languages Manually Translating Your Joomla! Site's Content into Your Desired Language
Read more
  • 0
  • 0
  • 7123

article-image-getting-started-windows-installer-xml-wix
Packt
20 Oct 2010
10 min read
Save for later

Getting Started with Windows Installer XML (WiX)

Packt
20 Oct 2010
10 min read
       Introducing Windows Installer XML In this section, we'll dive right in and talk about what WiX is, where to get it, and why you'd want to use it when building an installation package for your software. We'll follow up with a quick description of the WiX tools and the new project types made available in Visual Studio. What is WiX? Although it's the standard technology and has been around for years, creating a Windows Installer, or MSI package, has always been a challenging task. The package is actually a relational database that describes how the various components of an application should be unpacked and copied to the end user's computer. In the past you had two options: You could try to author the database yourself—a path that requires a thorough knowledge of the Windows Installer API. You could buy a commercial product like InstallShield to do it for you. These software products will take care of the details, but you'll forever be dependent on them. There will always be parts of the process that are hidden from you. WiX is relatively new to the scene, offering a route that exists somewhere in the middle. Abstracting away the low-level function calls while still allowing you to write much of the code by hand, WiX is an architecture for building an installer in ways that mere mortals can grasp. Best of all, it's free. As an open source product, it has quickly garnered a wide user base and a dedicated community of developers. Much of this has to do not only with its price tag but also with its simplicity. It can be authored in a simple text editor (such as Notepad) and compiled with the tools provided by WiX. As it's a flavor of XML, it can be read by humans, edited without expensive software, and lends itself to being stored in source control where it can be easily merged and compared. The examples in this article will show how to create a simple installer with WiX using Visual Studio. Is WiX for you? To answer the question "Is WiX for you?" we have to answer "What can WiX do for you?" It's fairly simple to copy files to an end user's computer. If that's all your product needs, then the Windows Installer technology might be overkill. However, there are many benefits to creating an installable package for your customers, some of which might be overlooked. Following is a list of features that you get when you author a Windows Installer package with WiX: All of your executable files can be packaged into one convenient bundle, simplifying deployment. Your software is automatically registered with Add/Remove Programs. Windows takes care of uninstalling all of the components that make up your product when the user chooses to do so. If files for your software are accidentlly removed, they can be replaced by right-clicking on the MSI file and selecting Repair. You can create different versions of your installer and detect which version has been installed. You can create patches to update only specific areas of your application. If something goes wrong while installing your software, the end user's computer can be rolled back to a previous state. You can create Wizard-style dialogs to guide the user through the installation. Many people today simply expect that your installer will have these features. Not having them could be seen as a real deficit. For example, what is a user supposed to do when they want to uninstall your product but can't find it in the Add/Remove Programs list and there isn't an uninstall shortcut? They're likely to remove files haphazardly and wonder why you didn't make things easy for them. Maybe you've already figured that Windows Installer is the way to go, but why WiX? One of my favorite reasons is that it gives you greater control over how things work. You get a much finer level of control over the development process. Commercial software that does this for you also produces an MSI file, but hides the details about how it was done. It's analogous to crafting a web site. You get much more control when you write the HTML yourself as opposed to using WYSIWYG software. Even though WiX gives you more control, it doesn't make things overly complex. You'll find that making a simple installer is very straightforward. For more complex projects, the parts can be split up into multiple XML source files to make it easier to work with. Going further, if your product is made up of multiple products that will be installed together as a suite, you can compile the different chunks into libraries that can be merged together into a single MSI. This allows each team to isolate and manage their part of the installation package. WiX is a stable technology, having been first released to the public in 2004, so you don't have to worry about it disappearing. It's also had a steady progression of version releases. The most current version is updated for Windows Installer 4.5 and the next release will include changes for Windows Installer 5.0, which is the version that comes preinstalled with Windows 7. These are just some of the reasons why you might choose to use WiX. Where can I get it? You can download WiX from the Codeplex site, http://wix.codeplex.com/, which has both stable releases and source code. The current release is version 3.0. Once you've downloaded the WiX installer package, double-click it to install it to your local hard drive. This installs all of the necessary files needed to build WiX projects. You'll also get the WiX SDK documentation and the settings for Visual Studio IntelliSense, highlighting and project templates. Version 3 supports Visual Studio 2005 and Visual Studio 2008, Standard edition or higher. WiX comes with the following tools:   Tool What it does Candle.exe Compiles WiX source files (.wxs) into intermediate object files (.wixobj). Light.exe Links and binds .wixobj files to create final .msi file. Also creates cabinet files and embeds streams in MSI database. Lit.exe Creates WiX libraries (.wixlib) that can be linked together by Light. Dark.exe Decompiles an MSI file into WiX code. Heat.exe Creates a WiX source file that specifies components from various inputs. Melt.exe Converts a "merge module" (.msm) into a component group in a WiX source file. Torch.exe Generates a transform file used to create a software patch. Smoke.exe Runs validation checks on an MSI or MSM file. Pyro.exe Creates an patch file (.msp) from .wixmsp and .wixmst files. WixCop.exe Converts version 2 WiX files to version 3. In order to use some of the functionality in WiX, you may need to download a more recent version of Windows Installer. You can check your current version by viewing the help file for msiexec.exe, which is the Windows Installer service. Go to your Start Menu and select Run, type cmd and then type msiexec /? at the prompt. This should bring up a window like the following: If you'd like to install a newer version of Windows Installer, you can get one from the Microsoft Download Center website. Go to: http://www.microsoft.com/downloads/en/default.aspx Search for Windows Installer. The current version for Windows XP, Vista, Server 2003, and Server 2008 is 4.5. Windows 7 and Windows Server 2008 R2 can support version 5.0. Each new version is backwards compatible and includes the features from earlier editions. Votive The WiX toolset provides files that update Visual Studio to provide new WiX IntelliSense, syntax highlighting, and project templates. Together these features, which are installed for you along with the other WiX tools, are called Votive. You must have Visual Studio 2005 or 2008 (Standard edition or higher). Votive won't work on the Express versions. If you're using Visual Studio 2005, you may need to install an additional component called ProjectAggregator2. Refer to the WiX site for more information: http://wix.sourceforge.net/votive.html After you've installed WiX, you should see a new category of project types in Visual Studio, labeled under the title WiX. To test it out, open Visual Studio and go to File New | Project|. Select the category WiX. There are six new project templates: WiX Project: Creates a Windows Installer package from one or more WiX source files WiX Library Project: Creates a .wixlib library C# Custom Action Project: Creates a .NET custom action in C# WiX Merge Module Project: Creates a merge module C++ Custom Action Project: Creates an unmanaged C++ custom action VB Custom Action Project: Creates a VB.NET custom action Using these templates is certainly easier than creating them on your own with a text editor. To start creating your own MSI installer, select the template WiX Project. This will create a new .wxs (WiX source file) for you to add XML markup to. Once we've added the necessary markup, you'll be able to build the solution by selecting Build Solution from the Build menu or by right-clicking on the project in the Solution Explorer and selecting Build. Visual Studio will take care of calling candle.exe and light.exe to compile and link your project files. If you right-click on your WiX project in the Solution Explorer and select Properties, you'll see several screens where you can tweak the build process. One thing you'll want to do is set the amount of information that you'd like to see when compiling and linking the project and how non-critical messages are treated. Refer to the following screenshot: Here, we're selecting the level of messages that we'd like to see. To see all warnings and messages, set the Warning Level to Pedantic. You can also check the Verbose output checkbox to get even more information. Checking Treat warnings as errors will cause warning messages that normally would not stop the build to be treated as fatal errors. You can also choose to suppress certain warnings. You'll need to know the specific warning message number, though. If you get a build-time warning, you'll see the warning message, but not the number. One way to get it is to open the WiX source code (available at http://wix.codeplex.com/SourceControl/list/changesets) and view the messages.xml file in the Wix solution. Search the file for the warning and from there you'll see its number. Note that you can suppress warnings but not errors. Another feature of WiX is its ability to run validity checks on the MSI package. Windows Installer uses a suite of tests called Internal Consistency Evaluators (ICEs) for this. These checks ensure that the database as a whole makes sense and that the keys on each table join correctly. Through Votive, you can choose to suppress specific ICE tests. Use the Tools Setting page of the project's properties as shown in the following screenshot: In this example, ICE test 102 is being suppressed. You can specify more than one test by separating them with semicolons. To find a full list of ICE tests, go to MSDN's ICE Reference web page at: http://msdn.microsoft.com/en-us/library/aa369206%28VS.85%29.aspx The Tool Settings screen also gives you the ability to add compiler or linker command-line flags. Simply add them to the text boxes at the bottom of the screen.
Read more
  • 0
  • 0
  • 10991
Modal Close icon
Modal Close icon