Developer log

Class spunQ_IArchiveHandler
Joyce Visne (2009-03-02): Note that functionality to unpack but not pack rar archives may be available and that there is a php archive "phar" which stores in many archivable forms, but these are probably not compatible with the non-php versions of them, since there is a double extension (e.g., ".phar.zip", ".phar.gz", etc.)

Member spunQ_Logger::getCaller ()
Necdet Can Atesman (2009-01-23): The debug_backtrace() provides lines where a function has been called. But we don't need the function that was called, but the function from which the call was made. So we iterate one more time in the foreach to get that function.

Member spunQ_Logger::getCaller ()
Necdet Can Atesman (2009-01-26): Switched to the new spunQ_Backtrace class.

Class spunQ_Map
Necdet Can Atesman (2009-02-09): Implements the Iterator and ArrayAccess interfaces.

Class spunQ_SelectQuery
Necdet Can Atesman (2009-07-27): How do we select collections? Possible solutions:
  • Forbid selecting collections: This was the approach in the old version. The usage was unconventional, thus not very user-friendly, there were two query types (ObjectRetrieval and CollectionRetrieval) and this solution is too specific to sql databases.
  • Select the id of the collection table: Trivial implementation, but we would need to create new functions for retrieving these values. Furthermore, these values should not have an id outside this package.
  • The only remaining option is to fetch whatever we can. Collections are processed recursively and returned in the correct data type (array/map). The user of the API is free to add transformers to his properties to fetch sub-sets. This will take some effort to implement, but should provide the most intuitive return value. Let's do it.

File BuiltinType.class.php
Necdet Can Atesman (2009-06-29): Removed two more builtin types: byte and char:
  • BYTE is merely an integer with a predefined range [0-255].
  • CHAR is a string with length 1

File db.class.php
Necdet Can Atesman (2009-07-31): Current status of this module:
The select query required our custom query langauge, so development of the database was frozen to generate the language itself and a parser. The parser already has several tests and looks quite OK, although it is very badly documented.
The language itself will be used for the queries in this module, as well as for the form fields in the html module. This will allow providing simple rules to fields (like: This field is disabled, if the value to be displayed is imported from a spreadsheet)
The next few things to do (after the PropertyParser is complete) include:
  • Finish the select query: The select query needs to parse conditions
  • Implement the update query: This should be easy, since all the code for messing with properties is already in the select query.
  • Implement the delete query: Trivial. Just a special update query.
After that, we'll probably need the user interface for graphically managing the database. The functions for creating database tables/columns will need to be adjusted for that. One should be able to give a proper table name, for example, if the module cannot determine a meaningful one. We'll need to decide if implementing change tracking makes sense at this stage.
Martin had found some bugs in the html module, which need to be fixed in the beta-branch.
If all this is done, we can start working on the @todo-items :)

File Form.class.php
Necdet Can Atesman (2009-10-21): A rewrite of this module is due already, let's analyze a bit on that occasion.
What do we need to separate in forms if we want to have the structure of a form completely isolated from its appearance or the data to display.
form file:
  • name
  • fields
    • name
    • validators
template using the form:
  • data to display
  • page to link to (target)
  • buttons + button labels.
How do we access the form in the templates. It should be as simple as possible. Ideally it should use a template. Templates don't work with normal classes; the form class would need to extend spunQ_DataObject - that would be possible, though.

