Demo Application

→ This pages introduces 'PHPasteBin', a small PHP4 application I wrote some time ago to see if it would be possible to create a layered application in PHP4.
→ You can download the demo application from http://dev.budts.be/releases/boron/PHPasteBin.20050729.7z (SHA-1; 2.3Mb). To keep installation as simple as possible, I included all required libs (hence the size). To install:

  • extract (by example by using 7-zip or winrar)
  • execute database.sql in mysql (this will create a database named “phpastebin”)
  • open “system/conf.php” and modify CONF_DB_DSN to include your username and password (mysql:USERNAME:PASSWORD@localhost/phpastebin) To make it even easier, I also included an already-generated version of the API-docs (build/doc/) and a code-coverage report (build/coverage/). IMPORTANT: Because the architecture is similar to the one I proposed in ”Basic Architecture of Boron” I'll only hightlight the differences here and also document what could be improved in the demo app. =====Different naming===== In Basic Architecture of Boron I renamed some concepts, because I found them more appropriate: ^ PHPasteBin ^ Boron ^ Note ^ | EntityHelpers | EntityManagers | they do more than just 'help' | | Components | services | i'm not entirely sure if “component” is a good name, so i currently used “services”) | =====Study the code===== To study the code, I advise starting with “index.php”. This page, first, loads the 10 most recent Pastes and, then, uses a template to show those Pastes and a form - to create a new template. To use the terms from the Basic Architecture: index.php (in this case, “the website”) is a client of the core. The complete core is located in the “system”-directory.
    In index.php you will find one call to the core: <code php> PasteComponent::getPastes(10) </code> Here, you see that the “Paste-service” is used to request the last 10 Pastes. The PasteComponent somehow gets the Pastes (From the client's viewpoint we are not interested in how this happens; we just want the Pastes.) and returns an array, containing Pastes (thus, entities of the type, Paste). With these Pastes, we are only allowed to use the data (Basically, this means only the use of GETers and SETers are allowed). You can see this in the template (tpl/recent_pastes.tpl.php) where only GETers are used from the Paste-entities. Now, we can go one step further:
    In the PasteComponent (system/components/PasteComponent.php) you'll see that it simply delegates the request to the PasteHelper (responsible for working with more than one paste and also for loading, persisting and deleting pastes.). The reason this component exists is to allow the use of transactions in the future and to represent “one unit of work”. By example: Sometimes a new paste will have to be created and something else will have to be updated. Both things should either fail together or succeed together (a la Transactions). By using the component both things will be done in one method - inside a database-transaction. The following step is the PasteHelper (system/helpers/PasteHelper).
    You'll see that this class inherits from HelperBase (which contains the persistency-layer). PasteHelper calls a method to load a collection. Notice that it uses a partial SQL-query as the argument. It is only a part of the query because the other parts of the query are written by the persistency-layer. So PasteHelper only has to offer the SQL-part in which it is really interested (which can vary for every request), how to limit the query and how to order it (and I just see that I forgot to implement the limit… whoops). The rest of the “magic” happens in HelperBase. In short, it verifies if it finds PersistencyInfo for the entity-type which is processed (in this case Paste). It does this by calling “getPersistencyInfo()” on the entity, which returns an array, describing it's table and columns. Then, the persistency-layer executes the query and processes the result. While processing the result, it reads every record in the result-set, creates a new object of the entity-type and sets all the properties to the values for that object. =====Testing===== I have tried to test as much code as possible (but some more tests would be needed). Notice that both the 'system' and the 'test'-directories have the same hierarchy. To run the tests, use Ant, as discussed in Development Tools.
    IMPORTANT: Due to a bug in the configuration you'll have to modify CONF_LIBS (in system/conf.php) from time to time. Sometimes it should be 'libs/', sometimes, '../libs/' and sometimes '../../libs'. If you get errors, try modifying it. (sorry) =====Development tools===== For ease of use almost everything is done using Ant. the build-file has the following targets: * test: this runs the tests with a text-based UI * test-report: runs the tests and creates html-output * coverage: runs all the test and generates a code-coverage report. * doc: this generates phpDocumentor API-docs. (note: you'll need darcs for this to work, since the doc-target depends on the changelog-target, which uses darcs to generate a changelog. * ctags: generates a ctags file, useful if you are using the Tags-plugin for jEdit by example. * dev-doc: generates doc, test-report and coverage. Important: You'll have to tell Ant where it can find the following binaries: php, darcs, ctags. If they are in your PATH it will work; otherwise, you'll have to create a build.properties to tell Ant where to find those files. An example build.properties is already included. =====Possible Improvement/Refactorings===== PHPasteBin was designed with php4 in mind; so, using new PHP5 language features, like 'private'-methods, is the next step. One necessary code refactoring is the “extract class” on HelperBase - to extract all the Persistency-logic; then, there would be a real separated (and more reusable) persistency-layer, that would be used by the HelperBase. =====Other notes===== You'll notice the “using()”-function. This is a function which tries to imitate the 'import'/'using' keywords from Java/.net . Instead of simply always including all available classes or loading a class everytime you need it, you just 'state' what class the current class will use. The using()-function then includes the needed classes. (In the names of the classes, you'll see dots (”.”), instead of slashes (”/”). I did this to give the illusion of namespaces) PHP4 doesn't support exceptions. To handle exceptions and error I created my own exception-classes and instead of “throwing” them, I simply return them. It's less useful than real exceptions but still it's better then an errorcode which doesn't give any more information. :!: This is part Nucleus 5 plans; click here to read more about the project.
nucleus5/demo_app.txt · Last modified: 2006/07/05 13:03 (external edit)
 
Except where otherwise noted, content on this wiki is licensed under the following license: CC Attribution-Noncommercial-Share Alike 3.0 Unported
Recent changes RSS feed Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki