<?xml version="1.0" encoding="utf-8" ?>
<?xml-stylesheet href="/templates/default/atom.css" type="text/css" ?>

<feed version="0.3" 
   xmlns="http://purl.org/atom/ns#"
   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
   xmlns:dc="http://purl.org/dc/elements/1.1/"
   xmlns:admin="http://webns.net/mvcb/"
   xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
   xmlns:wfw="http://wellformedweb.org/CommentAPI/">
    <link href="http://cnb.se/rss.php?version=atom0.3" rel="service.feed" title="Anders Hellström" type="application/x.atom+xml" />
    <link href="http://cnb.se/"                        rel="alternate"    title="Anders Hellström" type="text/html" />
    <link href="http://cnb.se/rss.php?version=2.0"     rel="alternate"    title="Anders Hellström" type="application/rss+xml" />
    <title mode="escaped" type="text/html">Anders Hellström</title>
    <tagline mode="escaped" type="text/html">The cnb experience</tagline>
    <id>http://cnb.se/</id>
    <modified>2011-07-29T22:15:53Z</modified>
    <generator url="http://www.s9y.org/" version="1.3.1">Serendipity 1.3.1 - http://www.s9y.org/</generator>
    <dc:language>en</dc:language>
    <info mode="xml" type="text/html">
        <div xmlns="http://www.w3.org/1999/xhtml">You are viewing an ATOM formatted XML site feed. Usually this file is inteded to be viewed in an aggregator or syndication software. If you want to know more about ATOM, please visist <a href="http://atomenabled.org/">Atomenabled.org</a></div>
    </info>

    <entry>
        <link href="http://cnb.se/archives/12-Skatteverkets-smygande-steg-in-i-framtiden.html" rel="alternate" title="Skatteverkets smygande steg in i framtiden" type="text/html" />
        <author>
            <name>Anders Hellstrom</name>
                    </author>
    
        <issued>2011-07-29T22:15:53Z</issued>
        <created>2011-07-29T22:15:53Z</created>
        <modified>2011-07-29T22:15:53Z</modified>
        <wfw:comment>http://cnb.se/wfwcomment.php?cid=12</wfw:comment>
        <slash:comments>2</slash:comments>
        <wfw:commentRss>http://cnb.se/rss.php?version=atom0.3&amp;type=comments&amp;cid=12</wfw:commentRss>
    
        <id>http://cnb.se/archives/12-guid.html</id>
        <title mode="escaped" type="text/html">Skatteverkets smygande steg in i framtiden</title>
        <content type="application/xhtml+xml" xml:base="http://cnb.se/">
            <div xmlns="http://www.w3.org/1999/xhtml">
                Uppsala Linux User Group i sin nuvarande form har funnits ett tag nu - nästa år firar vi vårt 10-årsjubileum. Dock är det först i år som vi har ansökt om ett organisationsnummer hos Skatteverket. Anledningen till att det dröjt så länge är att vi inte haft något större behov av ett organisationsnummer eftersom vi hanterat så lite pengar och alltid haft kassan kontant, och det framförallt är vid ärenden av ekonomisk karaktär som t.ex. bankkontakter eller bidragsansökningar som organisationsnumret blir viktigt för en ideell förening. Juridisk person blir man i Sverige direkt efter att grundandemötet antagit stadgarna utan något krav på registrering. Det har dock inneburit att våra domännamn (ulug.se och ulug.org) har varit registrerade på två enskilda medlemmar istället för på föreningen och när båda två sen en tid tillbaka flyttat ifrån Uppsala kände vi i styrelsen att det var dags att styra upp den delen av verksamheten och skickade in en ansökan till Skatteverket.<br />
