[PHP/MySQL] Cached menu werkt niet

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • BlackWhizz
  • Registratie: September 2004
  • Laatst online: 08-12-2024
Oke, ik zit heir al wel 3 dagen mee te proberen. ik heb dus een treemenu gemaakt met ongelimiteerd subs maken. Alleen omdat dit per laadpoging ongelovelijk veel tijd kost om de hele tijd query's te maken wil ik hem cachen. Daarom heb ik het geheel omgebouwd in een class.

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
<?php
class menu
{
    private $oDb,
            $sFormatted;
    protected $aMenuCache;
    
    function __construct()
    {
        global $oDb;
        $this->oDb          = $oDb;
        $this->sFormatted   = '';
        
        if ( !$this->cached() )
        {
            $this->write_cache();
        }
    }
    
    function build_menu( $aCached=null )
    {        
        if ( !is_array($aCached) )
        {
            $this->get_cache();
            $aCached = $this->aMenuCache;
        }
        
        $this->sFormatted .= '<ul>';
        
        foreach ( $aCached AS $aCache )
        {
            $this->sFormatted .= '<li><a href="'.$aCache['url'].'">'.htmlentities($aCache['title']).'</a></li>';
            
            if ( isset($aCache['_subs']) )
            {
                $this->sFormatted .= '<li>'.$this->build_menu( $aCache['_subs'] ).'</li>';
            }
        }
        $this->sFormatted .= '</ul>';
        
        return $this->sFormatted;
    }
    
    function cached ()
    {
        return file_exists( CACHE_PATH.'/cache/menu.txt' );
    }
    
    function get_cache()
    {
        if ( $sCache = @file_get_contents( CACHE_PATH.'/cache/menu.txt' ) )
        {
            $this->aMenuCache = unserialize( $sCache );
            
            return true;
        }
        else
        {
            trigger_error( 'Cannot load menu cache, please renew the cache in the admin panel.' );
            
            return false;
        }
    }
    
    function write_cache()
    {
        if ( $rHandle = @fopen( CACHE_PATH.'/cache/menu.txt', 'w' ) )
        {
            fwrite( $rHandle, serialize( $this->menu_cache() ) );
            fclose( $rHandle );
        }
        else
        {
            return trigger_error( 'Cannot create a cache file, please make shure the cache dir has chmod 777 and safe mode is turned off', E_USER_ERROR );
        }
    }

    function menu_cache( $iParent = 0, $sParent=ROOT_PATH )
    {
        if ( $this->oDb->count( 'categories', 'parent = ?', $iParent ) > 0 )
        {
            $aMenu = array();
            
            $aResult = $this->oDb->query( 'SELECT * FROM categories WHERE parent = ? ORDER BY niv ASC', $iParent );
            
            foreach ( $aResult AS $aData )
            {
                $aMenuCache = menu_cache( $aData['id'], $sParent.$aData['title_url'].'/' );
                
                if ( is_array($aMenuCache) )
                {
                    $aMenu[] = array( 'title' => $aData['title'], 'url' => $sParent.$aData['title_url'], '_subs' => $aMenuCache );
                    
                }
                else
                {
                    $aMenu[] = array( 'title' => $aData['title'], 'url' => $sParent.$aData['title_url'] );
                }
            }
            
            return $aMenu;
        }
        else
        {
            return false;
        }
    }
}
?>


In de array staat dit:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
Array
(
    [title] => Computers
    [url] => /computers
    [_subs] => Array
        (
            [0] => Array
                (
                    [title] => Hardware
                    [url] => /computers/hardware
                )

            [1] => Array
                (
                    [title] => Software
                    [url] => /computers/software
                    [_subs] => Array
                        (
                            [0] => Array
                                (
                                    [title] => Microsoft software
                                    [url] => /computers/software/microsoft-software
                                )

                        )

                )

        )

)


Echter, nu krijg ik dus doordat ik recursie gebruik de menu's 3x te zien.

Dat komt door dit:
code:
1
2
3
4
5
if ( !is_array($aCached) )
        {
            $this->get_cache();
            $aCached = $this->aMenuCache;
        }

Immers, die build_menu geeft een array door, zo niet dan maakt die een nieuwe array aan. Dit heb ik geprobeerd dooor het te onderdrukken om te kijken of $this->sFormatted leeg is, maar dat werkt dus nog steeds niet.

!is_array($aCached) && empty($this->sFormatted)

Kortom, ik weet niet wat ik fout doe, want als ik dat weghaal en het cache bestand verwijder dan werkt het nog steeds niet.

Acties:
  • 0 Henk 'm!

  • Xcalibur
  • Registratie: Augustus 2002
  • Laatst online: 20:33
is het niet gemakkelijker het hele menu in een sessievariabele te stoppen ofzo?
Per bezoeker wordt hij dan 1x gegenereerd, dat lijkt me niet zo'n probleem....

Overigens zijn er manieren om een tree wat efficienter in een database te stoppen, is dat niks? :P