File Form.class.php
Necdet Can Atesman (2010-09-27): The forms are undergoing another rewrite. All previous ideas had been implemented, but several new features had tainted the layout presented above. The next implementation shall not contain any presentational data within the form definition. I guess the primary problem was the wrong motivation for the show() function, which tried to provide a presentation of the form that could be left intact in a productive environment (i.e. in a finished project.) This erroneous assumption has been eliminated this time: that function is mereley there for providing a minimalistic html presentation of the form for PHP-developers this time, which means that forms don't need any presentational data now.
Here are the key ideas for this new version that were gathered during the design meeting:
  • Field::show(): Remove param $cssClasses, add a template name
  • Fields are solely defined by their I/O type (string, integer, …)
  • Form::show(): provides just a working prototype for PHP-Devs
  • form-Files go into a form-Folder
  • forms should be clone()able
  • FieldIterator / FieldGroup
  • Forms keep (and require) their name in a hidden field.
  • Validators need run-time parameters (a user, for example)
  • Validators for multiple fields (ex: password & password2)
  • Rename all *Validation classes to *Validator
  • Validators need Templates
  • Variables for Forms (just as for validators)
  • need Form::updateObject() & Form::createObject()
  • FormValidators:
    • captcha
    • honeyPot
    • notGuest
    • hash
    • accessControlValidator
  • javascript functions for:
    • copying a form
    • reindexing FieldGroupFields on submit
    • encrypting passwords in browser
    • setNewFieldGroupFieldId(fieldDom)

File Form.class.php
Necdet Can Atesman (2010-10-07): Implementation is going well, everything seems to be working out as planned. Implementation is not finished yet.
Currently missing features defined in the previous entry:
  • Validators for multiple fields (ex: password & password2)
  • need Form::updateObject() & Form::createObject()
  • FormValidators
  • javascript functions

File html.class.php
Necdet Can Atesman (2009-05-04): Just read on php.net that IE ignores custom error pages on occasion, if they don't exceed 1kb in size. That's why the padHtmlTo1k() function was introduced.

File html.class.php
Necdet Can Atesman (2009-05-20): Moved many of the functions in this class to a separate entity: The HttpResponse

File html.class.php
Necdet Can Atesman (2009-09-09): We need to move this whole html folder into the modules folder of spunQ.

File html.class.php
Necdet Can Atesman (2009-09-14): This package seems to be quite stable. Now on to the optimizations:
  • 304 header: If the same user requests a page that wasn't changed since the last time he requested it, a HTTP 304 should be returned. This is merely for saving bandwith, the whole page needs to be generated nonetheless.
  • Expires header: An Expires: header should prevent the browser from re-requesting certain files. We need a URL-transformer.
  • Page file caching: We really don't need to parse all page files on each request.
  • Image bundling: We need a function showImgTag() that is capable of bundling multiple small images into one.
  • spunQ state: There needs to be a development and a deployment mode. The deployment mode can omit several checks. We'll implement the following for now:
    • Omit checking of cache file state. The cache file holding type definitions can always be regarded as up-to-date. We need to store the type definitions in the spunQ cache for that.
    • Cache DB schema.

File html.class.php
Necdet Can Atesman (2009-10-07): Good news: All of the above have been implemented already :)

File HttpBrowser.class.php
Necdet Can Atesman (2009-06-03): This module provide very basic functions and will be expanded when the need arises.

File HttpEntryPoint.class.php
Necdet Can Atesman (2009-11-17): Page handling is quite lame currently. The issues are:
  • we're currently re-parsing all page files upon each request in development mode, there is really no need for that. Furthermore,
  • the decision algorithm for determining the page file responsible for a request is horrible.
So the steps we need to take are the following:
  • Caching: Should be obvious. Now that we have a nice function for recursively retrieving files with given suffixes, along with the most recently modified file's time stamp, we can cache very effectively.
  • Collision checking: We're checking for url collisions on each request (i.e. the url /contact can be served by user.page and contact.page.) This can be reduced to a single, but complicated check beforing caching the results.
  • Page determination: We're wasting too much time on deciding which URL maps to which page file. By demanding regular expressions from a page file, we could speed this process up a lot.
But before implementing this, we should re-design URL template syntax. This is a list of dynamic values, that can be present in URLs:
  • Basic types: int, string, real, array<string>, etc. The regular expression for these can be easily generated. It would be really interesting if we could tie these values to members directly, so we can do even more checks (This string value is a username, implying that it must not be longer than X characters.)
  • User types: We already had this. Can either be the id of an object or another property. Example: /user/14 or /user/soulmerge. If the values available here are really dynamic, it might lead to serious problems with collisions. Eventually a clever attacker will find a way to work around pre-defined urls or innocent users will not have a personal page because another, static page is overriding his user name (like contact.)
