Before getting too deep into individual features, take a look at Why earthli WebCore? It describes the philosophy behind this framework. Once you've got that under your belt, read on to see just how much the WebCore offers.
When you program with the WebCore, the different stages of preparing a web page are clearly defined and well-supported.
- First, you decide which data you want to show in a page. Use searches, lists or directly query to request your objects from the application.
- The request is filtered through the current login, which has certain permissions in the given context.
- Lists of objects and individual objects are rendered, each object using icons and formatting to return a consistent, compliant page to the browser.
Pretty much any marginally-interactive website needs to address the concept of logging in. As soon as you have stuff that some people can do and others can't, you're going to need a solid user concept.
The WebCore provides a pretty deep implementation of users, including auto-registered anonymous users. All users, registered and anonymous, are treated equally; anonymous users are uniquely identified by IP address and can be restricted with permissions just like normal users.
The user itself has a bunch of properties like name, home page, etc. already implemented. And, last but certainly not least, a pretty smooth avatar implementation lets your users customize their online appearance. WebCore applications can easily use this icon in different places to make users stand out.
Users can be shared across applications and handled with the same login; an application can also define its own users. See sharing for more information.
Logging in, logging out, applying user and content permissions: it's all taken care of for you. See security for more information about how it works.
Almost any website you can think of is separated into sections. If you're listing movies and movie reviews, you might break them up into genre. Photo albums are broken up by year or destination. Some areas might be private or allowed only for certain users.
Any earthli WebCore application can have as many folders as you like, nested as deeply as you like. While you can define keywords and categories for free searching and association, it's still nice to be able to apply at least a rudimentary hierarchy to your data.
Folders are also the framework in which you define your application's security. Subfolders automatically inherit permissions from their parent folder.
As soon as you start to mix online content with online users, you've got opinions. You can't have a community unless your users can talk to each other. The earthli WebCore provides a general solution to comments that integrate into any application.
Comments can be nested (so they answer each other) and presented in pages (so you don't have to serve enormous pages). There are a bunch of view options, like threaded or flat viewing.
As with comments, its not long before you realize that text isn't the only type of content your site has. You need a generic way to get binary content onto your site and keep it organized. If you've got an article with 3 pictures, it would be nice if those pictures were deleted if you deleted the article. Storage space isn't free, right?
Attachments can be made for any object in a WebCore application: folders, users, comments, even your custom application objects. Image attachments are automatically detected and stored with a thumbnail (if you want one); other file types get a type-specific icon. Since zip-file handling is integrated, a zip attachment displays its file contents when viewed.
Once you've attached a file, you can easily show it in your text as a thumbnail or full image. Check out paths to find out more.
"Who changed what when?"
When you're a publisher (and on the web, we're all publishers!), you've got to be concerned with auditing or tracking the history of the stuff you've got on your website. It's important to a user to know when an item was created and when it was last updated. When you're running a site, you want to know who made changes to it.
Your site users are usually just concerned with when an item was last updated, but you may want to know everything that's ever happened to it. Has it ever been deleted? Why was it brought back? When?
The earthli WebCore uses 'auditable' objects, which track their entire histories as a series of 'actions' that occurred to a website object, like an article, a comment, a folder or even a user. Pretty much everything is trackable.
You've got all of your stuff in a database and users are making comments and stories all the time. Now they want to find something. Well, you've got a nice folder hierarchy to help them out, right? The earthli WebCore offers much more powerful searching than that.
- All objects in a WebCore application (your own objects, comments, users, etc.) can be searched.
- Constrain and sort by almost any field in an object.
- Full-text search on any combination of text fields.
- A powerful API makes adding new fields a snap. User-friendly forms and search results are automatically generated for you.
The WebCore's search engine runs on top of the database layer. It takes care of displaying the search form and applying search parameters to the query.
You can save searches and retrieve their results again later. So, you can do cool things like "find all recipes made by Bob in the last week" and always be able to check out what Bob's been up to.
You can also leave parameters open when you save the search, and let the WebCore fill it in from the context. So, if you're on Alice's home page and you run the search from above, you'd see all the recipes Alice made in the last week.
The WebCore uses searches to define your default interface, showing the lists of different types of objects available. Users can redefine and add to these to customize the interface to suit them. Searches work hand-in-hand with lists to help you get the most out of a WebCore application.
With searches you ask the database a question. The database returns a list of objects as an answer. Now you want to do something with them: print, email, delete, etc. You can select one of more items from a search result and act on it directly, but what if one search result can't contain everything you want?
That's where lists come in. You can take any or all of the objects from a search result and move them to a list. Then you can run another search and add some more objects to that list. You can delete objects from a list. When your list is ready, print it, email it or just leave it. It'll be there when you come back.
Searches define views on the database, but lists just store a fixed set of objects that isn't necessarily based on a single query.
- You can make a list of stories you'd like to read and delete them from the list as you finish them.
- You can make a list of your all-time favorite funny comments or your favorite pictures.
- You can make lists of anything, just like you can search anything, so you can make a list of users to be your "buddy list".
- You can do a lot with the objects in a list: print, delete, purge, email, even edit them! You can gather a whole bunch of objects and edit them all in one big batch: a huge time-saver!
- Use temporary lists as you browse and search your way through an application. When you're done with your research, delete the list.
- Unlike searches, List contents don't change unless you change them.
You don't need to do anything special to make lists work with your own application objects. If your objects are searchable, they're listable.
People will be using your application from everywhere. If your application objects have a lot of text, users may not always be ready to publish their work right away. You want to be able to save to the server, but keep other users away from it until you're done.
The WebCore offers just that with drafts. If you define an object as draftable, the form for it is automatically generated with a 'Save as draft' button. Come back to the site later, search for your draft and keep working. When you're ready, you publish it.
Making it work
The WebCore gathers disparate PHP variables and functions that are really useful when building web pages into a sensible object-oriented API.
- The environment provides url information, redirecting, exception handling, basic date/time services and more.
- The page handles rendering and global configuration.
- Applications manage your data objects and create global objects like text-formatters, mailers and more.
- A global profiler lets you time different parts of your code to see what's slowing you down.
There are other classes and functions for file-handling, zip files and different exception handlers. When an error occurs, all associated information is automatically gathered and can be sent by the user via email.
You can't escape it. As soon as you have an interactive system, you've got to consider who gets to do what. Even if you don't spend a second actually thinking about it, you've implicitly decided that everyone gets to do everything.
Most web sites probably don't want that.
Everything you do in an earthli WebCore application is based on a logged-in-user (see users for more information). Even if no actual user has logged in, the system assumes the rights of an anonymous user. The user in the application answers the question "Is this operation allowed here?"
If you look more carefully at that question, you see it's got two important parts: operation and location ('here').
- Operations are 'view', 'edit', 'delete' and so on -- the usual suspects.
- Each object type (comments, folders, users, etc.) can be controlled individually.
- Objects can also add their own specialized privileges to this list. (e.g. Projects defines 'Can assign' for job objects.)
- Folders define the permissions that are used for all objects in that folder. They inherit permissions from their parent by default.
You will, of course, still need a super-user who's rights can't be limited by folder permissions. That's where user permissions come in. User permissions override folder permissions by either always granting or always denying a privilege. They also define privileges that are not folder-dependent (like login or offline privileges).
- You can make your super-user by defining a user that grants all rights.
- You can automatically ban a user by denying all rights.
- 'default' rights for registered and anonymous users are set using the same system.
You can also define user groups to apply folder permissions to lists of users. That way, you say that your folder allows certain privileges for the group 'Editors' and others for the group 'Moderators'. You can control who gets to do what by changing membership in those groups.
Dynamic websites are built with databases: static content is so 90's. MySQL has a lot of name recognition and the WebCore has run on it since its earliest days. But, this doesn't mean that it can only run on MySQL.
All references to PHP's data functions are made through a database abstraction layer. All SQL is produced by query objects which map your requests onto the underlying database. When you work with a WebCore application, you rarely, if ever, have to write even a snippet of SQL. This centralization makes your application much more mobile and flexible. If you want to try out PostGreSQL, you don't have to modify a thing: just switch your database type.
With the WebCore, you don't set up SQL and execute loops and call database-dependent functions. You work only with objects and list of objects returned by queries.
The database section shows how your application reads data without you writing any SQL. But, your application defines objects that need to store data.
There's another abstract layer here that makes creating and updating objects a piece of cake. If you define or extend objects, you just give the name of the field, its type and its value, and the WebCore takes care of marshalling and validating it into the database.
Again, no more SQL for you. Just call 'store' and you're done.
To make sure that content is always findable and restorable, WebCore applications can use a 'trash-can'. Users can delete objects and they'll disappear from their interface, but users with 'view hidden' privileges can still see them and restore them or purge them from the database for good.
- Insulate your users against lost data
- Since nothing's ever deleted right away, an admin can recover data for a user.
- Objects can be explictly purged from the database. You can, of course, set up your application to directly purge all objects, skipping the trash can completely.
Hidden objects also lets moderators or admins hide portions of the application while it is under maintenance and smoothly show it again when its ready. Drafts are implemented on top of this system.
Once you've got a bunch of content on your site, you need to be careful: it gets pretty fragile and you're not allowed to move it around too much. Links will break and you'll have missing images and styles popping up in the most unpleasant places.
The WebCore lets you define locations, which you use throughout your code as aliases to resources you need. That way, you just update the alias and move the files and your website keeps happily purring along. You can even move stuff to other servers without updating any of your content.
A standard application defines areas for icons, styles and scripts. There are even some special ones that are object-dependent, like 'attachment' and 'thumbnail'. You can add your own locations and reference them just like the built-in ones.
See paths for more information on referring to resources.
If you've done any web development, you know that forms take up the lion's share of your coding and testing time. You've got so much to consider: display, validation, value-conversion, error-handling: the list goes on and on.
The WebCore defines an extensive forms library. Forms define a list of fields and indicate how each field is loaded from and stored to the object it represents. Form rendering is separated into another layer, so your application can redefine the look of all forms from a central location.
Almost all conceivable control implementations are supported and tested: from all of the standard text fields and drop-downs to truly elegant and simple support for grouped controls like lists of radio buttons or checkboxes.
All you have to do for your form is:
- Decide which fields it has. You can set the name, type, required status, description and much more.
- Map values from your data representation (usually an object) to your fields.
- Map values from the submitted form back to your data.
- Draw the form with the WebCore's abstract rendering API.
- Marshalling data from the request object into the right form is handled automatically
It's so much easier and better-looking to use a form object, you'll never hand-code a form again.
Uploading is tightly integrated with the forms library, but it's so hard, it merits its own section. It's hard because of several reasons.
- The WebCore shields you from varying browser uploading behavior.
- PHP also behaves differently depending on the version.
- You're moving files around on the server -- the WebCore takes care of error-handling for you.
- The WebCore integrates uploading into the forms library, offering only-upload-once support, which transparently stores uploaded files even if the form didn't validate, so users only have to upload once.
Once your site is online and you've got users, you probably want to be able to let them know when you've updated your site. This opens up a whole new can of worms, though.
- Whom do you notify? You need a list of subscribers and they need to be able to say when and what you send. Spam's a bit of a touchy subject these days.
- When do you notify? What does it mean to update a site? There are changes you probably don't want to notify subscribers of.
Again, the earthli WebCore provides quite a bit of support in this department. The notion of subscribers is pretty deeply rooted in the library and based on the auditing system described in history.
When you make a change to a website object, you've got the option of modifying the history action that gets created for that change: you can modify the title (email subject) and decide whether messages even get sent at all. Publishing scripts can be set up to troll the database at regular intervals, sending out messages for unprocessed actions.
As a user, you've got a load of options to control how much you get and when.
- You can set your schedule (immediately, hourly, daily, etc.) and organize your notifications to be grouped into bulk emails.
- You can, of course, select HTML or plain text format.
- From the content side, you can subscribe to entire folders or to individual objects. You can even subscribe to a user so you're informed whenever that user does something (our stalking feature).
Since WebCore applications are built on the same base, they can easily share large parts of the database to integrate them even more tightly.
- Users are shared by default, allowing your users to browse multiple applications on your site with a single login.
- You can also elect to share user permissions, giving users the same non-content-specific permissions in all applications.
- Even tighter integration shares folders, giving all your applications the same structure. Tighter still shares folder permissions too; if users can create content in a folder in one application, they can do so in all the others. Administer all of your applications at once!
- Global resources like themes and icons are also shared, by default.
How do you deploy one of these applications to your own website?
The WebCore automatically searches for configuration files in a 'plugins' folder outside of the WebCore code folder. You can grab the default initialization files, customize them and save them here. There are a lot of options to help you get the application seamlessly integrated into your website (you can even make your own skin).
On top of that, some applications, like Projects, let you customize right from a web interface.
The WebCore is a development platform. How do you develop in it?
So you want to customize an existing application: add a field to an object or just change the way a list looks. All objects: data objects, lists, renderers, mailers etc. are created centrally. If you want the WebCore to create a different object for a particular type, say 'Comment renderer', you just register your own class name and file location and the application creates and uses that one instead.
All you do is make sure that your object supports the right interface (which you can easily do by inheriting from the class you're replacing) and it will integrate seamlessly. The objects used in the WebCore and its applications are extensively documented.
Existing WebCore applications use the same exact mechanism to 'customize' a default application, so you can develop your own applications in the same way. All modifications, from the smallest tweaks to the biggest overhauls, are supported with the same approach.
Store your personal class definitions in the 'plugins' folder and you won't overwrite anything when you upgrade the WebCore or the base application files.
Making it look good
All earthli WebCore template pages are defined using a strict set of CSS styles, which are easy to override to provide your own color and style for your application. You can make a bunch of them and let users pick the one they want to use. There are several to get you started in the default package.
You can even redefine the header/footer layout by defining your own template and placing specially-named elements in your layout so the WebCore can put the page together the way you want it. Tell your style to use your template instead of the default one and you're all set. This is perfect for adapting a WebCore application to an existing web-site's style. There are a couple of layouters included in your basic package too.
If you want to go further and change the layout of the content of pages, like the way a list is displayed or the information displayed with an object, you'll have to head on over to customization.
The WebCore provides a powerful formatting language that looks like HTML, but isn't. The formatting tags and attributes mirror HTML for familiarity, but are actually transformed to the target content by the munger (named after the Apple toolbox function). This HTML-independent language can just as well be transformed to other formats as well. A Plain text formatter is used to generate nicely-formatted emails.
Treating all user-entered text in this way has a lot of benefits.
- It guarantees compliant HTML, so your pages don't get bent out of shape by invalid user content.
- In fact, the forms library integrates a validator that keeps users from even entering invalid content. It reports all errors with line and character position to help them pinpoint their errors.
- Lines that should be single-line (like titles) simply don't generate block content and the validator flags non-single-line tags like lists.
- As mentioned above, it's much easier to export other formats.
To see what the tag format looks like, check out the text formatting manual.
The earthli WebCore provides a lot of display classes to render your application objects into a page. There are trees, grids, calendars, toolbars and more.
- Grids work directly with queries, displaying the desired rows and columns and paginating automatically for large lists.
- Toolbars, or buttons, are login-sensitive, automatically showing only buttons for users the logged-in user is allowed to do.
- Trees render as DHTML or static, depending on the browser.
- Print-preview pages are automatically generated. There are even print options that are specific to the type of object being printed (Projects makes heavy use of this to make very flexible changelists).
Every object also has an individual renderer, which shows all information for that object. These renderers are used everywhere when showing objects, so no more hunting through dozens of web pages with search/replace to get everything up-to-date.
This is very cool because the object's home page uses the HTML output to show the object as HTML, print-preview usually uses the HTML renderer too and emails use the HTML or plain text rendering to show the object. And, as you'll see in customization, you can hook in your own renderer for an object and the WebCore will automatically use your renderer everywhere.
Most websites have at least a feature or two that doesn't work on all browsers. For these things, you'd like to know who's asking for a page and send back the best possible version for it.
The WebCore's browser detection is a home-grown algorithm and lets you work with capabilities instead of browser types. You don't need to know which browsers support which features, you just ask if a feature is supported and the WebCore takes care of the rest.
So it's simple for your pages to ask if a browser handles DHTML. The WebCore takes care of figuring out which browser you're actually using (and the algorithm really is quite good at ignoring spoofing) and knowing which browsers can do what.
A lot of websites post pictures in all sorts of formats. PHP can read the files, figure out how big they are, even resize and reformat them. The WebCore makes all of this functionality accessible and transparent with an image object. You can use it to generate thumbnails of files (JPG or PNG) you've uploaded (like the attachments do), so you don't have that 1280x1024 game screenshot in the middle of your news page. The WebCore applications use the image library to seamlessly offer robust attachments; Albums uses it to make uploading pictures a snap.
WebCore images can also automatically extract EXIF information, so all of the information stored by your digital camera doesn't go lost when you add a picture to your site. The WebCore even extracts some EXIF information on older versions of PHP that don't have native EXIF support.
Icons and Avatars
You're probably thinking "icons ... big deal".
Take a look at any desktop application; there are icons everywhere. You want to make sure you can use icons for labels, buttons and just about everywhere. You don't really want to refer to a specific image file; what if you want to change it at some point?
The WebCore defines 'sets' of icons, which can be coordinated with themes to provide a consistent look to your application. You can use paths to refer to these icon resources and make sure you get the right one.
The WebCore comes with two sets of icons: a set of GIFs and a set of PNGs. You can add your own to these sets or make a whole new one. There is a whole framework for adding new avatar icons via browser and objects like folders and users have a predefined field for their icon.
As mentioned in skinning, earthli templates use strict CSS for all rendering and display. That makes printing a snap and all renderers and objects are "print-aware" and optimize their rendering for print formats. Print lists or items or just a single one. Making your own objects print nicely is a breeze using the library support.
In addition to publishing by email, earthli applications can be published as RSS feeds. Folder and application home pages have default feeds which are recognized by most modern browsers (shows up as a blue RSS icon in the address bar). Making new ones is easy, as there are base classes for rendering the feed itself and for rendering WebCore objects in a feed. The default implementation simply uses the existing HTML renderers, so any object you can display in a page can be published in an RSS feed instantly. All earthli applications have excellent-looking RSS feeds without any extra work whatsoever.
It's likely that an attachment or an upload is a zip file. The WebCore provides an easy-to-use callback-based API that makes displaying, extracting and working with archives easy. Even if PHP doesn't have the necessary extraction functions, the WebCore uses a third-party library to read the zip file. Your software doesn't change depending on PHP version - it neither knows nor cares which version is used.
Attachments use the zip libraries to display the list of files inside an uploaded archive. Albums uses them to provide multi-image batch uploading. The batch job extracts each file from the archive, generates a thumbnail using the image library and create a picture entry in the database.
A product like the earthli WebCore is never finished. There are always things that could be done better or cool features that could be added. Here are some that we're aware of:
- Multi-language support in all templates and text.
- Add a web-interface for administration. Configuration is still done only through config files written in PHP. A user-friendly admin interface to set the myriad available parameters would be helpful.
- Quizzes and voting supported in an application. As soon as you want quizzes, you have to ask "who gets to make/edit quizzes? ... can users comment on quizzes? " and you realize you need to define these in an application context too. Here's where you can use sharing to tightly integrate with another application.
- Categories/keywords for objects for improved searching.
- A moderation system for rating objects/comments/etc. A rudimentary vote gathering system would be good for a start. Almost any application could use a "what did you think about this item?" feature. Moderation-specific permissions could be easily integrated.
- User tracking -- who's online, how much you've been online, when you were last online. What's new since you last browsed here. Also a pretty low-level feature that any application should be able to snap in.
- User permissions assignable by group. Groups assignable to groups.
As you can see, once you start thinking about library vs. applications, you can think of a lot of features that aren't really application-specific. Isn't it much cooler to implement integrated moderation when you know it's going to be used in any application instead of just one?