Skip to content

Commit 8ffeb32

Browse files
committed
FC for NS case update II.
1 parent 70cf56c commit 8ffeb32

File tree

226 files changed

+24377
-4
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

226 files changed

+24377
-4
lines changed

composer.json

+4-4
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151
"homepage": "https://xsystems.io/"
5252
}
5353
],
54-
"version": "2.3.2",
54+
"version": "2.3.5",
5555
"minimum-stability": "dev",
5656
"prefer-stable": true,
5757
"config": {
@@ -60,8 +60,8 @@
6060
"require": {
6161
"php": ">=7.3.0",
6262
"ext-json": "*",
63-
"atk4/core": "~2.3.2",
64-
"atk4/data": "~2.3.2"
63+
"atk4/core": "~2.3.5",
64+
"atk4/data": "~2.3.5"
6565
},
6666
"require-dev": {
6767
"behat/behat": "^3.4",
@@ -78,7 +78,7 @@
7878
"autoload": {
7979
"psr-4": {
8080
"atk4\\ui\\": "src/",
81-
"Atk4\\Ui\\": "src/"
81+
"Atk4\\Ui\\": "srcAtk4/"
8282
}
8383
},
8484
"autoload-dev": {

srcAtk4/AbstractView.php

+212
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Atk4\Ui;
6+
7+
use atk4\core\AppScopeTrait;
8+
use atk4\core\ContainerTrait;
9+
use atk4\core\DiContainerTrait;
10+
use atk4\core\FactoryTrait;
11+
use atk4\core\InitializerTrait;
12+
use atk4\core\StaticAddToTrait;
13+
use atk4\core\TrackableTrait;
14+
15+
/**
16+
* Abstract view tree item (used only for View and Callback, you want probably to extend one of these).
17+
*
18+
* @property View $owner
19+
* @property View[] $elements
20+
*/
21+
abstract class AbstractView
22+
{
23+
use ContainerTrait {
24+
add as private _add;
25+
}
26+
use InitializerTrait {
27+
init as private _init;
28+
}
29+
use TrackableTrait;
30+
use AppScopeTrait;
31+
use FactoryTrait;
32+
use DiContainerTrait;
33+
use StaticAddToTrait;
34+
35+
/**
36+
* Default name of the element.
37+
*
38+
* @var string
39+
*/
40+
public $defaultName = 'atk';
41+
42+
/**
43+
* If add() method is called, but current view is not part of render tree yet,
44+
* then arguments to add() are simply stored in this array. When the view is
45+
* initialized by calling init() or adding into App or another initialized View,
46+
* then add() will be re-invoked with the contents of this array.
47+
*
48+
* @var array
49+
*/
50+
protected $_add_later = [];
51+
52+
/**
53+
* will be set to true after rendered. This is so that we don't render view twice.
54+
*
55+
* @var bool
56+
*/
57+
protected $_rendered = false;
58+
59+
// }}}
60+
61+
// {{{ Default init() method and add() logic
62+
63+
/**
64+
* For the absence of the application, we would add a very
65+
* simple one.
66+
*/
67+
protected function initDefaultApp()
68+
{
69+
$this->app = new App([
70+
'skin' => $this->skin,
71+
'catch_exceptions' => false,
72+
'always_run' => false,
73+
'catch_runaway_callbacks' => false,
74+
]);
75+
$this->app->invokeInit();
76+
}
77+
78+
/**
79+
* Called when view becomes part of render tree. You can override it but avoid
80+
* placing any "heavy processing" here.
81+
*/
82+
protected function init(): void
83+
{
84+
if (!$this->app) {
85+
$this->initDefaultApp();
86+
}
87+
88+
if ($this->name === null) {
89+
$this->name = $this->defaultName;
90+
}
91+
92+
$this->_init();
93+
94+
// add default objects
95+
foreach ($this->_add_later as [$object, $args]) {
96+
$this->add($object, $args);
97+
}
98+
$this->_add_later = [];
99+
}
100+
101+
/**
102+
* @param AbstractView $object
103+
*/
104+
public function add($object, $args = null): self
105+
{
106+
(self::class)::assertInstanceOf($object);
107+
108+
if (func_num_args() > 2) { // prevent bad usage
109+
throw new \Error('Too many method arguments');
110+
} elseif ($this->_rendered) {
111+
throw new Exception('You cannot add anything into the view after it was rendered');
112+
}
113+
114+
if (!$this->app) {
115+
$this->_add_later[] = [$object, $args];
116+
117+
return $object;
118+
}
119+
120+
// will call init() of the object
121+
$this->_add($object, $args);
122+
123+
return $object;
124+
}
125+
126+
// }}}
127+
128+
// {{{ Sticky URLs
129+
130+
/** @var string[] stickyGet arguments */
131+
public $stickyArgs = [];
132+
133+
/**
134+
* Build an URL which this view can use for js call-backs. It should
135+
* be guaranteed that requesting returned URL would at some point call
136+
* $this->invokeInit().
137+
*
138+
* @param array $page
139+
*
140+
* @return string
141+
*/
142+
public function jsUrl($page = [])
143+
{
144+
return $this->app->jsUrl($page, false, $this->_getStickyArgs());
145+
}
146+
147+
/**
148+
* Build an URL which this view can use for call-backs. It should
149+
* be guaranteed that requesting returned URL would at some point call
150+
* $this->invokeInit().
151+
*
152+
* @param string|array $page URL as string or array with page name as first element and other GET arguments
153+
*
154+
* @return string
155+
*/
156+
public function url($page = [])
157+
{
158+
return $this->app->url($page, false, $this->_getStickyArgs());
159+
}
160+
161+
/**
162+
* Get sticky arguments defined by the view and parents (including API).
163+
*/
164+
protected function _getStickyArgs(): array
165+
{
166+
if ($this->owner && $this->owner instanceof self) {
167+
$stickyArgs = array_merge($this->owner->_getStickyArgs(), $this->stickyArgs);
168+
} else {
169+
$stickyArgs = $this->stickyArgs;
170+
}
171+
172+
/** @var self $childView */
173+
$childView = $this->mergeStickyArgsFromChildView();
174+
if ($childView !== null && (!($childView instanceof Callback) || $childView->isTriggered())) {
175+
$alreadyCalled = false;
176+
foreach (debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT | DEBUG_BACKTRACE_IGNORE_ARGS) as $frame) {
177+
if ($childView === ($frame['object'] ?? null) && $frame['function'] === '_getStickyArgs') {
178+
$alreadyCalled = true;
179+
}
180+
}
181+
182+
if (!$alreadyCalled) {
183+
$stickyArgs = array_merge($stickyArgs, $childView->_getStickyArgs());
184+
}
185+
}
186+
187+
return $stickyArgs;
188+
}
189+
190+
protected function mergeStickyArgsFromChildView(): ?self
191+
{
192+
return null;
193+
}
194+
195+
/**
196+
* Mark GET argument as sticky. Calling url() on this view or any
197+
* sub-views will embedd the value of this GET argument.
198+
*
199+
* If GET argument is empty or false, it won't make into URL.
200+
*
201+
* If GET argument is not presently set you can specify a 2nd argument
202+
* to forge-set the GET argument for current view and it's sub-views.
203+
*/
204+
public function stickyGet(string $name, string $newValue = null): ?string
205+
{
206+
$this->stickyArgs[$name] = $newValue ?? $_GET[$name] ?? null;
207+
208+
return $this->stickyArgs[$name];
209+
}
210+
211+
// }}}
212+
}

0 commit comments

Comments
 (0)