How to recreate a nested Eloquent Collection in Laravel 9? - laravel-blade

I would like to re-use a Laravel 9 Blade template that I built to display the results of an Eloquent query. But this time I want to fill it with data from an API, so I need to re-create the structure of the Collection to match the Blade template.
Possible solutions:
1. Manually recreate the Collection with the same structure:
$author1 = ["name" => "John Smith"];
$author2 = ["name" => "Larry White"];
$authors = Collect([$author1, $author2]);
$library1 = ["title" => "City library", "authors" => $authors];
$libraries = Collect([$library1]);
return view('library', compact('libraries'));
2. Recreate the Collection using existing model and its relationships:
$author1 = new Author;
$author1->name = "John Smith";
$author2 = new Author;
$author2->name = "Larry White";
$library1 = new Library;
$library1->title = "City library";
$library1->authors->push($author1);
$library1->authors->push($author2);
$libraries = [$library1];
return view('library', compact('libraries'));
Both options don't work and throw error: "name" is not defined on $author->name
library.blade.php:
#forelse ($libraries as $library)
<h1>{{ $library->title }}</h1>
<ul>
#forelse ($library->authors as $author)
<li>{{ $author->name}}</li>
#endforelse
</ul>
#endforelse

Related

How to access Locale field values through ::get() using Silverstripe Fluent

We are working on a project using Silverstripe with the Fluent module to enable multiple translations.
Here's an example Data Object with Fluent enabled. First we create the Data Object & explicitly set the CMS fields:
namespace Yard;
use SilverStripe\ORM\DataObject;
use SilverStripe\Forms\FieldList;
use SilverStripe\Forms\TextField;
class Milkshake extends DataObject {
private static $table_name = 'Milkshake';
private static $db = [
'Title' => 'Varchar(255)'
]
public function getCMSFields() {
$fields = new FieldList(
new TextField('Title', 'Milkshake Title', null, 255)
);
$this->extend('updateCMSFields', $fields);
return $fields;
}
}
Then we set Title as translatable in a YML file:
Yard\Milkshake:
extensions:
- 'TractorCow\Fluent\Extension\FluentExtension'
translate:
- 'Title'
This gives us an object with a translatable Title field that can have different values in different locales. It creates the following database table:
Milkshake_Localised
ID | RecordID | Locale | Title
So far so good, except using:
$milkshake = Milkshake::get()->first() doesn't return the localised data & pulls from the Milkshake table.
I think it could be possible to use:
$locale= FluentState::singleton()->getLocale();
$milkshake = Milkshake_Localised::get()->filter(['Locale' => $locale])->first();
But this feels clumsy & has no fallback if the locale data doesn't exist for that field (at which point it should fall back to the default locale, or failing that the original Milkshake field).
What is the correct way to access Locale data in Fluent so there is a fallback if required?
I got the desired behaviour by wrapping the get command in "withState"
use TractorCow\Fluent\State\FluentState;
$milkshake = FluentState::singleton()->withState(function (FluentState $state) {
return Milkshake::get()->first();
});

laravel 5.3 having error to save directory name on the fly

i have tables artists, songs, and artist_song which is the pivot table
i want song to be uploaded and stored a new directory named after the artist that belongs that song . but iam getting this error
Undefined property: Illuminate\Database\Eloquent\Relations\BelongsToMany::$name
this is my store method on SongController.
public function store(Request $request)
{
//
$this->validate($request, [
'title' => 'required',
'mp3' => 'required',
'artists' => 'required'
]);
$song = new Song;
$song->title = $request->title;
$song->lyrics = $request->lyrics;
$song->youtube_id = $request->youtube_id;
$song->album_id = $request->album_id;
$song->category_id = $request->category_id;
if($request->hasFile('mp3')){
$mp3 = $request->file('mp3');
$trackname = $mp3->getClientOriginalName();
$path = public_path('/uploads/songs/'.$song->artists()->name);
if (!file_exists($path)){
mkdir($path, 0777, true);
}
$mp3->move($path, $trackname);
$song->mp3 = $trackname;
}
$song->save();
$song->artists()->sync($request->artists, false);
return redirect()->route('song.index')->with('success', 'New song successfully upploaded');
}
i cannot get name property of that artists..
so what is wrong with my code, and one more thing to help me with is this the correct way to do relation tables like this. i referenced a tutorial about tagging and i did the same

