TYPO3 returns "Array" to Fluid as String - arrays

I try to pass an array within my Viewhelper to the Fluidtemplate.
It always shows the string "Array". If I try to use it as parameter in the f:for each viewhelper, I get an exception because it is a string and not an array.
I used Typo3 6.2 before, now I have Typo3 7 and it stopped working.
public function render($uids) { // $uids='901,902,903'
$uidArray = explode(',', $uids);
$objectManager = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Extbase\\Object\\ObjectManager');
$repository = $objectManager->get('XXX\\X\\Domain\\Repository\\FooRepository');
$query = $repository->createQuery();
$query->getQuerySettings()->setRespectStoragePage(FALSE);
$query->matching(
$query->in('uid', $uidArray)
);
return $query->execute()->toArray();
}
This is my Fluid template:
{namespace vh=My/Namespace/ViewHelpers}
<f:for each="{vh:GetArray(uids: '901,902,903')}">...</f:for>

You cannot return an array with your viewhelper, because viewhelper always return strings.
You can however introduce a new variable to the current render context and then use this variable inside your viewhelper.
public function render() {
$returnArray = array('a' => 17, 'b' => 42);
$this->templateVariableContainer->add('returnArray', $returnArray);
$output = $this->renderChildren();
$this->templateVariableContainer->remove('returnArray');
return $output;
}
Inside your template you can then run a for loop over {returnArray}.

Try a combination of f:for and f:cycle in your Fluid template. See the f:cycle examples in the Fluid ViewHelper Reference.

Related

Validating array in Laravel using custom rule with additional parameter

I'm working with Laravel 5.7 and I need to validate a phone length by using 2 inputs (prefix+number). The total digits has to be 10 always.
I'm using this custom rule for other projects which works fine:
<?php
namespace App\Rules;
use Illuminate\Contracts\Validation\Rule;
class PhoneLength implements Rule
{
public $prefix;
/**
* Create a new rule instance.
*
* #return void
*/
public function __construct($prefix = null)
{
//
$this->prefix = $prefix;
}
/**
* Determine if the validation rule passes.
*
* #param string $attribute
* #param mixed $value
* #return bool
*/
public function passes($attribute, $value)
{
//
return strlen($this->prefix)+strlen($value) == 10 ? true : false;
}
/**
* Get the validation error message.
*
* #return string
*/
public function message()
{
return 'El Teléfono debe contener 10 dígitos (prefijo + número)';
}
}
In my controller I do something like
$validatedData = $request->validate([
'prefix' => 'integer|required',
'number' => ['integer','required', new PhoneLength($request->prefix)],
]);
Now I need to make use of arrays, so my new validation looks like
$validatedData = $request->validate([
'phones.*.prefix' => 'required',
'phones.*.number' => ['required', new PhoneLength('phones.*.prefix')],
]);
The above code doesn't work at all, the parameter is not being sent as expected.
How can I send an array value? Of course I need to get the values from the same array element, so if phones[0].number is under validation, the prefix phones[0].prefix is needed.
I've found this question, but I refuse to believe that is not possible to do in a "native" way:
Laravel array validation with custom rule
Thanks in advance
You could get $prefix from the request itself:
class PhoneLength implements Rule
{
public function passes($attribute, $value)
{
$index = explode('.', $attribute)[1];
$prefix = request()->input("phones.{$index}.prefix");
}
}
or pass the $request in the PhoneLength rule constructor, then use it.
The Abdeldayem Sherif's answer is good but there is a problem when the attribute has more level of nesting, for example: clients.*.phones.*.prefix. In this case, exploding and using the 1 index will cause an unexpected error. A better solution is using str_replace.
class PhoneLength implements Rule
{
public function passes($attribute, $value)
{
$prefixAttr = str_replace('.number', '.prefix', $attribute);
$prefix = request()->input($prefixAttr);
}
}
According to this https://github.com/laravel/framework/pull/18654 you can use, it will add your custom rule as dependent and replace asterix with needed indexes
Validator::extendDependent('contains', function ($attribute, $value, $parameters, $validator) {
// The $parameters passed from the validator below is ['*.provider'], when we imply that this
// custom rule is dependent the validator tends to replace the asterisks with the current
// indices as per the original attribute we're validating, so *.provider will be replaced
// with 0.provider, now we can use array_get() to get the value of the other field.
// So this custom rule validates that the attribute value contains the value of the other given
// attribute.
return str_contains($value,
array_get($validator->getData(), $parameters[0])
);
});
Validator::make(
[['email' => 'test#mail.com', 'provider' => 'mail.com']],
['*.email' => 'contains:*.provider']
)->validate();

Array to view output Laravel JSON

