go to post Vitaliy Serdtsev · Jun 13, 2018 You can change the XSLFO Stylesheet dynamically or statically. See XSLFOSTYLESHEET So, there is a class-report, for example MyApp.ReportDemo. Series of steps: remove option XSLFOSTYLESHEET, if any, and recompile class generate XSLFO Stylesheet: SAMPLES>d $system.OBJ.DisplayError(##class(MyApp.ReportDemo).GenerateToFile($system.CSP.GetFileName($system.CSP.GetDefaultApp($zu(5))_"/MyApp.ReportDemo.xsl"),4)) make changes to MyApp.ReportDemo.xsl add the parameter XSLFOSTYLESHEET and recompile the class again /// If defined, this provides a reference to the external /// stylesheet to use in generating the XSL-FO (PDF) report. /// If it is not provided, a stylesheet will be generated /// from the ReportDisplay XData block. Parameter XSLFOSTYLESHEET As String = "MyApp.ReportDemo.xsl"; Now open the report in your browser/command line/etc. Profit! Important: if you change something in ReportDisplay, you need to repeat the steps again.
go to post Vitaliy Serdtsev · Jun 12, 2018 Page numbering in Roman Numerals Need add the attribute format to the element <fo:page-sequence>, i.e. <fo:page-sequence master-reference='blablabla' format ='I' .. >Possible value format: format="1" results in 1 2 3 . . format="01" results in 01 02 03 format="a" results in a b c . . format="A" results in A B C. . format="i" results in i ii iii iv . . format="I" results in I II III IV . . more.. Example: Do all the steps according to Zen Report Tutorial Insert the page number into <pagefooter> <!-- Optional Pagefooter element. Does not apply in HTML output. --> <pagefooter> <item special="page-number"/> </pagefooter> Insert the following code into the class: ClassMethod ReplaceStream( ByRef stream As %Stream.TmpBinary, format) [ Private ] { s tmp=##class(%Stream.TmpBinary).%New() while 'stream.AtEnd { d tmp.Write($replace(stream.Read($$$MaxLocalLength),"<fo:page-sequence ",$$$FormatText("<fo:page-sequence format=%1 ",$$$quote(format)))) } d stream.CopyFrom(tmp) } /// d ##class(MyApp.ReportDemo).Test() ClassMethod Test(format = "1") { /* •0 = XML •1 = HTML •2 = PDF •3 = ToHTML Stylesheet •4 = ToXSLFO Stylesheet •5 = XSD Schema •6 = PrintPS •7 = Excel •8 = XSLFO •9 = ToEXCEL •10=xlsx •11=TIFF •12=pdfprint •13=displayxlsx •14=fo2pdf •15=foandpdf */ s xslfo=##class(%Stream.TmpBinary).%New() s t=..%New() d t.GenerateReportToStream(.xslfo,4) d ..ReplaceStream(.xslfo,format) s t.toxslfostream=xslfo d $system.OBJ.DisplayError(t.GenerateReport("c:\temp\test.pdf",2)) } SAMPLES>d ##class(MyApp.ReportDemo).Test("I") or SAMPLES>d ##class(MyApp.ReportDemo).Test("01") or SAMPLES>d ##class(MyApp.ReportDemo).Test("A") open test.pdf. Profit!
go to post Vitaliy Serdtsev · Jun 6, 2018 Yes, this (Classmethod Public) is only necessary for the second example.
go to post Vitaliy Serdtsev · Jun 6, 2018 Choose to your taste: Class dc.test [ Abstract ] { ClassMethod Public() [ Internal, Private, ProcedureBlock = 0 ] { q Choice0() q "Sunday" Choice1() q "Monday" Choice2() q "Tuesday" Choice3() q "Wednesday" Choice4() q "Thursday" Choice5() q "Friday" Choice6() q "Saturday" Choice() set a="entry " _"error" return a } /// d ##class(dc.test).Test() ClassMethod Test() { s daynum=$zd($h,10) w "1) ",$case(daynum, 0:$$Choice0, 1:$$Choice1, 2:$$Choice2, 3:$$Choice3, 4:$$Choice4, 5:$$Choice5, 6:$$Choice6, :$$Choice),! w "2) ",@("$$Choice"_$case(daynum, 0:0, 1:1, 2:2, 3:3, 4:4, 5:5, 6:6, :"")),! s daynum="-" w "3) ",$case(daynum, 0:"Sunday", 1:"Monday", 2:"Tuesday", 3:"Wednesday", 4:"Thursday", 5:"Friday", 6:"Saturday", :$xecute("()"_ " set a=""entry "" _""error"""_ " return a")),! } }
go to post Vitaliy Serdtsev · Jun 4, 2018 Here is my solution, which has a number of advantages: there are no restrictions to the order of ID you can search in queries for the entire timestamp or for parts of it standard, reliable and proven Caché features are used this works very, very fast. See my article for details: Indexing of non-atomic attributes Class dc.TSOrder Extends (%Persistent, %Populate) { Index Extent [ Extent, Type = bitmap ]; Index iSmartTS On (TS(KEYS), TS(ELEMENTS)); Index iTS On TS; Property TS As %TimeStamp(MAXVAL = "2016-07-31 23:59:59.999999", MINVAL = "2016-07-01 00:00:00.000000"); Property Data As %String(MAXLEN = 200, MINLEN = 100); ClassMethod TSBuildValueArray( value, ByRef array) As %Status { i value="" { s array(0)=value }else{ s date=$p(value," ",1), time=$p(value," ",2), array("date")=date, array("time")=time, array("ddhh")=$p(date,"-",3)_"-"_$p(time,":",1) } q $$$OK } /// d ##class(dc.TSOrder).Fill() ClassMethod Fill(N = {30e6}) { d ..%KillExtent(), ..Populate(N), $system.SQL.TuneTable($classname(),$$$YES), $system.OBJ.Compile($classname(),"cu-d") } }Results from SMP: select distinct null from dc.TSOrder where TS between {ts '2016-07-01 00:00:00.00000'} AND {ts '2016-07-01 23:59:59.999999'} Performance: 2.339 seconds 2109755 global references 14768692 lines executed (the number of selected records is 968476, used the normal index) select distinct null from dc.TSOrder where for some %element(TS) (%key='date' and %value = '2016-07-01') Performance: 2.269 seconds 1936962 global references 15496098 lines executed (the number of selected records is 968476, used the "smart" index) select distinct null from dc.TSOrder where for some %element(TS) (%key='ddhh' and %value = '01-13') Performance: 0.096 seconds 80488 global references 644270 lines executed (the number of selected records is 40239, used the "smart" index)
go to post Vitaliy Serdtsev · May 28, 2018 Try so: <tabGroup ... onshowTab="zenThis.refreshContents(true);"> </tabGroup>
go to post Vitaliy Serdtsev · May 11, 2018 You can see the code examples and coding style in the sources of namespaces '%SYS' and/or 'SAMPLES'. But keep in mind that the style of classes written a long time ago differs significantly from style of classes written relatively recently, ex. [$ZT vs try/catch] or [%ResultSet vs %SQL.Statement]
go to post Vitaliy Serdtsev · May 11, 2018 For self - education is the best - documentation, for example: Introduction to Caché Caché Programming Orientation Guide ObjectScript Tutorial Caché QuickStart Tutorial General System Limits Identifier Length Considerations and etc.
go to post Vitaliy Serdtsev · May 10, 2018 Localization in Caché DBMS Simple example: Class dc.test Extends %ZEN.Component.page { Parameter DOMAIN = "DCTEST"; XData Contents [ XMLNamespace = "http://www.intersystems.com/zen" ] { <page xmlns="http://www.intersystems.com/zen"> <radioSet id="lng" label="Текущий язык" layout="vertical" displayList="Португальский,Русский" valueList="pt-br,ru" value="ru" onchange="zenPage.changeLang(zenThis.value);" /> <form> <text label="Описание" required="true" requiredMessage="обязательно." /> <submit caption="Сохранить"/> </form> </page> } /// User clicked to change preferred language. ClientMethod changeLang(lng) [ Language = javascript ] { var ok = this.SrvChangeLang(lng); self.document.location.reload(); } /// Change preferred language for this session and page ClassMethod SrvChangeLang(lng) As %Boolean [ ZenMethod ] { s %session.Language=lng s %response.Language=lng q $$$YES } Method %OnAfterCreatePage() As %Status { d ..%SetValueById("lng",%session.Language) Quit $$$OK } } USER>d ##class(%MessageDictionary).ExportDomainList("messages_ru.xml","DCTEST","ru") Result (messages_ru.xml): <?xml version="1.0" encoding="UTF-8"?> <MsgFile Language="ru"> <MsgDomain Domain="DCTEST"> <Message Id="358179803">Текущий язык</Message> <Message Id="1805419696">Португальский,Русский</Message> <Message Id="2153752096">Описание</Message> <Message Id="2835101332">обязательно.</Message> <Message Id="3683485237">Сохранить</Message> </MsgDomain> </MsgFile> messages_pt-br.xml: <?xml version="1.0" encoding="UTF-8"?> <MsgFile Language="pt-br"> <MsgDomain Domain="DCTEST"> <Message Id="358179803">Idioma atual</Message> <Message Id="1805419696">Português,Russo</Message> <Message Id="2153752096">Descrição</Message> <Message Id="2835101332">é obrigatório.</Message> <Message Id="3683485237">Salvar</Message> </MsgDomain> </MsgFile> USER>d ##class(%MessageDictionary).Import("messages_pt-br.xml") Profit!
go to post Vitaliy Serdtsev · May 8, 2018 HOWTO: DER vs. CRT vs. CER vs. PEM Certificates and How To Convert Them
go to post Vitaliy Serdtsev · May 7, 2018 USER>w $zv Cache for Windows (x86-32) 2015.2 (Build 664_3U) Wed Aug 12 2015 12:29:34 EDTThe date is saved to the database correctly. Class dc.A Extends %Persistent { Property DOB As %Date; } Class dc.MVC.A Extends %ZEN.DataModel.ObjectDataModel { Property DOB As %Date(ZENATTRS = "id:DOB|format:DMY|separator:/", ZENCONTROL = "dateText"); Method %OnNewSource(Output pSC As %Status = {$$$OK}) As %RegisteredObject { q ##class(dc.A).%New() } Method %OnOpenSource( pID As %String, pConcurrency As %Integer = -1, Output pSC As %Status = {$$$OK}) As %RegisteredObject { q ##class(dc.A).%OpenId(pID,pConcurrency,.pSC) } Method %OnSaveSource(pSource As dc.A) As %Status { q pSource.%Save() } ClassMethod %OnDeleteSource(pID As %String) As %Status { q ##class(dc.A).%DeleteId(pID) } Method %OnLoadModel(pSource As dc.A) As %Status { s ..DOB = pSource.DOB q $$$OK } Method %OnStoreModel(pSource As dc.A) As %Status { s pSource.DOB = ..DOB q $$$OK } } Class dc.test Extends %ZEN.Component.page { XData Contents [ XMLNamespace = "http://www.intersystems.com/zen" ] { <page xmlns="http://www.intersystems.com/zen"> <dataController id="a-controller" modelClass="dc.MVC.A" modelId=""/> <dynaForm id="a-form" controllerId="a-controller"/> <button caption="Save" onclick="zen('a-form').save();" /> </page> } }
go to post Vitaliy Serdtsev · Apr 25, 2018 Still can be so: Class dc.test [ Abstract ] { ClassMethod Test(s = "#") { w "Test_",s } ClassMethod mac() [ ProcedureBlock = 0 ] { sub1(s=1) w "sub1_",s q sub2(s=2) w "sub2_",s q procPrivate(s=3) { w "procPrivate_",s } procPublic(s=3) public { w "procPublic_",s } } }Result: USER>d zTest^dc.test.1(1) Test_1 USER>d sub1^dc.test.1 sub1_1 USER>d sub2^dc.test.1 sub2_2 USER>d sub1^dc.test.1(10) sub1_10 USER>d sub2^dc.test.1(10) sub2_10 USER>d procPrivate^dc.test.1(10) D procPrivate^dc.test.1(10) ^ USER>d procPublic^dc.test.1(10) procPublic_10 USER>
go to post Vitaliy Serdtsev · Apr 23, 2018 This can be done also in the CLS. TEST(invar) [outvar] public { }=> ClassMethod TEST(invar) [PublicList=outvar] { }PublicList
go to post Vitaliy Serdtsev · Apr 14, 2018 %PosixTime %PosixTime is preferable to %TimeStamp, because it takes up less disk space and memory than the %TimeStamp data type and provides better performance than %TimeStamp.proof