<br />
Sedan ett par år tillbaka har vi en policy om att använda elektroniska signaturer på protokoll från styrelsemöten och årsmöten. I praktiken innebär det att vi sparar protokollen som PDF-filer och alla som ska underteckna ett protokoll skapar en frikopplad OpenPGP-signatur med gpg. När vi nu skulle skicka in undertecknade protokoll till Skatteverket så var vi rädda för att vi skulle behöva cirkulera papperskopior på allt och få alla som redan signerat med gpg att även underteckna för hand. Det kan låta som en enkel sak, men i en ideell föreningen där folk kommer och går som dom vill och alla inte alltid deltar vid alla aktiviteter kan det ta flera veckor att få ihop alla signaturer som krävs. Alternativet är att starta en dyr och långsam (om än snabbare) postkedja där en i taget får skriva på och sen skicka vidare till nästa person.<br />
<br />
Istället valde vi att chansa! Vi skrev ut utskriften från gpg --verify för alla signaturer och protokoll och lät samma person som bevittnade övriga handlingar även bevittna den utskriften. Ingen av oss trodde innerst inne att Skatteverket skulle acceptera detta, men vi tyckte det var värt en chansning. Dagarna gick och till slut kom helt oväntat ett registreringsbevis med posten!<br />
<br />
Det var en mycket positiv överraskning och det känns som en stor seger för fri/öppen mjukvara. I praktiken är det också ett erkännande från Skatteverkets sida om att OpenPGP är lika säkert för signering som de x.509-baserade e-leg som finns i Sverige idag.<br />
<br />
Själv så skulle jag nog påstå att OpenPGP, med ett bra web of trust, är mer säkert eftersom det har en helt annan transparens och inte är knutet till en viss leverantör och deras root-certifikat - men då ska det vara just ett riktigt bra web of trust. Förhoppningsvis skulle detta kunna vara ett första steg mot en mer öppen infrastruktur för elektroniska signaturer i Sverige, som även fungerar på internationell nivå. Att e-leg i Sverige och andra länder är helt obrukbara utanför landets gränser är en begränsning som vi inte kommer kunna leva med särskilt länge i det allt mer gränsöverskridande samhälle vi har.<br />
<br />
Gissningsvis var det här första gången en svensk myndighet accepterade OpenPGP-signaturer istället för handskrivna signaturer, men förhoppningsvis inte den sista och jag uppmuntrar er alla att testa själva vid framtida myndighetskontakter och sedan berätta hur det gick! 
            </div>
        </content>

        
    </entry>
    <entry>
        <link href="http://cnb.se/archives/9-Abstract-classes-and-static-methods.html" rel="alternate" title="Abstract classes and static methods" type="text/html" />
        <author>
            <name>Anders Hellstrom</name>
                    </author>
    
        <issued>2009-03-29T17:52:51Z</issued>
        <created>2009-03-29T17:52:51Z</created>
        <modified>2011-07-29T22:21:20Z</modified>
        <wfw:comment>http://cnb.se/wfwcomment.php?cid=9</wfw:comment>
        <slash:comments>0</slash:comments>
        <wfw:commentRss>http://cnb.se/rss.php?version=atom0.3&amp;type=comments&amp;cid=9</wfw:commentRss>
    
        <id>http://cnb.se/archives/9-guid.html</id>
        <title mode="escaped" type="text/html">Abstract classes and static methods</title>
        <content type="application/xhtml+xml" xml:base="http://cnb.se/">
            <div xmlns="http://www.w3.org/1999/xhtml">
                Working on my TemporalData class, i realized that it should be an <a href="http://php.net/oop5.abstract">abstract class</a>. It's the way I intended to use it all along, but I somehow forgot that PHP now supports abstract classes and didn't define it as such.<br />