The issue here is that we can't check dynamic values for collisions too well. Either we forbid defining URL templates that have the slightest chance of collision - unfortunately, this is not possible: we really need this feature - or we make checks throughout the application. The biggest problem is that the developer needs to take these collisions into account in the code. He mustn't allow users with the name contact to be generated, and every project needs to define such constraints on certain members (username mustn't be contact or details or about, etc.) This could even be somehow manageable, the real issue is that it should be possible to define conflicting URL templates with different user types. A CMS, for example, might define its "static" pages dynamically, while allowing access to other dynamic pages (like user profiles.)
For the CMS, we generally need a new type of pattern, the catch-all token that accepts any string, including slashes - the manager of the CMS should be able to define his URLs as he wishes. This, again, leads to difficulties: This catch-all url would need to have least priority, since everything else needs to be processed before that. On the other hand, the "static" pages created by the manager should have higher priority than user pages, for example. This could be solved by assigning a high priority to the catch-all URL and deciding if we can server the request by querying the database first. This would mean, we'd have to do additional checks beside the regular expression to decide which entry point will serve a request. Other than that, the regular expression might be dynamically generated and cached to skip the additional checks (i.e. as ^(about|details|contact).) This would be ok for a small amount of pages, but making that check for 20k users might be a bit difficult. Some immediately performed tests show that using regular expressions is pointless, as the overhead of querying the (indexed) database column is still much less than compiling and axecuting PCRE patterns containing the database values. So the idea of controlling pages with regular expressions only looks like a dead end.
The only remaining problem is an esthetic one: How do we define which page file overrides which others?
  • We could require them to provide a priority value.
  • A page file could state which other page files it overrides or deferres to.
  • An external resource (configuration file) could contain the relevance of all entry points.

File HttpEntryPoint.class.php
Necdet Can Atesman (2009-11-18): Having looked at the routing of other frameworks (which basically use regular expressions and/or map class and function names), I decided that this issue can be solved without developer interaction to great parts. A set of rules can be applied safely:
  • All static route names precede dynamic ones, i.e. /about matches before /$username.
  • String-variables match slashes, too. In order for this to work, URLs with multiple string values must precede those with less values. So, /objects/$tag/$page must be evaluated before /objects/$tag.
  • In case of collisions, we can assume that the id always precedes other members, if this solves the conflict. /user/14 should always match the user with id 14, not the one with that name.
  • To be able to express multiple values in the same URL, we can make use of the already-defined property paths. A slug would then become /blog/$post.slug/$post.id, whereas independant variables would have different names like /images/tagged/$tag1/$tag2.
  • If a member in the URL is not marked as @unique, the variable must be an array. /images/named/$image.name will expect $image to be an array of images if the member $name is not unique.
Anything that still is ambiguous after these rules (like /user/$user.username and /user/$user.lastname) must be solved manually. If the conflict is within a single file, it can be assumed that rules defined first override later ones.

File include.php
Necdet Can Atesman (2009-02-18): About performance: including all files one by one was causing performance issues. Creating a single include file containing all the source of the spunQ framework and using several optimization algorithms on that file (stripping comments, reducing unnecessary whitespace, etc.) improved the startup a bit. It went down from 0.032s on my box to 0.024s. That's quite ok.
Running the framework in debug/deployment mode could be reasonable, where the second mode could make use of such caching. The only real drawback is that the include file cannot react to modifications of the source files of the framework.

File include.php
Necdet Can Atesman (2009-03-11): Reading the lines above I just noticed that reacting to file changes is possible anyway. The code for that would be in a seperate file, so it could be decided which include method to use.

File include.php
Necdet Can Atesman (2009-04-07): Did some more tests and had these results:
  • No modification (include file including all other files):
    • inclusion: ~48 ms
    • initialization: ~27 ms
    • connecting to db: ~3 ms
    • Retrieving an object: ~21 ms
    • Total execution time: ~100 ms
  • Compressed include file (All source code in single file, removed as much white space as possible, removed all unneeded doc comments, removed all normal comments):
    • inclusion: ~25 ms
    • initialization: ~27 ms
    • connecting to db: ~3 ms
    • Retrieving an object: ~21 ms
    • Total execution time: ~77 ms
  • Removing all calls to debug() and vdebug():
    • inclusion: ~25 ms
    • initialization: ~27 ms
    • connecting to db: ~3 ms
    • Retrieving an object: ~8 ms
    • Total execution time: ~64 ms
This concludes the benchmarking for now. I would say that the inclusion time is acceptable for now - even if it can be cut in half. The debug/deployment modes are still an option but not needed yet. What is more important is that execution time went up almost by a factor of 3, as the debug calls were removed. This is obviously not an option during development - as well as the first few months the framework is in use.
Furthermore, the analysis of the startup showed that the bottleneck is still the recursive inclusion of source files - although this had been adjusted a bit with caching.
Summary of expensive operations (in order of magnitude):
  • Initializing framework (50%)
    • Including modules source code recursively in Type::init() (30%)
    • other stuff done in Type::_init() (10%)
    • RemotePeerConnection::_init() (5%)
    • Language::_init() (3%)
  • Including framework source code (20%)
  • Database interaction (13%)
  • Creating DataObjects (13%)
Many of these problems could be solved by the imminent redesign of certain parts.

File include.php
Necdet Can Atesman (2009-06-25): Just a note: Many of the metrics in the devlogs of this file are deprecated. The new include system (using the file names) has improved performance, for example. The inclusion of the files are done centrally, the core files have a direct mapping, etc, etc.

File Language.class.php
Necdet Can Atesman (2009-05-12): Where do we store translation information by default? The language must somehow be retrieved from the L10n object in the current environment (see today's devlogs of spunQ class). If the database module is really going to be part of the core (today's devlogs of spunQ_IPeerDescription), all translations/L10ns can be stored in the db somewhere, this would mean that all translations are to be found there (even the ones from templates), which would have the positive side effect that all translations can be found on a single page.
After a small brainstorming with Martin, we found out that this would make it impossible to copy-paste the gui of a module. This again means that wording files are to be stored in the same folder as their templates, as defined previously.
The next question is: Where do we put our localization definitions? These are part of the whole application, not part of a single template. The answer depends on the data to be stored. Let's start the Locale class and see.

File Language.class.php
Necdet Can Atesman (2009-06-09): There are two distinct sources for locales. One is the database containing spunQ.language.Locale objects, and the other one is the file system containing translation files. The latter have already been implemented and unfortunately are mutually exclusive with those in the database: The language translations need to be loaded before the database during initialization of the framework. It will also lead to inconsistencies due to StorableObjects that don't have id's, etc, so we're leaving the Language class as-is and introducing the new spunQ_Locale class independently.

File Language.class.php
Necdet Can Atesman (2009-11-09): Having the two locales is very confusing. The single problem is that the system language needs to be initialized at a point where we don't have a database connection. So we'll add a getSystemLocale() function to spunQ_Locale that doesn't connect to the database to eliminate this problem.

File Logger.class.php
Necdet Can Atesman (2009-02-23): The official log levels have been defined. The starting point were the 8 log levels defined in CISCO or the unix syslog, debug, info, notice, warning, error, critical error, alert and emergency. After the adjustments for the framework, we came up with six log levels:
  • vebose debug: Anything the developer can think of: variable dumps, logs in loops. This level is very verbose, so it should only be activated for the function that is being developed.
  • debug: Informative information for the devlopers. This level can be enabled when working on something in the same package. It should provide useful information about what the application currently does.
  • info: Informative information for the users of the application. Only the most important debug information should be here. This level can be enabled to keep track of how the whole application is currently performing. These messages can always be enabled without making the logs unreadable.
  • warning: A recoverable error has occured or the application is making an assumption about something. A typical example would be a communication breakdown within the network.
  • error: An unrecoverable error has occured, the current process terminates unsuccessfully, but the application in itself doesn't have to be affected. A remote peer sent an invalid packet, the connection to the database failed, etc.
  • critical: The application fails entirely. A required file could not be read, the temporary directory is not readable/writable, etc.

File Logger.class.php
Necdet Can Atesman (2009-02-26): Another description of the lower log levels:
  • verbose debug: Information that would help debug a function. The inner workings of the function must be known to understand the logs.
  • debug: Information that would help debug a class. The inner workings of the class must be known to understand the logs. Knowledge of the inner workings of each function is not necessary.
  • info: Someone reading logs on this level must know what the class does, without the need to know how it is done.

File Logger.class.php
Necdet Can Atesman (2009-07-31): This class needs to be partially rewritten. This task has been assigned to Joyce. This entry contains the specification for the new Logger. There are several sub-tasks to be accomplished for the rewrite to be complete:
  • Refactor the file: The helper class LoggerRule needs to be extracted into its own file. First, because it is the last helper class that is left in the framework, second, because it will be passed outside the class in the future. This has already been implemented, but not committed to version control.
  • Convert to singleton: The Logger class currently acts as a container for several global functions (it behaves somewhat like a module, not a class.) This behaviour is to be changed by applying the singleton pattern. This, too, has been implemented, but not committed.
  • Rule juggling: The function addRule() needs to accept a spunQ_LoggerRule object. Another function called removeRule() needs to implement rule elimination from the logging facility. @Joyce: You will need to alter your addRule() implementation again for this task. It should take just 1 parameter of type spunQ_LoggerRule.
  • Path types: The logger currently only browses source folders as defined in the configuration file to determine the path of a log event. This leads to confusion if a log event is triggered in a template file, for example (the file is not in any of the source folders, but in another folder, which does have an alias within the framework, like 'spunQ.backend'.) This alias->folder association cannot be hard-coded into the logger for other modules to keep the ability to add/remove modules. So the Logger must provide some means of registering classes providing this information to them. The function implementing this idea shall be called registerEventSource(), which takes 3 parameters:
    • $name: Name of the source, which will be prefixed to the actual path, separated by a colon. Example: 'spunQ.backend.main' will become 'css:spunQ.backend.main', if it belonged to a registered event source with the name 'css'.
    • $aliasToFolder: An array mapping aliases to folder names. Example: array('spunQ.backend' => spunQ_Folder::get('/home/spunQ/backend'))
    • $extensions: This array parameter is optional and contains all file extensions that come from this source. Any file that ends with any of the strings in the array is considered to be coming from this source. This is needed to distinguish event sources with different names pointing to the same directories (which is the case with css and js, for example.)
  • Adjusting users of the logger: Since these modifications are incompatible to the current API, we'll need to adjust the rest of the world:
    • spunQ::init() needs to register its own event source. Yes, that's right, the Logger doesn't recognize any file without being initialized. This should be done as early as possible in the spunQ initialization. The event source for the modules should be called 'src'.
    • html::init() needs to register its event sources ('css', 'js', 'tpl'). (NOTE: Can will do this part.)
  • Creating a fallback: If no event source rule matches, the logger currently uses the absolute path of the file that triggered the log event, where all path separators are replaced by periods. This just looks awful, so we'll need an optional configuration value that tells the logger what string can be removed from the beginning of uncaught log event files. If the configuration value holds '/home/spunQ/', all log events without an event source will be translated to hold a relative path in that folder, i.e. '/home/spunQ/src/core/logger/Logger.class.php' will become 'src/core/logger/Logger.class.php', which will further be translated to 'src.core.logger.Logger', as specified in the current version of the logger. Furthermore, any log events which do not match a predefined event source should be prefixed by '<undefined>:', which gives us the final path '<undefined>:src.core.logger.Logger'. @Joyce: Martin should be able to help you with configuration values.

File Logger.class.php
Joyce Visne (2009-08-25): A problem arises in removing the ending in the last situation above. We have defined endings (similar to class.php in the above example) in the registered event sources. If we have a source which has not been registered, then we need to keep the ending (e.g., 'class.php') in some form, but we need to keep a string which conforms to the standard form we have otherwise defined. Our solution was to add this information to the <undefined> tag (e.g., '<undefined/class.php>:src.core.logger.Logger').

File init/Module.class.php
Necdet Can Atesman (2009-10-21): Modules folders:
  • src: Contains source code (type and class files)
  • lib: Contains external dependencies - other PHP projects, jar files, etc.
  • page: Contains page declarations
  • tpl: tpl files
  • test: tests
  • doc: additional documentation
issues:
  • How do we prefix page urls?
  • How do we override templates?
  • When do we load language file?
  • What other features do they provide?
additional features:
  • drupal allows managing the backend menu.

File type/Module.class.php
Necdet Can Atesman (2009-01-15): Is it possible that an existing Module receives additionals subModules/types/functions after being instantiated (i.e. through a remote connection)? Guess we'll hav to live with the fact that users may add arbitrary functions/types to our modules.

File type/Module.class.php
Necdet Can Atesman (2009-01-15): There was an interesting idea about friend classes in PHP somewhere. They are not supported per se, but can be emulated by analyzing the stack using the function debug_backtrace(). This could be an option.

File type/Module.class.php
Necdet Can Atesman (2009-02-05): The name 'function' is a bit misleading, we'll call it service from now on.

File type/Module.class.php
Necdet Can Atesman (2009-02-12): The whole framework is undergoing heavy refactoring since yesterday. I noticed that the whole class is quite pointless and is not being used anywhere except by Type. All functions provided by this class will be moved to Type, so there is no reason to keep this one (The file itself will remain in the repository for now to keep the devlogs).

File PhpZipHandler.class.php
Joyce Visne (2009-03-20): The php ZipArchive::extractTo() function will overwrite destination files with the same name! If we want to catch and warn about this, this must be added here! (The shell zip function --at least in Linux/Unix-- does this.)

File PhpZipHandler.class.php
Necdet Can Atesman (2009-04-07): The above issue has been resolved by throwing an Exception in spunQ_ZipFile if the target folder is not empty.

File ReflectionTypeParser.class.php
Necdet Can Atesman (2009-01-29): This Type parser will possibly be replaced by a doxygen variant in the future.

File ReflectionTypeParser.class.php
Necdet Can Atesman (2009-06-30): Altered findClassName() to use the tokenizer extension to build find the class name. The old method using guessing was providing wrong class names for types in the same package belonging to different sub-packages. Noticed this in the tests, where test.library.Country had the same class name as test.dataObject.Country.

File spunQ.class.php
Necdet Can Atesman (2009-01-21): Broke down the initialization of the framework into two phases. First, all existing files are sourced and types are generated. After that, all objects are updated and their _type members are set to the right value. This was done since it was not possible to create a DataObject object without creating a type object, which in turn is a DataObject.

File spunQ.class.php
Necdet Can Atesman (2009-05-12): I guess we need a globally accessible environment variable containing a context for the current operations. This would include the currently active user (if that is going to be a part of the core), the chosen language, the chosen theme for templates, etc. Introducing such a global variable bares the risk of abusing it for storing arbitrary global values only relevant to the application, not to the whole framework. Examples of what not to put there:
  • User's registration step: This should be part of the user itself
  • State of a money transaction: This must be accessible through other means, like currentUser()->getLastTransaction() or similar - which evaluates to the same as the first point
  • Visited pages, breadcrumbs and the like: Such information is most probably only relevant to one specific presentation of a specific use case. If the application logic depends on these values, they should be stored along with other properties of the user.
One way of eliminating this abuse would be to hard-code the contents of the environment:
  • Current user: If great parts of the application take the current user into account, he should be promoted to a core functionality. After that, the value can be stored in the evnironment.
  • Errors and warnings encountered during the processing: Although the logger could take care of local warnings, anomalies occuring in remote peers could be accumulated at this point.
  • i18n: Objects with multiple translations would cause two distinct database queries (one for retrieving the translation key, one for the translation itself) if the translation to be used was not available during the retrieval of its members. Other handy values are date formats, float formats, etc. This could be a simple reference to a global resource, too. The ID could be an rfc4646 language string.

File spunQ.class.php
Necdet Can Atesman (2009-05-12): As discussed in the previous devlog, adding user management to the core functions could be required, this devlog entry will try to elaborate on that idea.
First of all the single important reason against user management in the core module: Loss of flexibility. The number of interdependencies within the module grows as more features are added to it, so we will see, if a user management is really required as a core function - maybe it can be implemented as an independent module.
On to the reasons we might need it as an inherent part of spunQ:
  • Enhanced security: Services can check a user's priviliges on critical operations. The database for example could map the spunQ user's group to database credentials to use for queries. Restricting usage of certain members to distinct user groups could be possible. Mapping spunQ groups to system users could resolve security issues.
  • Logging (who created/deleted/updated this entry?)
That's it, but I think that it is enough to require user management at the lowest possible level.

File spunQ.class.php
Necdet Can Atesman (2009-05-12): Another candidate for core types is the translatable string. Now that we can define a locale in the environment, we should consider implementing localized strings at the lowest possible level. Since localization is part of the specification, it has to be implemented somewhere, and implementing it somewhere else would require us to retrieve the translation key first and perform the lookup afterwards, which again would mean that such an operation would require two database queries. Let's continue this discussion in spunQ_Language.

File spunQ.class.php
Necdet Can Atesman (2009-05-14): More core type considerations:
  • Remote objects (We need them explicitly)
  • Multilocale strings

File StorableObject.type.php
Necdet Can Atesman (2009-08-25): I think the field deleted is not necessary here. To be correct, it would need to be given explicitly in every query (as opposed to adding an implicit condition to every statement, as we're doing now.)
It would be better to add the transparent column '_deleted' to the database that cannot be seen outside the mysql package, for example.
Then we'd need to add the function delete() to StorableObject.

File StorableObject.type.php
Necdet Can Atesman (2009-10-02): The above idea has been implemented.

File StorableObject.type.php
Necdet Can Atesman (2009-10-29): Reverse mappings are being implemented today. Such injected members will be stored in a separate container called $injectedMembers.

File StorableObject.type.php
Necdet Can Atesman (2010-02-16): Reverse mappings have been implemented today.

File Template.class.php
Necdet Can Atesman (2009-05-18): The current environment object had been removed from the spunQ.

File Type.type.php
Necdet Can Atesman (2009-01-27): Versioning DataObjects actually does not make any sense, since a minor version change would imply that a member has been added, while a major version change would indicate that the objects are completely incompatible. ICE has a nice feature called factes, which solves versioning quite well. To put their idea short: every object exports multiple interfaces which allow different peers to access the object in various ways. But since we're not handling any remote objects, we could regard each member as a facet. This consideration leads us to the idea that members are compared by the equality of their name/type combination. This would allow us to arbitrarily change our local definition of the type. As long as the remote peer has the same members as we do, both versions are compatible. To allow even more compatibility, we could allow marking certain members as optional. This would come in handy with function objects, too.

File Type.type.php
Joyce Visne (2009-01-23): There is no difference between double and float results (in php they are the same)

File Type.type.php
Necdet Can Atesman (2009-02-10): Current issues:
  • What do we do with Type windows?
    • Do we keep the name?
    • TypeWindows have TypeWindows as members/parents, so they're kept in parallel to the actual types. Is there a nicer way to implement this?
  • How do we handle service types?
    • Does a service type really need its own class? Wouldn't it be enough to generate additional information out of the already-processed documentation?
  • How do we handle array types? Anything here applies to map types as well.
    • Do we really need the abstract type 'array'?
    • Do we really need some abstract form of inheritance here?
    • isArray() should be refactored, using strings is pointless here.
  • How do we proceed with shared objects?
    • Are they accessed as usual? Do they have any implicit limitations?

File Type.type.php
Necdet Can Atesman (2009-02-12): Let's go through those questions above one by one:
  • TypeWindow: A TypeWindow is actually the same as a type. The only real difference is that TypeWindows are declared using other Types, as opposed to the generation out of source code. Furthermore, they don't have a class name to be used to create an instance, since they use the predefined classes. The question comes down to "Are TypeWindows visible outside their package?". This question is discussed along Shared objects, below.- Services: Services should actually be regarded as standard types with additional data attached to them. Furthermore they must provide a method to retreive the result for the actual computation (an abstract function getResult() or something similar). The additional data that is required by more static languages is confined to the exception types that could be thrown and the type of the return value. The latter can be solved by requiring a member called "result" and demanding a documentation - including its type - for it. The exceptions thrown could as well be stored in the documentation of the class, or in the documentation of the very same result member.
  • Arrays/Maps: These types should have their own classes, since they provide more information than the other types. This idea actually lead me to the solution that there are multiple types that can be distinguished:
    • BuiltinType (int, real, string, ...)
      • ArrayType
      • MapType
    • UserType
  • Shared objects: The questions aboved arised from the confusion regarding TypeWindows: The actual question should have been, whether TypeWindows should ever leave the network package. The following implementation could be possible:
    • interface IType
    • class LocalType implements IType
    • class RemoteType implements IType
    • class SharedType implements IType
    SharedType would be our TypeWindow in the above example. A simpler solution would be to ban TypeWindows to the network package and live outside of that with Type only. This looks like the more durable solution, since the networking layer should be absolutely transparent to the programmer which could mean that the peer providing the service could be a different one than the one used during the first call, which would again result in a new TypeWindow. The Type hierarchy outlined above is not too bad either, but the resulting classes should not be used outside of their target packages.
    Update: After finishing the analysis about Arrays and Maps above, I noticed that the only type that can be received by other peers are UserTypes. So this is the only class that we need subtypes for.

File Type.type.php
Necdet Can Atesman (2009-02-16): Thoughts on caching: If caching is intended to dump the variable $_cache into a file and possibly restore it through a call to unserialize(), it is not possible to cache individual modules. It's an all-or-nothing approach, since PHP can't store references to unserialized values. This means that if one tries to store the type User, which is has the DataObject as its parent, both type objects would be serialized - User and DataObject. If both types are from different packages, this would mean, there would be two type objects describing the DataObject class.
Another approach would be to replace links to types of other modules with their string representations. This would render the whole initialization extremely complicated, though. So we'll stick to this very conservative caching method.

File Type.type.php
Necdet Can Atesman (2009-02-16): Regarding speed: A brief profiling of the code revealed that the bottleneck of the initialization is the automatic scanning of the source folders. Another caching mechanism is introduced that will write the list of source files into an include file and include that one instead of scanning the whole directory each time.

File Type.type.php
Necdet Can Atesman (2009-06-03): Annotating basic types with options gives great control on the user types. The name of a user can be restricted to a certain length, within PHP itself. The number of entries in an array can be defined, allowing one to guarantee that an array will never have more than x entries. This features makes some of the types obsolete, actually. There is no need for a short type, since it is merely a signed integer with a given range. These types of optimizations are not needed anymore nowadays (especially not if one is working in PHP). The other unnecessary value is one of the floating-point types (float/double). Having one floating-point value (called real, for example) should be perfectly enough. The last numeric type - byte - could be needed for convenience, though, so it will stay a discrete type in the framework.
Type declarations could have some of these attributes attached, like the available range for example - merely for convenience, since we cannot express everything in a single type description. One example could be array<int(0,10)>(1,4): An array containing 1-4 integers, each of which being between 0 and 10. But adding the assertion that the integers should all be odd, between (0 and 3) or (10 and 13) and should be divisible by 7 doesn't need to be expressed that way :)

File Type.type.php
Necdet Can Atesman (2009-07-15): Removed the charset option today. Comparing using different character sets in mysql does not make use of any indexes and it is not necessary outside the database.

File Type.type.php
Necdet Can Atesman (2009-08-20): Reading through the devlogs today I had an idea about the type cache: Currently, the type cache stores all references of all types, thus all types, including the singleton instances of the builtin types. The momentary workaround involves returning all singletons as reference and replacing the value with the unserialized one.
Another approach might be to replace these references with strings before serializing the types. This would make it more robust, but could as well lead to some performance loss, since we would need to iterate over all user types and replace their member types with objects when unserializing (and that part should actually be as fast as possible).

Generated on Fri Jul 1 11:12:38 2011 for spunQ3 by  doxygen 1.5.9