1: <?php
2: /**
3: * QWatcher is a helper class that allows controls and forms to watch database tables
4: * and automatically redraw when changes are detected. It works together with the codegened
5: * model classes, the controls, and the QForm class to draw or refresh when needed.
6: *
7: * Static functions handle the database updating, while member variables store the current state
8: * of a control's watched tables.
9: *
10: * This Base class is a template on which to build watchers that use specific caching mechanisms.
11: * See QWatcher to select the caching mechanism you would like to use.
12: */
13:
14: abstract class QWatcherBase extends QBaseClass {
15:
16: /**
17: * @var string key representing all tables being watched. This is used to create a key so that we can
18: * know if any table that other forms care about changes, and notify other windows of the change. If you have multiple
19: * installations of QCubed running on the same machine, you should change this in the QWatcher override
20: * and make it different for each application. However, if two QCubed installations are modifying the same tables in
21: * the same databases, they should have the same app key
22: */
23: public static $strAppKey = 'QWATCH_APPKEY';
24:
25: protected static $blnWatcherChanged;
26:
27: protected $strWatchedKeys = array();
28:
29: /**
30: * Returns a unique key corresponding to the given table in the given database.
31: * Override this function to return a key value that will define a subset of the table to
32: * watch. For example, if you have records associated with User Ids,
33: * combine the user id with the table name, and then
34: * only records associated with that user id will be watched.
35: *
36: * Also, override this if you have multiple instances of QCubed running on the same PHP process, with possibly the same
37: * table names.
38: *
39: * @return string
40: */
41: protected static function GetKey($strDbName, $strTableName) {
42: return $strDbName . ':' . $strTableName;
43: }
44:
45: /**
46: * Call from control to watch a node. Watches all tables associated with the node.
47: *
48: * @param QQTableNode $objNode
49: */
50: public function Watch(QQTableNode $objNode) {
51: $strClassName = $objNode->_ClassName;
52:
53: if (!$strClassName::$blnWatchChanges) {
54: throw new QCallerException ($strClassName . ':$blnWatchChanges is false. To be able to watch this table, you should set it to true in your ' . $strClassName . '.class.php file.');
55: }
56:
57: if ($strClassName) {
58: $objDatabase = $strClassName::GetDatabase();
59: $this->RegisterTable($objDatabase->Database, $objNode->_TableName);
60: }
61: $objParentNode = $objNode->_ParentNode;
62: if ($objParentNode) {
63: $this->Watch ($objParentNode);
64: }
65: }
66:
67: /**
68: *
69: * Internal function to watch a single table.
70: *
71: * @param string $strTableName
72: */
73: protected function RegisterTable ($strDbName, $strTableName) {
74: $key = static::GetKey($strDbName, $strTableName);
75: if (empty($this->strWatchedKeys[$key])) {
76: $this->strWatchedKeys[$key] = true;
77: }
78: }
79:
80: /**
81: * Controls should call this function just after rendering. Updates strWatchedTables
82: * to the current state of the database.
83: *
84: */
85: abstract public function MakeCurrent();
86:
87: /**
88: * QControlBase uses this from IsModified to detect if it should redraw.
89: * Returns false if the database has been changed since the last draw.
90: * @return bool
91: */
92: abstract public function IsCurrent();
93:
94: /**
95: * Model Save() calls this to indicate that a table has changed.
96: *
97: * @param string $strTableName
98: * @throws QCallerException
99: */
100: static public function MarkTableModified ($strDbName, $strTableName) {
101: self::$blnWatcherChanged = true;
102: }
103:
104: /**
105: * Support function for the Form to determine if any of the watchers have changed since the last time
106: * it checked. Since this is relying on a global variable, the variable is reset upon program entry, including
107: * ajax entry. So really, we are just detecting if any operation we have currently done has changed a watcher, so
108: * that the form can broadcast that fact to other browser windows that might be looking.
109: *
110: * @param QWatcher[]|null $objWatchers
111: * @return bool
112: */
113: static public function WatchersChanged () {
114: $blnChanged = self::$blnWatcherChanged;
115: self::$blnWatcherChanged = false;
116: return $blnChanged;
117: }
118: }