1 <?php
2 /**
3 * @package FrameworkOnFramework
4 * @subpackage table
5 * @copyright Copyright (C) 2010-2016 Nicholas K. Dionysopoulos / Akeeba Ltd. All rights reserved.
6 * @license GNU General Public License version 2 or later; see LICENSE.txt
7 */
8 // Protect from unauthorized access
9 defined('FOF_INCLUDED') or die;
10
11 /**
12 * FrameworkOnFramework table behavior class for assets
13 *
14 * @package FrameworkOnFramework
15 * @since 2.1
16 */
17 class FOFTableBehaviorAssets extends FOFTableBehavior
18 {
19 /**
20 * The event which runs after storing (saving) data to the database
21 *
22 * @param FOFTable &$table The table which calls this event
23 *
24 * @return boolean True to allow saving
25 */
26 public function onAfterStore(&$table)
27 {
28 $result = true;
29
30 $asset_id_field = $table->getColumnAlias('asset_id');
31
32 if (in_array($asset_id_field, $table->getKnownFields()))
33 {
34 if (!empty($table->$asset_id_field))
35 {
36 $currentAssetId = $table->$asset_id_field;
37 }
38
39 // The asset id field is managed privately by this class.
40 if ($table->isAssetsTracked())
41 {
42 unset($table->$asset_id_field);
43 }
44 }
45
46 // Create the object used for inserting/udpating data to the database
47 $fields = $table->getTableFields();
48
49 // Let's remove the asset_id field, since we unset the property above and we would get a PHP notice
50 if (isset($fields[$asset_id_field]))
51 {
52 unset($fields[$asset_id_field]);
53 }
54
55 // Asset Tracking
56 if (in_array($asset_id_field, $table->getKnownFields()) && $table->isAssetsTracked())
57 {
58 $parentId = $table->getAssetParentId();
59
60 try{
61 $name = $table->getAssetName();
62 }
63 catch(Exception $e)
64 {
65 $table->setError($e->getMessage());
66 return false;
67 }
68
69 $title = $table->getAssetTitle();
70
71 $asset = JTable::getInstance('Asset');
72 $asset->loadByName($name);
73
74 // Re-inject the asset id.
75 $this->$asset_id_field = $asset->id;
76
77 // Check for an error.
78 $error = $asset->getError();
79
80 // Since we are using JTable, there is no way to mock it and test for failures :(
81 // @codeCoverageIgnoreStart
82 if ($error)
83 {
84 $table->setError($error);
85
86 return false;
87 }
88 // @codeCoverageIgnoreEnd
89
90 // Specify how a new or moved node asset is inserted into the tree.
91 // Since we're unsetting the table field before, this statement is always true...
92 if (empty($table->$asset_id_field) || $asset->parent_id != $parentId)
93 {
94 $asset->setLocation($parentId, 'last-child');
95 }
96
97 // Prepare the asset to be stored.
98 $asset->parent_id = $parentId;
99 $asset->name = $name;
100 $asset->title = $title;
101
102 if ($table->getRules() instanceof JAccessRules)
103 {
104 $asset->rules = (string) $table->getRules();
105 }
106
107 // Since we are using JTable, there is no way to mock it and test for failures :(
108 // @codeCoverageIgnoreStart
109 if (!$asset->check() || !$asset->store())
110 {
111 $table->setError($asset->getError());
112
113 return false;
114 }
115 // @codeCoverageIgnoreEnd
116
117 // Create an asset_id or heal one that is corrupted.
118 if (empty($table->$asset_id_field) || (($currentAssetId != $table->$asset_id_field) && !empty($table->$asset_id_field)))
119 {
120 // Update the asset_id field in this table.
121 $table->$asset_id_field = (int) $asset->id;
122
123 $k = $table->getKeyName();
124
125 $db = $table->getDbo();
126
127 $query = $db->getQuery(true)
128 ->update($db->qn($table->getTableName()))
129 ->set($db->qn($asset_id_field).' = ' . (int) $table->$asset_id_field)
130 ->where($db->qn($k) . ' = ' . (int) $table->$k);
131
132 $db->setQuery($query)->execute();
133 }
134
135 $result = true;
136 }
137
138 return $result;
139 }
140
141 /**
142 * The event which runs after binding data to the table
143 *
144 * @param FOFTable &$table The table which calls this event
145 * @param object|array &$src The data to bind
146 *
147 * @return boolean True on success
148 */
149 public function onAfterBind(&$table, &$src)
150 {
151 // Set rules for assets enabled tables
152 if ($table->isAssetsTracked())
153 {
154 // Bind the rules.
155 if (isset($src['rules']) && is_array($src['rules']))
156 {
157 // We have to manually remove any empty value, since they will be converted to int,
158 // and "Inherited" values will become "Denied". Joomla is doing this manually, too.
159 // @todo Should we move this logic inside the setRules method?
160 $rules = array();
161
162 foreach ($src['rules'] as $action => $ids)
163 {
164 // Build the rules array.
165 $rules[$action] = array();
166
167 foreach ($ids as $id => $p)
168 {
169 if ($p !== '')
170 {
171 $rules[$action][$id] = ($p == '1' || $p == 'true') ? true : false;
172 }
173 }
174 }
175
176 $table->setRules($rules);
177 }
178 }
179
180 return true;
181 }
182
183 /**
184 * The event which runs before deleting a record
185 *
186 * @param FOFTable &$table The table which calls this event
187 * @param integer $oid The PK value of the record to delete
188 *
189 * @return boolean True to allow the deletion
190 */
191 public function onBeforeDelete(&$table, $oid)
192 {
193 // If tracking assets, remove the asset first.
194 if ($table->isAssetsTracked())
195 {
196 $k = $table->getKeyName();
197
198 // If the table is not loaded, let's try to load it with the id
199 if(!$table->$k)
200 {
201 $table->load($oid);
202 }
203
204 // If I have an invalid assetName I have to stop
205 try
206 {
207 $name = $table->getAssetName();
208 }
209 catch(Exception $e)
210 {
211 $table->setError($e->getMessage());
212 return false;
213 }
214
215 // Do NOT touch JTable here -- we are loading the core asset table which is a JTable, not a FOFTable
216 $asset = JTable::getInstance('Asset');
217
218 if ($asset->loadByName($name))
219 {
220 // Since we are using JTable, there is no way to mock it and test for failures :(
221 // @codeCoverageIgnoreStart
222 if (!$asset->delete())
223 {
224 $table->setError($asset->getError());
225
226 return false;
227 }
228 // @codeCoverageIgnoreEnd
229 }
230 else
231 {
232 // I'll simply return true even if I couldn't load the asset. In this way I can still
233 // delete a broken record
234 return true;
235 }
236 }
237
238 return true;
239 }
240 }
241