<br />
The TemporalData class has a couple of <a href="http://php.net/oop5.static">static methods</a> used for selecting objects from the database, and I use <a href="http://php.net/oop5.late-static-bindings">late static bindings</a> (a php 5.3 feature) to figure out which class the call came through and in turn which table to query. If you were to call one of those methods directly on TemporalData it wouldn't have any way of knowing which table to query, so I used this code to block such calls:<br />
<br />
<div class="php geshi" style="text-align: left"><ol><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #000088;">$class</span> <span style="color: #339933;">=</span> get_called_class<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$class</span> <span style="color: #339933;">==</span> <span style="color: #0000ff;">'TemporalData'</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> </div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">&#160; throw <span style="color: #000000; font-weight: bold;">new</span> Exception<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;TemporalData::open() can not be called directly, only through its subclasses.&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #009900;">&#125;</span></div></li></ol></div><br />
<br />
I thought I could get rid of this check now that I defined the class to be abstract. Turns out this isn't the case:<br />
<br />
<div class="php geshi" style="text-align: left"><ol><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">abstract <span style="color: #000000; font-weight: bold;">class</span> A <span style="color: #009900;">&#123;</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">&#160; <span style="color: #000000; font-weight: bold;">public</span> <a href="http://www.php.net/static"><span style="color: #990000;">static</span></a> <span style="color: #000000; font-weight: bold;">function</span> foo<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> &#160; &#160; &#160; &#160; </div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">&#160; &#160; <a href="http://www.php.net/echo"><span style="color: #990000;">echo</span></a> <span style="color: #0000ff;">&quot;I'm in your foo(), eating your bar!<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">&#160; <span style="color: #009900;">&#125;</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #009900;">&#125;</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">&#160;</div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">A<span style="color: #339933;">::</span><span style="color: #004000;">foo</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></li></ol></div><br />
<br />
Output:<br />
<br />
<div class="text geshi" style="text-align: left"><ol><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">I'm in your foo(), eating your bar!</div></li></ol></div><br />
<br />
Tested with php 5.2.6 and 5.3.0beta1. 
            </div>
        </content>

        
    </entry>
    <entry>
        <link href="http://cnb.se/archives/8-Temporal-Databases.html" rel="alternate" title="Temporal Databases" type="text/html" />
        <author>
            <name>Anders Hellstrom</name>
                    </author>
    
        <issued>2009-03-14T16:23:13Z</issued>
        <created>2009-03-14T16:23:13Z</created>
        <modified>2011-07-29T22:21:24Z</modified>
        <wfw:comment>http://cnb.se/wfwcomment.php?cid=8</wfw:comment>
        <slash:comments>0</slash:comments>
        <wfw:commentRss>http://cnb.se/rss.php?version=atom0.3&amp;type=comments&amp;cid=8</wfw:commentRss>
    
        <id>http://cnb.se/archives/8-guid.html</id>
        <title mode="escaped" type="text/html">Temporal Databases</title>
        <content type="application/xhtml+xml" xml:base="http://cnb.se/">
            <div xmlns="http://www.w3.org/1999/xhtml">
                I was talking to <a href="http://blog.cgeek.net/">Johan</a> some time ago and he mentioned working on <a href="http://en.wikipedia.org/wiki/Temporal_database">Temporal Databases</a>. At the time it sounded interesting, but I didn't give it much more thought. Lately I've started thinking more about it, and it's such a simple yet ingenious concept. Instead of deleting or modifying data you'll mark the old data as invalid and insert the new valid data. Of course, in a true temporal database, this is largely transparent to the application. It's useful in pretty much any context. Of course there are exceptions, where it's just unneeded overhead, but usually there's no reason to not keep historic data around. Especially these days when disk space is so cheap. (BTW, did you see the new <a href="http://wdc.com/en/products/products.asp?driveid=576">2 TB 3.5" disk from Western Digital</a>?)<br />
