How to access markup twig variable from code in OctoberCMS - laravel

I'm trying to access variable from markup (Twig) in octoberCMS code module. This variable is printed in loop by plugin builder.
I have this variable in markup:
{% set frontId = record.id %}
{{frontId}}
And I want to access {{frontId}} variable it in code module.
function onStart()
{
$this["slots"] = Db::table('oblikovanje_izobrazevanja_vnos')->where('id', $frontId)->value('free_slots');
echo $frontId;
}

Hmm, unfortunately you can not pass variables from Markup to Code section. Because Code section as whole executed before Markup so you can not do that.
It seems you are using Builder's Record details component so you must be passing :id from url
Solution 1 [ use param ]
function onStart() { // you can use onEnd as well
$frontId = $this->param('id'); // this will get :id param from url
// now slots variable are available in `Markup section`
$this["slots"] = Db::table('oblikovanje_izobrazevanja_vnos')->where('id', $frontId)->value('free_slots');
}
Solution 2 [ you can use global component array with its alias name, make sure to use onEnd life-cycle hook ]
function onEnd () { // you must use onEnd as at this moment all components are initialized properly
// we can access component from $this->components with alias name and get its details
$frontId = $this->components['builderDetails']->record->id;
// now slots variable are available in `Markup section`
$this["slots"] = Db::table('oblikovanje_izobrazevanja_vnos')->where('id', $frontId)->value('free_slots');
}
Reference Screenshot
if any doubts please comment.

Related

Cakephp 3 View variables set in App controller not available when rendering specific template / AJAX requests

