Model-View-Controller Architecture
Note: This document is out of date and an updated description of the PhpGedView Architecture can be found on the Architecture page.
PhpGedView attempts to follow the Model-View-Controller (MVC) architecture. The goal of an MVC architecture is to separate the data model, the business logic, and the user interface from each other. This means that you don't have business logic in the presentation or your data model and that your presentation can operate completely independent of the underlying data model.
Contents
Presentation (HTML, CSS, JavaScript, PDF) | View | |
HTML Generation | ||
Privacy Filters | Controller | |
PhpGedView Functions | ||
Record Cache | Model | |
Index Files | PEAR SQL Database | |
GEDCOM 5.5 |
The data model is built up around the GEDCOM 5.5 specification. The controller consists of an API written in PHP that allows access to the data model, privacy filtering, and generation of the user interface (UI). The UI delivered in the view layer is sent to the browser as HTML, CSS, and JavaScript.
Data Model
The foundation of the data model is the GEDCOM 5.5 specification. Diagrams of the GEDOCM 5.5 data model can be seen at:
- http://homepages.rootsweb.com/~pmcbride/gedcom/55model1.gif
- http://homepages.rootsweb.com/~pmcbride/gedcom/55model2.gif
The GEDCOM specification defines several records such as INDI, FAM, and SOUR which reside at level 0 in the file. These level 0 records are parsed from the Gedcom file into PHP array structures. These array structures are then indexed in a serialized index file (PhpGedView <= vX.Y.Z), or in SQL database tables (PhpGedView >= vX.Y.Z). One of the fields in these arrays keeps a copy of the original Gedcom record as it was parsed from the file. This allows for the greatest compatibility and ensures that no data is lost during the Gedcom file import. To further improve performance, an in-memory record cache layer is used to reduce the number of database queries. In fact, the record cache is simply the unserialized version of the index files. So in index mode, everything is running on the cache, while in SQL database mode, the cache is built-up as the scripts run.
The SQL database model is composed of five main tables: pgv_individuals, pgv_families, pgv_sources, pgv_other, and pgv_users. The pgv_individual table holds information for level 0 INDI records. The pgv_families table holds information about level 0 FAM Gedcom records. The pgv_sources table stores information parsed from level 0 SOUR records and the pgv_other table catches all other level 0 records (eg. NOTE, REPO, and OBJE) that are not stored in the other tables. The pgv_users table contains all of the information about PGV users and is not parsed from the Gedcom file.
Controller
The controller layer provides an API through which you can access the data from the Gedcom. A JavaDoc style reference of this API can be found online at http://www.phpgedview.net/devdocs/api/.
Before any data is sent to the UI, it must first pass through privacy checks. These privacy checks determine what the user at the UI can access based on privacy settings established by the site administrator.
View
The User Interface is sent out to a client browser in rich dynamic HTML. One of the goals of the PhpGedView project is to try and give the user more information on the screen at a time, so that they can get at more data without losing their current context and without many clicks.
We make the UI even more interesting through CSS which allows themes to be defined. Through the themes, site administrators can completely change the look and feel of the site without modifying the code.
User Levels
The following table show the different user levels in the PGV system and what they have access to:
User Level | Description |
---|---|
Public visitor | This is a public visitor that has not authenticated by entering a username and password. Default privacy settings do not give them access to the data of living people. They cannot edit data. |
User | This is an authenticated user. They will have access to the MyGedView portal and can view private data depending on privacy settings. |
Editor | This is an authenticated user who has been given editing privileges. They will be able to edit anything that they can see. Their changes will still need to be accepted by a user with higher access privileges. |
Acceptor | This is an authenticated user who has edit privileges, but who can also accept or undo changes into the database. |
Gedcom Admin | This is a user who can accept changes and also administer Gedcom configuration and privacy settings. |
Site Admin | This user can do and see anything on any Gedcom in the site and can create new users. |
Editing
There are currently two methods of online editing. The first is through HTML forms at the UI layer. The second is through Web Services at the control layer. Any changes to the data are made at the bottom GEDCOM layer of the architecture stack in the actual Gedcom file. They remain at this level until they are reviewed and accepted by another user. When changes are accepted they bubble up into the database and index file layers.
To Merge in with rest of article
PGV is a document centric architecture. The documents are GEDCOM records. The only reason we need a DB at all is so that we can quickly lookup and search for the GEDCOM records. So our objects are representations of GEDCOM records, not of the DB.
The PGV architecture consists of a stack of layers. Each layer should communicate with the layers "near" it. The application layers (from lowest to highest) are: 1. GEDCOM 2. DB 3. CACHE 4. PRIVACY 5. OBJECTS 6. HTML GENERATION
1. GEDCOM layer is the lowest level and all data is stored in the GEDCOM format.
2. The DB Layer provides a fast convenient way to index the GEDCOM and look up the records. It breaks them up into level 0 records and indexes various portions of them. Originally we didn't have a DB layer. In fact the very first version of PGV only had the levels 1, 4, and 6 and worked directly with the GEDCOM file. For performance on large files we added the DB and originally had an "index" mode which was able to look up the GEDCOM records from PHP indexes. Index mode was eventually dropped because it doesn't scale and it doesn't allow for the complicated searching that we do now. Index mode also didn't move well into allowing online editing. The DB layer functions are encapsulated in the functions_db.php file.
3. The CACHE layer provides an in memory cache of records that are pulled from the database. This reduces the number of calls to the DB. (The DB is the greatest bottleneck). The cache is stored in global variables such as $indilist, $famlist, $sourcelist, etc. The find_* methods in functions_db.php first check the cache before going to the DB.
4. The PRIVACY layer provides the API to make sure that the user has sufficient privileges to view/edit the data. This api is provided by the functions_privacy.php file. There has been much debate over the position of this layer in the stack. In the future it will probably be moved down between the DB and CACHE layers. It is here because user's wanted to be able to see statistical information of how many records are hidden.
5. The OBJECT layer provides convenience methods for working with GEDCOM. It also automatically privatizes the data. So when you create a new Person you give it a GEDCOM document:
//-- lookup the person's record from the cache or the DB $indirec = find_person_record("I1"); //-- create an instance of Person object from the record $person = new Person($indirec);
Now we also don't want to be creating Person objects all of the time, so we also store them in the cache. To access them from the cache or create them we have implemented a factory pattern using the static getInstance() methods on the various classes:
$person = Person::getInstance("I1");
Person class extends a more generic GedcomRecord class. So you can ask it for an object of any level 0 GEDCOM record and it will return an instance of the appropriate class for that type.
$repo = GedcomRecord::getInstance("R1"); $person = GedcomRecord::getInstance("I1"); $source = GedcomRecord::getInstance("S1"); // etc.
6. HTML/Presenation Generation. All other pages should operate at this level and work with the OBJECT level just below it. Some pages may go down to level 2 for searching or other DB related stuff. Now there is a *LOT* of legacy code which works with the APIs at the lower layers. They haven't been updated because they work the way they are.