<br />
Many applications (though far from all or even most) keep logs over when things change, so if there is some problem you can backtrack through the logs and if you are lucky see what changed, and if you are even more lucky you might even be able to see what or who caused the change, and why. The data most likely isn't machine readable any more though, and it takes a lot of manual labour to figure out the history of any given object.<br />
<br />
Temporal Database solve this at the database layer, and can be implemented in an existing SQL database using a couple of views, triggers, rules and PLSQL functions. What you need is a couple of extra columns. A <em>start</em> column that marks the first moment in time when the record became valid, and an <em>end</em> column that marks when the record became invalid.<br />
<br />
The <em>start</em> column is always set and defaults to <em>current_time</em>. The <em>end</em> column can be <em>null</em> though, as would be the case when you first insert a new record in the database. When you do an UPDATE a trigger catches your query and changes it into two queries: The existing row only gets one row changed, the <em>end</em> column, which is set to <em>current_time</em> - then a new row is inserted with all the data from the existing row, after your changes have been applied, and <em>start</em> set to <em>current_time</em> and <em>end</em> set to <em>null</em>. The procedure for a DELETE is a bit more simple. A rule is created that traps the DELETE statement and replaces it with an UPDATE that sets <em>end</em> to <em>current_time</em>.<br />
<br />
Another thing you'll need to keep this logic completely contained in the database is a view for the currently valid data in the table, which simply selects all the rows where <em>end</em> is <em>null</em>. To make things even more transparent you could probably add some rules and triggers to this view which acts on the real table, and then only use this view for everything in the application, though I have yet to try this out.<br />
<br />
The above setup is pretty sweet since everything happens automatically. It does have a couple of drawbacks though.<br />
<ul><br />
<li>You have to manually set up all the views, triggers, rules and functions for each and every table.</li><br />
<li>When you make changes to your tables, you will need to make the corresponding changes in the views etc.</li><br />
<li>If you ever need to purge historic data things get complicated.</li><br />
</ul><br />
<br />
The last point is something I personally like. I wouldn't want it to be easy to permanently delete data from a database set up this way. It's however a very important point here in Sweden when dealing with information about living persons since "<a href="http://www.datainspektionen.se/lagar-och-regler/personuppgiftslagen/">Personuppgiftslagen</a>" ("The Personal Data Act") applies. One paragraph of the law states that personal information may not be stored longer than necessary. This is obviously an issue if the database system intercepts any DELETE statements and blocks them. One way of working around this would be to disable the delete rule while removing the old data, which could probably be implemented as a PLSQL function. However, there are probably other parts of the law that applies too, e.g. keeping historic records of a persons addresses as they move around may be storing too much information. It'd be interesting to have a lawyer look at that.<br />
<br />
While the advantages in keeping all the temporal logic inside the database are numerous I'm considering the alternative of implementing it all in the application layer. Since I started looking at temporal databases I've experimented with both versions, and I'm torn between them, and I think that will always be the case.<br />
<br />
I'm currently working on a new member database for <a href="http://www.ulug.org/">ULUG</a> which will employ the temporal database concepts, and I've decided to go with the application layer approach, and I'll be extending the concept a bit. I've added two columns for <em>editor</em> and <em>logmessage</em>. The <em>editor</em> column will contain the user id of the person who performed the last record update, and the <em>logmessage</em> will allow the editor to comment on his changes for future reference. It can also be used to specify things automatically, such as "User changed their password". I've also added a column named <em>revision</em>. With every record update it will be incremented by one. This will make it easier to refer to a specific update of an object, for example "User ID 1, revision 5" instead of "User ID 1, as it looked at 2007-04-06 15:45:32". I also decided to use this in combination with the record ID as the primary key, instead of a more complex key using the <em>start</em> and <em>end</em> timestamp columns.<br />
<br />
Every page in the system displaying data that come from a temporal source will automatically display a small clock that when clicked allows the user to pick a date and time and show the object as it looked at that point in time. When an old revision is being displayed, the background will change and a warning text will appear at the top of the page to make it clear without a doubt that this data is no longer valid. There should also be some kind of way to show a log of all the revisions of an object, though I'm not completely done with the thought process on the specifics of this feature.<br />
<br />
My goal is to implement the temporal aspects of this as a special class that holds all the temporal logic. Any other objects, e.g. Member, WikiPage, etc, should be able to inherit from this object and automatically get the benefits of temporal data without having to manually add the extra code as would be the case when it is implemented in the database layer. The only thing needed are the extra columns in their respective table.<br />
<br />
If I can get that to work nicely I'm sure I'll end up using the application layer approach much more than the database layer approach. The drawback of course is that an application error could potentially erase data, but that's a problem with regular databases as well and I've managed to avoid any such bugs in my code so far. And if the worst case would happen, that's where my point-in-time-recovery backup system enters the picture! 
            </div>
        </content>

        
    </entry>
    <entry>
        <link href="http://cnb.se/archives/7-PHP-OOP-Bug.html" rel="alternate" title="PHP OOP Bug" type="text/html" />
        <author>
            <name>Anders Hellstrom</name>
                    </author>
    
        <issued>2009-03-09T08:50:10Z</issued>
        <created>2009-03-09T08:50:10Z</created>
        <modified>2011-07-29T22:21:29Z</modified>
        <wfw:comment>http://cnb.se/wfwcomment.php?cid=7</wfw:comment>
        <slash:comments>0</slash:comments>
        <wfw:commentRss>http://cnb.se/rss.php?version=atom0.3&amp;type=comments&amp;cid=7</wfw:commentRss>
    
        <id>http://cnb.se/archives/7-guid.html</id>
        <title mode="escaped" type="text/html">PHP OOP Bug</title>
        <content type="application/xhtml+xml" xml:base="http://cnb.se/">
            <div xmlns="http://www.w3.org/1999/xhtml">
                While working on a project this morning I discovered what appears to be a bug in PHP when dealing with objects and calling functions statically. I was calling a static function of a class from within an object of a different class. However, I had forgotten the name of the function I needed to call and ended up calling the wrong function. And even though the function I called wasn't declared as static I didn't get any error. Instead $this in the function ended up referring to the calling object.<br />
