TYPO3. Passing objects as arguments in FLUID View Helpers - parameter-passing

In the following code booksis a list of book object containing certain properties. And by clicking on the title, it goes to an action display
Fluid template is
<f:for each="books" as="book">
<f:link.action action="display" arguments="{book: book}"> {book.title} </f:link.action>
</f:for>
In controller
public function displayAction(){
print_r($this->request->getArguments());
}
The value of book here is not being set. [book] => null. I try printing the class of it, it still gives me null.
It works fine when I send the arguments as book.title instead of the entire object
What am I missing here? Is this the right way to pass objects as arguments ?
EDIT:
Initially I tried this way.
public function displayAction(\TYPO3\MyExt\Domain\Model\Book $book) {}
But this gives me
Exception while property mapping at property path "":No converter found which can be used to convert from "string" to "TYPO3\MyExt\Domain\Model\Book"
The class Book is something which I created manually and is not registered under extension builder.

You could try it with a parameter for the action:
public function myAction(Tx_MyExt_Domain_Model_Book $book) {
$this->view->assignMultiple(array(
'title' => $book->getTitle(),
'label' => $book->getLabel(),
'content' => $book->getContent()
));
}
EDIT: I updated the example.
Update:
It works with book.title because it's just a string. When you want a complete book object it needs to be found in some storage. A database e.g.. Hence that means you need a model and a repository. Also an entry in the tca and the tables files. Better create your Models with the extension builder, it's much easier and safer for the beginning.

Related

GetX - How to wrap custom class in Obx

In GetX, a Widget can be easily wrapped with in the widget tree like this:
Obx (() => Container(//observable stuff in here //)),
However I have an object of a custom type that also returns a widget but cannot be wrapped in Obx. I cannot declare it as a Widget because constructor fields can't be accessed when using Widget as a generic type. I need to access object fields for logic purposes.
For example:
Widget test = MyCustomWidget ({myBool: false, otherStuff: 'bla'});
test.myBool // DOESN'T WORK, CAN'T ACCESS
BUT
MyCustomWidget test = MyCustomWidget ({myBool: false, otherStuff: 'bla'});
test.myBool // DOES WORK -< This is what I need access to.
However
Obx(() => test)
// DOESNT WORK : A value of Obx cannot be assigned to type MyCustomWidget
// if cast: type 'Obx' is not a subtype of type 'MyCustomWidget'
My Questions:
Is there a way to wrap widgets declared as their types with Obx
If not, is there a way to access the constructor fields of an object declared as Widget
As stated above, I need access to a custom widget's fields for logic to avoid huge boilerplate and dirty code.
Cheers

CakePHP static name of controller

I'm probably missing something really obvious here, but is there a function in CakePHP (I'm on 3.8) that returns the name of a controller without creating an instance of the class?
An instanced controller can call this function:
echo $this->name;
But what I'd like to be able to do, is avoid typing the controller name as a string in, say, an HTML->link(); ie a static call something like:
echo $this->Html->link(
'Dashboard',
['controller' => DashboardsController::name, 'action' => 'index']
);
The reason is that I'm refactoring a couple of controllers and am having to find and replace all of those strings by hand. I come from a .Net background and CakePHP is pretty new to me, so if there's a better (more cakeish) way to carry out the refactoring than the question I'm asking, then I'd be really glad to hear it.
Nothing in the documents is leaping out at me, but I've a feeling there should be a simple answer.
The namespace of a class can be retrieved using ::class property. Checkout the following example:
DashboardsController::class // Cake/Controllers/DashboardController
The name without the namespace can be retrieved with ReflectionClass:
$function = new \ReflectionClass(DashboardsController::class);
var_dump($function->inNamespace());
var_dump($function->getShortName());
Shortname can be used to get the class without namespace:
namespace App;
class Test {
public static function name(){
$function = new \ReflectionClass(self::class);
return $function->getShortName();
}
}
var_dump(Test::name());
Checkout the docs: https://www.php.net/manual/en/language.oop5.constants.php#example-186
Reflection: https://www.php.net/manual/en/reflectionclass.getname.php

Meaning of Yii::$app->user->identity->role->role_name;

In a book called Yii2 for Beginners, which is mainly about the advanced template, I have encountered the following unexplained code, which seems relevant to RBAC:
$userHasRoleName = Yii::$app->user->identity->role->role_name;
What exactly does this mean? For example, I guess that this:
Yii::$app->user
refers to this file:
vendor\yiisoft\yii2\web\User.php
Is this correct?
In any case, what does the rest of the code refer to? Specifically:
->identity->role->role_name
In the above User.php file, I have not been able to find anything like "function identity()", so it can't be that. I have found numerous $identity variables, but I don't know which one the code might be referring to. And there is no $role variable at all.
What is this code referring to:
Yii::$app->user->identity->role->role_name;
Yii described magic methods like __get, __set and so on, to get access for inaccessible properties. Oftenly such methods begins from get or set (in Yii implementation it is). To get access to ->identity, \yii\web\User has method getIdentity. This method return identity wich you described in config with identityClass property for user component. Oftenly identityClass is a AR model which implements IdentityInterface.
'components' => [
'user' => [
'identityClass' => 'common\models\User',
]
]
To get access to ->role for example you must to create a new method
namespace common\models;
class User extends ActiveRecord implements IdentityInterface {
public function getRole(){
// if user can have only one role
return current( \Yii::$app->authManager->getRolesByUser( $this->id ) );
}
}
Btw implementation of ->role->role_name may be very different.

How to pass viewData back to the controller from partial view?

I have a main view using several partial Views.
Each of these partials use a different model and have post action.
My problem is I need one property from my main view's model to be used in one of my partials.
The partial view which I need to pass this property view is the last stage in the process.
The application reaches a partial view that contains a switch statement , based on the status on the item being queried, decides which partial will be rendered.
I have the property passing that far and even have it included in the Renderaction for the partial but I don't know how to retrieve it in the controller, PartialViewResult.
In the main view:
#{Html.RenderPartial("StatusForm", Model.HeadingDataModel.Status, new ViewDataDictionary { { "PurchaseOrderNumber", Model.AccordionModel.LtsSpecific.PurchaseOrderNumber } });}
PurchaseOrderNumber is what I'm after. The value gets passed to the next stage:
#{
var obj = ViewData["PurchaseOrderNumber"];
}
And within the same view:
Html.RenderAction("FinishedCalibrationForm", obj);
How can I retreive this in my controller ?? The following is not correct I know, but you get the idea.
public PartialViewResult FinishedCalibrationForm( string obj)
All help is appreciated.
Calling Html.RenderAction or Html.Action is largely the same as Url.Action. There's many different overloads, but essentially, the first parameter is the action name, the second parameter is going to be either the controller name or an anonymous object of route values, and the third parameter will be an anonymous object of route values if the second parameter was used for the controller name.
Anyways, whatever you pass in the route values will be used to find and call the associated action, which includes parameters for the action. So, for your example:
Html.RenderAction("FinishedCalibrationForm", new { obj = obj })
Would properly pass obj into your action method. As you have it now, it's going to interpret the value of obj as the controller name the action is within, which is obviously not correct.