Get a bundles object/instance

How would I go about obtaining the instance of a specific bundle?
In trying to adhere to this best practice:
http://symfony.com/doc/current/best_practices/configuration.html#constants-vs-configuration-options
I would like to stick some configuration details in a global bundle as they are likely to rarely change but are not specific to any given entity or bundle. Multiple bundles from multiple entities can use this to pre-populate a "Unit of Measure" drop down.
So I have done something like:
class ZincBundle extends Bundle {
private $units = [
'PCS' => 'PCS',
'LOT' => 'LOT',
'LBS' => 'LBS',
'SET' => 'SET',
'EACH' => 'EACH'
];
public function getUnitsOfMeasure ()
{
return $this->units;
}
}
Now I am trying to access this to populate some forms - this is what I have:
$container = $this->getConfigurationPool()->getContainer();
//$bundle = $this->container->get('ZincBundle');
What am I missing???

Drupal - Importing a taxonomy with migrate module from a table and creating/updating existing terms

I need to import a list of terms into my taxonomy from a source I loaded in the database.
The problem is I allready have this taxonomy on my site (loaded wihtout migrate) with terms that are used by reference in other content, so I got to keep existing term and update them or create the new ones.
To link my taxonomy source and the existing taxonomy I have an unique code for each term, so I added a code field to my vocabulary and filled it for each existing term.
I am currently able to create and update terms with my current Migration class, but if the name of my term on the site and the name of the term in my source is different, the import will create a new term instead of updating its name even if the code is the same.
Here my Migration Class :
class TotoMigration extends Migration {
private $list_term = array();
public function __construct($arguments) {
parent::__construct();
$this->softDependencies = array('TotoParent');
// get data from the custom table containing the new terms to create or update
$query = db_select('toto', 'f')
->fields('f', array(
'CODE', // code
'LIBLONG', // name
'PARENT', // parent
)
);
$this->source = new MigrateSourceSQL($query);
$this->destination = new MigrateDestinationTerm('toto_tax');
$this->map = new MigrateSQLMap($this->machineName,
array(
'CODE' => array('type' => 'varchar',
'length' => 5,
'not null' => TRUE,
'description' => 'Code',
)
),
MigrateDestinationTerm::getKeySchema()
);
$this->addFieldMapping('name', 'LIBLONG');
$this->addFieldMapping('field_code', 'CODE');
$this->addFieldMapping('parent', 'PARENT')
->arguments(array('source_type' => 'tid'))
->sourceMigration('TotoParent');
// create a list of existing toto terms with code => tid
$list_term = db_query("select fc.field_code_value, ttd.tid
from taxonomy_term_data ttd
left join taxonomy_term_hierarchy tth on tth.tid=ttd.tid
left join field_data_field_code fc on fc.entity_id = ttd.tid
where ttd.vid=10
and tth.parent!=0;")->fetchAllKeyed();
}
public function prepareRow($row) {
// Always include this fragment at the beginning of every prepareRow()
// implementation, so parent classes can ignore rows.
if (parent::prepareRow($row) === FALSE) {
return FALSE;
}
// if the destination is not mapped in migrate we tell him where to go
if (!isset($row->migrate_map_destid1) && isset($list_term[$row->CODE])) {
$row->migrate_map_destid1 = $list_term[$row->CODE];
}
}
}
I then load the import with drush (and --update option).
I must be missing something, if anyone got a clue it will be welcome.
After many tries, the problem reside in the fact the module Migrate does not support Creating content and Updating content in the same migration class (I even read it will sometime claim to update content and just do nothing).
So the solution is pretty simple, create 2 classes :
One for Creating content
One for Updating content
Your Creating class will be the same.
Your Updating class will need to have a systemeOfRecord set to DESTINATION :
$this->systemOfRecord = Migration::DESTINATION;
So it knows to only update and not recreate the content, it will keep current fields not mapped and update fields mapped that are not part of the MigrateSQLMap :
$this->map = new MigrateSQLMap($this->machineName,array(...));
The tricky part will be to find corresponding nid/tid of your content so you can map it to your imported data and then to separate data used to update or create content.

Symfony2 KnpPaginator bundle, cannot do sorting with 2 paginated tables in my view

I have 1 controller that passes 2 paginated set of results to a twig (as 2 arrays representing tables) using KnpPaginator Bundle.
While both tables show up and are paginated, I am not able to sort any of them.
Edit: When I change page of table 1, table 2's page also changes to that page number.
Trying to sort either of them returns: There is no component aliased by [t] in the given Query or There is no component aliased by [r] in the given Query.
The controller:
$em = $this->getDoctrine()->getEntityManager();
$pageSize = $this->container->getParameter('page_size');
$paginator = $this->get('knp_paginator');
/* Queries */
$queryTest = $em
->createQuery('
SELECT t FROM PanasonicTestEtAvisBundle:Test t
JOIN t.product p
WHERE p.id = :id
AND t.isDeleted = :isdeleted
ORDER BY t.creationDate DESC'
)->setParameter('id', $id)
->setParameter('isdeleted', '0');
$queryReview = $em
->createQuery('
SELECT r FROM PanasonicTestEtAvisBundle:Review r
JOIN r.product p
WHERE p.id = :id
AND r.isDeleted = :isdeleted
ORDER BY r.creationDate DESC'
)->setParameter('id', $id)
->setParameter('isdeleted', '0');
/* paginated results */
$paginationTest = $paginator->paginate($queryTest, $this->get('request')->query->get('page', 1), $pageSize);
// compact('paginationTest');
$paginationReview = $paginator->paginate($queryReview, $this->get('request')->query->get('page', 1), $pageSize);
// compact('paginationReview');
// compact('pagination');
return $this->render('PanasonicTestEtAvisBundle:Product:show.html.twig', array(
'paginationTest' => $paginationTest,
'paginationReview' => $paginationReview
));
The error shows up only when I pass both pagination (paginationTest & paginationReview), if I pass only one it works flawlessly.
Anyone can tell me how I can solve this problem?
Your example didn't work, because you use the same page variable "page" for both of pagination sets.
If you want to use two or more pagination sets in the same place, you must do this:
Your Controller:
...
$pagename1 = 'page1'; // Set custom page variable name
$page1 = this->get('request')->query->get($pagename1, 1); // Get custom page variable
$paginationReview = $paginator->paginate(
$queryReview,
$page1,
$pageSize,
array('pageParameterName' => $pagename1)
);
$pagename2 = 'page2'; // Set another custom page variable name
$page2 = this->get('request')->query->get($pagename2, 1); // Get another custom page variable
$paginationReview = $paginator->paginate(
$queryReview,
$page2,
$pageSize,
array('pageParameterName' => $pagename2)
);
return $this->render('PanasonicTestEtAvisBundle:Product:show.html.twig', array(
'paginationTest' => $paginationTest,
'paginationReview' => $paginationReview
));
Your view:
// PanasonicTestEtAvisBundle:Product:show.html.twig
{# First set #}
{% for test in paginationTest %}
<tr>
<td>{{ test.id }}</td>
</tr>
{% endfor %}
{{ paginationTest.render()|raw }}
{# Second set #}
{% for review in paginationReview %}
<tr>
<td>{{ review.id }}</td>
</tr>
{% endfor %}
{{ paginationReview.render()|raw }}
Enjoy!
It's 2017 and I got into similar problem. Just for reference, I'm using:
"knplabs/knp-paginator-bundle": "^2.5",
I was trying to run several functional tests with Symfony's crawler. Some of them were using Knp Paginator with such options:
[
'defaultSortFieldName' => 'voucher.id',
'defaultSortDirection' => 'DESC',
'wrap-queries' => true,
'defaultFilterFields' => ['voucherText.title']
]
while others with those options:
[
'defaultSortFieldName' => 'event.id',
'defaultSortDirection' => 'DESC',
'wrap-queries' => true,
'defaultFilterFields' => ['event.name', 'eventText.description']
]
Problem appeared with sorting parameter name, because both Paginators were using defaul 'sort' key, taking it from global $_GET array - you can check it yourself: Knp\Component\Pager\Event\Subscriber\Sortable\Doctrine\ORM\QuerySubscriber.
However the enigmatic part was the error being thrown:
UnexpectedValueException: There is no component aliased by [event] in the given Query
In order to avoid this weirdos/crappiness, I found a 'sortFieldParameterName' option, which you can add to all of your Paginators' options:
[
'sortFieldParameterName' => 'sort_event',
'defaultSortFieldName' => 'event.id',
'defaultSortDirection' => 'DESC',
'wrap-queries' => true,
]

Resources