<br />
Here's a short example:<br />
<br />
<div class="php geshi" style="text-align: left"><ol><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #000000; font-weight: bold;">class</span> A <span style="color: #009900;">&#123;</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">&#160; <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000088;">$variable</span><span style="color: #339933;">;</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">&#160;</div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">&#160; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> foo<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">&#160; &#160; <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">variable</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'Hello B!'</span><span style="color: #339933;">;</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">&#160; <span style="color: #009900;">&#125;</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #009900;">&#125;</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">&#160;</div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #000000; font-weight: bold;">class</span> B <span style="color: #009900;">&#123;</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">&#160; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> bar<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">&#160; &#160; A<span style="color: #339933;">::</span><span style="color: #004000;">foo</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">&#160; <span style="color: #009900;">&#125;</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #009900;">&#125;</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">&#160;</div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #000088;">$myB</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> B<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><a href="http://www.php.net/print_r"><span style="color: #990000;">print_r</span></a><span style="color: #009900;">&#40;</span><span style="color: #000088;">$myB</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">&#160;</div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #000088;">$myB</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">bar</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><a href="http://www.php.net/print_r"><span style="color: #990000;">print_r</span></a><span style="color: #009900;">&#40;</span><span style="color: #000088;">$myB</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></li></ol></div><br />
<br />
And the output:<br />
<br />
<div class="text geshi" style="text-align: left"><ol><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">B Object</div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">(</div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">)</div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">B Object</div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">(</div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">&#160; &#160; [variable] =&gt; Hello B!</div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">)</div></li></ol></div><br />
<br />
<br />
Update:<br />
I've only tried this in version 5.2.6 so far. I suppose it might be the intended behavior but it seems rather odd to me. Though come to think of it, you don't get any errors when calling a non-static function statically from global scope when the function never use $this. In my opinion, these situations should cause a fatal error. 
            </div>
        </content>

        
    </entry>
    <entry>
        <link href="http://cnb.se/archives/2-Customized-Workflows-in-Trac.html" rel="alternate" title="Customized Workflows in Trac" type="text/html" />
        <author>
            <name>Anders Hellstrom</name>
                    </author>
    
        <issued>2008-11-01T11:15:00Z</issued>
        <created>2008-11-01T11:15:00Z</created>
        <modified>2011-07-29T22:21:34Z</modified>
        <wfw:comment>http://cnb.se/wfwcomment.php?cid=2</wfw:comment>
        <slash:comments>0</slash:comments>
        <wfw:commentRss>http://cnb.se/rss.php?version=atom0.3&amp;type=comments&amp;cid=2</wfw:commentRss>
    
        <id>http://cnb.se/archives/2-guid.html</id>
        <title mode="escaped" type="text/html">Customized Workflows in Trac</title>
        <content type="application/xhtml+xml" xml:base="http://cnb.se/">
            <div xmlns="http://www.w3.org/1999/xhtml">
                Here is a little update on what I've been doing with customized workflows in Trac. I've only recently convinced everybody at work to move over to Trac, so we're still in the process of streamlining everything. It wasn't a hard sell, the last couple of projects have been set up with a shared document in Google docs, where they've had a hard time telling which "tickets" have been started, finished, or are even supposed to be included in the current milestone. However, as they have started using Trac in a more serious manner, and now even letting customers into the system, I've gotten a couple of customization requests.<br />
<br />
For example, just because a feature is implemented or a bug is fixed, the ticket is not considered ready to be closed. It's only closed once the code has been deployed to the production server. From the get go we tried to work around this, since in Trac a ticket is either open or closed. By having different resolutions and reopening the ticket and then closing it again with a new resolution, we were able to almost get what we wanted. However this does not look good in many places around Trac, for example in the timeline, and when the customer sees the ticket as closed, they expect it to be live on the production server as well.<br />
<br />
Thankfully Trac 0.11 introduces a new feature which solves this completely for us - <a href="http://trac.edgewall.org/wiki/TracWorkflow">Customizable Workflows</a>. It's an amazingly powerful yet simple to use feature and I got a sample setup up and running surprisingly quickly. The showworkflow command line tool that ships with Trac now was extremely helpful and made it even easier to see that you set things up the way you planned without requiring extensive testing when you make modifications. It simply takes your configuration file and generates, using graphviz, a flowchart of your workflow:<br />
<br />
<div class="serendipity_imageComment_center" style="width: 230px"><div class="serendipity_imageComment_img"><!-- s9ymdb:3 --><a  class='serendipity_image_link'  rel='lightbox' href='http://cnb.se/uploads/Charts/default-trac-workflow.png'><img class="serendipity_image_center" width="110" height="107"  src="http://cnb.se/uploads/Charts/default-trac-workflow.serendipityThumb.png" alt="" /></a> <!-- s9ymdb:4 --><a  class='serendipity_image_link'  rel='lightbox' href='http://cnb.se/uploads/Charts/sample-trac-workflow.png'><img class="serendipity_image_center" width="110" height="80"  src="http://cnb.se/uploads/Charts/sample-trac-workflow.serendipityThumb.png" alt="" /></a></div><div class="serendipity_imageComment_txt">Default and Sample trac workflows</div></div><br />
<br />
As you can see when comparing the default and my sample workflows above, we've added a couple of extra steps in between the accepted and closed states. Once you've accepted a ticket it cannot be closed, the only possible actions are to either reassign it or to submit it for review by the project manager. When you submit it for review, it ends up in a new Status called validation. While in this state, the manager can choose whether to let it pass the review or to reopen the ticket and send it back to the developer.<br />
<br />
Once it has passed the review it ends up in yet another new Status - ready_for_deployment. From this state the developers can choose to either deploy the new code to the shared development server and demo it to the customer, or directly deploy it to the production server. It's also still possible to reopen the ticket from this point. If they however deploy it to the development server the ticket ends up in yet another new status called deployed_dev. Only when a deployment on the production server is completed the ticket will be closed. This can be performed either from the ready_for_deployment status, or from the deployed_dev status.<br />
<br />
While we haven't put this new workflow to the test yet, I'm certain it will work much better than the previous system with different resolutions. Since I find this feature to be well-documented I don't see any need to repeat the steps needed here, however I will post the [ticket-workflow] section from my trac.ini here for your reference:<br />
<br />
<div class="ini geshi" style="text-align: left"><ol><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #000066; font-weight:bold;"><span style="">&#91;</span>ticket-workflow<span style="">&#93;</span></span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #000099;">accept</span> <span style="color: #000066; font-weight:bold;">=</span><span style="color: #660066;"> new,assigned,accepted,reopened -&gt; accepted</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #000099;">accept.operations</span> <span style="color: #000066; font-weight:bold;">=</span><span style="color: #660066;"> set_owner_to_self</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #000099;">accept.permissions</span> <span style="color: #000066; font-weight:bold;">=</span><span style="color: #660066;"> TICKET_MODIFY &#160; </span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #000099;">leave</span> <span style="color: #000066; font-weight:bold;">=</span><span style="color: #660066;"> * -&gt; *</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #000099;">leave.default</span> <span style="color: #000066; font-weight:bold;">=</span><span style="color: #660066;"> 1</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #000099;">leave.operations</span> <span style="color: #000066; font-weight:bold;">=</span><span style="color: #660066;"> leave_status</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #000099;">reassign</span> <span style="color: #000066; font-weight:bold;">=</span><span style="color: #660066;"> new,assigned,accepted,reopened -&gt; assigned</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #000099;">reassign.operations</span> <span style="color: #000066; font-weight:bold;">=</span><span style="color: #660066;"> set_owner</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #000099;">reassign.permissions</span> <span style="color: #000066; font-weight:bold;">=</span><span style="color: #660066;"> TICKET_MODIFY</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #000099;">reopen</span> <span style="color: #000066; font-weight:bold;">=</span><span style="color: #660066;"> closed,deployed_dev,ready_for_deployment -&gt; reopened</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #000099;">reopen.operations</span> <span style="color: #000066; font-weight:bold;">=</span><span style="color: #660066;"> del_resolution</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #000099;">reopen.permissions</span> <span style="color: #000066; font-weight:bold;">=</span><span style="color: #660066;"> TICKET_CREATE</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #000099;">resolve</span> <span style="color: #000066; font-weight:bold;">=</span><span style="color: #660066;"> new,assigned,accepted,reopened -&gt; closed</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #000099;">resolve.operations</span> <span style="color: #000066; font-weight:bold;">=</span><span style="color: #660066;"> set_resolution</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #000099;">resolve.permissions</span> <span style="color: #000066; font-weight:bold;">=</span><span style="color: #660066;"> TICKET_MODIFY</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #000099;">review</span> <span style="color: #000066; font-weight:bold;">=</span><span style="color: #660066;"> accepted -&gt; validation</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #000099;">review.name</span> <span style="color: #000066; font-weight:bold;">=</span><span style="color: #660066;"> Submit for Review</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #000099;">review.permissions</span> <span style="color: #000066; font-weight:bold;">=</span><span style="color: #660066;"> TICKET_MODIFY</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #000099;">reject</span> <span style="color: #000066; font-weight:bold;">=</span><span style="color: #660066;"> validation -&gt; reopened</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #000099;">reject.name</span> <span style="color: #000066; font-weight:bold;">=</span><span style="color: #660066;"> Failed Review, return to developer</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #000099;">pass</span> <span style="color: #000066; font-weight:bold;">=</span><span style="color: #660066;"> validation -&gt; ready_for_deployment</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #000099;">pass.name</span> <span style="color: #000066; font-weight:bold;">=</span><span style="color: #660066;"> Passes Review</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #000099;">pass.permissions</span> <span style="color: #000066; font-weight:bold;">=</span><span style="color: #660066;"> TICKET_MODIFY</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #000099;">deploy_dev</span> <span style="color: #000066; font-weight:bold;">=</span><span style="color: #660066;"> ready_for_deployment -&gt; deployed_dev</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #000099;">deploy_dev.name</span> <span style="color: #000066; font-weight:bold;">=</span><span style="color: #660066;"> Deployed to Development server </span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #000099;">deploy_dev.permissions</span> <span style="color: #000066; font-weight:bold;">=</span><span style="color: #660066;"> TICKET_MODIFY</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #000099;">deploy_live</span> <span style="color: #000066; font-weight:bold;">=</span><span style="color: #660066;"> ready_for_deployment,deployed_dev -&gt; closed</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #000099;">deploy_live.name</span> <span style="color: #000066; font-weight:bold;">=</span><span style="color: #660066;"> Deployed to Production server</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #000099;">deploy_live.permissions</span> <span style="color: #000066; font-weight:bold;">=</span><span style="color: #660066;"> TICKET_MODIFY</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #000099;">deploy_live.operations</span> <span style="color: #000066; font-weight:bold;">=</span><span style="color: #660066;"> set_resolution</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #000099;">deploy_live.set_resolution</span> <span style="color: #000066; font-weight:bold;">=</span><span style="color: #660066;"> fixed</span></div></li></ol></div><br />
<br />
Things I have planned for the future is customizing the permissions so that indeed only the manager can say a ticket has passed the review (With the configuration above, any developer can do it since they all have the TICKET_MODIFY permission) as well as modifying the milestone status page to account for the new states.<br />
<br />
 
            </div>
        </content>

        
    </entry>
</feed>