Designer | Developer | Director | Photographer | LARPer | Geek | Male | 39


Acties:
  • 0 Henk 'm!

  • Johnny
  • Registratie: December 2001
  • Laatst online: 14:39

Johnny

ondergewaardeerde internetguru

Ik zie de fout zo snel ook niet, maar de hele opbouw van de class lijkt me niet erg handig. Het idee van Object Georienteerd programmeren is dat je data binnen objecten afschermd. Als je $menu->get_menu() doet wordt het menu opgehaald, of het nu uit een cache-bestand komt of een database is buiten die class niet belangrijk. Functies zoals get_cache() hoef je dus niet te gebruiken.

Als je dit doet wordt het ontwerp ook meteen een stuk simpeler, zodra het menu wordt opgehaald wordt er gekeken of er een cache-bestand bestaat als dat zo is wordt dat direct ingelezen en terug gegeven. Als het niet zo is haal je de data uit de database, maak je het, schrijf het naar het cache en geef het terug. De eerste keer laden gaat dan wel iets langzamer, maar als je cache-bestand wordt verwijderd heb je geen last van fouten zoals "Cannot load menu cache, please renew the cache in the admin panel."

Verder kan je beter het hele menu in een enkele query ophalen uit de database en vervolgens recursief opbouwen, het is een beetje ingewikkelder maar gaat vele malen sneller. Als laatste tip kan je gewoon file_put_contents() gebruiken om je cache-bestand sneller en simpeler weg te schrijven.

Aan de inhoud van de bovenstaande tekst kunnen geen rechten worden ontleend, tenzij dit expliciet in dit bericht is verwoord.


Acties:
  • 0 Henk 'm!

  • mocean
  • Registratie: November 2000
  • Laatst online: 04-09 10:34
Als je toch het hele menu cached, zou je die ook als HTML kunnen cachen. Dan hoef je bij iedere aanroep ook niet de array om te zetten in het menu.

Wat bepaald trouwens of het menu is gewijzigd? Je zou de functionaliteit ook kunnen opsplitsen: Je CMS (ik ga er van uit dat er iets van een CMS achter zit) kan weten als er iets in het menu wordt gewijzigd. Op dat moment kan je daar al een nieuwe cache file genereren.

Ter check in de front-end natuurlijk altijd kijken of de cache file wel bestaat, maar in principe heb je dan altijd een menu klaarstaan.

Koop of verkoop je webshop: ecquisition.com


Acties:
  • 0 Henk 'm!

  • BlackWhizz
  • Registratie: September 2004
  • Laatst online: 08-12-2024
Oke, om het duidelijk te maken. Dit menu komt voor een CMS. Waarom ik hem opsla als serialized array? Omdat ik dan makkelijk kan of de bezoeker zich op die pagina bevindt. Echter, ik wilde eerst de basis functionaliteit maken.

Die renew cache error komt alleen als die cache niet geschreven kan worden (dus bijvoorbeeld de cache map bestaat niet of is niet beschrijfbaar).

Maar ik snap niet hoe ik dat probleem kan oplossen dat die het 3x herhaalt. Deze class is een class apart. Het wordt geen OOP, alleen maar OO.

Maar hoe kan ik dan onderdrukken dat die het 3x herhaalt. Of wat is die 2e manier?

Acties:
  • 0 Henk 'm!

  • Voutloos
  • Registratie: Januari 2002
  • Niet online
BlackWhizz schreef op donderdag 26 juni 2008 @ 10:45:
Deze class is een class apart. Het wordt geen OOP, alleen maar OO.
Dus? Dan kan je deze class nog wel netjes doen. ;)

{signature}


Acties:
  • 0 Henk 'm!

  • BlackWhizz
  • Registratie: September 2004
  • Laatst online: 08-12-2024
Moderator, kan dit topic dicht?

Acties:
  • 0 Henk 'm!

  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 02:21

Janoz

Moderator Devschuur®

!litemod

Waarom?

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


Acties:
  • 0 Henk 'm!

  • BlackWhizz
  • Registratie: September 2004
  • Laatst online: 08-12-2024
Ik heb de oplossing gevonden, dus het werkt.

Acties:
  • 0 Henk 'm!

  • Creepy
  • Registratie: Juni 2001
  • Laatst online: 19:51

Creepy

Tactical Espionage Splatterer

Misschien is het wel zo aardig even te vertellen wat het was zodat iemand die met een soortgelijk probleem zit daar ook nog wat aan heeft?

"I had a problem, I solved it with regular expressions. Now I have two problems". That's shows a lack of appreciation for regular expressions: "I know have _star_ problems" --Kevlin Henney


Acties:
  • 0 Henk 'm!

  • BlackWhizz
  • Registratie: September 2004
  • Laatst online: 08-12-2024
Oplossing was dit:

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
<?php
class menu
{
    private $oDb;
    protected $aMenuCache,
              $sFormatted;
    