I am setting few view variables within my App controller such as company name, address, contact information which changes based on sub domains so that they are available throughout all view templates. However I am struggling to identify why the are not available when making ajax request.
//App Controller beforeFilter
$this->set('company', 'Test Company');
$this->set('address', '14 Test Street, Test, TE5 3ST');
$this->set('email', 'test#test.com');
Above variable are available for all none ajax i.e when I am not rendering specific template request however for below example request I am not able to access those variables in test_data template.
function _ajaxGetTestData()
{
$view = new View();
$content = $view->render('Home/Ajax/test_data');
$response['content'] = $content;
$response['success'] = TRUE;
$this->set(compact('response'));
$this->set('_serialize', ['response']);
}
That is because you did not serialize the variables from the app controller.
You can try in your method:
$response['company'] = $company;
$response['address'] = $address;
$response['email'] = $email;
Or https://book.cakephp.org/3/en/views/json-and-xml-views.html#using-a-data-view-with-template-files
You have to set view variables before render is called.
$this->set('data');
$this->render('custom_view');
When you call $this->set it sets the view variables on the Controller class. These variables are eventually passed to the View Builder, which creates a new View class and returns a Result containing the HTML for this new View.
When you want to render your own View manually you need to pass it the view variables manually too - $this->set isn't setting view variables in this new View class you created here:
$view = new View();
$content = $view->render('Home/Ajax/test_data'); // Has nothing to do with $this->set, you'd have to pass the variables in manually
This isn't generally the simplest approach to take to render an AJAX view.
While you can generally continue to use $this->set in beforeFilter as you already are:
public function beforeFilter(Event $event)
{
$this->set('company', 'Test Company');
$this->set('address', '14 Test Street, Test, TE5 3ST');
$this->set('email', 'test#test.com');
}
.. the easiest method to make an AJAX-compatible is to enable the JSON/XML handler let the built-in JSON/XML renderers do their magic.
In the action function (index/view/edit/whatever) just include the company/address/email in the _serialize variable.
For example, a "view" function might look like:
public function view($id = null)
{
// Do regular view stuff:
$entity = $this->MyTable->get($id);
$this->set('entity', $entity);
// Include ALL the variables you want in the response in _serialize:
$this->set('_serialize', ['entity', 'company','address', 'email']);
}
If you are sure you need a custom template (which isn't required), don't render it manually, just set the template when AJAX is detected:
if($this->request->is('ajax')){
$this->viewBuilder()->setTemplate('Home/Ajax/test_data');
}
This will automatically be rendered for you, using the variables you set with $this->set.
If you want to make a global custom template (for example, wrapping all your data with a "response" node), for all AJAX requests, use a new Layout instead of a custom template:
if($this->request->is('ajax')){
$this->viewBuilder()->setLayout('custom_json');
}
Create this layout in src/Template/Layout/custom_json.ctp and format it as you wish, for example:
<?php
/**
* #var \App\View\AppView $this
*/
?>
{"response": <?= $this->fetch('content') ?> }
See from docs:
Enabling Data Views https://book.cakephp.org/3/en/views/json-and-xml-views.html#enabling-data-views-in-your-application
Using the _serialize Key https://book.cakephp.org/3/en/views/json-and-xml-views.html#using-data-views-with-the-serialize-key
Custom Layouts https://book.cakephp.org/3/en/views.html#layouts

How to route an dynamic url?

I am new to laravel. I am defining this route to an edit button:
<button class="btn btn-primary">Edit task</button>
The url is generated fine but the page is not found. I am returning a view with my TaskController#edit with this route:
Route::get('/editTasks/{{ $task->id }}', 'TaskController#edit');
Can someone help me out figuring what i am doing wrong?
When defining routes, the route parameters should only have one { around them. Also, you should not use a variable in the declaration but a name for the variable.
In your example, this could be a valid declaration:
Route::get('/editTasks/{id}', 'TaskController#edit');
More information can be found in the docs: https://laravel.com/docs/5.7/routing#route-parameters
It is also recommended to use route names, so the url can be automatically generated.
For example:
// Route declaration
Route::get('/editTasks/{id}', 'TaskController#edit')->name('tasks.edit');
// In view
Edit task
no you have to define in your route just like this :
Route::get('/editTasks/{id}', 'TaskController#edit');
you don't have $task in your route and you dont need to write any other thing in your route. in your controller you can access to this id like this :
public function edit($taskId) {
}
and only you do this
You need to use single { instead of double, so it needs to be the following in your route:
Route::get('/editTasks/{taskId}', 'TaskController#edit');
And in your edit function:
public function edit($taskId) { }
The double { in the template is correct as this indicates to retrieve a variable
Extra information/recommendation:
It is recommended to let the variable name in the route match the variable in your function definition (as shown above), so you always get the expected variable in your function. If they do not match Laravel will use indexing to resolve the variable, i.e. if you have multiple variables in your route pattern and only use one variable in the function it will take your first route parameter even if you might want the second variable.
Example:
If you have a route with the pattern /something/{var1}/something/{var2} and your function is public function test($variable2) it would use var1 instead of var2. So it it better to let these names match so you always get the expected value in your function.
It's better to use "Route Model Binding". Your route should be like this:
Route::get('/editTasks/{task}', 'TaskController#edit');
And in Controller use something like this:
public function edit($task){
}

How do I send data to partial views from controller in laravel?

I have setup my navigation menu from a ViewComposer (see laravel view composers: https://laravel.com/docs/5.6/views#view-composers) like this
View::composer('partials.nav', function ($view) {
$view->with('menu', Nav::all());
});
What I need is that from some controllers to setup which navigation item is active, ie "current section".
Question:
How do I send from some controllers a variable to "partials.nav" like currentNavItem?
Do I send it with the rest of the variables for returned view?
like
return view('page.blade.php",$viewVariables + $optionalVariablesForPartialsViews);
It looks spammy
Side notes:
I use laravel 5.6
Later edit
It looks Laravel 5.1 : Passing Data to View Composer might be an options. I will try and get back .
Because the $variable you want to send differs in different controller's actions yes you need to specify the $variable
return view('page.blade.php",$viewVariables,$variablesForPartialsViews);
of course you might need to set a default value for the $variable in order to avoid undefined variable error
You should handle the parameters.
for exemple:
public function compose(View $view)
{
$view->with('page', $this->getPage());
}
public function getPage()
{
$viewVariables = 2;
$optionalVariablesForPartialsViews = 1;
return $viewVariables + $optionalVariablesForPartialsViews;
}
Under your app folder make a class named yourClassNameFacade. Your class would look like this.
class yourClassNameFacade extends Facade
{
protected static function getFacadeAccessor()
{
return 'keyNameYouDecide';
}
}
Then go to the file app/Providers/AppServiceProvider.php and add to the register function
public function register()
{
$this->app->bind('keyNameYouDecide', function (){
//below your logic, in my case a call to the eloquent database model to retrieve all items.
//but you can return whatever you want and its available in your whole application.
return \App\MyEloquentClassName::all();
});
}
Then in your view or any other place you want it in your application you do this to reference it.
view is the following code:
{{ resolve('keyNameYouDecide') }}
if you want to check what is in it do this:
{{ ddd(resolve('keyNameYouDecide')) }}
anywhere else in your code you can just do:
resolve('keyNameYouDecide'))

How to build an anchor in CodeIgniter where you want to change a variable that is already present in the URI?

Normally I would just use URL GET parameters but CodeIgniter doesn't seem to like them and none of the URL helper functions are designed for them, so I'm trying to do this the 'CodeIgniter way'.
I would like to build a page where the model can accept a number of different URI paramters, none necessarily present, and none having to be in any particular order, much like a regular URL query string with get parameters.
Let's say I have the following url:
http://example.com/site/data/name/joe/
Here not including the controller or the method there would be one parameter:
$params = $this->uri->uri_to_assoc(1);
print_r($params);
// output
array( [name] => [joe] )
If I wanted 'joe' to change to 'ray' I could do this:
echo anchor('name/ray');
Simple enough but what if there are more parameters and the position of the parameters are changing? Like:
http://example.com/site/data/town/losangeles/name/joe/
http://example.com/site/data/age/21/name/joe/town/seattle
Is there a way to just grab the URL and output it with just the 'name' parameter changed?
Edit: As per landons advice I took his script and set it up as a url helper function by creating the file:
application/helpers/MY_url_helper.php
Basically I rewrote the function current_url() to optionally accept an array of parameters that will be substituted into the current URI. If you don't pass the array the function acts as originally designed:
function current_url($vars = NULL)
{
$CI =& get_instance();
if ( ! is_array($vars))
{
return $CI->config->site_url($CI->uri->uri_string());
}
else
{
$start_index = 1;
$params = $CI->uri->uri_to_assoc($start_index);
foreach ($vars as $key => $value)
{
$params[$key] = $value;
}
$new_uri = $CI->uri->assoc_to_uri($params);
return $CI->config->site_url($new_uri);
}
}
It works OK. I think the bottom line is I do not like the 'CodeIgniter Way' and I will be looking at mixing segment based URL's with querystrings or another framework altogether.
You can use the assoc_to_uri() method to get it back to URI format:
<?php
// The segment offset to use for associative data (change me!)
$start_index = 1;
// Parse URI path into associative array
$params = $this->uri->uri_to_assoc($start_index);
// Change the value you want (change me!)
$params['name'] = 'ray';
// Convert back to path format
$new_uri = $this->uri->assoc_to_uri($params);
// Prepend the leading segments back to the URI
for ($i=1; $i<$start_index; $i++)
{
$new_uri = $this->uri->segment($i).'/'.$new_uri;
}
// Output anchor
echo anchor($new_uri);
I'd recommend wrapping this in a helper function of some sort. Happy coding!
Why not use CodeIgniter's built in URI Class? It allows you to select the relevant segments from the URL which you could use to create the anchor. However, unless you created custom routes, it would mean that your methods would need to accept more parameters.
To use the URI Class, you would have the following in your method:
echo anchor($this->uri->segment(3).'/ray');
Assuming /site/data/name are all CodeIgniter specific (/controller/method/parameter)
Now, I think this could be made a lot easier if you were using routes. Your route would look like this:
$route['site/data/name/(:any)'] = 'site/data/$1';
Effictively, your URL can be as detailed and specific as you want it to be, but in your code the function is a lot cleaner and the parameters are quite descriptive. You method would defined like this:
function data($name) { }
To extend your route to accept more parameters, your route for the the example URL "http://example.com/site/data/age/21/name/joe/town/seattle" you supplied would look like this:
$route['site/data/age/(:num)/name/(:any)/town/(:any)'] = 'controller/data/$1/$2/$3';
And your function would look like this:
function data($age, $name, $town) { }

Extjs 4 MVC loading a view from controller

Ok so I have a controller with a method in which I want to load a view.
How do I load a view from a controller?
How do I pass some parameters from the controller to the view when I load it?
Any help is much appreciated.
To load a view, you can use Ext.widget(). Use Ext.define() to create a view in your view file. I would recommend using the alias property to define an inline xtype for the view.
When you need to load the view, you create an view using Ext.widget() and specify the xtype (alias for your view). Here is an example:
// define a window
Ext.define('MyApp.view.user.Add',
extend: 'Ext.window.Window',
alias : 'widget.adduser',
.
. // Add other properties, custom properties, methods, event handlers etc..
});
Now, when you want to create an instance in your user controller, you do:
// create an instance
var view = Ext.widget('adduser'); // refer the below note!
Note: note that there is no 'widget.'! it automatically gets added to the widget name you pass.
Now, taking about passing parameters. Like Ext.create method, you should be able to pass any parameters as:
// create an instance with params
var view = Ext.widget('adduser', {title: 'New User title'});
Regarding ref: refs help you in getting references to Views on your page. They do not help in creating an instance or load a view. If you have your view rendered, you can make use of the ref system to get hold of that instance and manipulate the view. You need to make use of the ComponentQuery to get reference of your view.
refs can be used to create new instances as well as access existing ones. By adding the option autoCreate: true to your ref, a call to the getter will result in a new instance being created using the ref definition as its config if no existing component matches the selector.
refs: [{
ref: 'list'
,selector: 'myusersgrid#users'
,autoCreate: true
// any additional options get passed as config when an instance needs to be created
,xtype: 'myusersgrid'
,itemId: 'users'
,store: 'Users'
,title: 'Users'
},{
ref: 'otherList'
,selector: 'myusersgrid#administrators'
,autoCreate: true
// any additional options get passed as config when an instance needs to be created
,xtype: 'myusersgrid'
,itemId: 'administrators'
,store: 'SpecialUsers'
,title: 'Special Users'
}],
Notice the use of the # to additionally match the itemId so I could have refs to multiple instances of the same xtype
There's also a forceCreate: true option which will make the ref's getter always return a new instance, without it autoCreate will create one instance the first time it's retrieved and then keep returning the same one.
If I understand your question I think you want to use refs, take a look at the docs for Ext.app.Controller: http://dev.sencha.com/deploy/ext-4.0.0/docs/api/Ext.app.Controller.html
Basically you create a list of refs using css selectors:
refs: [
{
ref: 'list',
selector: 'grid'
}
],
Then later in the class you can access this ref by using get, i.e.:
refreshGrid: function() {
this.getList().store.load();
}
The getList() method is created for you when you create the ref to 'list'.
I ran into this same problem. I created a method on my abstract base controller to retrieve the view instance and create on if it does not exist.
This will work properly even after the view has been destroyed - a new one will be created.
Ext.define('My.controller.Base', {
extend: 'Ext.app.Controller',
//Retrieves an instance of the top-level view
//If it has not been created yet than one is instantiated
//Also, overrides the .close() method on the view to
//null out the instance reference on the controller (very necessary)
getViewInstance: function () {
var self = this;
if(!this.viewInstance) {
if(this.views && this.views.length) {
var view = this.getView(this.views[0]);
this.viewInstance = view.create();
this.viewInstance.close = function () {
view.prototype.close.apply(this, arguments);
self.viewInstance = null;
};
}
}
return this.viewInstance;
}
});
Now all my controllers can easily access their view from w/i controller code w/o any external variables.
Use Ext.create('Proper File Name to be opened',param1 = me);
In the newly created view, use this.param1 to access the parameters.
EG: Ext.create('view.HelloOverlay, param1 = "Hello", param2 = "World");
in the controller of HelloOverlay, using this.param1 will give "Hello" and this.param2 will give "World".
Sometimes the parameters passed will be present in the view so use this.getView().paramName

Resources