at the moment I use the following function to respond data to view
public function getSpiel(){
$spiel = Input::get('spieleID');
$teamOutput = Spielplan::where('Spielplan_ID', '=', $spiel)->get();
/*
$heimName = Verein::where('V_ID', '=', $teamOutput->Heimmannschaft)->first();
$gastName = Verein::where('V_ID', '=', $teamOutput->Gastmannschaft)->first();
$shop = array(
array($teamOutput->Spielplan_ID, $heimName ),
array($teamOutput->Spielplan_ID, $gastName)
);
*/
return Response::json($teamOutput);
Now, I need to change the input array? At the comment lines is the new logic.
How can I put the new array $shop into return Response::json($shop)? And how can I use the three fields in the view?
There I have a java script function and at the moment I use fields like this.
$.each(data, function(index, valueAusData){
$('#spiel').append('<option value="' + valueAusData.Heimmannschaft + '">'+valueAusData.Heimmannschaft+'</option>');
$('#spiel').append('<option value="' + valueAusData.Gastmannschaft + '">'+valueAusData.Gastmannschaft+'</option>');
});
In Spielplan_ID and in > //Here I need $heimName
You can return both arrays in json:
return Response::json(['team'=>$teamOutput, 'shop'=>$shop]);
Then, parse and use the json in javascript.
Or, you can pass the arrays to view in your response
return view('view_name', ['team'=>$teamOutput, 'shop'=>$shop]);
Then, in view file use the values of the arrays from $team and $shop.

Multiple collections in an array (session variable) — Property does not exist

I'am trying to fetch a session variable if the user is a guest. The variable is called "cart" and is set like this:
$product = new Collection((object) [
'product_id' => $request->pId,
'amount' => $request->amount,
'variations' => $variations
]);
Session::push('cart', $product);
Then I later fetch it:
if(Auth::check()){
$cartProducts = ShoppingCartItem::where('user_id', '=', Auth::user()->id)->get();
}else{
$cartProducts = Session::get('cart');
}
foreach($cartProducts as $product){
dd($product);
$totalAmount += $product->amount;
$totalPrice += (PriceHelper::getProductPrice($product->product->id, $product->amount));
}
The problem here is that dd($product) still outputs an array (the session variable array I assume) which means that for example $product->amount does not exist.
This is the output from dd($product):
You can either access the values using get():
foreach ($cartProducts as $product) {
$totalAmount += $product->get('amount');
$totalPrice += PriceHelper::getProductPrice($product->get('product_id'), $product->get('amount'));
}
or as an array:
foreach ($cartProducts as $product) {
$totalAmount += $product['amount'];
$totalPrice += PriceHelper::getProductPrice($product['product_id'], $product['amount']);
}
or you could use sum() on the collection instead of using foreach:
$cartProducts = collect(Session::get('cart'));
$totalAmount = $cartProducts->sum('amount');
$totalPrice = $cartProducts->sum(function ($product) {
return PriceHelper::getProductPrice($product['product_id'], $product['amount']);
});
Edit
For a quick fix if you need $product to be an object you could do something like:
$cartProducts = collect(Session::get('cart'))->map(function ($item) {
return (object)$item->toArray();
});
Hope this helps!

symfony2 custom entity to array function

I have to help me convert an entity to array but I have issues resolving associated records, which I need.
However, this gives me an error
The class 'Doctrine\ORM\PersistentCollection' was not found in the
chain configured namespaces ...
The code follows:
public function serialize($entityObject)
{
$data = array();
$className = get_class($entityObject);
$metaData = $this->entityManager->getClassMetadata($className);
foreach ($metaData->fieldMappings as $field => $mapping)
{
$method = "get" . ucfirst($field);
$data[$field] = call_user_func(array($entityObject, $method));
}
foreach ($metaData->associationMappings as $field => $mapping)
{
// Sort of entity object
$object = $metaData->reflFields[$field]->getValue($entityObject);
if ($object instanceof ArrayCollection) {
$object = $object->toArray();
}
else {
$data[$field] = $this->serialize($object);
}
}
return $data;
}
How can I resolve the associated fields into their respective arrays.
I have tried using the built-in, and JMS serialiser, but this gives me issues of nestedness limits, so this is not an option for me.
UPDATE:
I have updated the code to handle instance of ArrayCollection as per #ScayTrase's suggestion. However, the error above is still reported with a one-to-many field map. In debug, the variable $object is of type "Doctrine\ORM\PersistentCollection"
For *toMany association properties implemented with ArrayCollection you should call ArrayCollection::toArray() first. Just check it with instanceof before, like this
if ($object instanceof ArrayCollection) {
$object = $object->toArray();
}

CakePHP label convention

When using $this->Form->input('fieldname'), CakePHP creates a label element that, by convention, uses the fieldname. I know I can specify another string to use for the label as an argument to the input method, but is there any way I can specify the label name in the model, so I don't have to repeat the label name in multiple ctp files (e.g. so I only have to change it in one place)?
So I created this and made a quick test which worked, however, can't guarantee it's bug free:
<?php
App::uses('FormHelper', 'View/Helper');
class MyFormHelper extends FormHelper {
public function label($fieldName = null, $text = null, $options = array()) {
if ($text === null) {
$entity = $this->entity();
$field = array_pop($entity);
$model = $this->model();
$object = $this->_models[$model];
if (isset($object->labels[$field])) {
$text = $object->labels[$field];
}
}
return parent::label($fieldName, $text, $options);
}
}
Drop that in app/View/Helper/MyFormHelper.php
Add it to the helper array and alias it if you want to.
Add a public $labels array to the model with field => label-text structure.
Hope it works.

Resources