    function __construct()
    {
        global $oDb;
        $this->oDb          = $oDb;
        $this->sFormatted   = '';
        $this->aMenuCache   = array();
        
        if ( !$this->cached() )
        {
            $this->write_cache();
        }
        
        $this->get_cache();
    }
    
    function build_menu( $aCached=null )
    {        
        $sReqUri    = strtolower( trim( $_SERVER['REQUEST_URI'], '/' ) );
        
        $sFormatted = '';
        $sFormatted .= '<ul>'.PHP_EOL;
        
        foreach ( $aCached AS $aCacheData )
        {
            $sUrl = strtolower( trim( $aCacheData['url'], '/' ) );
            
            if ( $sUrl == substr( $sReqUri, 0, strlen($sUrl) ) )
            {
                $sFormatted .= '<li><a href="'.$aCacheData['url'].'" title="Ga naar de categorie '.htmlentities( $aCacheData['title'], ENT_QUOTES ).'" class="current">'.htmlentities( $aCacheData['title'], ENT_QUOTES ).'</li>'.PHP_EOL;
            }
            else
            {
                $sFormatted .= '<li><a href="'.$aCacheData['url'].'" title="Ga naar de categorie '.htmlentities( $aCacheData['title'], ENT_QUOTES ).'">'.htmlentities( $aCacheData['title'], ENT_QUOTES ).'</li>'.PHP_EOL;
            }
            
            if ( isset( $aCacheData['_subs'] ) && is_array( $aCacheData['_subs'] ) )
            {
                $sFormatted .= '<li>'.$this->build_menu( $aCacheData['_subs'] ).'</li>';
            }
        }
        
        $sFormatted .= '</ul>';
        
        $this->sFormatted = $sFormatted;
        
        return $sFormatted;
    }
    
    /**
    *   Menu::Get_Menu
    */
    
    function get_menu()
    {
        if ( empty($this->sFormatted) )
        {
            $this->build_menu( $this->aMenuCache );
        }
        
        return $this->sFormatted;
    }
    
    /**
    *   Menu::Cached
    *
    *   @desc   Checks if the cache file exists
    *   @access Public
    *   @return Bool    True/false
    */
    
    public function cached ()
    {
        return file_exists( CACHE_PATH.'menu.txt' );
    }
    
    /**
    *   Menu::Get_Cache
    *
    *   @desc   Gets the cache from a file and write it to a var
    *   @access Private
    *   @return Bool    True/false
    */
    private function get_cache()
    {
        if ( $sCache = @file_get_contents( CACHE_PATH.'menu.txt' ) )
        {
            $this->aMenuCache = unserialize( $sCache );
            
            return true;
        }
        else
        {
            trigger_error( 'Cannot load menu cache, please renew the cache in the admin panel.', E_USER_ERROR );
            
            return false;
        }
    }
    
    /**
    *   Menu::Write_Cache
    *
    *   @desc   Writes the cache to a file
    *   @return Bool    True/false
    *   @access Private
    */
    
    private function write_cache()
    {
        if ( $rHandle = @fopen( CACHE_PATH.'menu.txt', 'w' ) )
        {
            fwrite( $rHandle, serialize( $this->menu_cache() ) );
            fclose( $rHandle );
            
            return true;
        }
        else
        {
            return trigger_error( 'Cannot create a cache file, please make shure the cache dir has chmod 777 and safe mode is turned off', E_USER_ERROR );
        }
    }
    
    /**
    *   Menu::Menu_Cache
    *
    *   @desc   Creates an array which contains the menu cache
    *   @access Private
    *   @return Mixed   False on error, else an array which contains menu cache.
    *
    *   @param1 Int     Parent ( which contains the id of the parent to get from)
    *   @param2 String  Url from parent (to build seo-friendly url's)
    */
    
    private function menu_cache( $iParent = 0, $sParent=ROOT_PATH )
    {
        if ( $this->oDb->count( 'categories', 'parent = ?', $iParent ) > 0 )
        {
            $aMenu  = array();
            
            $aResult = $this->oDb->query( 'SELECT * FROM categories WHERE parent = ? ORDER BY niv ASC', $iParent );
            
            foreach ( $aResult AS $aData )
            {
                $aMenuCache = menu_cache( $aData['id'], $sParent.$aData['title_url'].'/' );
                
                if ( is_array($aMenuCache) )
                {
                    $aMenu[] = array( 'title' => $aData['title'], 'url' => $sParent.$aData['title_url'], '_subs' => $aMenuCache );
                }
                else
                {
                    $aMenu[] = array( 'title' => $aData['title'], 'url' => $sParent.$aData['title_url'] );
                }
            }
            
            return $aMenu;
        }
        else
        {
            return false;
        }
    }
    
    /**
    *   Menu::_Destruct
    *
    *   @desc   Menu class destructor, clears all filled variables
    *   @access Public
    *   @return None
    */
    
    public function __destruct ()
    {
        $this->sFormatted   = '';
        $this->oDb          = null;
        $this->aMenuCache   = null;
    }
}
?>
Pagina: 1