Laravel - Eloquent: Polymorphic relations with namespace

My situation is: a Calendar belongs to a Customer or Salesman
Because I also have classes like Event and File, I used the namespace App\Models for all my model classes.
so I set up the polymorphic relation:
in Calender.php
public function user() {
return $this->morphTo();
}
in Customer.php and Salesman.php
public function calendars() {
return $this->morphMany('App\Models\Calendar', 'user');
}
Now when i do
$calendar= Calendar::find(1); //calendar from a salesman
$calendar->user; //error here
...
I get this error message:
Symfony \ Component \ Debug \ Exception \ FatalErrorException
Class 'salesman' not found
I noticed that 'salesman' is low cased, maybe this is the problem?
and this is what I get from Laravels stacktrace
open: /var/www/cloudcube/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php
// foreign key name by using the name of the relationship function, which
// when combined with an "_id" should conventionally match the columns.
if (is_null($foreignKey))
{
$foreignKey = snake_case($relation).'_id';
}
$instance = new $related; //HIGHLIGHTED
I had a similar error before on this line, when I was messing with the namespaces, so I guess it has something to do with that. Is there any way I can tell the morphTo() method to use the correct namespace?
Or is it something else causing this issue?
Also found this solution, but can't seem to get it working:
Polymorphic Eloquent relationships with namespaces
I found a solution that worked for me.
I always define relationships with the correct namespace, for example in Calendar:
public function events() {
return $this->hasMany('App\Models\Event');
}
My problem consisted out of 2 complications:
$calendar->user() with the morphTo(...) function was not working because my models were in a namespace, and morphTo(...) had no way of giving this namespace.
$salesman->calenders()->get() returned and empty list, although my relations in the database were there. I found out this is because of bindings with the query.
Solution for 1. : Writing a custom morphTo(...) function in Calendar to override the one of Laravel. I used the source of Laravels morphTo(...) as a base. The final statement of this function is return $this->belongsTo($class, $id);
There $class must be the namespaced class name. I used basic string operations to pull that off.
Solution for 2. : Writing a custom morphMany(...) function in Salesman and letting it return a MyMorphMany(...) similar to what Polymorphic Eloquent relationships with namespaces described.
The problem here is that $query that is passed to the MyMorphMany constructor has the wrong (namespaced) binding. It will look for where user_type = "App\\Models\\Salesman".
To fix this I used a custom getResults() function in MyMorphMany which overrides the default Laravels implementation, there I changed the bindings to use the correct, un-namespaced lower cased, class name. Then I called this getResults() function in the get() function of the MyMorphMany class.
I used $query->getBindings() and $query->setBindings() to correct the bindings.
Hope this saves someone else a few days of work, like it would have saved me :)