can't create many pdf files using dompdf - php

I'm trying to create many pdf files using a loop and put them in a specific place, but I'm getting this error:
DOMPDF_Exception
File:
C:\wamp\www\leadmarket\vendor\dompdf\dompdf\include\inline_positioner.cls.php:37
Message:
No block-level parent found. Not good.
Here is my code:
for($i = 0 ; $i < 3 ; $i++){
$pdf = new PdfModel();
$pdf->setOption("paperSize", "a4"); //Defaults to 8x11
$pdfView = new ViewModel($pdf);
$pdfView->setTerminal(true)
->setTemplate('application/annonceur/generer-facture-mensuelle.phtml')
->setVariables(array(
'client' => $i
)
);
$html = $this->getServiceLocator()->get('viewpdfrenderer')->getHtmlRenderer()->render($pdfView);
$eng = $this->getServiceLocator()->get('viewpdfrenderer')->getEngine();
$eng->load_html($html);
$eng->render();
$pdfCode = $eng->output();
file_put_contents('public/folder/file-'.$i'.pdf', $pdfCode);
}

Dompdf currently only supports rendering a single document per instance (issue #1056). Until this issue is resolved you'll need to unset the Dompdf instance and create a new one.
It looks like you're creating an instance per loop of your PdfModel and ViewModel, but the Dompdf instance is part of the class that contains your loop ($this->getServiceLocator...).
I'm not familiar with the framework you're using, so I can't give you a specific answer. The quickest solution would be to not use the Dompdf instance that's part of your ServiceLocator instance.
Replace
$eng = $this->getServiceLocator()->get('viewpdfrenderer')->getEngine();
With
$eng = new Dompdf();
$eng->setOption("paperSize", "a4");
As you see the paper size had to be set again, and that's the drawback. Any options configured in the ServiceLocator will be lost.

Related

Can we edit a mustache template in runtime?

Can I add new nodes to mustache template at run-time in PHP? Let's say below is a code where ProductDetails will contain few single products:
{{#ProductDetails}}
{{#SingleProduct}}
{{OldDetail}}
{{/SingleProduct}}
{{/ProductDetails}}
I want to add a new node like {{NewDetail}} just after {{OldDetail}} through some function in run-time(i.e just before I am compiling the template as these templates have been shipped to customers in such a way that only code to compile can be changed but not the template)? I don't want to do string manipulation(customers created few new templates with above parameters present at least but the spacing may change & few new entries can be added by them around nodes). Does mustache library provide any functions for that?
If I were you, I will try Lambdas.
Template.mustache will be like this:
{{#ProductDetails}}
{{#SingleProduct}}
{{OldDetail}}
{{/SingleProduct}}
{{/ProductDetails}}
And codes will be like:
$Mustache = new Mustache_Engine(['loader' => new Mustache_Loader_FilesystemLoader($YOUR_TEMPLATE_FOLDER),]);
$Template = $Mustache->loadTemplate('Template');
$OriginalOldDetail = '<h1>this is old detail</h1>';
echo $Template->Render([
'ProductDetails' => true,
'SingleProduct' => true,
'OldDetail' => function($text, Mustache_LambdaHelper $helper){
// Render your original view first.
$result = $helper->render($text);
// Now you got your oldDetail, let's make your new detail.
#do somthing and get $NewDetail;
$NewDetail = $YourStuff;
// If your NewDetail is some mustache format content and need to be render first.
$result .= $help->render($NewDetail);
// If is some content which not need to be render ? just apend on it.
$result .= $NewDetail;
return $result;
}
]);
Hope that will help.
(English is not my first language so hope you can understand what I'm talking about.)

Azure PHP SDK: get the asset by asset name

Is it possible to get the asset details using asset name with Azure PHP sdk. I can get all the asset list, but it's loading first 1000 assets only.
getAssetList();
I can get single asset details using asset id.
getAsset($asset);
But in my case, I don't have asset id with me. I just have asset name alone. Now how do I get the asset details using this?
EDIT:
I got some help from Azure support saying that, we can use $skip parameter for pagination. I got code snippet in c#
for (int i = 0; i < _context.Assets.Count(); i += 1000 )
{
var assets = _context.Assets.Skip(i);
foreach (IAsset objIAsset in assets)
{
Console.WriteLine(objIAsset.Name.ToString());
}
}
How can I use this param in PHP SDK.
It seem that Azure SDK for PHP don't support skip method. However, I used the fiddler to monitor C# skip method and got the URL like this:
https://***-hs.cloudapp.net/api/Assets()?$skip=1000
So I think we can bulid up the request path like above in our PHP project and we can modify the getAssetList method in "MediaServicesRestProxy" file.
I add a function named "getAssetListBySkip($number)" into "MediaServicesRestProxy" class, the code like this:
/**
* Get asset list using skip number
*
* */
public function getAssetListBySkip($number)
{
$propertyList = $this->_getEntityList("Assets()?".'$skip='.$number);
$result = array();
foreach ($propertyList as $properties) {
$result[] = Asset::createFromOptions($properties);
}
return $result;
}
We can call this method like this:
$mediaServiceProxy = ServicesBuilder::getInstance()->createMediaServicesService(
new MediaServicesSettings("**","**/**="));
$result=$mediaServiceProxy->getAssetListBySkip(1000);
Azure Media services supports filtering by name. You can construct web request to be like
/api/assets()?$filter=Name%20eq%20'Your Name'&$top=1
You can also filter by other properties
Have you tried REST API that are used when creating, processing, managing, and delivering Assets. https://msdn.microsoft.com/en-us/library/azure/hh974277.aspx#list_an_asset but I do think we can list asset via a name directly since id is an unique indentifier of asset entity. PHP Azure SDK leverages assetId to get an Asset as well:
public function getAsset($asset)
{
$assetId = Utilities::getEntityId(
$asset,
'WindowsAzure\MediaServices\Models\Asset'
);
return Asset::createFromOptions($this->_getEntity("Assets('{$assetId}')"));
}
But in my case, I don't have asset id with me. I just have asset name
alone. Now how do I get the asset details using this?
Here are some test function code snippets for your reference:
public function testListAllAssets(){
// Setup
$asset1 = new Asset(Asset::OPTIONS_NONE);
$asset1->setName(TestResources::MEDIA_SERVICES_ASSET_NAME . $this->createSuffix());
$asset2 = new Asset(Asset::OPTIONS_NONE);
$asset2->setName(TestResources::MEDIA_SERVICES_ASSET_NAME . $this->createSuffix());
// Test
$asset1 = $this->createAsset($asset1);
$asset2 = $this->createAsset($asset2);
$result = $this->restProxy->getAssetList();
// Assert
$this->assertCount(2, $result);
$names = array(
$result[0]->getName(),
$result[1]->getName()
);
$id = array(
$result[0]->getId(),
$result[1]->getId()
);
$this->assertContains($asset1->getName(), $names);
$this->assertContains($asset2->getName(), $names);
$this->assertContains($asset1->getId(), $id);
$this->assertContains($asset2->getId(), $id);
}
public function testGetAnAssetReference(){
// Setup
$assetName = TestResources::MEDIA_SERVICES_ASSET_NAME . $this->createSuffix();
$asset = new Asset(Asset::OPTIONS_NONE);
$asset->setName($assetName);
$asset = $this->createAsset($asset);
// Test
$result = $this->restProxy->getAsset($asset);
// Assert
$this->assertEquals($asset->getId(), $result->getId());
$this->assertEquals($asset->getName(), $result->getName());
}
From: https://github.com/Azure/azure-sdk-for-php/blob/master/tests/functional/WindowsAzure/MediaServices/MediaServicesFunctionalTest.php
According to my testing, it seems that we can’t use Asset’s name to get the information of asset in Media Service.
$mediaServiceProxy = ServicesBuilder::getInstance()->createMediaServicesService(
new MediaServicesSettings("**","******"));
$asset = new Asset(Asset::OPTIONS_NONE);
$asset->setName('For-Test-wmv-Source');
//$asset don't have the value of id,
// unless execute ‘createAsset($asset)’, "$asset1" will be set the ID
$asset1 =$mediaServiceProxy->createAsset($asset);
$result2=$mediaServiceProxy->getAsset($asset1);
PHP SDK support the method named “getAsset($asset)”. Actually, the method get the Asset information by Asset id, just like the Aka's reference code.And Azure REST API don’t support the method queried by Asset’s name.
Please refer to the official document.
Alternative approach is that you can store your assets information (such as Id,URl,name and ect.) into Azure table storage when you upload them into media service. If you want to use it, you can fetch and filter the data of Asset’s name you wants from table storage.

Creating Multiple Custom Attibutes For Product with google-api-php-client

According to that answer https://support.google.com/merchants/answer/4588281?hl=en-GB
if I want set multiple promotions ids for the product with the API I can specify multiple lines of:
<sc:attribute name="promotion_id">PROMOTION_ID</sc:attribute>
I am using this lib https://github.com/google/google-api-php-client
My question is how can i do it with this library. Should I use custom attributes? for example.
$feed_entry = new Google_Service_Content_Product();
$promotions_ids = array (20,21,22);
foreach ($promotions_ids as $promotion_id ) {
$promotion = new Google_Service_Content_ProductCustomAttribute();
$promotion->setName('promotion_id');
$promotion->setValue($promotion_id);
$feed_entry->setCustomAttributes($promotion);
}
But that would just set this attribute over again for different ids. I am not even sure if I am doing this in a right way. Probably missing something. The full code example would be really helpful.
I couldn't find a definitive code sample for PHP. That being said, if you look at API libraries for other languages you find that:
For Java it uses a List<ProductCustomAttribute>:
public Product setCustomAttributes(java.util.List<ProductCustomAttribute> customAttributes)
Source
For JavaScript it uses a map:
setCustomAttributes(map)
setCustomAttributes({ 'size': 'Large', 'color': 'Green' })
Source
Conclusion:
there's a very good chance the PHP method in question uses an array of Google_Service_Content_ProductCustomAttribute objects:
public function setCustomAttributes($customAttributes)
$feed_entry = new Google_Service_Content_Product();
$promotions_ids = array (20,21,22);
$customAttributes = array();
foreach ($promotions_ids as $promotion_id ) {
$promotion = new Google_Service_Content_ProductCustomAttribute();
$promotion->setName('promotion_id');
$promotion->setValue($promotion_id);
$customAttributes[] = $promotion;
}
$feed_entry->setCustomAttributes($customAttributes);
Try it!

Drupal 7 Render a Comment Object

So this is the problem I am running into. If I have a comment object, I want to create a renderable array that is using the display settings of that comment. As of now this is what I have:
$commentNew = comment_load($var);
$reply[] = field_view_value('comment', $commentNew, 'comment_body', $commentNew->comment_body['und'][0]);
Which works fine because I dont have any specific settings setup for the body. But I also have image fields and video embed fields that I need to have rendered the way they are setup in the system. How would I go about doing that?
Drupal core does it with the comment_view() function:
$comment = comment_load($var);
$node = node_load($comment->nid);
$view_mode = 'full'; // Or whatever view mode is appropriate
$build = comment_view($comment, $node, $view_mode);
If you need to change a particular field from the default, use hook_comment_view():
function MYMODULE_comment_view($comment, $view_mode, $langcode) {
$comment->content['body'] = array('#markup' => 'something');
}
or just edit the $build array received from comment_view() as you need to if implementing the hook won't work for your use case.

Zend Framework Paginator cache doesn't work (no hit)

I use a file based cache to cache a paginator:
$table = $this->getDbTable();
$ret = $table ->select()
->from($table,array('id',
'UNIX_TIMESTAMP(`date`) as date',
'categoryId',
'title',
'teaser'))
->where('`categoryId`=?',$cat)
->order('date desc');
$adapter = new Zend_Paginator_Adapter_DbTableSelect($ret);
$paginator = new Zend_Paginator($adapter);
$fO = array('lifetime' => 3600, 'automatic_serialization' => true);
$bO = array('cache_dir'=>APPLICATION_PATH . '/cache');
$cache = Zend_cache::factory('Core', 'File', $fO, $bO);
Zend_Paginator::setCache($cache);
$paginator->setItemCountPerPage(5);
$paginator->setCurrentPageNumber($page);
$this->view->paginator = $paginator;
Now every request, the paginator creates a neew cache entry and ignors the old one created? Any ideas?
I had some similar problems with Zend_Paginator. These problems only come with Zend_Paginator_Adapter_DbTableSelect (I had no problems with Zend_Paginator_Adapter_Array).
The bolded part of the cache filename zend_cache---Zend_Paginator_3_2b49905a9282f742e1cefafc53892794 is made by _getCacheId function (check Zend_Paginator) based on the adapter passed to the constructor. On each request, the paginator creates a new code because the adapter is never the same at the $_cache->load moment and $_cache->save moment.
The md5 serialized value of the adapter used as filename when data is saved into cache is different from the one used when data is read from cache if you have DB profiler enabled. You must not use DB profiler in order for the Zend_Paginator cache to work (use it only in development stage).
Another failure reason that I have found is determined by these two lines of code:
$offset = ($pageNumber - 1) * $this->getItemCountPerPage();
$items = $this->_adapter->getItems($offset, $this->getItemCountPerPage());
They are called between $_cache->load and $_cache->save and they add a limitcount value and a limitoffset value to adapter. This values aren't set when $_cache->load is called so the filename based on the md5 serialized value of the adapter will be different in this case too.
They must be placed before $_cache->load. You can make a paginator class that extends Zend_Paginator and modify getItemsByPage function. Add the two lines at the beggining, after $pageNumber = $this->normalizePageNumber($pageNumber).
This worked for me. I hope it will help others too.

Categories