Completed
Push — 16.1 ( 4aafcf...095a95 )
by Ralf
70:38 queued 43:13
created

Cache::read()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 16
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 7
nc 3
nop 1
dl 0
loc 16
rs 9.4285
c 0
b 0
f 0
1
<?php
2
/**
3
 * eGroupWare - eTemplate request object storing the data in EGroupware instance cache
4
 *
5
 * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
6
 * @package api
7
 * @subpackage etemplate
8
 * @link http://www.egroupware.org
9
 * @author Ralf Becker <[email protected]>
10
 * @copyright (c) 2014-16 by Ralf Becker <[email protected]>
11
 * @version $Id$
12
 */
13
14
namespace EGroupware\Api\Etemplate\Request;
15
16
use EGroupware\Api\Etemplate;
17
use EGroupware\Api;
18
19
/**
20
 * Class to represent the persitent information stored on the server for each eTemplate request
21
 *
22
 * The information is stored in EGroupware tree cache with a given fixed expiration time.
23
 * We use tree cache with install-id as part of key to not loose all requests, if admin
24
 * clears instance cache (Admin >> Clear cache and register hooks)!
25
 *
26
 * To enable the use of this handler, you have to set (in etemplate/inc/class.etemplate_request.inc.php):
27
 *
28
 * 		Api\Etemplate\Request::$request_class = 'etemplate_request_cache';
29
 *
30
 * The request object should be instancated only via the factory method Api\Etemplate\Request::read($id=null)
31
 *
32
 * $request = Api\Etemplate\Request::read();
33
 *
34
 * // add request data
35
 *
36
 * $id = $request->id();
37
 *
38
 * b) open or modify an existing request:
39
 *
40
 * if (!($request = Api\Etemplate\Request::read($id)))
41
 * {
42
 * 		// request not found
43
 * }
44
 *
45
 * Ajax requests can use this object to open the original request by using the id, they have to transmit back,
46
 * and register further variables, modify the registered ones or delete them AND then update the id, if it changed:
47
 *
48
 *	if (($new_id = $request->id()) != $id)
49
 *	{
50
 *		$response->addAssign('etemplate_exec_id','value',$new_id);
51
 *	}
52
 *
53
 * For an example look in link_widget::ajax_search()
54
 */
55
56
class Cache extends Etemplate\Request
0 ignored issues
show
Coding Style introduced by
Since you have declared the constructor as private, maybe you should also declare the class as final.
Loading history...
57
{
58
	/**
59
	 * Expiration time of 4 hours
60
	 */
61
	const EXPIRATION = 14400;
62
63
	/**
64
	 * request id
65
	 *
66
	 * @var string
67
	 */
68
	protected $id;
69
70
	/**
71
	 * Private constructor to force the instancation of this class only via it's static factory method read
72
	 *
73
	 * @param string $_id
74
	 */
75
	private function __construct($_id=null)
0 ignored issues
show
Bug introduced by
Consider using a different method name as you override a private method of the parent class.

Overwriting private methods is generally fine as long as you also use private visibility. It might still be preferable for understandability to use a different method name.

Loading history...
76
	{
77
		$this->id = $_id ? $_id : self::request_id();
78
		//error_log(__METHOD__."($_id) this->id=$this->id");
79
80
		// hack to quiten IDE Warning for not calling parent::__construct, which we can not!
81
		if (false) parent::__construct();
0 ignored issues
show
Unused Code introduced by
The call to the method EGroupware\Api\Etemplate\Request::__construct() seems un-needed as the method has no side-effects.

PHP Analyzer performs a side-effects analysis of your code. A side-effect is basically anything that might be visible after the scope of the method is left.

Let’s take a look at an example:

class User
{
    private $email;

    public function getEmail()
    {
        return $this->email;
    }

    public function setEmail($email)
    {
        $this->email = $email;
    }
}

If we look at the getEmail() method, we can see that it has no side-effect. Whether you call this method or not, no future calls to other methods are affected by this. As such code as the following is useless:

$user = new User();
$user->getEmail(); // This line could safely be removed as it has no effect.

On the hand, if we look at the setEmail(), this method _has_ side-effects. In the following case, we could not remove the method call:

$user = new User();
$user->setEmail('email@domain'); // This line has a side-effect (it changes an
                                 // instance variable).
Loading history...
82
	}
83
84
	/**
85
	 * return the id of this request
86
	 *
87
	 * @return string
88
	 */
89
	public function &id()
90
	{
91
		//error_log(__METHOD__."() id=$this->id");
92
		return $this->id;
93
	}
94
95
	/**
96
	 * Factory method to get a new request object or the one for an existing request
97
	 *
98
	 * @param string $id =null
99
	 * @return Request|boolean the object or false if $id is not found
100
	 */
101
	static function read($id=null)
102
	{
103
		$request = new Cache($id);
104
105
		if (!is_null($id))
106
		{
107
			//error_log(__METHOD__."() reading $id");
108
			if (!($request->data = Api\Cache::getTree($GLOBALS['egw_info']['server']['install_id'].'_etemplate', $id)))
109
			{
110
				error_log("Error reading etemplate request data for id=$id!");
111
				return false;
112
			}
113
		}
114
		//error_log(__METHOD__."(id=$id) returning ".array2string($request));
115
		return $request;
116
	}
117
118
	/**
119
	 * saves content,readonlys,template-keys, ... via eGW's appsession function
120
	 *
121
	 * As a user may open several windows with the same content/template wie generate a location-id from microtime
122
	 * which is used as location for request to descriminate between the different windows. This location-id
123
	 * is then saved as a hidden-var in the form. The above mentions session-id has nothing to do / is different
124
	 * from the session-id which is constant for all windows opened in one session.
125
	 */
126
	function __destruct()
127
	{
128
		if ($this->remove_if_not_modified && !$this->data_modified && isset($this->data['last_saved']))
129
		{
130
			//error_log(__METHOD__."() destroying $this->id");
131
			Api\Cache::unsetTree($GLOBALS['egw_info']['server']['install_id'].'_etemplate', $this->id);
132
		}
133
		elseif (($this->data_modified ||
134
			// if half of expiration time is over, save it anyway, to restart expiration time
135
			isset($this->data['last_saved']) && (time()-$this->data['last_saved']) > self::EXPIRATION/2))
136
		{
137
			//error_log(__METHOD__."() saving $this->id".($this->data_modified?'':' data NOT modified, just keeping session alife'));
138
			$this->cleanup();
139
			$this->data['last_saved'] = time();
140
			if (!Api\Cache::setTree($GLOBALS['egw_info']['server']['install_id'].'_etemplate', $this->id, $this->data,
141
				// use bigger one of our own self::EXPIRATION=4h and session lifetime (session.gc_maxlifetime) as expiration time
142
				max(self::EXPIRATION, ini_get('session.gc_maxlifetime'))))
143
			{
144
				error_log("Error storing etemplate request data for id=$this->id!");
145
			}
146
		}
147
	}
148
}