I finally got doxygen to work with php and PHPDoc styled comments (I'm removing '#package' with filter since it breaks up doxygen) though there's one thing I would love to have and are not able to figure out how.
In PHP I'm writing multiple property declaration in a class like this:
class Foo
{
private
/// the blue color
$blue,
/// the red color
$red,
/// the yellow color
$yellow;
public
/// the orange color
$orange,
/// black (no color)
$black;
public function bar() {}
}
If I'm now generating the docs, only the first property is shown as private Attribute while all other properties are simply referenced as Data Fields. So doxygen obviously doesn't parse the accesors of every property after the first one.
Is it possible to make this commentation style compatible to doxygen ?
P.S: I thought about applying a filter which converts it in doxygen-parsable code style. Though this would only be a fix I'm currently working on it.
I wrote this filter, that works for the example you provided. I think it should also work for more complex examples.
// Get the input
$source = file_get_contents($argv[1]);
$count = 0;
do {
$source = preg_replace('#(private|public|protected)(\s*[^$]*)(\$[^,;]+),#',
"$2 $1 $3;\n$1 ", $source, -1, $count);
} while($count > 0);
// Output
echo $source;
You can find this and other filters at my GitHub repository doxygen-php-filters.
Related
I have an issue with dompdf where it shows me strange padding all the time that should not be there.
Above is the image where it is happening where my html itself i just a simple 1 tag with some text in it.
I initiate the library as:
class OmnPdf extends \Dompdf\Dompdf
{
public function __construct($options = null)
{
if($options == null){
$options = new \Dompdf\Options();
}
$options->setIsPhpEnabled(true);
$options->setIsHtml5ParserEnabled(true); // For combining multiple pdf outputs
$options->setIsFontSubsettingEnabled(true);
$options->setDefaultPaperSize('A4');
$options->setDebugCss(true);
$options->setDebugLayout(true);
$options->setDpi(72);
parent::__construct($options);
}
}
What i am expecting is that the text will be alligned according the outer page (see red line).
Thanks,
Pim
Are you loading a custom font? Because I'm pretty sure this is causing your issue.
I'm calling these 3 functions one after other in this exact order
public function setPrintFitToWidth()
{
$this->sheet->getPageSetup()->setFitToWidth(1);
}
public function setPrintArea($cell_area)
{
$this->sheet->getPageSetup()->setPrintArea($cell_area);
}
public function setPrintMargins($top, $right, $bottom, $left)
{
$this->sheet->getPageMargins()->setTop($top);
$this->sheet->getPageMargins()->setRight($right);
$this->sheet->getPageMargins()->setLeft($left);
$this->sheet->getPageMargins()->setBottom($bottom);
}
The problem is that, opening resulting Excel file, I've page margin set to 'custom' but, in fact, set to different values instead of margin I passed to my function. In fact I called with argument (1,0.5,0.5,1) but I got, in the same orders, 2, 0.8, 0.8, 2. It's really strange ...
Also: I cannot get working setFittoWidth(1); I expect to see adapted for all column in one page, but Excel tell me It's setup on adapt sheet on a page.
What am I doing wrong?
Resolved:
changed
public function setPrintFitToWidth()
{
$this->sheet->getPageSetup()->setFitToWidth(1);
}
to
public function setPrintFitToWidth()
{
$this->sheet->getPageSetup()->setFitToWidth(1);
$this->sheet->getPageSetup()->setFitToHeight(0);
}
About the margins: I tried with zero and margin are respected, so I concluded than PHPExcel unit are in someway 'scaled down'... So, after some 'try' and 'redo', I found the values that generate the correct magins
This class is fairly simple, it adds a twitter hashtag to a string if there is room for it. Twitter only allows 140 characters (minus 23 for a url). So the hashtags keep getting added if there is space for one.
I don't think it's 100% working as expected, but that is not relevant to my question which is located below.
class Hashtags {
private $url_character_count = 23;
private $characters_allowed = 140;
public function __construct(Article $article)
{
$this->article = $article;
$this->characters_remaining = $this->characters_allowed - $this->url_character_count;
}
public function createHashtagString()
{
$hashtags = '';
$hashtags .= $this->addEachNodeHashtag();
$hashtags .= $this->addHashtagIfSpace($this->article->topic_hashtag);
$hashtags .= $this->addHashtagIfSpace($this->article->pubissue_hashtag);
$hashtags .= $this->addHashtagIfSpace($this->article->subject_area_hashtag);
$hashtags .= $this->addHashtagIfSpace('#aviation');
return $hashtags;
}
private function addEachNodeHashtag()
{
//Returns a hashtag or calls hashtagString() if it is a comma separated list
}
private function hashtagString()
{
//Explodes a comma seperated string of hashtags and calls addHashtagIfSpace()
}
private function addHashtagIfSpace($hashtag_string)
{
if((strlen($hashtag_string) + 1) <= $this->characters_remaining)
{
$this->characters_remaining = $this->characters_remaining - strlen($hashtag_string);
if(empty($hashtag_string))
{
return '';
}
return ' ' . $hashtag_string;
}
}
}
Here is my test, my problem is that this only tests one specific case, where all the fields are filled in, and when there is enough space to fit them all. Should I just keep making a bunch of these test functions for different cases? I am guessing there will be about 10 of them. I have never done testing before, so I am a bit out of my element and need to to pointed in the correct direction.
Thank you
class HashtagsSpec extends ObjectBehavior
{
function it_creates_hashtag_string_with_all_fields_filled_in(Article $article)
{
$this->beConstructedWith($article);
$article->title = 'This is the article title';
$article->url = 'http://website.com/node/XXX';
$article->pubissue_hashtag = '#AHASHTAG';
$article->subject_area_hashtag = '#SUBAREA';
$article->topic_hashtag = '#TOPIC';
$article->node_hashtags = '#Test1,#Test2,#Test3';
$this->createHashtagString()->shouldReturn(' #Test1 #Test2 #Test3 #TOPIC #AHASHTAG #SUBAREA #aviation');
}
}
Step 0
Remove your class and start over by writing specs first.
When doing this you'll often find yourself writing a different (simpler) implementation, when driving it with specs. It won't take much time, but your class will benefit of a better design and testability.
I often use this practice when I don't know what code should look like. I prototype it first. Once the design starts to clarify, I remove the code and start over by speccing it.
You don't have to remove it for real, make a backup ;)
Step 1
Define your initial test list. This will be a list of behaviours you think you need to cover. It doesn't have to be complete and it will evolve as you go along.
You could start with:
it adds a topic hashtag if there is room for it in the message
it adds a pubissue hashtag if there is room for it in the message after adding a topic hashtag
it adds a subject area hashtag if there is room for it in the message after adding topic and pubissue hashtags
it does not add a topic hashtag if there is no room for it in the message
it does not add a pubissue hashtag if there is no room for it in the message after adding a topic hashtag
it does not add a subject area hashtag if there is no room for it in the message after adding topic and pubissue hashtags
Step 2
Write a first spec. Think of better naming as Hashtags might not be specific enough. Also consider a better API for your class. I chose to accept Article in a method call rather than passing it via the constructor:
class HashtagsSpec
{
function it_adds_a_topic_hashtag_if_there_is_room_for_it_in_the_message(Article $article)
{
$article->pubissue_hashtag = '#AHASHTAG';
$article->subject_area_hashtag = '#SUBAREA';
$article->topic_hashtag = '#TOPIC';
$article->node_hashtags = '#Test1,#Test2,#Test3';
$this->createHashtagString($article)->shouldMatch('/#TOPIC/');
}
}
Step 3
Run phpspec and write the simplest code to make specs pass.
class Hashtags
{
public function createHashtagString(Article $article)
{
return $article->topic_hashtag;
}
}
Step 4
Refactor - improve the design of code you wrote in Step 3.
It might be that there's nothing to improve, especially in the first iteration(s).
As you go along, your code will become more generic, while your specs become more specific.
Step 5
Repeat steps 2 to 5 until you're done. Simply pickup next behaviour you want to cover. It doesn't have to be the next one on your list. Whatever you feel is best to implement next.
During the whole process you'll often discover new behaviours or edge cases you haven't thought about before. Simply add them to your test list so it doesn't distract your flow.
I'd like to be able to return an image in Black&white in a controller, so I can use it in a template. On this page I found that the GD class has a greyscale method. Unfortunately I don't understand the GD class and how I can use it. I tried doing
$final = $image->getFormattedImage('greyscale',36,36,36);
But that didn't work. It does return an image object with a new URL but the image does not exist.
Can anyone explain to me how to make an imageobject into a greyscale image in a Silverstripe page Controller?
Well I had a go myself and this is what I came up with:
_config.php
Object::add_extension('Image', 'Greyscaled');
UPDATE: as of SilverStripe 3.1, you should use the config system instead of _config.php. Put the following in your mysite/_config/config.yml (Don't forget to ?flush=1 to reload the config cache after adding it):
Image:
extensions:
- 'Greyscaled'
Greyscaled.php
<?php
class Greyscaled extends DataExtension {
//This allows the template to pick up "GreyscaleImage" property, it requests a copy of the image from the cache or if it doesn't exist, generates a new one
public function GreyscaleImage($RGB = '76 147 29') {
return $this->owner->getFormattedImage('GreyscaleImage', $RGB);
}
//This is called internally by "generateFormattedImage" when the item is not already cached
public function generateGreyscaleImage(GD $gd, $RGB) {
$Vars = explode(' ', $RGB);
return $gd->greyscale($Vars[0], $Vars[1], $Vars[2]);
}
}
UPDATE2: With newer Versions of 3.1 ?? you can pass in more than 2 parameters and GD has been renamed to Image_Backend. This way you do not have spaces between the RGB-values in the image-name. Be aware $gd->greyscale needs a lot of juice - so you probable better downsize first and GreyscaleImage afterwards.
UPDATE3: Since this answer got some votes recently I assume people still using it, but I think in 2017 CSS filters are in many cases a better choice. Prefixed you'll have close to 90% coverage.
css-filters on caniuse.com
<?php
class Greyscaled extends DataExtension {
public function GreyscaleImage($R = '76', $G = '147', $B = '29') {
return $this->owner->getFormattedImage('GreyscaleImage', $R, $G, $B);
}
public function generateGreyscaleImage(Image_Backend $gd, $R, $G, $B) {
return $gd->greyscale($R, $G, $B);
}
}
and in the template:
<img src="$Images.GreyscaleImage.CroppedImage(1000,400).URL" alt="$Images.Title" />
Silverstripe 3.1 Image API
There is a module for this. Sorry but it's not on packagist just yet.
https://github.com/NightJar/ssrigging-greyscaleimages
I have an issue with rendering wikitext in hook for tag processing.
public static function onTagRender( $input, array $args, $parser, $frame ) {
...
$text = $parser->recursiveTagParse($sometext, $frame);
...
return $text;
}
If $sometext contains e.g.
"Example from page [[XYZ]]"
then I expect returned $text should contain
"Example from page XYZ"
But I get only
"Example from page <!--LINK 0:0-->"
I have tried also $parser->replaceInternalLinks(), but with same result. What have I overlooked?
If some people run into the same problem, try calling replaceLinkHolders after recursiveTagParse. (I didn't have the same problem so I didn't test it.)
So in OP's code snippet, that would be:
public static function onTagRender( $input, array $args, $parser, $frame ) {
...
$text = $parser->recursiveTagParse($sometext, $frame);
$text = $parser->replaceLinkHolders($text);
...
return $text;
}
Explanation according to my understanding:
Actually, the usual parse method calls the internalParse method -- which does most of the job -- and then do some other stuff. On the other hand, recursiveTagParse is almost only calling internalParse, so it doesn't execute the other stuff from parse.
Problem is, links are parsed in two steps:
Links are first extracted into LinkHolderArray and they are replaced with <!--LINK $ns:$key--> in the text.
(This is done by replaceInternalLinks, called by internalParse, so that's fine.)
Then <!--LINK $ns:$key--> markers are parsed into HTML links.
(This is done by replaceLinkHolders which is called by parse, not by internalParse, and thus not by recursiveTagParse.)
Parser::recursiveTagParse only do partial rendering, afaik. That may or may not be the problem. To fully render any user input, you will have to create a parser function (http://www.mediawiki.org/wiki/Manual:Parser_functions) instead of a tag function.
See http://www.mediawiki.org/wiki/Manual:Tag_extensions#How_do_I_render_wikitext_in_my_extension.3F