 |
|
Monday, August 28. 2006
We've rolled out SyntaxCMS on a handful of low cost, shared hosting providers and found our initial experiences more frustrating than they had to be. Of course, we expected a number of difficulties, primarliy because of the directory structure we assume. By default syntax cms expects:
+ Your Site Directory
- private
- public (document root)
The public folder contains all the files that Apache serves to the public, while the private directory contains all our code and configuration settings safely outside of the document root. On most cheap ISPs, you can only put you files in your web root and that requires a lot of tinkering.
Another limitation is not being able to add files to your host's PEAR directory. Since SyntaxCMS depends on Pear_Cache, this is problematic if your ISP doesn't provide it. To make life easier, we've added a private/lib/ext/PEAR directory that is added automatically to your include_path. If you need to include a pear library, extract the archive into that directory and SyntaxCMS will find it.
This is currently in the latest CVS versions but a new release should be just around the corner.
Friday, June 9. 2006
We've added a lot of very convenient methods to various SyntaxCMS classes to automate repetitive tasks and overall make common tasks easier. Here are 8 tips for using the API.
1) Get a URL to a Record's detail page.
Perfect for a module or template where you're working with muliple content types. It also makes it possible to rename a module without having to update templates.
<a href="<?= f1cms::getDetailUrl($Record) ?>"><?= $Record->getName() ?></a>
2) Get a section's absolute URL on the site
Sections, which are essentialy a site's pages, also have a method to return a public URL.
<a href="<?= $Section->getNavPath() ?>"><?= $Section->getName() ?></a>
3) Get all of a section's ancestors as a collection object
In some cases you might want to know all the ancestors for your section, maybe for building a breadcrumb.
$ancestor = $Section->getAncestorCollection()
4) Tell the general module to use a custom listitem template
The general module is very flexible in how it can retrieve lists of content. It has some built in automatic logic for determining what template to use to display a particular record in a list. You can override this behavior by passing the list capability a parameter named listitem.
echo f1cms::callModule('general', 'list', array('listitem' => 'summary'))
This will have the general module look for a file named listitem-summary.tpl first in the template director of the module that handles a datatype. If that module does not exist or have that file, general will look for the template file in its own template directory.
5) obfuscate and email string
Useful to hide email from some spam harvesting bots.
echo StxUtilities::obfuscate_asci('omerida@example.com');
6) Test if a record contains a field with a given name
In cases where you are working with collections of mixed content types, you may not know if a given record has a particular field. You can test for this with the following code:
if ($Record->has_field('upload'))
{
/ do something /
}
7) Test if a record is approved
Usually, a Collection object will only return approved records. If you need to test this at the record level, you can do:
if ( true == $Record->is_approved())
{
/ do something /
}
Test if the current user is authorized to see a record
Again, a Collection object will only return records that the current user can read. If you need to test this, use:
if ( true == $Record->is_authorized())
{
/ do something /
}
Monday, September 26. 2005
I've just checked into CVS updated section handling code that verifies if a user (or the public user 'Everybody') has been given read privileges to a requested section. Remember, sections are what make up the page-based content management part of Syntax CMS. The ability to specify the privileges has been in the content administration application for quite a while now, but the request handling code wasn't enforcing it at all. Now, when you request a section, SyntaxCMS will first check if the user has 'read' privileges to that section and all of its ancestors.
This means you can create a section called 'Member Only' and then create children sections beneath it. By just restricting access to the 'Member Only' section, you're also effectively restricting content to all of its descendants (not just its immediate children).
I also fixed a very broken getAncestorsCollection method in the SectionNavigator class and eliminated a lot of php notices as well.
Tuesday, July 19. 2005
There are additional sections, articles, and links to documentation in the developers' support area of the SyntaxCMS.org site.
Among the new goodies:
Thursday, June 16. 2005
When trying to install SyntaxCMS on a new Debian server, I ran into a weird problem. Everything worked except SyntaxCMS's file-handling script. It works by taking a request, such as:
/files/123_file_mydoc.doc
and using a mod_rewrite rule to turn it into:
files.php?file=123_file_mydoc.doc.
files.php then checks to see if the current user (or anybody if the user isn't logged in) has permission to read that file, and then passes it through with the proper MIME types.
Well, it was churning and giving me a zero-length file. So I commented out that rewrite rule to verify that the rewrite was being performed. I expected a 404 error once I commented out the rule. However, it worked the same way!
So I commented out the other rules to make sure they were working properly. Sure enough, 404 errors were generated for most pages. So I went ahead and moved the entire .htaccess file out of the public root.
It still rewrote the /files/123_file_mydoc.doc request!
After much floundering and checking, Oscar and I figured out that mod_negotiation was on and that MultiViews was set.
Here's the relevant quote from the mod_negotiation docs:
A MultiViews search (enabled by the MultiViews Options), where the server does an implicit filename pattern match, and choose from amongst the results.
So it was taking any request in the form of /foo/whatever and mapping it to any file named foo.*, no matter the file extension. So foo.php would work, as would foo.txt.
The fix was to disable the MultiViews directive from Apache's configuration file and restart Apache--bingo! Everything worked.
So beware MultiViews when using fancy rewrite rules in your applications, as well as when you install SyntaxCMS.
Tuesday, May 10. 2005
There has been some bruhaha over Google Web Accelerator and web applications. Google Web Accelerator works by "prefetching" pages in the background so clicking on a link results in a faster page load. Unfortunately, it blindly follows any link on the page, regardless of whether you've put a JavaScript confirmation on it.
The practical upshot of this is that links to delete items may be followed, leading to simply viewing a list of items causing them to disappear.
Fortunately, Google Web Accelerator uses the Mozilla Foundation's X-moz: prefetch HTTP header. So it can be detected and stopped with the following two lines in an .htaccess file:
RewriteCond %{X-moz} ^prefetch
RewriteRule ^.* - [F]
We have implemented this fix for the administration application in SyntaxCMS, so you can grab the latest copy of /syntax-cms/src/public/admin/.htaccess from the SyntaxCMS CVS repository on Tigris or, if you've modified that file, simply put the above two lines below RewriteEngine On in /public/admin/.htaccess on your installation.
Friday, April 22. 2005
I'll be documenting how to setup a Syntax CMS site and use it to build a simple blogging site. This post will focus on getting the framework up and running and future posts will be about setting up content types (data objects) to publish a blog. Some of this post is duplicative of the INSTALL intructions bundled with Syntax and I will not be going through all the details of setting everything up. Instead, I'll be trying to provide a practical look at what it takes to install and troubleshoot a new instance.
Web and Database setup
Of course, you'll need to have PHP4, Mysql and a webserver already setup before you proceed. We'll assume you have setup your apache server or a vrtual host that serves requests from directory called /var/www/htdocs/my_blog/public. You should also have downloaded the latest . Syntax CMS release 1.2.1.Extract the archive into the directory /var/www/htdocs/my_blog. Note that it will create both a private/ and public/ directory under my_blog. Syntax CMS is setup to keep configuration files, PHP libraries and classes, and any other code out of your document root. The public directory contains anything your site visitors will need to view your site - images, css, javascript, as well as the web-based Content Adminsitration application and developer tools.
The next step is to create our database and a user. From the mysql command line:
create database myblog;
grant all on myblog.* to myblogdb@localhost identified by 'secret';
You'll need to update the database connection parameters in private/config/db.conf.php to match the database name, host, user, and password used above. Next, from your my_blog directory, dump the database file to create and populate the necessary database tables:
mysql myblog < dump.sql
Testing and Troubleshooting
If you're web server and database are setup correctly, you can check your syntax settings by requesting the /admin/testing URL in your browser. You should see a page similar to the screenshot below. This script tests various components of the framework to make sure they are configured correctly. Pay attention to the boxes in red, they'll indicate something that is not set correctly and provide the fix for them.

Once you've quashed any warnings you have from the testing script, you're ready to start customizing Syntax CMS to behave like a blog. There is enough out-of-the-box functionality that at this point you could use it to serve up a basic website after customizing the section, header, and footer templates to match the look you want, but that is not the point of this overview.
In our next part, we'll look at Content Types - what they are and how to define them.
Friday, April 1. 2005
We came across an odd mod_rewrite behavior today that is worth documenting. Some of the code uses the environment variables SCRIPT_URI and SCRIPT_URL, which are supposed to be registerd by mod_rewrite. However, if you use the "RewriteEngine on" directive in .htaccess to enable rewrites but don't have a similar line in your apache configuration or vhost configuration block, rewrites will work but those variables will not be set.
Tuesday, January 18. 2005
Here is a quick example of how the Syntax API accelerates development by making it easy to search for a collection of objects. In this case, I had an array with some country info, including the name. I needed to see if any documents were tagged to that country:
Step one, figure out the numeric id of the country:
pxdb_import( 'content.output.pxdb_picktable' );
$country_picktable = new pxdb_picktable( 'country' );
$pick_id = $country_picktable->lookup_value( $country['name'] );
Step two, use a Document Collection to find matching records:
$documents = new DocumentCollection();
$documents->findByCountries( $pick_id );
$documents->execute();
If you use dbasis to generate the code for your abstract collection object, it will create methods for filtering/finding by any relationship or pick field in your object.
Monday, December 20. 2004
Has this ever happened to you?
You're coding along, and you need to reference a module. You remember you called it 'calendar'. You know modules are references with URLs that begin with /content/, so you put in a link to /content/calendar/, and you test the link only to find it barf horribly.
Oh, that's right, you forgot to specify a default path in path_rewrites.conf.php...so mnemonically named, how could you forget!
Well, fret no more, dear developer. I too was annoyed by this and did something about it. Now you just need to have a new module attribute that you add when you're configuring the module in user.conf.php, where all the other module-related config stuff lives. Just add the line Modules::setAttribute('my_module_name', 'default_action', 'my_default_action'); and you're good to go.
But what if, in the heat of development, you forget? Well, since the code generators and example modules in Syntax CMS tend to assume that your default action is going to be called "list" anyway, it will try that. If that fails, you'll get the same old ugly screen you would have gotten otherwise.
The other good news is that there is now one less configuration file for you to worry about, as path_rewrites.conf.php is now history.
All this will be included in the 1.2.0 release, and is in CVS now.
Monday, December 13. 2004
Syntax CMS has a flexible records privileges system in place that controls what users and groups can read and/or write a particular data record. As long as you use the pxdb_collections class to retrieve data, the appropriate sql and checks are added automatically. Through the Access Privileges tab in the Admin application, you can manually specify what groups can have read and/or write access to a specific record. For example, you could have a 'registered users' group that will have access to embargoed content on your site. To make sure only a logged in user in that group can see that record, you'd remove read access for the 'Everyone' group, and give read access to the 'registered users' group. On the front-end, Syntax CMS would take care of showing that record, in any collection or on a detail page, only to the 'registered users' group.
But, Syntax also assigns privileges automagically by default whenever a new record is entered. Here is how:
- The 'Everyone' group gets read privileges.
- If a user is logged in, then that user gets both read/write privileges to a record.
- The group id specified in the pxdb preference 'gid_admin' gets read/write privileges
This works fine most of the time. It'd be nice to have more control, maybe at the content type level, over if Everyone gets read access automatically or to specify additional groups that should get default read/write access to a content types's records.
Update: currently, only the admin group can see the 'Access Privileges' tab in the Admin application. Maybe we need to add a 'set_privileges' datatype priv and use that to test if a group can modify the record privileges.
To clarify, Syntax CMS has two levels of privileges. Datatype privs define what a group can do (add|edit|delete|approve) with a specific type of content ( ie documents|links|events). Record privs define what a user or group can do with a specific instance of a content type ( the link to Google, the Annual Conference event, and so on ).
Friday, December 10. 2004
With our new release of Syntax CMS, we've re-rolled the API-level documentation for developers:
Class and method-level documentation for the data access API that Syntax CMS uses. These are the classes that developers creating new modules or modifying template behavior will deal with most of the time.
The DocumentInfo class helps you provide automatically-generated download info based on file types and sizes. It works for local and remote files.
The DynTables class automates the creation of sortable tables from Syntax CMS data. It's a presentation-level helper class.
Class and method-level documentation of the CMS-level Syntax CMS classes. They provide functionality for handling requests (both browser and internal), creating site nativation, and many other functions.
Tuesday, December 7. 2004
If you're looking to install an Apache, MySql, PHP environment ( on either Linux or Windows ), instead of doing it piecemeal you may be better off grabing a middleware stack like XAMPP from Apache Friends. An article at IBM, details how to install such a middleware stack. This is perfect for folks who may not have the expertise, time, and or patience to install all these components seperately and, inevitably, troubleshoot the bugs that arise. Instead, you can concentrate on building your website instead of building your infrastructure. Seen in PHP Magazine.
Thursday, November 4. 2004
I added another out-of-the-box feature into CVS today. It's a module that automatically builds a sitemap based on the sections you create for content. The output is simply unstyle, nested lists inside of a div with an id named, cleverly, "sitemap". You can use CSS selectors to customize the output of the template. You can also write your own display template to tweak the layout to your liking. This will be part of the next release, which should be real-soon-now.
An example of the sitemap module, with a few added bells and whistles.
Tuesday, October 26. 2004
Detail pages display a particular record on a site. If you have datatype specific modules, you might be tempted to have a detail.php capability within it - usually by just copying the detail.php file from the general module. Unless you'll be implementing a lot of custom code on the detail page, say to hook in to a third party shopping cart app, you're probably safer just re-using the general detail script.
Let's assume you have Press Releases to display and have put the related code in modules/press_release. Your user.conf.php file would have at least the following lines to register the module:
// The Abstract Documents Module
Modules::addModule('press_release', 'Press Releases');
Modules::setAttribute('press_release', 'content_label', 'Press Release');
Modules::setAttribute('press_release', 'datatype', array( DATATYPE_DOCUMENT ));
Modules::setAttribute('press_release', 'public_exposure', true);
Moduels::setCapability('press_release', 'list' );
By NOT specifying a detail capability above, Syntax will route requests to /content/press_releases/detail/444 through modules/general/detail.php. This gains you a few things:
- Fetching the record is done using collections, so that record privileges will be checked and enforced. If a record is restricted to a specific group or user, then it will only be displayed to them.
- Will check if the datatype is in the exposed content datatypes list.
- Breadcrumb to the detail page will be automatically built depending on if user's came to the page from a section or another module.
- Less time coding or copying this code and one less file to manage.
Detail.php is smart enough to look for a custom detail.tpl file to use to display the matching record. It will look in the first module that works with the specified datatype. So, in this case it would look for modules/press_release/templates/detail.tpl and use that file if it exists. In your custom template, you have to use the $Record variable to get information out for display.
|
|