Set labels from array - symfony

I'm starting with chartjs and i'm already struggling. I want to set my labels with data I get from a query :
public function find4Chart($joueur){
$qb = $this->createQueryBuilder('p');
$qb->join('p.partie','y')
->join('y.game','g')
->select('g.name')
->addSelect('COUNT(p) AS sumParties')
->where('p.joueur = :joueur')
->setParameter('joueur', $joueur)
->groupBY('g.name');
$query = $qb->getQuery();
return $query->getResult();
}
Then I set up the chart like this :
var ctx = document.getElementById('myChart');
var myChart = new Chart(ctx, {
type: 'doughnut',
data: {
labels: [{{ chart.name }}],
But it gives me the following error and I don't know why or what to do here :/
Key "name" for array with keys "0, 1" does not exist.
Thx !

Regarding your own answer - you could change this part:
$arrChart = array();
foreach($chart as $c){
$name = $c['name'];
array_push($arrChart, $name);
}
into this:
$arrChart = array_column($chart, 'name');
You can read more about array_column here

Ok it worked for me this way :
public function show(Joueur $joueur): Response
{
$em = $this->getDoctrine()->getManager();
$chart = $em->getRepository(Played::class)->find4Chart($joueur);
$arrChart = array();
foreach($chart as $c){
$name = $c['name'];
array_push($arrChart, $name);
}
return $this->render('joueur/show.html.twig', [
'joueur' => $joueur,
'chart' => $arrChart,
]);
}
Chart :
var ctx = document.getElementById('myChart');
var myChart = new Chart(ctx, {
type: 'doughnut',
data: {
labels: {{chart | json_encode | raw}},
I don't know if it's the right way to do it but it works, if any of you have a better idea, I'll take it ;)

Related

How do I modify wpDataTables cell values using filters?

In wpDataTables, I would like to modify (i.e. conditionally format) each cell value in a specific column for a specific table programmatically using PHP. How would I accomplish this?
First, install the Code Snippets plugin. Then create a new snippet set to "Run Snippet Everywhere" (required for JSON filtering) using the code below. It will filter both HTML and JSON. For more information, refer to wpDataTables - Filters.
function custom_wpdatatables_filter_initial_table_construct($tbl) {
// Edit below.
$table_name_to_modify = 'My Table Name';
$table_column_to_modify = 'my_table_column';
$cell_modification_function = function($value) {
return 'Modified: ' . $value;
};
// Check table name.
if ($tbl->getName() !== $table_name_to_modify) {
return $tbl;
}
$rows = $tbl->getDataRows();
foreach ($rows as &$row) {
if (array_key_exists($table_column_to_modify, $row)) {
$row['intermentobituary'] = $cell_modification_function($row['intermentobituary']);
}
}
$tbl->setDataRows($rows);
return $tbl;
}
add_filter('wpdatatables_filter_initial_table_construct', 'custom_wpdatatables_filter_initial_table_construct', 10, 1);
function custom_wpdatatables_filter_server_side_data($json, $tableId, $get) {
// Edit below.
$table_name_to_modify = 'My Table Name';
$table_column_to_modify = 'my_table_column';
$cell_modification_function = function($value) {
return 'Modified: ' . $value;
};
// Check table name.
$tableData = WDTConfigController::loadTableFromDB($tableId);
if (empty($tableData->content)) {
return $json;
} else if ($tableData->title !== $table_name_to_modify) {
return $json;
}
// Get columns.
$columns = [];
foreach ($tableData->columns as $column) {
// wdt_ID will be first column.
$columns[] = $column->orig_header;
}
// Modify column values.
$json = json_decode($json, true);
$rows = $json['data'];
foreach ($rows as $row_key => $row_value) {
foreach ($row_value as $row_attr_key => $row_attr_value) {
if ( ! empty($columns[$row_attr_key]) && $columns[$row_attr_key] === $table_column_to_modify) {
$rows[$row_key][$row_attr_key] = $cell_modification_function($row_attr_value);
}
}
}
$json['data'] = $rows;
return json_encode($json);
}
add_filter('wpdatatables_filter_server_side_data', 'custom_wpdatatables_filter_server_side_data', 10, 3);

How to modify data before the denormalization and send It back?

I'd like to have advice on the best practice to achieve something.
I've a JSON output of an entity called "Session" with 3 related entities (platform, user, course ) and I'd like to use the nested way to create those 3 related if they don't exist.
But If they do exist I'd like to add their IRI (or ID) to the JSON output before API Platform does the magic. (or another way to achieve this behavior)
I naively thought that I should bind to the pre_denormalization event but I've no idea how to return the data to the event.
Here is what I've got so far.
public static function getSubscribedEvents()
{
return [
KernelEvents::REQUEST => ['onSessionDenormalize', EventPriorities::PRE_DESERIALIZE],
];
}
public function onSessionDenormalize(RequestEvent $event)
{
$data = $event->getRequest()->getContent();
}
public function modifyPayLoad($data) {
$dataObject = json_decode($data);
$platform = $dataObject->platform;
$user = $dataObject->user;
$course = $dataObject->course;
if($this->platformRepository->findOneBy(['slug' => $platform->slug])) {
$platformID = $this->courseRepository->findOneBy(['slug' => $platform->slug])->getId();
$dataObject->id = $platformID;
if($this->userRepository->findOneBy(['email' => $user->slug])) {
$dataObject->id = $this->userRepository->findOneBy(['email' => $user->slug])->getId();
$dataObject->user->platform->id = $platformID;
}
if($this->courseRepository->findOneBy(['slug' => $course->slug])) {
$dataObject->id = $this->courseRepository->findOneBy(['slug' => $course->slug])->getId();
$dataObject->course->platform->id = $platformID;
}
}
return json_encode($dataObject);
}
And the JSON:
{
"user": {
"firstname": "string",
"lastname": "string",
"address": "string",
"city": "string",
"email": "string",
"zipCode": int,
"hubspotID": int
},
"course": {
"id": "string",
"title": "string",
"platform": {
"slug": "string",
"name": "string"
}
},
"startDate": "2022-01-09T23:59:00.000Z",
"endDate": "2022-02-09T23:59:00.000Z",
"hubspotDealId": int
}
I can't get the ID in this JSON since those information are provided by a Puppeteer APP, or I should do 3 request to check if the related entity exist first, which is not adviced I think.
I also tried to change the identifier on the user, course and platform but In both cases, I've duplicate entries in database
I manage to do what I want with a custom denormalizer.
So I can post and update data comming from tierce source without ID.
class SessionDenormalizer implements DenormalizerAwareInterface, ContextAwareDenormalizerInterface
{
use DenormalizerAwareTrait;
public function __construct(
private UserRepository $userRepository,
private PlatformRepository $platformRepository,
private CourseRepository $courseRepository,
private SessionRepository $sessionRepository,
)
{
}
private const ALREADY_CALLED = 'SESSION_DENORMALIZER_ALREADY_CALLED';
public function supportsDenormalization($data, string $type, string $format = null, array $context = []): bool
{
if (isset($context[self::ALREADY_CALLED])) {
return false;
}
return $type === Session::class;
}
public function denormalize($data, string $type, string $format = null, array $context = [])
{
if (isset(
$data["user"]["email"],
$data["course"]["slug"],
$data["course"]["platform"]["slug"],
)) {
$user = $this->userRepository->findOneBy(["email" => $data["user"]["email"]]);
$course = $this->courseRepository->findOneBy(["slug" => $data["course"]["slug"]]);
$platform = $this->platformRepository->findOneBy(["slug" => $data["course"]["platform"]["slug"]]);
if ($user && $course && $platform) {
$data["user"]["#id"] = "/v1/users/" . $user?->getId();
$data["course"]["#id"] = "/v1/courses/" . $course?->getId();
$data["course"]["platform"]["#id"] = "/v1/platforms/" . $platform?->getId();
$session = $this->sessionRepository->findOneBy(["cpfID" => $data["cpfID"]]);
if($session) {
$data["#id"] = "/v1/sessions/" . $session->getId();
if(isset($context["collection_operation_name"])) {
$context["collection_operation_name"] = "put";
}
if(isset($context['api_allow_update'])) {
$context['api_allow_update'] = true;
}
}
}
}
$context[self::ALREADY_CALLED] = true;
return $this->denormalizer->denormalize($data , $type , $format , $context);
}
}
Services.yaml :
'app.session.denormalizer.json':
class: 'App\Serializer\Denormalizer\SessionDenormalizer'
tags:
- { name: 'serializer.normalizer', priority: 64 }

WP_REST_REQUEST: how to add "_embed" to request parameters

I added this function to my wordpress REST API to have a custom endpoint
function getSettimanaEventi(){
$request = new WP_REST_Request( 'GET', '/wp/v2/tribe_events' );
$request['_embed'] = '1';
$request['filter[meta_query][0][key]'] = '_EventStartDate';
$request['filter[meta_query][0][value][0]'] = '2017-07-03 00:00:00';
$request['filter[meta_query][0][value][1]'] = '2017-07-09 00:00:00';
$request['filter[meta_query][0][compare]'] = 'BETWEEN';
$request['filter[meta_query][0][type]'] = 'DATE';
$response = rest_do_request( $request );
return $response;
i got a response but there isn't the embedded content.
I know the parameters with a leading '_' are private but i need embedded content.
How can i do?
This works for me perfectly
global $wp_rest_server;
$request = new WP_Rest_Request('GET', '/wp/v2/posts');
$response = rest_do_request($request);
$response = $wp_rest_server->response_to_data($response, true);
The only way i found is to add the "_embed" parameter to the url (when you call it from Postman for example) and delete it from the request parameters
(Update - this doesn't seem to be working. I'll update if I figure it out.)
You must set it in the super global like this:
function getSettimanaEventi () {
// Set super global to simulate request param
$_GET['_embed'] = 1;
$request = new WP_REST_Request( 'GET', '/wp/v2/tribe_events' );
$request['filter[meta_query][0][key]'] = '_EventStartDate';
$request['filter[meta_query][0][value][0]'] = '2017-07-03 00:00:00';
$request['filter[meta_query][0][value][1]'] = '2017-07-09 00:00:00';
$request['filter[meta_query][0][compare]'] = 'BETWEEN';
$request['filter[meta_query][0][type]'] = 'DATE';
$response = rest_do_request( $request );
// cleanup after
unset($_GET['_embed']);
return $response;
}
I found this info in this ticket for WP-API:
https://github.com/WP-API/WP-API/issues/2857

Silex: RouteNotFoundException with PHPUnit - Unable to generate a URL for the named route "homepage" as such route does not exist

I asked this on https://github.com/silexphp/Silex/issues/1442 but I have a feeling it isn't necessarily a code problem so I thought I would extend the reach.
upgrading to silex 2 and symfony 3 and all the rest...
routes are included at end of app.php and look something like this...
$app->get('/', 'queue.controller:indexAction')
->after(function (Request $request, Response $response, $app) {
$response->setPublic();
$response->setSharedMaxAge($app['cache']['s-maxage']);
})
->host($app['domains']['xxx'])
->bind('homepage');
this works great in a browser, goto homepage, works fine. If I am running phpunit though... I get the following error when trying to generate a route...
Symfony\Component\Routing\Exception\RouteNotFoundException: Unable to generate a URL for the named route "homepage" as such route does not exist.
and the test looks something like this...
public function testTargetingOnHomepage()
{
$client = $this->createClient();
echo $this->app->url('homepage');
.....
}
i am bewildered as to why my routes are not getting added to app when being executed from phpunit.
test case class has ...
class AdTargetControllerTest extends SomeWebTestCase
and that somewebtestcase.php looks like ...
<?php
namespace theapp\SomeFramework;
use Silex\WebTestCase;
use Fixtures\UserFixture;
use Symfony\Component\BrowserKit\Client;
use Symfony\Component\HttpFoundation\Session\Storage\MockFileSessionStorage;
class SomeWebTestCase extends WebTestCase
{
public $youtubeEmbed;
private $mockSessionDir;
public function createApplication()
{
$appDir = __DIR__.'/../../..';
$app = include "$appDir/app.php";
$app['debug'] = true;
$app['session.test'] = true;
$this->mockSessionDir = $app['tmpdir']. '/mocksessions';
$app['session.storage.test'] = function ($app) {
return new MockFileSessionStorage($app['tmpdir']. '/mocksessions');
};
unset($app['exception_handler']);
// Emails get stored in the mail "logger" ... not delivered.
$app['mailer.logger'] = function ($app) {
return new \Someecards\SomeFramework\MessageLogger();
};
// Force silex to use transport and not spooltransport
$app['swiftmailer.use_spool'] = false;
$app["swiftmailer.transport"] = function ($app) {
return new \Swift_Transport_NullTransport($app['swiftmailer.transport.eventdispatcher']);
};
$app->extend('mailer', function ($mailer, $app) {
$mailer->registerPlugin($app['mailer.logger']);
return $mailer;
});
$this->youtubeEmbed = '<iframe width="480" height="270" src="https://www.youtube.com/embed/';
$this->youtubeEmbed .= 'LDtHJYa6xu4?feature=oembed" frameborder="0" allowfullscreen></iframe>';
// using Mockery since this library uses a static method for create
$app['oembedMock'] = \Mockery::mock('alias:Embed\Embed');
$app['oembedMock']
->shouldReceive('create')
->andReturn(
(object) array(
'title' => 'Oembed title',
'description' => 'Oembed Description',
'providerName' => 'YouTube',
'code' => $this->youtubeEmbed,
'type' => 'video',
'author' => 'test',
'authorUrl' => 'test',
'width' => 500,
'height' => 500,
'image' => 'test',
'imageWidth' => 500,
'imageHeight' => 500
)
);
$app->boot();
return $app;
}
there are other functions here but thats the important one i believe.
phpunit bootstraps with ...
<?php
use theapp\SomeFramework\TestingUtil;
// autoload libraries
require_once __DIR__.'/../thirdparty/vendor/autoload.php';
TestingUtil::init();
and then testingutil.php looks like ...
namespace Someecards\SomeFramework;
class TestingUtil
{
public static function init()
{
// This if/else allows the phpunit processIsolation flag to be set to true.
// We're not currently doing that because it slows things down three fold.
// If you see errors about too many open connections/files you can run
// ulimit -n 10000, try to close db connections and log files (couldn't fclose
// these in tearDowns for some reason), or turn on processIsolation.
if (!defined('PHPUNIT_HAS_BOOTSTRAPED')) {
self::bootstrap();
define('PHPUNIT_HAS_BOOTSTRAPED', true);
}
}
public static function bootstrap()
{
$app = require __DIR__.'/../../../app.php';
$app->boot();
$dbOptions = $app['db.options'];
if ($dbOptions['driver'] == 'pdo_sqlite') {
$testdb = $dbOptions['path'];
if (file_exists($testdb)) {
#unlink($testdb);
}
$cacheDriver = $app['orm.em']->getConfiguration()->getMetadataCacheImpl();
$cacheDriver->deleteAll();
$cacheDriver = $app['orm.em']->getConfiguration()->getResultCacheImpl();
$cacheDriver->deleteAll();
$cacheDriver = $app['orm.em']->getConfiguration()->getQueryCacheImpl();
$cacheDriver->deleteAll();
$tool = new \Doctrine\ORM\Tools\SchemaTool($app['orm.em']);
$classes = $app['orm.em']->getMetadataFactory()->getAllMetadata();
$tool->createSchema($classes);
$loader = new \Doctrine\Common\DataFixtures\Loader();
$loader->loadFromDirectory(__DIR__ ."/../../Fixtures");
$purger = new \Doctrine\Common\DataFixtures\Purger\ORMPurger();
$executor = new \Doctrine\Common\DataFixtures\Executor\ORMExecutor($app['orm.em'], $purger);
$executor->execute($loader->getFixtures());
}
register_shutdown_function(
function ($app) {
$path = $app['orm.default_cache']['path'];
if (is_dir($path) === true) {
$files = new \RecursiveIteratorIterator(
new \RecursiveDirectoryIterator($path),
\RecursiveIteratorIterator::CHILD_FIRST
);
foreach ($files as $file) {
if (in_array($file->getBasename(), array('.', '..')) !== true) {
if ($file->isDir() === true) {
rmdir($file->getPathName());
} elseif (($file->isFile() === true) || ($file->isLink() === true)) {
unlink($file->getPathname());
}
}
}
rmdir($path);
} elseif ((is_file($path) === true) || (is_link($path) === true)) {
return unlink($path);
}
},
$app
);
}
}

Symfony2 select choice ajax

I haven't found any comprehensive answer at the moment ..
I would like to learn how to change a select option based on the choices of another select.
eg.
Category One-to-Many SubCategory
I select an option from the Category and SubCategory select content changes.
Could you give me a hand?
First you need to use the routing url to pass the control to the action using jquery
eg
$('# category id').change(function(){
var Id = $('#category id').val();
var url = Routing.generate('route_to_retrieve_subcategory', { 'Id': Id });
$.post(url,
{ 'Id': Id
},function(data){
$('#subcategoryId').html(data);
},"text");
}
});
In controller
/**
* #Route("subcategory/{Id}",name="route_to_retrieve_subcategory" )
* #Template()
*/
public function getSubcategoryAction($Id)
{
//code
return new Response($subcategoryList, 200);
}
Note:
the route must be listed in routing.yml file
route_to_retrieve_subcategory:
pattern: /route_to_retrieve_subcategory/{Id}
defaults: {_controller: YourBundle:YourController:getSubcategory}
options:
expose: true
in the end I decided to use this method:
javascript:
$('select[name*="[category][category]"]').prop('selected', true).change(function(){
var Id = $(this).val();
var url = Routing.generate('route_to_retrieve_subcategory');
$.post(url,
{ 'idCat': Id
}, function(results){
var sub = $('select[name*="[category][category]"]').parent().find('select[name*="[subCategory][]"]');
sub.empty();
$.each(results , function(key, value) {
sub
.append($("<option></option>")
.attr("value",value.id)
.text(value.subCategory));
});
});
});
controller:
public function getSubcategoryAction(Request $request)
{
$Id = $request->get('idCat');
$em = $this->getDoctrine()->getManager();
$entities = $em->getRepository('MyBusinessBundle:SubCategories')->findSubCategories($Id);
$output = array();
foreach ($entities as $member) {
$output[] = array(
'id' => $member->getId(),
'subCategory' => $member->getSubCategory(),
);
}
$response = new Response();
$response->headers->set('Content-Type', 'application/json');
$response->setContent(json_encode($output));
return $response;
}
route:
route_to_retrieve_subcategory:
pattern: /route_to_retrieve_subcategory
defaults: { _controller: "MyBusinessBundle:ajax:getSubcategory" }
options:
expose: true
I prefer not to pass parameters through the course, I feel that it does not make sense!
A big thank you to shrujan shetty for the inspiration.

Resources