Completed
Push — master ( af6f2f...54d848 )
by Jean-Christophe
01:36
created

UbiquityMyAdminBaseController::getSingleton()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 6
rs 9.4285
cc 2
eloc 4
nc 2
nop 2
1
<?php
2
namespace micro\controllers\admin;
3
use Ajax\service\JString;
4
use Ajax\semantic\html\elements\HtmlHeader;
5
use Ajax\semantic\html\elements\HtmlButton;
6
use micro\orm\DAO;
7
use micro\orm\OrmUtils;
8
use micro\orm\parser\Reflexion;
9
use micro\controllers\Startup;
10
use micro\controllers\Autoloader;
11
use micro\controllers\admin\UbiquityMyAdminData;
12
use controllers\ControllerBase;
13
14
class UbiquityMyAdminBaseController extends ControllerBase{
15
	private $adminData;
16
	private $adminViewer;
17
18
	public function index(){
19
		$semantic=$this->jquery->semantic();
20
		$dbs=$this->getTableNames();
21
		$menu=$semantic->htmlMenu("menuDbs");
22
		$menu->setVertical()->setInverted();
23
		foreach ($dbs as $table){
24
			$model=$this->getModelsNS()."\\".ucfirst($table);
25
			$file=\str_replace("\\", DS, ROOT . DS.$model).".php";
26
			$find=Autoloader::tryToRequire($file);
27
			if ($find){
28
				$count=DAO::count($model);
29
				$item=$menu->addItem(ucfirst($table));
30
				$item->addLabel($count);
31
				$item->setProperty("data-ajax", $table);
32
			}
33
		}
34
		$menu->getOnClick("Admin/showTable","#divTable",["attr"=>"data-ajax"]);
35
		$menu->onClick("$('.ui.label.left.pointing.teal').removeClass('left pointing teal');$(this).find('.ui.label').addClass('left pointing teal');");
36
		$this->jquery->compile($this->view);
37
		$this->loadView("Admin/index.html");
38
	}
39
40
	public function showTable($table){
0 ignored issues
show
Coding Style introduced by
showTable uses the super-global variable $_SESSION which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
41
		$_SESSION["table"]= $table;
42
		$semantic=$this->jquery->semantic();
43
		$model=$this->getModelsNS()."\\".ucfirst($table);
44
45
		$datas=DAO::getAll($model);
46
		$lv=$semantic->dataTable("lv", $model, $datas);
47
		$attributes=$this->getFieldNames($model);
48
49
		$lv->setCaptions(array_map("ucfirst", $attributes));
50
		$lv->setFields($attributes);
51
		$lv->onPreCompile(function() use ($attributes,&$lv){
52
			$lv->getHtmlComponent()->colRight(\count($attributes));
53
		});
54
55
		$lv->setIdentifierFunction($this->getIdentifierFunction($model));
56
		$lv->getOnRow("click", "Admin/showDetail","#table-details",["attr"=>"data-ajax"]);
57
		$lv->setUrls(["delete"=>"Admin/delete","edit"=>"Admin/edit"]);
58
		$lv->setTargetSelector(["delete"=>"#table-messages","edit"=>"#table-details"]);
59
		$lv->addClass("small very compact");
60
		$lv->addEditDeleteButtons(false,["ajaxTransition"=>"random"]);
61
		$lv->setActiveRowSelector("error");
62
63
		$this->jquery->compile($this->view);
64
		$this->loadView("admin\showTable.html",["classname"=>$model]);
65
	}
66
67
	public function edit($ids){
68
		$instance=$this->getModelInstance($ids);
69
		$this->getAdminViewer()->getForm($instance);
70
		$this->jquery->click("#bt-okay","$('#frmEdit').form('submit');");
71
		$this->jquery->click("#bt-cancel","$('#form-container').transition('drop');");
72
		$this->jquery->compile($this->view);
73
		$this->loadView("admin/editTable.html");
74
	}
75
76
	public function update(){
0 ignored issues
show
Coding Style introduced by
update uses the super-global variable $_POST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
77
		\var_dump($_POST);
0 ignored issues
show
Security Debugging Code introduced by
\var_dump($_POST); looks like debug code. Are you sure you do not want to remove it? This might expose sensitive data.
Loading history...
78
	}
79
80
	private function getIdentifierFunction($model){
81
		$pks=$this->getPks($model);
82
		return function($index,$instance) use ($pks){
83
			$values=[];
84
			foreach ($pks as $pk){
85
				$getter="get".ucfirst($pk);
86
				if(method_exists($instance, $getter)){
87
					$values[]=$instance->{$getter}();
88
				}
89
			}
90
			return implode("_", $values);
91
		};
92
	}
93
94
	private function getPks($model){
95
		$instance = new $model();
96
		return OrmUtils::getKeyFields($instance);
97
	}
98
99
	private function getOneWhere($ids,$table){
100
		$ids=explode("_", $ids);
101
		if(sizeof($ids)<1)
102
			return "";
103
		$pks=$this->getPks(ucfirst($table));
104
		$strs=[];
105
		for($i=0;$i<sizeof($ids);$i++){
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function sizeof() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
106
			$strs[]=$pks[$i]."='".$ids[$i]."'";
107
		}
108
		return implode(" AND ", $strs);
109
	}
110
111
	private function getModelInstance($ids){
0 ignored issues
show
Coding Style introduced by
getModelInstance uses the super-global variable $_SESSION which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
112
		$table=$_SESSION['table'];
113
		$model=$this->getModelsNS()."\\".ucfirst($table);
114
		$ids=\explode("_", $ids);
115
		return DAO::getOne($model,$ids);
116
	}
117
118
	public function delete($ids){
0 ignored issues
show
Coding Style introduced by
delete uses the super-global variable $_POST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
119
		$instance=$this->getModelInstance($ids);
120
		if(method_exists($instance, "__toString"))
121
			$instanceString=$instance."";
122
		else
123
			$instanceString=get_class($instance);
124
		if(sizeof($_POST)>0){
125
			if(DAO::remove($instance)){
126
				$message=$this->showSimpleMessage("Suppression de `".$instanceString."`", "info","info",4000);
127
				$this->jquery->exec("$('tr[data-ajax={$ids}]').remove();",true);
128
			}else{
129
				$message=$this->showSimpleMessage("Impossible de supprimer `".$instanceString."`", "warning","warning");
130
			}
131
		}else{
132
			$message=$this->showConfMessage("Confirmez la suppression de `".$instanceString."`?", "", "Admin/delete/{$ids}", "#table-messages", $ids);
133
		}
134
		echo $message;
135
		echo $this->jquery->compile($this->view);
136
	}
137
138
	private function getFKMethods($model){
139
		$reflection=new \ReflectionClass($model);
140
		$publicMethods=$reflection->getMethods(\ReflectionMethod::IS_PUBLIC);
141
		$result=[];
142
		foreach ($publicMethods as $method){
143
			$methodName=$method->getName();
1 ignored issue
show
Bug introduced by
Consider using $method->name. There is an issue with getName() and APC-enabled PHP versions.
Loading history...
144
			if(JString::startswith($methodName, "get")){
145
				$attributeName=lcfirst(JString::replaceAtFirst($methodName, "get", ""));
146
				if(!property_exists($model, $attributeName))
147
					$result[]=$methodName;
148
			}
149
		}
150
		return $result;
151
	}
152
153
	private function showSimpleMessage($content,$type,$icon="info",$timeout=NULL){
154
		$semantic=$this->jquery->semantic();
155
		$message=$semantic->htmlMessage("msg-".rand(0,50),$content,$type);
156
		$message->setIcon($icon." circle");
157
		$message->setDismissable();
158
		if(isset($timeout))
159
			$message->setTimeout(3000);
160
		return $message;
161
	}
162
163
	private function showConfMessage($content,$type,$url,$responseElement,$data,$attributes=NULL){
164
		$messageDlg=$this->showSimpleMessage($content, $type,"help circle");
165
		$btOkay=new HtmlButton("bt-okay","Confirmer","positive");
166
		$btOkay->addIcon("check circle");
167
		$btOkay->postOnClick($url,"{data:'".$data."'}",$responseElement,$attributes);
168
		$btCancel=new HtmlButton("bt-cancel","Annuler","negative");
169
		$btCancel->addIcon("remove circle outline");
170
		$btCancel->onClick($messageDlg->jsHide());
171
172
		$messageDlg->addContent([$btOkay,$btCancel]);
173
		return $messageDlg;
174
	}
175
176
	public function showDetail($ids){
0 ignored issues
show
Coding Style introduced by
showDetail uses the super-global variable $_SESSION which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
177
		$hasElements=false;
178
		$instance=$this->getModelInstance($ids);
179
		$table=$_SESSION['table'];
180
		$model=$this->getModelsNS()."\\".ucfirst($table);
181
		$relations = OrmUtils::getFieldsInRelations($model);
182
		$semantic=$this->jquery->semantic();
183
		$grid=$semantic->htmlGrid("detail");
184
		if(sizeof($relations)>0){
185
		$wide=intval(16/sizeof($relations));
186
		if($wide<4)
187
			$wide=4;
188
			foreach ($relations as $member){
189
				if(OrmUtils::getAnnotationInfoMember($model, "#oneToMany",$member)!==false){
190
					$objectFK=DAO::getOneToMany($instance, $member);
0 ignored issues
show
Unused Code introduced by
$objectFK is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
191
				}if(OrmUtils::getAnnotationInfoMember($model, "#manyToMany",$member)!==false){
192
					$objectFK=DAO::getManyToMany($instance, $member);
193
				}else{
194
					$objectFK=Reflexion::getMemberValue($instance, $member);
195
				}
196
				$memberFK=$member;
197
198
				$header=new HtmlHeader("",4,$memberFK,"content");
199
				if(is_array($objectFK) || $objectFK instanceof Traversable){
0 ignored issues
show
Bug introduced by
The class micro\controllers\admin\Traversable does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
200
					$element=$semantic->htmlList("");
201
					$element->addClass("animated divided celled");
202
					$header->addIcon("folder");
203
					foreach ($objectFK as $item){
204
						if(method_exists($item, "__toString")){
205
							$element->addItem($item."");
206
							$hasElements=true;
207
						}
208
					}
209
				}else{
210
					if(method_exists($objectFK, "__toString")){
211
						$element=$semantic->htmlLabel("",$objectFK."");
212
						$header->addIcon("file outline");
213
					}
214
				}
215
				if(isset($element)){
216
					$grid->addCol($wide)->setContent($header.$element);
217
					$hasElements=true;
218
				}
219
			}
220
			if($hasElements)
221
				echo $grid;
222
		}
223
	}
224
225
	protected function getModelsNS(){
226
		return Startup::getConfig()["mvcNS"]["models"];
227
	}
228
229
	protected function getUbiquityMyAdminData(){
230
		return new UbiquityMyAdminData();
231
	}
232
233
	protected function getUbiquityMyAdminViewer(){
234
		return new UbiquityMyAdminViewer($this);
235
	}
236
237
	private function getSingleton($value,$method){
238
		if(!isset($value)){
239
			$value=$this->$method();
240
		}
241
		return $value;
242
	}
243
244
	/**
245
	 * @return UbiquityMyAdminData
246
	 */
247
	public function getAdminData(){
248
		return $this->getSingleton($this->adminData, "getUbiquityMyAdminData");
249
	}
250
251
	/**
252
	 * @return UbiquityMyAdminViewer
253
	 */
254
	public function getAdminViewer(){
255
		return $this->getSingleton($this->adminViewer, "getUbiquityMyAdminViewer");
256
	}
257
258
	protected function getTableNames(){
259
		return $this->getAdminData()->getTableNames();
260
	}
261
262
	protected function getFieldNames($model){
263
		return $this->getAdminData()->getFieldNames($model);
264
	}
265
}
266
267