_temp_manual.xml 958 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415841684178418841984208421842284238424842584268427842884298430843184328433843484358436843784388439844084418442844384448445844684478448844984508451845284538454845584568457845884598460846184628463846484658466846784688469847084718472847384748475847684778478847984808481848284838484848584868487848884898490849184928493849484958496849784988499850085018502850385048505850685078508850985108511851285138514851585168517851885198520852185228523852485258526852785288529853085318532853385348535853685378538853985408541854285438544854585468547854885498550855185528553855485558556855785588559856085618562856385648565856685678568856985708571857285738574857585768577857885798580858185828583858485858586858785888589859085918592859385948595859685978598859986008601860286038604860586068607860886098610861186128613861486158616861786188619862086218622862386248625862686278628862986308631863286338634863586368637863886398640864186428643864486458646864786488649865086518652865386548655865686578658865986608661866286638664866586668667866886698670867186728673867486758676867786788679868086818682868386848685868686878688868986908691869286938694869586968697869886998700870187028703870487058706870787088709871087118712871387148715871687178718871987208721872287238724872587268727872887298730873187328733873487358736873787388739874087418742874387448745874687478748874987508751875287538754875587568757875887598760876187628763876487658766876787688769877087718772877387748775877687778778877987808781878287838784878587868787878887898790879187928793879487958796879787988799880088018802880388048805880688078808880988108811881288138814881588168817881888198820882188228823882488258826882788288829883088318832883388348835883688378838883988408841884288438844884588468847884888498850885188528853885488558856885788588859886088618862886388648865886688678868886988708871887288738874887588768877887888798880888188828883888488858886888788888889889088918892889388948895889688978898889989008901890289038904890589068907890889098910891189128913891489158916891789188919892089218922892389248925892689278928892989308931893289338934893589368937893889398940894189428943894489458946894789488949895089518952895389548955895689578958895989608961896289638964896589668967896889698970897189728973897489758976897789788979898089818982898389848985898689878988898989908991899289938994899589968997899889999000900190029003900490059006900790089009901090119012901390149015901690179018901990209021902290239024902590269027902890299030903190329033903490359036903790389039904090419042904390449045904690479048904990509051905290539054905590569057905890599060906190629063906490659066906790689069907090719072907390749075907690779078907990809081908290839084908590869087908890899090909190929093909490959096909790989099910091019102910391049105910691079108910991109111911291139114911591169117911891199120912191229123912491259126912791289129913091319132913391349135913691379138913991409141914291439144914591469147914891499150915191529153915491559156915791589159916091619162916391649165916691679168916991709171917291739174917591769177917891799180918191829183918491859186918791889189919091919192919391949195919691979198919992009201920292039204920592069207920892099210921192129213921492159216921792189219922092219222922392249225922692279228922992309231923292339234923592369237923892399240924192429243924492459246924792489249925092519252925392549255925692579258925992609261926292639264926592669267926892699270927192729273927492759276927792789279928092819282928392849285928692879288928992909291929292939294929592969297929892999300930193029303930493059306930793089309931093119312931393149315931693179318931993209321932293239324932593269327932893299330933193329333933493359336933793389339934093419342934393449345934693479348934993509351935293539354935593569357935893599360936193629363936493659366936793689369937093719372937393749375937693779378937993809381938293839384938593869387938893899390939193929393939493959396939793989399940094019402940394049405940694079408940994109411941294139414941594169417941894199420942194229423942494259426942794289429943094319432943394349435943694379438943994409441944294439444944594469447944894499450945194529453945494559456945794589459946094619462946394649465946694679468946994709471947294739474947594769477947894799480948194829483948494859486948794889489949094919492949394949495949694979498949995009501950295039504950595069507950895099510951195129513951495159516951795189519952095219522952395249525952695279528952995309531953295339534953595369537953895399540954195429543954495459546954795489549955095519552955395549555955695579558955995609561956295639564956595669567956895699570957195729573957495759576957795789579958095819582958395849585958695879588958995909591959295939594959595969597959895999600960196029603960496059606960796089609961096119612961396149615961696179618961996209621962296239624962596269627962896299630963196329633963496359636963796389639964096419642964396449645964696479648964996509651965296539654965596569657965896599660966196629663966496659666966796689669967096719672967396749675967696779678967996809681968296839684968596869687968896899690969196929693969496959696969796989699970097019702970397049705970697079708970997109711971297139714971597169717971897199720972197229723972497259726972797289729973097319732973397349735973697379738973997409741974297439744974597469747974897499750975197529753975497559756975797589759976097619762976397649765976697679768976997709771977297739774977597769777977897799780978197829783978497859786978797889789979097919792979397949795979697979798979998009801980298039804980598069807980898099810981198129813981498159816981798189819982098219822982398249825982698279828982998309831983298339834983598369837983898399840984198429843984498459846984798489849985098519852985398549855985698579858985998609861986298639864986598669867986898699870987198729873987498759876987798789879988098819882988398849885988698879888988998909891989298939894989598969897989898999900990199029903990499059906990799089909991099119912991399149915991699179918991999209921992299239924992599269927992899299930993199329933993499359936993799389939994099419942994399449945994699479948994999509951995299539954995599569957995899599960996199629963996499659966996799689969997099719972997399749975997699779978997999809981998299839984998599869987998899899990999199929993999499959996999799989999100001000110002100031000410005100061000710008100091001010011100121001310014100151001610017100181001910020100211002210023100241002510026100271002810029100301003110032100331003410035100361003710038100391004010041100421004310044100451004610047100481004910050100511005210053100541005510056100571005810059100601006110062100631006410065100661006710068100691007010071100721007310074100751007610077100781007910080100811008210083100841008510086100871008810089100901009110092100931009410095100961009710098100991010010101101021010310104101051010610107101081010910110101111011210113101141011510116101171011810119101201012110122101231012410125101261012710128101291013010131101321013310134101351013610137101381013910140101411014210143101441014510146101471014810149101501015110152101531015410155101561015710158101591016010161101621016310164101651016610167101681016910170101711017210173101741017510176101771017810179101801018110182101831018410185101861018710188101891019010191101921019310194101951019610197101981019910200102011020210203102041020510206102071020810209102101021110212102131021410215102161021710218102191022010221102221022310224102251022610227102281022910230102311023210233102341023510236102371023810239102401024110242102431024410245102461024710248102491025010251102521025310254102551025610257102581025910260102611026210263102641026510266102671026810269102701027110272102731027410275102761027710278102791028010281102821028310284102851028610287102881028910290102911029210293102941029510296102971029810299103001030110302103031030410305103061030710308103091031010311103121031310314103151031610317103181031910320103211032210323103241032510326103271032810329103301033110332103331033410335103361033710338103391034010341103421034310344103451034610347103481034910350103511035210353103541035510356103571035810359103601036110362103631036410365103661036710368103691037010371103721037310374103751037610377103781037910380103811038210383103841038510386103871038810389103901039110392103931039410395103961039710398103991040010401104021040310404104051040610407104081040910410104111041210413104141041510416104171041810419104201042110422104231042410425104261042710428104291043010431104321043310434104351043610437104381043910440104411044210443104441044510446104471044810449104501045110452104531045410455104561045710458104591046010461104621046310464104651046610467104681046910470104711047210473104741047510476104771047810479104801048110482104831048410485104861048710488104891049010491104921049310494104951049610497104981049910500105011050210503105041050510506105071050810509105101051110512105131051410515105161051710518105191052010521105221052310524105251052610527105281052910530105311053210533105341053510536105371053810539105401054110542105431054410545105461054710548105491055010551105521055310554105551055610557105581055910560105611056210563105641056510566105671056810569105701057110572105731057410575105761057710578105791058010581105821058310584105851058610587105881058910590105911059210593105941059510596105971059810599106001060110602106031060410605106061060710608106091061010611106121061310614106151061610617106181061910620106211062210623106241062510626106271062810629106301063110632106331063410635106361063710638106391064010641106421064310644106451064610647106481064910650106511065210653106541065510656106571065810659106601066110662106631066410665106661066710668106691067010671106721067310674106751067610677106781067910680106811068210683106841068510686106871068810689106901069110692106931069410695106961069710698106991070010701107021070310704107051070610707107081070910710107111071210713107141071510716107171071810719107201072110722107231072410725107261072710728107291073010731107321073310734107351073610737107381073910740107411074210743107441074510746107471074810749107501075110752107531075410755107561075710758107591076010761107621076310764107651076610767107681076910770107711077210773107741077510776107771077810779107801078110782107831078410785107861078710788107891079010791107921079310794107951079610797107981079910800108011080210803108041080510806108071080810809108101081110812108131081410815108161081710818108191082010821108221082310824108251082610827108281082910830108311083210833108341083510836108371083810839108401084110842108431084410845108461084710848108491085010851108521085310854108551085610857108581085910860108611086210863108641086510866108671086810869108701087110872108731087410875108761087710878108791088010881108821088310884108851088610887108881088910890108911089210893108941089510896108971089810899109001090110902109031090410905109061090710908109091091010911109121091310914109151091610917109181091910920109211092210923109241092510926109271092810929109301093110932109331093410935109361093710938109391094010941109421094310944109451094610947109481094910950109511095210953109541095510956109571095810959109601096110962109631096410965109661096710968109691097010971109721097310974109751097610977109781097910980109811098210983109841098510986109871098810989109901099110992109931099410995109961099710998109991100011001110021100311004110051100611007110081100911010110111101211013110141101511016110171101811019110201102111022110231102411025110261102711028110291103011031110321103311034110351103611037110381103911040110411104211043110441104511046110471104811049110501105111052110531105411055110561105711058110591106011061110621106311064110651106611067110681106911070110711107211073110741107511076110771107811079110801108111082110831108411085110861108711088110891109011091110921109311094110951109611097110981109911100111011110211103111041110511106111071110811109111101111111112111131111411115111161111711118111191112011121111221112311124111251112611127111281112911130111311113211133111341113511136111371113811139111401114111142111431114411145111461114711148111491115011151111521115311154111551115611157111581115911160111611116211163111641116511166111671116811169111701117111172111731117411175111761117711178111791118011181111821118311184111851118611187111881118911190111911119211193111941119511196111971119811199112001120111202112031120411205112061120711208112091121011211112121121311214112151121611217112181121911220112211122211223112241122511226112271122811229112301123111232112331123411235112361123711238112391124011241112421124311244112451124611247112481124911250112511125211253112541125511256112571125811259112601126111262112631126411265112661126711268112691127011271112721127311274112751127611277112781127911280112811128211283112841128511286112871128811289112901129111292112931129411295112961129711298112991130011301113021130311304113051130611307113081130911310113111131211313113141131511316113171131811319113201132111322113231132411325113261132711328113291133011331113321133311334113351133611337113381133911340113411134211343113441134511346113471134811349113501135111352113531135411355113561135711358113591136011361113621136311364113651136611367113681136911370113711137211373113741137511376113771137811379113801138111382113831138411385113861138711388113891139011391113921139311394113951139611397113981139911400114011140211403114041140511406114071140811409114101141111412114131141411415114161141711418114191142011421114221142311424114251142611427114281142911430114311143211433114341143511436114371143811439114401144111442114431144411445114461144711448114491145011451114521145311454114551145611457114581145911460114611146211463114641146511466114671146811469114701147111472114731147411475114761147711478114791148011481114821148311484114851148611487114881148911490114911149211493114941149511496114971149811499115001150111502115031150411505115061150711508115091151011511115121151311514115151151611517115181151911520115211152211523115241152511526115271152811529115301153111532115331153411535115361153711538115391154011541115421154311544115451154611547115481154911550115511155211553115541155511556115571155811559115601156111562115631156411565115661156711568115691157011571115721157311574115751157611577115781157911580115811158211583115841158511586115871158811589115901159111592115931159411595115961159711598115991160011601116021160311604116051160611607116081160911610116111161211613116141161511616116171161811619116201162111622116231162411625116261162711628116291163011631116321163311634116351163611637116381163911640116411164211643116441164511646116471164811649116501165111652116531165411655116561165711658116591166011661116621166311664116651166611667116681166911670116711167211673116741167511676116771167811679116801168111682116831168411685116861168711688116891169011691116921169311694116951169611697116981169911700117011170211703117041170511706117071170811709117101171111712117131171411715117161171711718117191172011721117221172311724117251172611727117281172911730117311173211733117341173511736117371173811739117401174111742117431174411745117461174711748117491175011751117521175311754117551175611757117581175911760117611176211763117641176511766117671176811769117701177111772117731177411775117761177711778117791178011781117821178311784117851178611787117881178911790117911179211793117941179511796117971179811799118001180111802118031180411805118061180711808118091181011811118121181311814118151181611817118181181911820118211182211823118241182511826118271182811829118301183111832118331183411835118361183711838118391184011841118421184311844118451184611847118481184911850118511185211853118541185511856118571185811859118601186111862118631186411865118661186711868118691187011871118721187311874118751187611877118781187911880118811188211883118841188511886118871188811889118901189111892118931189411895118961189711898118991190011901119021190311904119051190611907119081190911910119111191211913119141191511916119171191811919119201192111922119231192411925119261192711928119291193011931119321193311934119351193611937119381193911940119411194211943119441194511946119471194811949119501195111952119531195411955119561195711958119591196011961119621196311964119651196611967119681196911970119711197211973119741197511976119771197811979119801198111982119831198411985119861198711988119891199011991119921199311994119951199611997119981199912000120011200212003120041200512006120071200812009120101201112012120131201412015120161201712018120191202012021120221202312024120251202612027120281202912030120311203212033120341203512036120371203812039120401204112042120431204412045120461204712048120491205012051120521205312054120551205612057120581205912060120611206212063120641206512066120671206812069120701207112072120731207412075120761207712078120791208012081120821208312084120851208612087120881208912090120911209212093120941209512096120971209812099121001210112102121031210412105121061210712108121091211012111121121211312114121151211612117121181211912120121211212212123121241212512126121271212812129121301213112132121331213412135121361213712138121391214012141121421214312144121451214612147121481214912150121511215212153121541215512156121571215812159121601216112162121631216412165121661216712168121691217012171121721217312174121751217612177121781217912180121811218212183121841218512186121871218812189121901219112192121931219412195121961219712198121991220012201122021220312204122051220612207122081220912210122111221212213122141221512216122171221812219122201222112222122231222412225122261222712228122291223012231122321223312234122351223612237122381223912240122411224212243122441224512246122471224812249122501225112252122531225412255122561225712258122591226012261122621226312264122651226612267122681226912270122711227212273122741227512276122771227812279122801228112282122831228412285122861228712288122891229012291122921229312294122951229612297122981229912300123011230212303123041230512306123071230812309123101231112312123131231412315123161231712318123191232012321123221232312324123251232612327123281232912330123311233212333123341233512336123371233812339123401234112342123431234412345123461234712348123491235012351123521235312354123551235612357123581235912360123611236212363123641236512366123671236812369123701237112372123731237412375123761237712378123791238012381123821238312384123851238612387123881238912390123911239212393123941239512396123971239812399124001240112402124031240412405124061240712408124091241012411124121241312414124151241612417124181241912420124211242212423124241242512426124271242812429124301243112432124331243412435124361243712438124391244012441124421244312444124451244612447124481244912450124511245212453124541245512456124571245812459124601246112462124631246412465124661246712468124691247012471124721247312474124751247612477124781247912480124811248212483124841248512486124871248812489124901249112492124931249412495124961249712498124991250012501125021250312504125051250612507125081250912510125111251212513125141251512516125171251812519125201252112522125231252412525125261252712528125291253012531125321253312534125351253612537125381253912540125411254212543125441254512546125471254812549125501255112552125531255412555125561255712558125591256012561125621256312564125651256612567125681256912570125711257212573125741257512576125771257812579125801258112582125831258412585125861258712588125891259012591125921259312594125951259612597125981259912600126011260212603126041260512606126071260812609126101261112612126131261412615126161261712618126191262012621126221262312624126251262612627126281262912630126311263212633126341263512636126371263812639126401264112642126431264412645126461264712648126491265012651126521265312654126551265612657126581265912660126611266212663126641266512666126671266812669126701267112672126731267412675126761267712678126791268012681126821268312684126851268612687126881268912690126911269212693126941269512696126971269812699127001270112702127031270412705127061270712708127091271012711127121271312714127151271612717127181271912720127211272212723127241272512726127271272812729127301273112732127331273412735127361273712738127391274012741127421274312744127451274612747127481274912750127511275212753127541275512756127571275812759127601276112762127631276412765127661276712768127691277012771127721277312774127751277612777127781277912780127811278212783127841278512786127871278812789127901279112792127931279412795127961279712798127991280012801128021280312804128051280612807128081280912810128111281212813128141281512816128171281812819128201282112822128231282412825128261282712828128291283012831128321283312834128351283612837128381283912840128411284212843128441284512846128471284812849128501285112852128531285412855128561285712858128591286012861128621286312864128651286612867128681286912870128711287212873128741287512876128771287812879128801288112882128831288412885128861288712888128891289012891128921289312894128951289612897128981289912900129011290212903129041290512906129071290812909129101291112912129131291412915129161291712918129191292012921129221292312924129251292612927129281292912930129311293212933129341293512936129371293812939129401294112942129431294412945129461294712948129491295012951129521295312954129551295612957129581295912960129611296212963129641296512966129671296812969129701297112972129731297412975129761297712978129791298012981129821298312984129851298612987129881298912990129911299212993129941299512996129971299812999130001300113002130031300413005130061300713008130091301013011130121301313014130151301613017130181301913020130211302213023130241302513026130271302813029130301303113032130331303413035130361303713038130391304013041130421304313044130451304613047130481304913050130511305213053130541305513056130571305813059130601306113062130631306413065130661306713068130691307013071130721307313074130751307613077130781307913080130811308213083130841308513086130871308813089130901309113092130931309413095130961309713098130991310013101131021310313104131051310613107131081310913110131111311213113131141311513116131171311813119131201312113122131231312413125131261312713128131291313013131131321313313134131351313613137131381313913140131411314213143131441314513146131471314813149131501315113152131531315413155131561315713158131591316013161131621316313164131651316613167131681316913170131711317213173131741317513176131771317813179131801318113182131831318413185131861318713188131891319013191131921319313194131951319613197131981319913200132011320213203132041320513206132071320813209132101321113212132131321413215132161321713218132191322013221132221322313224132251322613227132281322913230132311323213233132341323513236132371323813239132401324113242132431324413245132461324713248132491325013251132521325313254132551325613257132581325913260132611326213263132641326513266132671326813269132701327113272132731327413275132761327713278132791328013281132821328313284132851328613287132881328913290132911329213293132941329513296132971329813299133001330113302133031330413305133061330713308133091331013311133121331313314133151331613317133181331913320133211332213323133241332513326133271332813329133301333113332133331333413335133361333713338133391334013341133421334313344133451334613347133481334913350133511335213353133541335513356133571335813359133601336113362133631336413365133661336713368133691337013371133721337313374133751337613377133781337913380133811338213383133841338513386133871338813389133901339113392133931339413395133961339713398133991340013401134021340313404134051340613407134081340913410134111341213413134141341513416134171341813419134201342113422134231342413425134261342713428134291343013431134321343313434134351343613437134381343913440134411344213443134441344513446134471344813449134501345113452134531345413455134561345713458134591346013461134621346313464134651346613467134681346913470134711347213473134741347513476134771347813479134801348113482134831348413485134861348713488134891349013491134921349313494134951349613497134981349913500135011350213503135041350513506135071350813509135101351113512135131351413515135161351713518135191352013521135221352313524135251352613527135281352913530135311353213533135341353513536135371353813539135401354113542135431354413545135461354713548135491355013551135521355313554135551355613557135581355913560135611356213563135641356513566135671356813569135701357113572135731357413575135761357713578135791358013581135821358313584135851358613587135881358913590135911359213593135941359513596135971359813599136001360113602136031360413605136061360713608136091361013611136121361313614136151361613617136181361913620136211362213623136241362513626136271362813629136301363113632136331363413635136361363713638136391364013641136421364313644136451364613647136481364913650136511365213653136541365513656136571365813659136601366113662136631366413665136661366713668136691367013671136721367313674136751367613677136781367913680136811368213683136841368513686136871368813689136901369113692136931369413695136961369713698136991370013701137021370313704137051370613707137081370913710137111371213713137141371513716137171371813719137201372113722137231372413725137261372713728137291373013731137321373313734137351373613737137381373913740137411374213743137441374513746137471374813749137501375113752137531375413755137561375713758137591376013761137621376313764137651376613767137681376913770137711377213773137741377513776137771377813779137801378113782137831378413785137861378713788137891379013791137921379313794137951379613797137981379913800138011380213803138041380513806138071380813809138101381113812138131381413815138161381713818138191382013821138221382313824138251382613827138281382913830138311383213833138341383513836138371383813839138401384113842138431384413845138461384713848138491385013851138521385313854138551385613857138581385913860138611386213863138641386513866138671386813869138701387113872138731387413875138761387713878138791388013881138821388313884138851388613887138881388913890138911389213893138941389513896138971389813899139001390113902139031390413905139061390713908139091391013911139121391313914139151391613917139181391913920139211392213923139241392513926139271392813929139301393113932139331393413935139361393713938139391394013941139421394313944139451394613947139481394913950139511395213953139541395513956139571395813959139601396113962139631396413965139661396713968139691397013971139721397313974139751397613977139781397913980139811398213983139841398513986139871398813989139901399113992139931399413995139961399713998139991400014001140021400314004140051400614007140081400914010140111401214013140141401514016140171401814019140201402114022140231402414025140261402714028140291403014031140321403314034140351403614037140381403914040140411404214043140441404514046140471404814049140501405114052140531405414055140561405714058140591406014061140621406314064140651406614067140681406914070140711407214073140741407514076140771407814079140801408114082140831408414085140861408714088140891409014091140921409314094140951409614097140981409914100141011410214103141041410514106141071410814109141101411114112141131411414115141161411714118141191412014121141221412314124141251412614127141281412914130141311413214133141341413514136141371413814139141401414114142141431414414145141461414714148141491415014151141521415314154141551415614157141581415914160141611416214163141641416514166141671416814169141701417114172141731417414175141761417714178141791418014181141821418314184141851418614187141881418914190141911419214193141941419514196141971419814199142001420114202142031420414205142061420714208142091421014211142121421314214142151421614217142181421914220142211422214223142241422514226142271422814229142301423114232142331423414235142361423714238142391424014241142421424314244142451424614247142481424914250142511425214253142541425514256142571425814259142601426114262142631426414265142661426714268142691427014271142721427314274142751427614277142781427914280142811428214283142841428514286142871428814289142901429114292142931429414295142961429714298142991430014301143021430314304143051430614307143081430914310143111431214313143141431514316143171431814319143201432114322143231432414325143261432714328143291433014331143321433314334143351433614337143381433914340143411434214343143441434514346143471434814349143501435114352143531435414355143561435714358143591436014361143621436314364143651436614367143681436914370143711437214373143741437514376143771437814379143801438114382143831438414385143861438714388143891439014391143921439314394143951439614397143981439914400144011440214403144041440514406144071440814409144101441114412144131441414415144161441714418144191442014421144221442314424144251442614427144281442914430144311443214433144341443514436144371443814439144401444114442144431444414445144461444714448144491445014451144521445314454144551445614457144581445914460144611446214463144641446514466144671446814469144701447114472144731447414475144761447714478144791448014481144821448314484144851448614487144881448914490144911449214493144941449514496144971449814499145001450114502145031450414505145061450714508145091451014511145121451314514145151451614517145181451914520145211452214523145241452514526145271452814529145301453114532145331453414535145361453714538145391454014541145421454314544145451454614547145481454914550145511455214553145541455514556145571455814559145601456114562145631456414565145661456714568145691457014571145721457314574145751457614577145781457914580145811458214583145841458514586145871458814589145901459114592145931459414595145961459714598145991460014601146021460314604146051460614607146081460914610146111461214613146141461514616146171461814619146201462114622146231462414625146261462714628146291463014631146321463314634146351463614637146381463914640146411464214643146441464514646146471464814649146501465114652146531465414655146561465714658146591466014661146621466314664146651466614667146681466914670146711467214673146741467514676146771467814679146801468114682146831468414685146861468714688146891469014691146921469314694146951469614697146981469914700147011470214703147041470514706147071470814709147101471114712147131471414715147161471714718147191472014721147221472314724147251472614727147281472914730147311473214733147341473514736147371473814739147401474114742147431474414745147461474714748147491475014751147521475314754147551475614757147581475914760147611476214763147641476514766147671476814769147701477114772147731477414775147761477714778147791478014781147821478314784147851478614787147881478914790147911479214793147941479514796147971479814799148001480114802148031480414805148061480714808148091481014811148121481314814148151481614817148181481914820148211482214823148241482514826148271482814829148301483114832148331483414835148361483714838148391484014841148421484314844148451484614847148481484914850148511485214853148541485514856148571485814859148601486114862148631486414865148661486714868148691487014871148721487314874148751487614877148781487914880148811488214883148841488514886148871488814889148901489114892148931489414895148961489714898148991490014901149021490314904149051490614907149081490914910149111491214913149141491514916149171491814919149201492114922149231492414925149261492714928149291493014931149321493314934149351493614937149381493914940149411494214943149441494514946149471494814949149501495114952149531495414955149561495714958149591496014961149621496314964149651496614967149681496914970149711497214973149741497514976149771497814979149801498114982149831498414985149861498714988149891499014991149921499314994149951499614997149981499915000150011500215003150041500515006150071500815009150101501115012150131501415015150161501715018150191502015021150221502315024150251502615027150281502915030150311503215033150341503515036150371503815039150401504115042150431504415045150461504715048150491505015051150521505315054150551505615057150581505915060150611506215063150641506515066150671506815069150701507115072150731507415075150761507715078150791508015081150821508315084150851508615087150881508915090150911509215093150941509515096150971509815099151001510115102151031510415105151061510715108151091511015111151121511315114151151511615117151181511915120151211512215123151241512515126151271512815129151301513115132151331513415135151361513715138151391514015141151421514315144151451514615147151481514915150151511515215153151541515515156151571515815159151601516115162151631516415165151661516715168151691517015171151721517315174151751517615177151781517915180151811518215183151841518515186151871518815189151901519115192151931519415195151961519715198151991520015201152021520315204152051520615207152081520915210152111521215213152141521515216152171521815219152201522115222152231522415225152261522715228152291523015231152321523315234152351523615237152381523915240152411524215243152441524515246152471524815249152501525115252152531525415255152561525715258152591526015261152621526315264152651526615267152681526915270152711527215273152741527515276152771527815279152801528115282152831528415285152861528715288152891529015291152921529315294152951529615297152981529915300153011530215303153041530515306153071530815309153101531115312153131531415315153161531715318153191532015321153221532315324153251532615327153281532915330153311533215333153341533515336153371533815339153401534115342153431534415345153461534715348153491535015351153521535315354153551535615357153581535915360153611536215363153641536515366153671536815369153701537115372153731537415375153761537715378153791538015381153821538315384153851538615387153881538915390153911539215393153941539515396153971539815399154001540115402154031540415405154061540715408154091541015411154121541315414154151541615417154181541915420154211542215423154241542515426154271542815429154301543115432154331543415435154361543715438154391544015441154421544315444154451544615447154481544915450154511545215453154541545515456154571545815459154601546115462154631546415465154661546715468154691547015471154721547315474154751547615477154781547915480154811548215483154841548515486154871548815489154901549115492154931549415495154961549715498154991550015501155021550315504155051550615507155081550915510155111551215513155141551515516155171551815519155201552115522155231552415525155261552715528155291553015531155321553315534155351553615537155381553915540155411554215543155441554515546155471554815549155501555115552155531555415555155561555715558155591556015561155621556315564155651556615567155681556915570155711557215573155741557515576155771557815579155801558115582155831558415585155861558715588155891559015591155921559315594155951559615597155981559915600156011560215603156041560515606156071560815609156101561115612156131561415615156161561715618156191562015621156221562315624156251562615627156281562915630156311563215633156341563515636156371563815639156401564115642156431564415645156461564715648156491565015651156521565315654156551565615657156581565915660156611566215663156641566515666156671566815669156701567115672156731567415675156761567715678156791568015681156821568315684156851568615687156881568915690156911569215693156941569515696156971569815699157001570115702157031570415705157061570715708157091571015711157121571315714157151571615717157181571915720157211572215723157241572515726157271572815729157301573115732157331573415735157361573715738157391574015741157421574315744157451574615747157481574915750157511575215753157541575515756157571575815759157601576115762157631576415765157661576715768157691577015771157721577315774157751577615777157781577915780157811578215783157841578515786157871578815789157901579115792157931579415795157961579715798157991580015801158021580315804158051580615807158081580915810158111581215813158141581515816158171581815819158201582115822158231582415825158261582715828158291583015831158321583315834158351583615837158381583915840158411584215843158441584515846158471584815849158501585115852158531585415855158561585715858158591586015861158621586315864158651586615867158681586915870158711587215873158741587515876158771587815879158801588115882158831588415885158861588715888158891589015891158921589315894158951589615897158981589915900159011590215903159041590515906159071590815909159101591115912159131591415915159161591715918159191592015921159221592315924159251592615927159281592915930159311593215933159341593515936159371593815939159401594115942159431594415945159461594715948159491595015951159521595315954159551595615957159581595915960159611596215963159641596515966159671596815969159701597115972159731597415975159761597715978159791598015981159821598315984159851598615987159881598915990159911599215993159941599515996159971599815999160001600116002160031600416005160061600716008160091601016011160121601316014160151601616017160181601916020160211602216023160241602516026160271602816029160301603116032160331603416035160361603716038160391604016041160421604316044160451604616047160481604916050160511605216053160541605516056160571605816059160601606116062160631606416065160661606716068160691607016071160721607316074160751607616077160781607916080160811608216083160841608516086160871608816089160901609116092160931609416095160961609716098160991610016101161021610316104161051610616107161081610916110161111611216113161141611516116161171611816119161201612116122161231612416125161261612716128161291613016131161321613316134161351613616137161381613916140161411614216143161441614516146161471614816149161501615116152161531615416155161561615716158161591616016161161621616316164161651616616167161681616916170161711617216173161741617516176161771617816179161801618116182161831618416185161861618716188161891619016191161921619316194161951619616197161981619916200162011620216203162041620516206162071620816209162101621116212162131621416215162161621716218162191622016221162221622316224162251622616227162281622916230162311623216233162341623516236162371623816239162401624116242162431624416245162461624716248162491625016251162521625316254162551625616257162581625916260162611626216263162641626516266162671626816269162701627116272162731627416275162761627716278162791628016281162821628316284162851628616287162881628916290162911629216293162941629516296162971629816299163001630116302163031630416305163061630716308163091631016311163121631316314163151631616317163181631916320163211632216323163241632516326163271632816329163301633116332163331633416335163361633716338163391634016341163421634316344163451634616347163481634916350163511635216353163541635516356163571635816359163601636116362163631636416365163661636716368163691637016371163721637316374163751637616377163781637916380163811638216383163841638516386163871638816389163901639116392163931639416395163961639716398163991640016401164021640316404164051640616407164081640916410164111641216413164141641516416164171641816419164201642116422164231642416425164261642716428164291643016431164321643316434164351643616437164381643916440164411644216443164441644516446164471644816449164501645116452164531645416455164561645716458164591646016461164621646316464164651646616467164681646916470164711647216473164741647516476164771647816479164801648116482164831648416485164861648716488164891649016491164921649316494164951649616497164981649916500165011650216503165041650516506165071650816509165101651116512165131651416515165161651716518165191652016521165221652316524165251652616527165281652916530165311653216533165341653516536165371653816539165401654116542165431654416545165461654716548165491655016551165521655316554165551655616557165581655916560165611656216563165641656516566165671656816569165701657116572165731657416575165761657716578165791658016581165821658316584165851658616587165881658916590165911659216593165941659516596165971659816599166001660116602166031660416605166061660716608166091661016611166121661316614166151661616617166181661916620166211662216623166241662516626166271662816629166301663116632166331663416635166361663716638166391664016641166421664316644166451664616647166481664916650166511665216653166541665516656166571665816659166601666116662166631666416665166661666716668166691667016671166721667316674166751667616677166781667916680166811668216683166841668516686166871668816689166901669116692166931669416695166961669716698166991670016701167021670316704167051670616707167081670916710167111671216713167141671516716167171671816719167201672116722167231672416725167261672716728167291673016731167321673316734167351673616737167381673916740167411674216743167441674516746167471674816749167501675116752167531675416755167561675716758167591676016761167621676316764167651676616767167681676916770167711677216773167741677516776167771677816779167801678116782167831678416785167861678716788167891679016791167921679316794167951679616797167981679916800168011680216803168041680516806168071680816809168101681116812168131681416815168161681716818168191682016821168221682316824168251682616827168281682916830168311683216833168341683516836168371683816839168401684116842168431684416845168461684716848168491685016851168521685316854168551685616857168581685916860168611686216863168641686516866168671686816869168701687116872168731687416875168761687716878168791688016881168821688316884168851688616887168881688916890168911689216893168941689516896168971689816899169001690116902169031690416905169061690716908169091691016911169121691316914169151691616917169181691916920169211692216923169241692516926169271692816929169301693116932169331693416935169361693716938169391694016941169421694316944169451694616947169481694916950169511695216953169541695516956169571695816959169601696116962169631696416965169661696716968169691697016971169721697316974169751697616977169781697916980169811698216983169841698516986169871698816989169901699116992169931699416995169961699716998169991700017001170021700317004170051700617007170081700917010170111701217013170141701517016170171701817019170201702117022170231702417025170261702717028170291703017031170321703317034170351703617037170381703917040170411704217043170441704517046170471704817049170501705117052170531705417055170561705717058170591706017061170621706317064170651706617067170681706917070170711707217073170741707517076170771707817079170801708117082170831708417085170861708717088170891709017091170921709317094170951709617097170981709917100171011710217103171041710517106171071710817109171101711117112171131711417115171161711717118171191712017121171221712317124171251712617127171281712917130171311713217133171341713517136171371713817139171401714117142171431714417145171461714717148171491715017151171521715317154171551715617157171581715917160171611716217163171641716517166171671716817169171701717117172171731717417175171761717717178171791718017181171821718317184171851718617187171881718917190171911719217193171941719517196171971719817199172001720117202172031720417205172061720717208172091721017211172121721317214172151721617217172181721917220172211722217223172241722517226172271722817229172301723117232172331723417235172361723717238172391724017241172421724317244172451724617247172481724917250172511725217253172541725517256172571725817259172601726117262172631726417265172661726717268172691727017271172721727317274172751727617277172781727917280172811728217283172841728517286172871728817289172901729117292172931729417295172961729717298172991730017301173021730317304173051730617307173081730917310173111731217313173141731517316173171731817319173201732117322173231732417325173261732717328173291733017331173321733317334173351733617337173381733917340173411734217343173441734517346173471734817349173501735117352173531735417355173561735717358173591736017361173621736317364173651736617367173681736917370173711737217373173741737517376173771737817379173801738117382173831738417385173861738717388173891739017391173921739317394173951739617397173981739917400174011740217403174041740517406174071740817409174101741117412174131741417415174161741717418174191742017421174221742317424174251742617427174281742917430174311743217433174341743517436174371743817439174401744117442174431744417445174461744717448174491745017451174521745317454174551745617457174581745917460174611746217463174641746517466174671746817469174701747117472174731747417475174761747717478174791748017481174821748317484174851748617487174881748917490174911749217493174941749517496174971749817499175001750117502175031750417505175061750717508175091751017511175121751317514175151751617517175181751917520175211752217523175241752517526175271752817529175301753117532175331753417535175361753717538175391754017541175421754317544175451754617547175481754917550175511755217553175541755517556175571755817559175601756117562175631756417565175661756717568175691757017571175721757317574175751757617577175781757917580175811758217583175841758517586175871758817589175901759117592175931759417595175961759717598175991760017601176021760317604176051760617607176081760917610176111761217613176141761517616176171761817619176201762117622176231762417625176261762717628176291763017631176321763317634176351763617637176381763917640176411764217643176441764517646176471764817649176501765117652176531765417655176561765717658176591766017661176621766317664176651766617667176681766917670176711767217673176741767517676176771767817679176801768117682176831768417685176861768717688176891769017691176921769317694176951769617697176981769917700177011770217703177041770517706177071770817709177101771117712177131771417715177161771717718177191772017721177221772317724177251772617727177281772917730177311773217733177341773517736177371773817739177401774117742177431774417745177461774717748177491775017751177521775317754177551775617757177581775917760177611776217763177641776517766177671776817769177701777117772177731777417775177761777717778177791778017781177821778317784177851778617787177881778917790177911779217793177941779517796177971779817799178001780117802178031780417805178061780717808178091781017811178121781317814178151781617817178181781917820178211782217823178241782517826178271782817829178301783117832178331783417835178361783717838178391784017841178421784317844178451784617847178481784917850178511785217853178541785517856178571785817859178601786117862178631786417865178661786717868178691787017871178721787317874178751787617877178781787917880178811788217883178841788517886178871788817889178901789117892178931789417895178961789717898178991790017901179021790317904179051790617907179081790917910179111791217913179141791517916179171791817919179201792117922179231792417925179261792717928179291793017931179321793317934179351793617937179381793917940179411794217943179441794517946179471794817949179501795117952179531795417955179561795717958179591796017961179621796317964179651796617967179681796917970179711797217973179741797517976179771797817979179801798117982179831798417985179861798717988179891799017991179921799317994179951799617997179981799918000180011800218003180041800518006180071800818009180101801118012180131801418015180161801718018180191802018021180221802318024180251802618027180281802918030180311803218033180341803518036180371803818039180401804118042180431804418045180461804718048180491805018051180521805318054180551805618057180581805918060180611806218063180641806518066180671806818069180701807118072180731807418075180761807718078180791808018081180821808318084180851808618087180881808918090180911809218093180941809518096180971809818099181001810118102181031810418105181061810718108181091811018111181121811318114181151811618117181181811918120181211812218123181241812518126181271812818129181301813118132181331813418135181361813718138181391814018141181421814318144181451814618147181481814918150181511815218153181541815518156181571815818159181601816118162181631816418165181661816718168181691817018171181721817318174181751817618177181781817918180181811818218183181841818518186181871818818189181901819118192181931819418195181961819718198181991820018201182021820318204182051820618207182081820918210182111821218213182141821518216182171821818219182201822118222182231822418225182261822718228182291823018231182321823318234182351823618237182381823918240182411824218243182441824518246182471824818249182501825118252182531825418255182561825718258182591826018261182621826318264182651826618267182681826918270182711827218273182741827518276182771827818279182801828118282182831828418285182861828718288182891829018291182921829318294182951829618297182981829918300183011830218303183041830518306183071830818309183101831118312183131831418315183161831718318183191832018321183221832318324183251832618327183281832918330183311833218333183341833518336183371833818339183401834118342183431834418345183461834718348183491835018351183521835318354183551835618357183581835918360183611836218363183641836518366183671836818369183701837118372183731837418375183761837718378183791838018381183821838318384183851838618387183881838918390183911839218393183941839518396183971839818399184001840118402184031840418405184061840718408184091841018411184121841318414184151841618417184181841918420184211842218423184241842518426184271842818429184301843118432184331843418435184361843718438184391844018441184421844318444184451844618447184481844918450184511845218453184541845518456184571845818459184601846118462184631846418465184661846718468184691847018471184721847318474184751847618477184781847918480184811848218483184841848518486184871848818489184901849118492184931849418495184961849718498184991850018501185021850318504185051850618507185081850918510185111851218513185141851518516185171851818519185201852118522185231852418525185261852718528185291853018531185321853318534185351853618537185381853918540185411854218543185441854518546185471854818549185501855118552185531855418555185561855718558185591856018561185621856318564185651856618567185681856918570185711857218573185741857518576185771857818579185801858118582185831858418585185861858718588185891859018591185921859318594185951859618597185981859918600186011860218603186041860518606186071860818609186101861118612186131861418615186161861718618186191862018621186221862318624186251862618627186281862918630186311863218633186341863518636186371863818639186401864118642186431864418645186461864718648186491865018651186521865318654186551865618657186581865918660186611866218663186641866518666186671866818669186701867118672186731867418675186761867718678186791868018681186821868318684186851868618687186881868918690186911869218693186941869518696186971869818699187001870118702187031870418705187061870718708187091871018711187121871318714187151871618717187181871918720187211872218723187241872518726187271872818729187301873118732187331873418735187361873718738187391874018741187421874318744187451874618747187481874918750187511875218753187541875518756187571875818759187601876118762187631876418765187661876718768187691877018771187721877318774187751877618777187781877918780187811878218783187841878518786187871878818789187901879118792187931879418795187961879718798187991880018801188021880318804188051880618807188081880918810188111881218813188141881518816188171881818819188201882118822188231882418825188261882718828188291883018831188321883318834188351883618837188381883918840188411884218843188441884518846188471884818849188501885118852188531885418855188561885718858188591886018861188621886318864188651886618867188681886918870188711887218873188741887518876188771887818879188801888118882188831888418885188861888718888188891889018891188921889318894188951889618897188981889918900189011890218903189041890518906189071890818909189101891118912189131891418915189161891718918189191892018921189221892318924189251892618927189281892918930189311893218933189341893518936189371893818939189401894118942189431894418945189461894718948189491895018951189521895318954189551895618957189581895918960189611896218963189641896518966189671896818969189701897118972189731897418975189761897718978189791898018981189821898318984189851898618987189881898918990189911899218993189941899518996189971899818999190001900119002190031900419005190061900719008190091901019011190121901319014190151901619017190181901919020190211902219023190241902519026190271902819029190301903119032190331903419035190361903719038190391904019041190421904319044190451904619047190481904919050190511905219053190541905519056190571905819059190601906119062190631906419065190661906719068190691907019071190721907319074190751907619077190781907919080190811908219083190841908519086190871908819089190901909119092190931909419095190961909719098190991910019101191021910319104191051910619107191081910919110191111911219113191141911519116191171911819119191201912119122191231912419125191261912719128191291913019131191321913319134191351913619137191381913919140191411914219143191441914519146191471914819149191501915119152191531915419155191561915719158191591916019161191621916319164191651916619167191681916919170191711917219173191741917519176191771917819179191801918119182191831918419185191861918719188191891919019191191921919319194191951919619197191981919919200192011920219203192041920519206192071920819209192101921119212192131921419215192161921719218192191922019221192221922319224192251922619227192281922919230192311923219233192341923519236192371923819239192401924119242192431924419245192461924719248192491925019251192521925319254192551925619257192581925919260192611926219263192641926519266192671926819269192701927119272192731927419275192761927719278192791928019281192821928319284192851928619287192881928919290192911929219293192941929519296192971929819299193001930119302193031930419305193061930719308193091931019311193121931319314193151931619317193181931919320193211932219323193241932519326193271932819329193301933119332193331933419335193361933719338193391934019341193421934319344193451934619347193481934919350193511935219353193541935519356193571935819359193601936119362193631936419365193661936719368193691937019371193721937319374193751937619377193781937919380193811938219383193841938519386193871938819389193901939119392193931939419395193961939719398193991940019401194021940319404194051940619407194081940919410194111941219413194141941519416194171941819419194201942119422194231942419425194261942719428194291943019431194321943319434194351943619437194381943919440194411944219443194441944519446194471944819449194501945119452194531945419455194561945719458194591946019461194621946319464194651946619467194681946919470194711947219473194741947519476194771947819479194801948119482194831948419485194861948719488194891949019491194921949319494194951949619497194981949919500195011950219503195041950519506195071950819509195101951119512195131951419515195161951719518195191952019521195221952319524195251952619527195281952919530195311953219533195341953519536195371953819539195401954119542195431954419545195461954719548195491955019551195521955319554195551955619557195581955919560195611956219563195641956519566195671956819569195701957119572195731957419575195761957719578195791958019581195821958319584195851958619587195881958919590195911959219593195941959519596195971959819599196001960119602196031960419605196061960719608196091961019611196121961319614196151961619617196181961919620196211962219623196241962519626196271962819629196301963119632196331963419635196361963719638196391964019641196421964319644196451964619647196481964919650196511965219653196541965519656196571965819659196601966119662196631966419665196661966719668196691967019671196721967319674196751967619677196781967919680196811968219683196841968519686196871968819689196901969119692196931969419695196961969719698196991970019701197021970319704197051970619707197081970919710197111971219713197141971519716197171971819719197201972119722197231972419725197261972719728197291973019731197321973319734197351973619737197381973919740197411974219743197441974519746197471974819749197501975119752197531975419755197561975719758197591976019761197621976319764197651976619767197681976919770197711977219773197741977519776197771977819779197801978119782197831978419785197861978719788197891979019791197921979319794197951979619797197981979919800198011980219803198041980519806198071980819809198101981119812198131981419815198161981719818198191982019821198221982319824198251982619827198281982919830198311983219833198341983519836198371983819839198401984119842198431984419845198461984719848198491985019851198521985319854198551985619857198581985919860198611986219863198641986519866198671986819869198701987119872198731987419875198761987719878198791988019881198821988319884198851988619887198881988919890198911989219893198941989519896198971989819899199001990119902199031990419905199061990719908199091991019911199121991319914199151991619917199181991919920199211992219923199241992519926199271992819929199301993119932199331993419935199361993719938199391994019941199421994319944199451994619947199481994919950199511995219953199541995519956199571995819959199601996119962199631996419965199661996719968199691997019971199721997319974199751997619977199781997919980199811998219983199841998519986199871998819989199901999119992199931999419995199961999719998199992000020001200022000320004200052000620007200082000920010200112001220013200142001520016200172001820019200202002120022200232002420025200262002720028200292003020031200322003320034200352003620037200382003920040200412004220043200442004520046200472004820049200502005120052200532005420055200562005720058200592006020061200622006320064200652006620067200682006920070200712007220073200742007520076200772007820079200802008120082200832008420085200862008720088200892009020091200922009320094200952009620097200982009920100201012010220103201042010520106201072010820109201102011120112201132011420115201162011720118201192012020121201222012320124201252012620127201282012920130201312013220133201342013520136201372013820139201402014120142201432014420145201462014720148201492015020151201522015320154201552015620157201582015920160201612016220163201642016520166201672016820169201702017120172201732017420175201762017720178201792018020181201822018320184201852018620187201882018920190201912019220193201942019520196201972019820199202002020120202202032020420205202062020720208202092021020211202122021320214202152021620217202182021920220202212022220223202242022520226202272022820229202302023120232202332023420235202362023720238202392024020241202422024320244202452024620247202482024920250202512025220253202542025520256202572025820259202602026120262202632026420265202662026720268202692027020271202722027320274202752027620277202782027920280202812028220283202842028520286202872028820289202902029120292202932029420295202962029720298202992030020301203022030320304203052030620307203082030920310203112031220313203142031520316203172031820319203202032120322203232032420325203262032720328203292033020331203322033320334203352033620337203382033920340203412034220343203442034520346203472034820349203502035120352203532035420355203562035720358203592036020361203622036320364203652036620367203682036920370203712037220373203742037520376203772037820379203802038120382203832038420385203862038720388203892039020391203922039320394203952039620397203982039920400204012040220403204042040520406204072040820409204102041120412204132041420415204162041720418204192042020421204222042320424204252042620427204282042920430204312043220433204342043520436204372043820439204402044120442204432044420445204462044720448204492045020451204522045320454204552045620457204582045920460204612046220463204642046520466204672046820469204702047120472204732047420475204762047720478204792048020481204822048320484204852048620487204882048920490204912049220493204942049520496204972049820499205002050120502205032050420505205062050720508205092051020511205122051320514205152051620517205182051920520205212052220523205242052520526205272052820529205302053120532205332053420535205362053720538205392054020541205422054320544205452054620547205482054920550205512055220553205542055520556205572055820559205602056120562205632056420565205662056720568205692057020571205722057320574205752057620577205782057920580205812058220583205842058520586205872058820589205902059120592205932059420595205962059720598205992060020601206022060320604206052060620607206082060920610206112061220613206142061520616206172061820619206202062120622206232062420625206262062720628206292063020631206322063320634206352063620637206382063920640206412064220643206442064520646206472064820649206502065120652206532065420655206562065720658206592066020661206622066320664206652066620667206682066920670206712067220673206742067520676206772067820679206802068120682206832068420685206862068720688206892069020691206922069320694206952069620697206982069920700207012070220703207042070520706207072070820709207102071120712207132071420715207162071720718207192072020721207222072320724207252072620727207282072920730207312073220733207342073520736207372073820739207402074120742207432074420745207462074720748207492075020751207522075320754207552075620757207582075920760207612076220763207642076520766207672076820769207702077120772207732077420775207762077720778207792078020781207822078320784207852078620787207882078920790207912079220793207942079520796207972079820799208002080120802208032080420805208062080720808208092081020811208122081320814208152081620817208182081920820208212082220823208242082520826208272082820829208302083120832208332083420835208362083720838208392084020841208422084320844208452084620847208482084920850208512085220853208542085520856208572085820859208602086120862208632086420865208662086720868208692087020871208722087320874208752087620877208782087920880208812088220883208842088520886208872088820889208902089120892208932089420895208962089720898208992090020901209022090320904209052090620907209082090920910209112091220913209142091520916209172091820919209202092120922209232092420925209262092720928209292093020931209322093320934209352093620937209382093920940209412094220943209442094520946209472094820949209502095120952209532095420955209562095720958209592096020961209622096320964209652096620967209682096920970209712097220973209742097520976209772097820979209802098120982209832098420985209862098720988209892099020991209922099320994209952099620997209982099921000210012100221003210042100521006210072100821009210102101121012210132101421015210162101721018210192102021021210222102321024210252102621027210282102921030210312103221033210342103521036210372103821039210402104121042210432104421045210462104721048210492105021051210522105321054210552105621057210582105921060210612106221063210642106521066210672106821069210702107121072210732107421075210762107721078210792108021081210822108321084210852108621087210882108921090210912109221093210942109521096210972109821099211002110121102211032110421105211062110721108211092111021111211122111321114211152111621117211182111921120211212112221123211242112521126211272112821129211302113121132211332113421135211362113721138211392114021141211422114321144211452114621147211482114921150211512115221153211542115521156211572115821159211602116121162211632116421165211662116721168211692117021171211722117321174211752117621177211782117921180211812118221183211842118521186211872118821189211902119121192211932119421195211962119721198211992120021201212022120321204212052120621207212082120921210212112121221213212142121521216212172121821219212202122121222212232122421225212262122721228212292123021231212322123321234212352123621237212382123921240212412124221243212442124521246212472124821249212502125121252212532125421255212562125721258212592126021261212622126321264212652126621267212682126921270212712127221273212742127521276212772127821279212802128121282212832128421285212862128721288212892129021291212922129321294212952129621297212982129921300213012130221303213042130521306213072130821309213102131121312213132131421315213162131721318213192132021321213222132321324213252132621327213282132921330213312133221333213342133521336213372133821339213402134121342213432134421345213462134721348213492135021351213522135321354213552135621357213582135921360213612136221363213642136521366213672136821369213702137121372213732137421375213762137721378213792138021381213822138321384213852138621387213882138921390213912139221393213942139521396213972139821399214002140121402214032140421405214062140721408214092141021411214122141321414214152141621417214182141921420214212142221423214242142521426214272142821429214302143121432214332143421435214362143721438214392144021441214422144321444214452144621447214482144921450214512145221453214542145521456214572145821459214602146121462214632146421465214662146721468214692147021471214722147321474214752147621477214782147921480214812148221483214842148521486214872148821489214902149121492214932149421495214962149721498214992150021501215022150321504215052150621507215082150921510215112151221513215142151521516215172151821519215202152121522215232152421525215262152721528215292153021531215322153321534215352153621537215382153921540215412154221543215442154521546215472154821549215502155121552215532155421555215562155721558215592156021561215622156321564215652156621567215682156921570215712157221573215742157521576215772157821579215802158121582215832158421585215862158721588215892159021591215922159321594215952159621597215982159921600216012160221603216042160521606216072160821609216102161121612216132161421615216162161721618216192162021621216222162321624216252162621627216282162921630216312163221633216342163521636216372163821639216402164121642216432164421645216462164721648216492165021651216522165321654216552165621657216582165921660216612166221663216642166521666216672166821669216702167121672216732167421675216762167721678216792168021681216822168321684216852168621687216882168921690216912169221693216942169521696216972169821699217002170121702217032170421705217062170721708217092171021711217122171321714217152171621717217182171921720217212172221723217242172521726217272172821729217302173121732217332173421735217362173721738217392174021741217422174321744217452174621747217482174921750217512175221753217542175521756217572175821759217602176121762217632176421765217662176721768217692177021771217722177321774217752177621777217782177921780217812178221783217842178521786217872178821789217902179121792217932179421795217962179721798217992180021801218022180321804218052180621807218082180921810218112181221813218142181521816218172181821819218202182121822218232182421825218262182721828218292183021831218322183321834218352183621837218382183921840218412184221843218442184521846218472184821849218502185121852218532185421855218562185721858218592186021861218622186321864218652186621867218682186921870218712187221873218742187521876218772187821879218802188121882218832188421885218862188721888218892189021891218922189321894218952189621897218982189921900219012190221903219042190521906219072190821909219102191121912219132191421915219162191721918219192192021921219222192321924219252192621927219282192921930219312193221933219342193521936219372193821939219402194121942219432194421945219462194721948219492195021951219522195321954219552195621957219582195921960219612196221963219642196521966219672196821969219702197121972219732197421975219762197721978219792198021981219822198321984219852198621987219882198921990219912199221993219942199521996219972199821999220002200122002220032200422005220062200722008220092201022011220122201322014220152201622017220182201922020220212202222023220242202522026220272202822029220302203122032220332203422035220362203722038220392204022041220422204322044220452204622047220482204922050220512205222053220542205522056220572205822059220602206122062220632206422065220662206722068220692207022071220722207322074220752207622077220782207922080220812208222083220842208522086220872208822089220902209122092220932209422095220962209722098220992210022101221022210322104221052210622107221082210922110221112211222113221142211522116221172211822119221202212122122221232212422125221262212722128221292213022131221322213322134221352213622137221382213922140221412214222143221442214522146221472214822149221502215122152221532215422155221562215722158221592216022161221622216322164221652216622167221682216922170221712217222173221742217522176221772217822179221802218122182221832218422185221862218722188221892219022191221922219322194221952219622197221982219922200222012220222203222042220522206222072220822209222102221122212222132221422215222162221722218222192222022221222222222322224222252222622227222282222922230222312223222233222342223522236222372223822239222402224122242222432224422245222462224722248222492225022251222522225322254222552225622257222582225922260222612226222263222642226522266222672226822269222702227122272222732227422275222762227722278222792228022281222822228322284222852228622287222882228922290222912229222293222942229522296222972229822299223002230122302223032230422305223062230722308223092231022311223122231322314223152231622317223182231922320223212232222323223242232522326223272232822329223302233122332223332233422335223362233722338223392234022341223422234322344223452234622347223482234922350223512235222353223542235522356223572235822359223602236122362223632236422365223662236722368223692237022371223722237322374223752237622377223782237922380223812238222383223842238522386223872238822389223902239122392223932239422395223962239722398223992240022401224022240322404224052240622407224082240922410224112241222413224142241522416224172241822419224202242122422224232242422425224262242722428224292243022431224322243322434224352243622437224382243922440224412244222443224442244522446224472244822449224502245122452224532245422455224562245722458224592246022461224622246322464224652246622467224682246922470224712247222473224742247522476224772247822479224802248122482224832248422485224862248722488224892249022491224922249322494224952249622497224982249922500225012250222503225042250522506225072250822509225102251122512225132251422515225162251722518225192252022521225222252322524225252252622527225282252922530225312253222533225342253522536225372253822539225402254122542225432254422545225462254722548225492255022551225522255322554225552255622557225582255922560225612256222563225642256522566225672256822569225702257122572225732257422575225762257722578225792258022581225822258322584225852258622587225882258922590225912259222593225942259522596225972259822599226002260122602226032260422605226062260722608226092261022611226122261322614226152261622617226182261922620226212262222623226242262522626226272262822629226302263122632226332263422635226362263722638226392264022641226422264322644226452264622647226482264922650226512265222653226542265522656226572265822659226602266122662226632266422665226662266722668226692267022671226722267322674226752267622677226782267922680226812268222683226842268522686226872268822689226902269122692226932269422695226962269722698226992270022701227022270322704227052270622707227082270922710227112271222713227142271522716227172271822719227202272122722227232272422725227262272722728227292273022731227322273322734227352273622737227382273922740227412274222743227442274522746227472274822749227502275122752227532275422755227562275722758227592276022761227622276322764227652276622767227682276922770227712277222773227742277522776227772277822779227802278122782227832278422785227862278722788227892279022791227922279322794227952279622797227982279922800228012280222803228042280522806228072280822809228102281122812228132281422815228162281722818228192282022821228222282322824228252282622827228282282922830228312283222833228342283522836228372283822839228402284122842228432284422845228462284722848228492285022851228522285322854228552285622857228582285922860228612286222863228642286522866228672286822869228702287122872228732287422875228762287722878228792288022881228822288322884228852288622887228882288922890228912289222893228942289522896228972289822899229002290122902229032290422905229062290722908229092291022911229122291322914229152291622917229182291922920229212292222923229242292522926229272292822929229302293122932229332293422935229362293722938229392294022941229422294322944229452294622947229482294922950229512295222953229542295522956229572295822959229602296122962229632296422965229662296722968229692297022971229722297322974229752297622977229782297922980229812298222983229842298522986229872298822989229902299122992229932299422995229962299722998229992300023001230022300323004230052300623007230082300923010230112301223013230142301523016230172301823019230202302123022230232302423025230262302723028230292303023031230322303323034230352303623037230382303923040230412304223043230442304523046230472304823049230502305123052230532305423055230562305723058230592306023061230622306323064230652306623067230682306923070230712307223073230742307523076230772307823079230802308123082230832308423085230862308723088230892309023091230922309323094230952309623097230982309923100231012310223103231042310523106231072310823109231102311123112231132311423115231162311723118231192312023121231222312323124231252312623127231282312923130231312313223133231342313523136231372313823139231402314123142231432314423145231462314723148231492315023151231522315323154231552315623157231582315923160231612316223163231642316523166231672316823169231702317123172231732317423175231762317723178231792318023181231822318323184231852318623187231882318923190231912319223193231942319523196231972319823199232002320123202232032320423205232062320723208232092321023211232122321323214232152321623217232182321923220232212322223223232242322523226232272322823229232302323123232232332323423235232362323723238232392324023241232422324323244232452324623247232482324923250232512325223253232542325523256232572325823259232602326123262232632326423265232662326723268232692327023271232722327323274232752327623277232782327923280232812328223283232842328523286232872328823289232902329123292232932329423295232962329723298232992330023301233022330323304233052330623307233082330923310233112331223313233142331523316233172331823319233202332123322233232332423325233262332723328233292333023331233322333323334233352333623337233382333923340233412334223343233442334523346233472334823349233502335123352233532335423355233562335723358233592336023361233622336323364233652336623367233682336923370233712337223373233742337523376233772337823379233802338123382233832338423385233862338723388233892339023391233922339323394233952339623397233982339923400234012340223403234042340523406234072340823409234102341123412234132341423415234162341723418234192342023421234222342323424234252342623427234282342923430234312343223433234342343523436234372343823439234402344123442234432344423445234462344723448234492345023451234522345323454234552345623457234582345923460234612346223463234642346523466234672346823469234702347123472234732347423475234762347723478234792348023481234822348323484234852348623487234882348923490234912349223493234942349523496234972349823499235002350123502235032350423505235062350723508235092351023511235122351323514235152351623517235182351923520235212352223523235242352523526235272352823529235302353123532235332353423535235362353723538235392354023541235422354323544235452354623547235482354923550235512355223553235542355523556235572355823559235602356123562235632356423565235662356723568235692357023571235722357323574235752357623577235782357923580235812358223583235842358523586235872358823589235902359123592235932359423595235962359723598235992360023601236022360323604236052360623607236082360923610236112361223613236142361523616236172361823619236202362123622236232362423625236262362723628236292363023631236322363323634236352363623637236382363923640236412364223643236442364523646236472364823649236502365123652236532365423655236562365723658236592366023661236622366323664236652366623667236682366923670236712367223673236742367523676236772367823679236802368123682236832368423685236862368723688236892369023691236922369323694236952369623697236982369923700237012370223703237042370523706237072370823709237102371123712237132371423715237162371723718237192372023721237222372323724237252372623727237282372923730237312373223733237342373523736237372373823739237402374123742237432374423745237462374723748237492375023751237522375323754237552375623757237582375923760237612376223763237642376523766237672376823769237702377123772237732377423775237762377723778237792378023781237822378323784237852378623787237882378923790237912379223793237942379523796237972379823799238002380123802238032380423805238062380723808238092381023811238122381323814238152381623817238182381923820238212382223823238242382523826238272382823829238302383123832238332383423835238362383723838238392384023841238422384323844238452384623847238482384923850238512385223853238542385523856238572385823859238602386123862238632386423865238662386723868238692387023871238722387323874238752387623877238782387923880238812388223883238842388523886238872388823889238902389123892238932389423895238962389723898238992390023901239022390323904239052390623907239082390923910239112391223913239142391523916239172391823919239202392123922239232392423925239262392723928239292393023931239322393323934239352393623937239382393923940239412394223943239442394523946239472394823949239502395123952239532395423955239562395723958239592396023961239622396323964239652396623967239682396923970239712397223973239742397523976239772397823979239802398123982239832398423985239862398723988239892399023991239922399323994239952399623997239982399924000240012400224003240042400524006240072400824009240102401124012240132401424015240162401724018240192402024021240222402324024240252402624027240282402924030240312403224033240342403524036240372403824039240402404124042240432404424045240462404724048240492405024051240522405324054240552405624057240582405924060240612406224063240642406524066240672406824069240702407124072240732407424075240762407724078240792408024081240822408324084240852408624087240882408924090240912409224093240942409524096240972409824099241002410124102241032410424105241062410724108241092411024111241122411324114241152411624117241182411924120241212412224123241242412524126241272412824129241302413124132241332413424135241362413724138241392414024141241422414324144241452414624147241482414924150241512415224153241542415524156241572415824159241602416124162241632416424165241662416724168241692417024171241722417324174241752417624177241782417924180241812418224183241842418524186241872418824189241902419124192241932419424195241962419724198241992420024201242022420324204242052420624207242082420924210242112421224213242142421524216242172421824219242202422124222242232422424225242262422724228242292423024231242322423324234242352423624237242382423924240242412424224243242442424524246242472424824249242502425124252242532425424255242562425724258242592426024261242622426324264242652426624267242682426924270242712427224273242742427524276242772427824279242802428124282242832428424285242862428724288242892429024291242922429324294242952429624297242982429924300243012430224303243042430524306243072430824309243102431124312243132431424315243162431724318243192432024321243222432324324243252432624327243282432924330243312433224333243342433524336243372433824339243402434124342243432434424345243462434724348243492435024351243522435324354243552435624357243582435924360243612436224363243642436524366243672436824369243702437124372243732437424375243762437724378243792438024381243822438324384243852438624387243882438924390243912439224393243942439524396243972439824399244002440124402244032440424405244062440724408244092441024411244122441324414244152441624417244182441924420244212442224423244242442524426244272442824429244302443124432244332443424435244362443724438244392444024441244422444324444244452444624447
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN" "http://framework.zend.com/docbook/xml/4.5/docbookx.dtd" [
  3. <!ENTITY % xinclude SYSTEM "xinclude.mod">
  4. <!-- $Id: $ --><!ELEMENT xi:include (xi:fallback)?>
  5. <!ATTLIST xi:include xmlns:xi CDATA #FIXED "http://www.w3.org/2001/XInclude">
  6. <!ATTLIST xi:include href CDATA #REQUIRED>
  7. <!ATTLIST xi:include parse (xml | text) "xml">
  8. <!ATTLIST xi:include encoding CDATA #IMPLIED>
  9. <!ELEMENT xi:fallback ANY>
  10. <!ATTLIST xi:fallback xmlns:xi CDATA #FIXED "http://www.w3.org/2001/XInclude">
  11. <!-- inside chapter or section elements --><!ENTITY % local.divcomponent.mix "| xi:include">
  12. <!-- inside para, programlisting, literallayout, etc. --><!ENTITY % local.para.char.mix "| xi:include">
  13. <!-- inside bookinfo, chapterinfo, etc. --><!ENTITY % local.info.class "| xi:include">
  14. <!ENTITY % local.chapter.class "| xi:include">
  15. ]>
  16. <book id="manual" lang="es">
  17. <bookinfo>
  18. <title>Guía de Referencia del Programador</title>
  19. <subtitle>Zend Framework</subtitle>
  20. <edition>Guía de Referencia del Programador para Zend Framework</edition>
  21. <pubdate><?dbtimestamp format="Y-m-d"?></pubdate>
  22. <copyright>
  23. <year>2005-<?dbtimestamp format="Y"?></year>
  24. <holder>
  25. Zend Technologies Inc.
  26. (<ulink url="http://www.zend.com"/>)
  27. </holder>
  28. </copyright>
  29. <!--
  30. A Title page graphic can be included like this
  31. <mediaobject>
  32. <imageobject>
  33. <imagedata fileref="../web/images/foo.jpg"/>
  34. </imageobject>
  35. </mediaobject>
  36. -->
  37. </bookinfo>
  38. <chapter id="introduction">
  39. <title>Introducción a Zend Framework</title>
  40. <sect1 id="introduction.overview" xml:base="ref/overview.xml">
  41. <title>Descripción general </title>
  42. <para>
  43. Zend Framework (ZF) es un framework de código abierto para desarrollar aplicaciones web y servicios web con PHP5. ZF es una implementación que usa código 100% orientado a objetos. La estructura de los componentes de ZF es algo único; cada componente está construido con una baja dependencia de otros componentes. Esta arquitectura débilmente acoplada permite a los desarrolladores utilizar los componentes por separado. A menudo se refiere a este tipo de diseño como "use-at-will" (uso a voluntad).
  44. </para>
  45. <para>
  46. Aunque se pueden utilizar de forma individual, los componentes de la librería estándar de Zend Framework conforman un potente y extensible framework de aplicaciones web al combinarse. ZF ofrece un gran rendimiento y una robusta implementación MVC, una abstración de base de datos fácil de usar, y un componente de formularios que implementa la prestación de formularios HTML, validación y filtado para que los desarrolladores puedan consolidar todas las operaciones usando de una manera sencilla la interfaz orientada a objetos. Otros componentes, como Zend_Auth y Zend_Acl, proveen autentificación de usuarios y autorización diferentes a las tiendas de certificados comunes (REVISAR ESTO). También existen componentes que implementan librerías de cliente para acceder de forma sencilla a los web services más populares. Cualesquiera que sean las necesidades de su solicitud, usted tiene todas las posibilidades de encontrar un componente de Zend Framework que se pueda utilizar para reducir drásticamente el tiempo de desarrollo, con una base completamente sólida.
  47. </para>
  48. <para>
  49. El principal patrocinador del proyecto Zend Framework es <ulink url="http://www.zend.com">
  50. Zend Technologies</ulink>, pero muchas empresas han contribuido con componentes o características importantes para el marco. Empresas como Google, Microsoft y StrikeIron se han asociado con Zend para proporcionar interfaces de servicios web y otras tecnologías que desean poner a disposición de los desarrolladores de Zend Framework.
  51. </para>
  52. <para>
  53. Zend Framework no podría haber proporcionado y apoyado todas estas características sin la ayuda de la vibrante comunidad de ZF. Los miembros de la comunidad, incluidos los contribuyentes, están disponibles en las , <ulink url="http://framework.zend.com/archives">listas de correo</ulink>, <ulink url="http://www.zftalk.com">
  54. canales de IRC</ulink>, y en otros foros. Cualquier duda que tenga acerca de ZF, la comunidad está siempre disponible para responder.
  55. </para>
  56. </sect1><!--
  57. vim:se ts=4 sw=4 et:
  58. -->
  59. <sect1 id="introduction.installation" xml:base="ref/installation.xml">
  60. <title> Instalación</title>
  61. <para>
  62. Zend Framework requiere por lo menos PHP 5.1.4 o superior, aunque Zend recomienda encarecidamente la versión 5.2.3 o superior, porque hay parches de seguridad y mejoras en el rendimiento entre estas dos versiones. Por favor, consulte el anexo sobre los <link linkend="requirements">requisitos del sistema</link>. para obtener más información.
  63. </para>
  64. <para>
  65. La instalación del Zend Framework es muy simple. Una vez que haya descargado y descomprimido el framework, deberá añadir la carpeta "/library" de la distribución al principio de su "include path". También puede mover la carpeta "library" a cualquier otra posición (compartida o no) de su sistema de archivos.
  66. <itemizedlist>
  67. <listitem>
  68. <para>
  69. <ulink url="http://framework.zend.com/download">Descargar la última versión estable.</ulink> Esta versión esta disponible en formatos<code>.zip</code>. <code>.tar.gz</code>, es una buena opción para aquellos que comienzan o son nuevos en Zend Framework.
  70. </para>
  71. </listitem>
  72. <listitem>
  73. <para>
  74. <ulink url="http://framework.zend.com/download/snapshot">Download the latest nightly
  75. snapshot.</ulink> For those who would brave the cutting edge, the nightly snapshots represent the
  76. latest progress of Zend Framework development. Snapshots are bundled with documentation either in
  77. English only or in all available languages. If you anticipate working with the latest Zend
  78. Framework developments, consider using a Subversion (SVN) client.
  79. </para>
  80. </listitem>
  81. <listitem>
  82. <para>
  83. Using a <ulink url="http://subversion.tigris.org">Subversion</ulink> (SVN) client. Zend Framework
  84. is open source software, and the Subversion repository used for its development is publicly
  85. available. Consider using SVN to get the Zend Framework if you already use SVN for your
  86. application development, want to contribute back to the framework, or need to upgrade your
  87. framework version more often than releases occur.
  88. </para>
  89. <para>
  90. <ulink url="http://svnbook.red-bean.com/nightly/en/svn.ref.svn.c.export.html">Exporting</ulink> is
  91. useful if you want to get a particular framework revision without the <code>.svn</code>
  92. directories as created in a working copy.
  93. </para>
  94. <para>
  95. <ulink url="http://svnbook.red-bean.com/nightly/en/svn.ref.svn.c.checkout.html">Checking out a
  96. working copy</ulink> is good when you might contribute to Zend Framework, and a working copy can
  97. be updated any time with
  98. <ulink url="http://svnbook.red-bean.com/nightly/en/svn.ref.svn.c.update.html"><code>svn
  99. update</code></ulink>.
  100. </para>
  101. <para>
  102. <ulink url="http://svnbook.red-bean.com/nightly/en/svn.advanced.externals.html">An externals
  103. definition</ulink> is highly convenient for developers already using SVN to manage their
  104. application working copies.
  105. </para>
  106. <para>
  107. La URL del almacén del repository SVN de Zend Framework es:
  108. <ulink url="http://framework.zend.com/svn/framework/standard/trunk">http://framework.zend.com/svn/framework/standard/trunk</ulink>
  109. </para>
  110. </listitem>
  111. </itemizedlist>
  112. </para>
  113. <para>
  114. Una vez que tenga disponible una copia de Zend Framework, su aplicación necesita poder acceder a las clases del framework. Aunque hay
  115. <ulink url="http://www.php.net/manual/en/configuration.changes.php">
  116. diferentes maneras de lograr esto</ulink>, su
  117. <ulink url="http://www.php.net/manual/en/ini.core.php#ini.include-path"><code>include_path</code></ulink> de PHP necesita contener una ruta a la librería de Zend Framework.
  118. </para>
  119. <para>
  120. Zend provides a <ulink url="http://framework.zend.com/docs/quickstart">QuickStart</ulink> to get you up and running
  121. as quickly as possible. This is an excellent way to begin learning about the framework with an emphasis
  122. on real world examples that you can built upon.
  123. </para>
  124. <para>
  125. Ya que los componentes de Zend Framework están débilmente conectados, tiene la opción de usar cualquier combinación de ellos en sus aplicaciones. Los siguientes capítulos presentan una referencia exhaustiva de Zend Framework, componente a componente.
  126. </para>
  127. </sect1>
  128. </chapter>
  129. <chapter id="zend.acl">
  130. <title>Zend_Acl</title>
  131. <sect1 id="zend.acl.introduction" xml:base="module_specs/Zend_Acl.xml">
  132. <title>Introducción</title>
  133. <para>
  134. Zend_Acl provee la implementación de un sistema simple y
  135. flexible de Listas de Control de Acceso (ACL, por sus siglas en
  136. inglés) para la administración de privilegios. En general, una
  137. aplicación puede utilizar las ACL para controlar el acceso a
  138. ciertos objetos protegidos, que son requeridos por otros
  139. objetos.
  140. </para>
  141. <para>
  142. Para los propósitos de esta documentación,
  143. <itemizedlist>
  144. <listitem>
  145. <para>
  146. Un
  147. <emphasis role="strong">recurso</emphasis>
  148. es un objeto al cual el acceso esta controlado.
  149. </para>
  150. </listitem>
  151. <listitem>
  152. <para>
  153. Un
  154. <emphasis role="strong">rol</emphasis>
  155. es un objeto que puede solicitar acceso a un
  156. recurso.
  157. </para>
  158. </listitem>
  159. </itemizedlist>
  160. En términos generales,
  161. <emphasis role="strong">
  162. Los roles solicitan acceso a los recursos
  163. </emphasis>
  164. . Por ejemplo, si una persona solicita acceso a un automóvil,
  165. entonces la persona se convierte en el rol solicitante, y el
  166. automóvil en el recurso, puesto que el acceso al automóvil puede
  167. no estar disponible a cualquiera.
  168. </para>
  169. <para>
  170. A través de la especificación y uso de Listas de Control de
  171. Acceso (ACL), una aplicación puede controlar cómo los objetos
  172. solicitantes (roles) han obtenido acceso a objetos protegidos
  173. (recursos).
  174. </para>
  175. <sect2 id="zend.acl.introduction.resources">
  176. <title>Acerca de los Recursos</title>
  177. <para>
  178. En Zend_Acl, crear un recurso es muy sencillo. Zend_Acl
  179. proporciona el
  180. <code>Zend_Acl_Resource_Interface</code>
  181. para facilitar a los desarrolladores la creacción de
  182. recursos. Una clase solo necesita implementar su interfaz,
  183. la cual consiste en un método único,
  184. <code>getResourceId()</code>
  185. , para que Zend_Acl considere el objeto como un recurso.
  186. Adicionalmente,
  187. <code>Zend_Acl_Resource</code>
  188. se incluye con Zend_Acl como una implementación principal de
  189. recursos para los desarrolladores para extenderla hasta
  190. donde lo deseen.
  191. </para>
  192. <para>
  193. Zend_Acl provee un estructura de árbol a la cual pueden ser
  194. agregados múltiples recursos (o "Áreas con Controles de
  195. Acceso").Ya que los recursos son almacenados en esta
  196. estructura de árbol, estos pueden ser organizados desde lo
  197. general (hacia la raíz del árbol) a lo específico (hacia las
  198. ramas del árbol). Consultas sobre un recurso específico
  199. buscarán automáticamente, en la jerarquía del
  200. recurso, reglas asignadas a recursos anteriores a los que
  201. el recurso actual haga referencia, permitiendo la herencia
  202. simple de reglas. Por ejemplo, si una regla por defecto se
  203. aplica a cada edificio en una ciudad, uno simplemente
  204. podría asignar la regla a la ciudad, en lugar de asignar la
  205. misma regla a cada edificio. Algunos edificios pueden
  206. necesitar excepciones a la regla, sin embargo, y esto es
  207. fácil de hacer en Zend_Acl asignando esta excepción a
  208. cada edificio que necesite una excepción a la regla. Un
  209. recurso sólo puede heredar de un recurso padre, aunque este
  210. recurso padre puede tener a la vez su propio recurso padre,
  211. y así; sucesivamente.
  212. </para>
  213. <para>
  214. Zend_Acl también soporta privilegios sobre recursos (ej.
  215. "crear","leer","actualizar", "borrar"), y el desarrollador
  216. puede asignar reglas que afecten o a todos los privilegios o
  217. a privilegios específicos sobre un recurso.
  218. </para>
  219. </sect2>
  220. <sect2 id="zend.acl.introduction.roles">
  221. <title>Acerca de las Reglas</title>
  222. <para>
  223. Al igual que los recursos, la creación de un rol
  224. también es muy simple. Zend_Acl proporciona
  225. <code>Zend_Acl_Role_Interface</code>
  226. para facilitar a los desarrolladores la creación de
  227. roles. Una clase solo necesita la implementación de su
  228. interfaz, la cual consiste en un método único,
  229. <code>getRoleId()</code>
  230. , para que Zend_Acl considere que el objeto es un Rol.
  231. Adicionalmente,
  232. <code>Zend_Acl_Role</code>
  233. está incluido con Zend_Acl como una implementación principal
  234. del rol para que los desarrolladores la extiendan hasta
  235. donde lo deseen.
  236. </para>
  237. <para>
  238. En Zend_Acl, un Rol puede heredar de otro o más roles. Esto
  239. es para soportar herencia de reglas entre roles. Por ejemplo,
  240. un Rol de usuario, como "sally", puede estar bajo uno o más
  241. roles padre, como "editor" y "administrador". El
  242. desarrollador puede asignar reglas a "editor" y
  243. "administrador" por separado, y "sally" puede heredar tales
  244. reglas de ambos, sin tener que asignar reglas directamente a
  245. "sally".
  246. </para>
  247. <para>
  248. Dado que la habilidad de herencia desde múltiples roles es
  249. muy util, múltiples herencias tambien introduce cierto grado
  250. de complejidad. El siguiente ejemplo ilustra la condición de
  251. ambiguedad y como Zend_Acl soluciona esto.
  252. </para>
  253. <example id="zend.acl.introduction.roles.example.multiple_inheritance">
  254. <title>Herencia Multiple entre Roles</title>
  255. <para>
  256. El siguiente código define tres roles principales - "
  257. <code>invitado</code>
  258. ", "
  259. <code>miembro</code>
  260. ", y "
  261. <code>admin</code>
  262. " - de los cuales otros roles pueden heredar. Entonces,
  263. un rol identificado como "
  264. <code>unUsuario</code>
  265. " es colocado y hereda de los otros tres roles. El orden en
  266. el cual estos roles aparecen en el array
  267. <code>$parents</code>
  268. es importante. Cuando es necesario, Zend_Acl busca por
  269. reglas de acceso definidas no solo para el rol
  270. solicitado (aquí, "
  271. <code>unUsuario</code>
  272. "), sino también sobre los roles heredados (aquí, "
  273. <code>invitado</code>
  274. ", "
  275. <code>miembro</code>
  276. ", y "
  277. <code>admin</code>
  278. "):
  279. </para>
  280. <programlisting role="php"><![CDATA[<?php
  281. require_once 'Zend/Acl.php';
  282. $acl = new Zend_Acl();
  283. require_once 'Zend/Acl/Role.php';
  284. $acl->addRole(new Zend_Acl_Role('invitado'))
  285. ->addRole(new Zend_Acl_Role('miembro'))
  286. ->addRole(new Zend_Acl_Role('admin'));
  287. $parents = array('invitado', 'miembro', 'admin');
  288. $acl->addRole(new Zend_Acl_Role('unUsuario'), $parents);
  289. require_once 'Zend/Acl/Resource.php';
  290. $acl->add(new Zend_Acl_Resource('unRecurso'));
  291. $acl->deny('invitado', 'unRecurso');
  292. $acl->allow('miembro', 'unRecurso');
  293. echo $acl->isAllowed('unUsuario', 'unRecurso') ? 'permitido' : 'denegado';]]>
  294. </programlisting>
  295. <para>
  296. Ya que no hay reglas específicamente definidas para
  297. el rol "
  298. <code>unUsuario</code>
  299. " y "
  300. <code>unRecurso</code>
  301. ", Zend_Acl debe buscar por reglas que puedan estar
  302. definidas para roles "
  303. <code>unUsuario</code>
  304. " hereda. Primero, el rol "
  305. <code>admin</code>
  306. " es visitado, y no hay regla de acceso definida
  307. para éste. Luego, el rol "
  308. <code>miembro</code>
  309. " es visitado, y Zend_Acl encuentra que aquí hay una
  310. regla especificando que "
  311. <code>miembro</code>
  312. " tiene permiso para acceder a "
  313. <code>unRecurso</code>
  314. ".
  315. </para>
  316. <para>
  317. Así, Zend_Acl va a seguir examinando las reglas definidas
  318. para otros roles padre, sin embargo, encontraría que "
  319. <code>invitado</code>
  320. " tiene el acceso denegado a "
  321. <code>unRecurso</code>
  322. ". Este hecho introduce una ambigüedad debido a que
  323. ahora "
  324. <code>unUsuario</code>
  325. " está tanto denegado como permitido para acceder a "
  326. <code>unRecurso</code>
  327. ", por la razon de tener un conflicto de reglas
  328. heredadas de diferentes roles padre.
  329. </para>
  330. <para>
  331. Zend_Acl resuelve esta ambiguedad completando la
  332. consulta cuando encuentra la primera regla que es
  333. directamente aplicable a la consulta. En este caso, dado
  334. que el rol "
  335. <code>miembro</code>
  336. " es examinado antes que el rol "
  337. <code>invitado</code>
  338. ", el código de ejemplo mostraría "
  339. <code>permitido</code>
  340. ".
  341. </para>
  342. </example>
  343. <note>
  344. <para>
  345. Cuando se especifican múltiples padres para un Rol, se
  346. debe tener en cuenta que el último padre listado es el
  347. primero en ser buscado por reglas aplicables para una
  348. solicitud de autorización.
  349. </para>
  350. </note>
  351. </sect2>
  352. <sect2 id="zend.acl.introduction.creating">
  353. <title>Creando las Listas de Control de Acceso (ACL)</title>
  354. <para>
  355. Una ACL puede representar cualquier grupo de objetos físicos
  356. o virtuales que desee. Para propósitos de demostración,
  357. sin embargo, crearemos un ACL básico para un Sistema de
  358. Administración de Contenido que mantendrá varias escalas de
  359. grupos sobre una amplia variedad de áreas. Para crear un
  360. nuevo objeto ACL, iniciamos la ACL sin parámetros:
  361. </para>
  362. <programlisting role="php"><![CDATA[<?php
  363. require_once 'Zend/Acl.php';
  364. $acl = new Zend_Acl();]]>
  365. </programlisting>
  366. <note>
  367. <para>
  368. Hasta que un desarrollador especifique una regla
  369. "permitido", Zend_Acl deniega el acceso a cada privilegio
  370. sobre cada recurso para cada rol.
  371. </para>
  372. </note>
  373. </sect2>
  374. <sect2 id="zend.acl.introduction.role_registry">
  375. <title>Registrando Roles</title>
  376. <para>
  377. El Sistema de Administración de Contenido casi
  378. siempre necesita una jerarquía de permisos para determinar
  379. la capacidad de identificación de sus usuarios. Puede haber
  380. un grupo de 'Invitados' para permitir acceso limitado para
  381. demostraciones, un grupo de 'Personal' para la mayoría de
  382. usuarios del CMS quienes realizan la mayor parte de
  383. operaciones del día a día, un grupo 'Editores' para las
  384. responsabilidades de publicación, revisión, archivo y
  385. eliminación de contenido, y finalmente un grupo
  386. 'Administradores' cuyas tareas pueden incluir todas las de los
  387. otros grupos y también el mantenimiento de la información
  388. delicada, manejo de usuarios, configuración de los datos
  389. básicos y su respaldo/exportación. Este grupo de permisos
  390. pueden ser representados en un registro de roles,
  391. permitiendo a cada grupo heredar los privilegios de los
  392. grupos 'padre', al igual que proporcionando distintos
  393. privilegios solo para su grupo individual. Los permisos pueden
  394. ser expresados como:
  395. </para>
  396. <table id="zend.acl.introduction.role_registry.table.example_cms_access_controls">
  397. <title>Controles de Acceso para un CMS de ejemplo</title>
  398. <tgroup cols="3">
  399. <thead>
  400. <row>
  401. <entry>Nombre</entry>
  402. <entry>Permisos Individuales</entry>
  403. <entry>Hereda permisos de</entry>
  404. </row>
  405. </thead>
  406. <tbody>
  407. <row>
  408. <entry>Invitado</entry>
  409. <entry>View</entry>
  410. <entry>N/A</entry>
  411. </row>
  412. <row>
  413. <entry>Personal</entry>
  414. <entry>Editar, Enviar, Revisar</entry>
  415. <entry>Invitado</entry>
  416. </row>
  417. <row>
  418. <entry>Editor</entry>
  419. <entry>Publicar, Archivar, Eliminar</entry>
  420. <entry>Personal</entry>
  421. </row>
  422. <row>
  423. <entry>Administrador</entry>
  424. <entry>(Todos los accesos permitidos)</entry>
  425. <entry>N/A</entry>
  426. </row>
  427. </tbody>
  428. </tgroup>
  429. </table>
  430. <para>
  431. Para este ejemplo, se usa
  432. <code>Zend_Acl_Role</code>
  433. , pero cualquier objeto que implemente
  434. <code>Zend_Acl_Role_Interface</code>
  435. es admisible. Estos grupos pueden ser agragados al registro
  436. de roles de la siguiente manera:
  437. </para>
  438. <programlisting role="php"><![CDATA[<?php
  439. require_once 'Zend/Acl.php';
  440. $acl = new Zend_Acl();
  441. // Agregar grupos al registro de roles usando Zend_Acl_Role
  442. require_once 'Zend/Acl/Role.php';
  443. // Invitado no hereda controles de acceso
  444. $rolInvitado = new Zend_Acl_Role('invitado');
  445. $acl->addRole($rolInvitado);
  446. // Personal hereda de Invitado
  447. $acl->addRole(new Zend_Acl_Role('personal'), $rolInvitado);
  448. /* alternativamente, lo de arriba puede ser escrito así:
  449. $rolInvitado = $acl->addRole(new Zend_Acl_Role('personal'), 'invitado');
  450. //*/
  451. // Editor hereda desde personal
  452. $acl->addRole(new Zend_Acl_Role('editor'), 'personal');
  453. // Administrador no hereda controles de acceso
  454. $acl->addRole(new Zend_Acl_Role('administrador'));]]>
  455. </programlisting>
  456. </sect2>
  457. <sect2 id="zend.acl.introduction.defining">
  458. <title>Definiendo Controles de Acceso</title>
  459. <para>
  460. Ahora que la ACL contiene los roles relevantes, se pueden
  461. establecer reglas que definan cómo los roles pueden acceder
  462. a los recursos. Tenga en cuenta que no definiremos ningún
  463. recurso en particular para este ejemplo, el cual está
  464. simplificado para ilustrar que las reglas se aplican a todos
  465. los recursos. Zend_Acl proporciona una forma práctica por la
  466. cual las reglas solo necesitan ser asignadas de lo general a
  467. lo especifico, minimizando el número de reglas necesarias,
  468. porque los recursos y roles heredan reglas que están
  469. definidas en sus padres.
  470. </para>
  471. <para>
  472. Consecuentemente, podemos definir un grupo razonablemente
  473. complejo de reglas con un mínimo de código. Para aplicar
  474. estos permisos básicos como están definidos arriba:
  475. </para>
  476. <programlisting role="php"><![CDATA[<?php
  477. require_once 'Zend/Acl.php';
  478. $acl = new Zend_Acl();
  479. require_once 'Zend/Acl/Role.php';
  480. $rolInvitado = new Zend_Acl_Role('invitado');
  481. $acl->addRole($rolInvitado);
  482. $acl->addRole(new Zend_Acl_Role('personal'), $rolInvitado);
  483. $acl->addRole(new Zend_Acl_Role('editor'), 'personal');
  484. $acl->addRole(new Zend_Acl_Role('administrador'));
  485. // Invitado solo puede ver el contenido
  486. $acl->allow($rolInvitado, null, 'ver');
  487. /* Lo de arriba puede ser escrito de la siguiente forma alternativa:
  488. $acl->allow('invitado', null, 'ver');
  489. //*/
  490. // Personal hereda el privilegio de ver de invitado, pero también necesita privilegios adicionales
  491. $acl->allow('personal', null, array('editar', 'enviar', 'revisar'));
  492. // Editor hereda los privilegios de ver, editar, enviar, y revisar de personal,
  493. // pero también necesita privilegios adicionales
  494. $acl->allow('editor', null, array('publicar', 'archivar', 'eliminar'));
  495. // Administrador no hereda nada, pero tiene todos los privilegios permitidos
  496. $acl->allow('administrador');]]>
  497. </programlisting>
  498. <para>
  499. El valor
  500. <code>null</code>
  501. en las llamadas de
  502. <code>allow()</code>
  503. es usado para indicar que las reglas de permiso se aplican a
  504. todos los recursos.
  505. </para>
  506. </sect2>
  507. <sect2 id="zend.acl.introduction.querying">
  508. <title>Consultando la ACL</title>
  509. <para>
  510. Ahora tenemos una ACL flexible que puede ser usada para
  511. determinar qué solicitantes tienen permisos para realizar
  512. funciones a través de la aplicacion web. Ejecutar
  513. consultas es la forma más simple de usar el método
  514. <code>isAllowed()</code>
  515. :
  516. </para>
  517. <programlisting role="php"><![CDATA[<?php
  518. echo $acl->isAllowed('invitado', null, 'ver') ?
  519. "permitido" : "denegado"; // permitido
  520. echo $acl->isAllowed('personal', null, 'publicar') ?
  521. "permitido" : "denegado"; // denegado
  522. echo $acl->isAllowed('personal', null, 'revisar') ?
  523. "permitido" : "denegado"; // permitido
  524. echo $acl->isAllowed('editor', null, 'ver') ?
  525. "permitido" : "denegado"; // permitido debido a la herencia de invitado
  526. echo $acl->isAllowed('editor', null, 'actualizar') ?
  527. "permitido" : "denegado"; // denegado debido a que no hay regla de permiso para 'actualizar'
  528. echo $acl->isAllowed('administrador', null, 'ver') ?
  529. "permitido" : "denegado"; // permitido porque administrador tiene permitidos todos los privilegios
  530. echo $acl->isAllowed('administrador') ?
  531. "permitido" : "denegado"; // permitido porque administrador tiene permitidos todos los privilegios
  532. echo $acl->isAllowed('administrador', null, 'actualizar') ?
  533. "permitido" : "denegado"; // permitido porque administrador tiene permitidos todos los privilegios]]>
  534. </programlisting>
  535. </sect2>
  536. </sect1><!--
  537. vim:se ts=4 sw=4 et:
  538. -->
  539. <sect1 id="zend.acl.refining" xml:base="module_specs/Zend_Acl-Refining.xml">
  540. <title>Perfeccionamiento de los controles de acceso</title>
  541. <sect2 id="zend.acl.refining.precise">
  542. <title>Definir mejor los controles de acceso</title>
  543. <para>
  544. El ACL básico según lo definido en la
  545. <link linkend="zend.acl.introduction">
  546. sección anterior
  547. </link>
  548. demuestra cómo los diversos privilegios se pueden otorgar
  549. sobre todo el ACL (todos los recursos). En la práctica, sin
  550. embargo, los controles de acceso tienden a tener excepciones
  551. y diversos grados de complejidad. Zend_Acl permite lograr
  552. estos refinamientos de una manera sencilla y flexible.
  553. </para>
  554. <para>
  555. Para el CMS del ejemplo se ha determinado que, si bien el
  556. grupo 'staff' cubre las necesidades de la gran mayoría de
  557. usuarios, hay una necesidad de un nuevo grupo 'marketing'
  558. que requiere el acceso al boletín de noticias y las últimas
  559. noticias en el CMS. El grupo es bastante autosuficiente y
  560. tendrá la capacidad de publicar y de archivar los boletines
  561. de noticias y las últimas noticias.
  562. </para>
  563. <para>
  564. Primero revisamos el registro del rol para reflejar estos
  565. cambios. Hemos determinado que el grupo 'marketing' tiene
  566. los mismos permisos básicos que 'staff', así que definimos
  567. 'marketing' de tal manera que herede los permisos de
  568. 'staff':
  569. </para>
  570. <programlisting role="php"><![CDATA[
  571. // El nuevo grupo de Marketing hereda los permisos de Staff
  572. $acl->addRole(new Zend_Acl_Role('marketing'), 'staff'); ]]>
  573. </programlisting>
  574. <para>
  575. A continuación, la nota que por encima de los controles de
  576. acceso se refieren a recursos específicos (por ejemplo,
  577. "boletín informativo", "últimas noticias", "anuncio de
  578. noticias"). Ahora añadimos estos recursos:
  579. </para>
  580. <programlisting role="php"><![CDATA[
  581. // Crear recursos para las reglas
  582. // newsletter
  583. $acl->add(new Zend_Acl_Resource('newsletter'));
  584. // news
  585. $acl->add(new Zend_Acl_Resource('news'));
  586. // Últimas Noticias
  587. $acl->add(new Zend_Acl_Resource('latest'), 'news');
  588. // anuncio de noticias
  589. $acl->add(new Zend_Acl_Resource('announcement'), 'news'); ]]>
  590. </programlisting>
  591. <para>
  592. Entonces es simplemente una cuestión de la definición de
  593. estas normas más específicas en ámbitos de la ACL:
  594. </para>
  595. <programlisting role="php"><![CDATA[ //
  596. Marketing debe ser capaz de archivar y publicar boletines informativos y
  597. // las últimas noticias
  598. $acl->allow('marketing',
  599. array('newsletter', 'latest'),
  600. array('publish', 'archive'));
  601. // Staff (y marketing, por herencia), se le denega el permiso a
  602. // revisar las últimas noticias
  603. $acl->deny('staff', 'latest', 'revise');
  604. // Todos (incluyendo los administradores) tienen permiso denegado para
  605. // archivar anuncios y noticias
  606. $acl->deny(null, 'announcement', 'archive'); ]]>
  607. </programlisting>
  608. <para>
  609. Ahora podemos consultar el ACL con respecto a los últimos
  610. cambios:
  611. </para>
  612. <programlisting role="php"><![CDATA[
  613. echo $acl->isAllowed('staff', 'newsletter', 'publish') ?
  614. "allowed" : "denied";
  615. // denegado
  616. echo $acl->isAllowed('marketing', 'newsletter', 'publish') ?
  617. "allowed" : "denied";
  618. // permitido
  619. echo $acl->isAllowed('staff', 'latest', 'publish') ?
  620. "allowed" : "denied";
  621. // denegado
  622. echo $acl->isAllowed('marketing', 'latest', 'publish') ?
  623. "allowed" : "denied";
  624. // permitido
  625. echo $acl->isAllowed('marketing', 'latest', 'archive') ?
  626. "allowed" : "denied";
  627. // permitido
  628. echo $acl->isAllowed('marketing', 'latest', 'revise') ?
  629. "allowed" : "denied";
  630. // denegado
  631. echo $acl->isAllowed('editor', 'announcement', 'archive') ?
  632. "allowed" : "denied";
  633. // denegado
  634. echo $acl->isAllowed('administrator', 'announcement', 'archive') ?
  635. "allowed" : "denied";
  636. // denegado
  637. ]]>
  638. </programlisting>
  639. </sect2>
  640. <sect2 id="zend.acl.refining.removing">
  641. <title>Eliminar los controles de acceso</title>
  642. <para>
  643. Para eliminar una o más reglas ACL, simplemente utilice el
  644. método removeAllow() o removeDeny(). Al igual que con
  645. allow() y deny(), puede utilizar un valor null para indicar
  646. que el método es aplicable a todos los roles, recursos y/o
  647. privilegios:
  648. </para>
  649. <programlisting role="php"><![CDATA[
  650. // Elimina la prohibición de leer las últimas noticias de staff (y marketing,
  651. // por herencia)
  652. $acl->removeDeny('staff', 'latest', 'revise');
  653. echo $acl->isAllowed('marketing', 'latest', 'revise') ?
  654. "allowed" : "denied";
  655. // permitido
  656. // Elimina la autorización para publicar y archivar los boletines
  657. // marketing
  658. $acl->removeAllow('marketing',
  659. 'newsletter',
  660. array('publish', 'archive'));
  661. echo $acl->isAllowed('marketing', 'newsletter', 'publish') ?
  662. "allowed" : "denied";
  663. // denegado
  664. echo $acl->isAllowed('marketing', 'newsletter', 'archive') ?
  665. "allowed" : "denied";
  666. // denegado
  667. ]]>
  668. </programlisting>
  669. <para>
  670. Los privilegios pueden ser modificados de manera incremental como se
  671. ha indicado anteriormente, pero un valor null para los
  672. privilegios anula tales cambios incrementales:
  673. </para>
  674. <programlisting role="php">
  675. <![CDATA[
  676. //Permitir al grupo de "marketing" todos los permisos a las últimas noticias
  677. $acl->allow('marketing', 'latest');
  678. echo $acl->isAllowed('marketing', 'latest', 'publish') ?
  679. "allowed" : "denied";
  680. //permitido
  681. echo $acl->isAllowed('marketing', 'latest', 'archive') ?
  682. "allowed" : "denied";
  683. //permitido
  684. echo $acl->isAllowed('marketing', 'latest', 'anything') ?
  685. "allowed" : "denied";
  686. // permitido
  687. ]]>
  688. </programlisting>
  689. </sect2>
  690. </sect1>
  691. <sect1 id="zend.acl.advanced" xml:base="module_specs/Zend_Acl-Advanced.xml">
  692. <title>Uso Avanzado</title>
  693. <sect2 id="zend.acl.advanced.storing">
  694. <title>Almacenamiento Permanente de los Datos ACL</title>
  695. <para>
  696. Zend_Acl fue diseñado de tal manera que no requiere ninguna
  697. tecnología particular como bases de datos o un servidor de
  698. cache para el almacenamiento de datos ACL. Al poseer una
  699. implementación completamente construida en PHP, es posible
  700. contruir herramientas de administración personalizadas sobre
  701. Zend_Acl con relativa facilidad y flexibilidad. En muchas
  702. situaciones se requiere alguna forma de mantenimiento
  703. interactivo de una ACL, y Zend_Acl provee métodos para
  704. configurar, y consultar, los controles de acceso de una
  705. aplicación.
  706. </para>
  707. <para>
  708. El almacenamiento de los datos ACL es una tarea que se
  709. delega al desarrollador, puesto que la utilización variará
  710. exténsamente en distintas situaciones. Dado que Zend_Acl es
  711. serializable, los objetos ACL pueden serializarse con la
  712. función
  713. <ulink url="http://php.net/serialize">
  714. <code>serialize()</code>
  715. </ulink>
  716. de PHP, y los resultados pueden ser almacenados donde sea
  717. que el desarrollador lo desee, en un archivo, base de datos,
  718. o mecanismo de cache
  719. </para>
  720. </sect2>
  721. <sect2 id="zend.acl.advanced.assertions">
  722. <title>
  723. Escribiendo reglas condicionales ACL con aserciones
  724. </title>
  725. <para>
  726. A veces, una regla para permitir o negar una función de acceso a un
  727. recurso no debería ser absoluta sino que depende de varios criterios.
  728. Por ejemplo, supóngase que debe permitirse cierto acceso, pero
  729. únicamente entre las 8:00am y 5:00pm. Otro ejemplo sería negar el
  730. acceso debido a una petición que proviene de una dirección IP que se
  731. ha marcado como una fuente de abusos. Zend_Acl tiene soporte para la
  732. aplicación de normas basadas en cualquier condición que el
  733. desarrollador necesite.
  734. </para>
  735. <para>
  736. Zend_Acl provee soporte para reglas condicionales con
  737. <code>Zend_Acl_Assert_Interface</code>
  738. . Con el fin de utilizar la regla de aserción de la interfaz,
  739. un desarrollador escribe una clase que implemente el método
  740. <code>assert()</code>
  741. de la interfaz:
  742. </para>
  743. <programlisting role="php"><![CDATA[
  744. class CleanIPAssertion implements Zend_Acl_Assert_Interface
  745. {
  746. public function assert(Zend_Acl $acl,
  747. Zend_Acl_Role_Interface $role = null,
  748. Zend_Acl_Resource_Interface $resource = null,
  749. $privilege = null)
  750. {
  751. return $this->_isCleanIP($_SERVER['REMOTE_ADDR']);
  752. }
  753. protected function _isCleanIP($ip)
  754. {
  755. // ...
  756. }
  757. }
  758. ]]>
  759. </programlisting>
  760. <para>
  761. Una vez la clase de aserción esta disponible, el desarrollador puede
  762. suministrar una instancia de la clase de aserción cuando asigna reglas
  763. condicionales. Una regla que es creada con una aserción
  764. sólo se aplica cuando el método de la aserción devuelve true.
  765. </para>
  766. <programlisting role="php"><![CDATA[
  767. $acl = new Zend_Acl();
  768. $acl->allow(null, null, null, new CleanIPAssertion());
  769. ]]>
  770. </programlisting>
  771. <para>
  772. El código anterior crea una regla condicional que permite el acceso a
  773. todos los privilegios sobre todo, por todo el mundo, excepto cuando la IP
  774. de quien hace la petición está en la "lista negra". Si una petición
  775. viene desde una IP que no está considerada "limpia", entonces la regla no
  776. se aplica. Dado que la regla se aplica a todos los roles, todos los
  777. recursos, y todos los privilegios, una IP "no limpia" daría lugar a una
  778. negación de acceso. Éste es un caso especial, sin embargo, y debería ser
  779. entendido que en todos los otros casos (por ejemplo, cuando un rol
  780. específico, recurso, o privilegio está especificado por la regla),
  781. una aserción fallida provoca que la regla no se aplique, y otras reglas
  782. deberían ser usadas para determinar si el acceso está permitido o
  783. denegado.
  784. </para>
  785. <para>
  786. El método
  787. <code>assert()</code>
  788. de un objeto aserción es pasado a la ACL, regla, recurso, y privilegio
  789. para el cual una consulta de autorización (por ejemplo,
  790. <code>isAllowed()</code>
  791. ) se aplica, con el fin de proporcionar un contexto para que la clase de
  792. aserción determine sus condiciones cuando fuera necesario.
  793. </para>
  794. </sect2>
  795. </sect1><!--
  796. vim:se ts=4 sw=4 et:
  797. -->
  798. </chapter>
  799. <chapter id="zend.amf">
  800. <title>Zend_Amf</title>
  801. <sect1 id="zend.amf.introduction" xml:base="module_specs/Zend_Amf.xml">
  802. <title>IntroducciГіn</title>
  803. <para>
  804. <code>Zend_Amf</code>
  805. provee apoyo para el Formato de Mensajes de ActionScript
  806. <ulink url="http://en.wikipedia.org/wiki/Action_Message_Format">Action
  807. Message Format</ulink>
  808. (AMF) de Adobe, que permite la comunicaciГіn
  809. entre Adobe
  810. <ulink url="http://en.wikipedia.org/wiki/Adobe_Flash_Player">Flash
  811. Player</ulink>
  812. y PHP. EspecГ­ficamente, proporciona una aplicaciГіn
  813. para un
  814. servidor gateway que tramita las solicitudes enviadas desde
  815. Flash Player al servidor, mapeando estos requerimientos
  816. al objeto y a sus mГ©todos de clase, como asГ­ tambiГ©n a llamadas
  817. arbitrarias de comunicaciГіn.
  818. </para>
  819. <para>
  820. Las
  821. <ulink>
  822. url="http://download.macromedia.com/pub/labs/amf/amf3_spec_121207.pdf"&gt;
  823. </ulink>
  824. especificaciones
  825. (en inglГ©s) de AMF3 son de libre disponibilidad y sirven como referencia
  826. para establecer quГ© tipos de mensajes
  827. pueden ser enviados entre Flash Player y el servidor.
  828. </para>
  829. </sect1><!--
  830. vim:se ts=4 sw=4 et:
  831. -->
  832. <sect1 id="zend.amf.server" xml:base="module_specs/Zend_Amf-Server.xml">
  833. <title>Zend_Amf_Server</title>
  834. <para>
  835. <code>Zend_Amf_Server</code> proporciona un servidor al estilo RPC para
  836. tramitar solicitudes hechas desde Adobe Flash Player utilizando el protocolo AMF.
  837. Al igual que todas las clases de servidor, Zend Framework sigue la API de
  838. SoapServer, proporcionando una interfaz para crear servidores fácil de recordar.
  839. </para>
  840. <example id="zend.amf.server.basic">
  841. <title>Servidor AMF básico</title>
  842. <para>
  843. Asumamos que ha creado la clase <code>Foo</code> con una
  844. variedad de métodos públicos. Usando el siguiente código, puede
  845. crear un servidor AMF:
  846. </para>
  847. <programlisting role="php"><![CDATA[
  848. $servidor = new Zend_Amf_Server();
  849. $servidor->setClass('Foo');
  850. $respuesta = $servidor->handle();
  851. echo $respuesta;
  852. ]]>
  853. </programlisting>
  854. <para>
  855. Alternativamente, en su lugar puede elegir agregar una función simple como
  856. llamada de retorno:
  857. </para>
  858. <programlisting role="php"><![CDATA[
  859. $servidor = new Zend_Amf_Server();
  860. $servidor->addFunction('myUberCoolFunction');
  861. $respuesta = $servidor->handle();
  862. echo $respuesta;
  863. ]]>
  864. </programlisting>
  865. <para>
  866. También puede combinar y examinar la identidad de varias clases y funciones.
  867. Al hacerlo, sugerimos darle un espacio de nombres a cada una para
  868. garantizar que no ocurran colisiones entre nombres de métodos;
  869. puede hacerse simplemente pasando una segunda cadena de argumentos para cualquier <code>addFunction()</code> o
  870. <code>setClass()</code>:
  871. </para>
  872. <programlisting role="php"><![CDATA[
  873. $servidor = new Zend_Amf_Server();
  874. $servidor->addFunction('myUberCoolFunction', 'my')
  875. ->setClass('Foo', 'foo')
  876. ->setClass('Bar', 'bar');
  877. $respuesta = $servidor->handle();
  878. echo $respuesta;
  879. ]]>
  880. </programlisting>
  881. <para>
  882. El <code>Zend_Amf_Server</code> también permite cargar servicios
  883. dinámicamente, en función de una ruta de directorio ya suministrada.
  884. Puede añadir al servidor tantos directorios como desee.
  885. El orden en que se añadan los directorios al servidor será el orden en que
  886. se realizarán las búsquedas LIFO en los directorios para coincidir
  887. con la clase.
  888. El método <code>addDirectory()</code> realiza la acción de añadir directorios.
  889. </para>
  890. <programlisting role="php"><![CDATA[
  891. $servidor->addDirectory(dirname(__FILE__) .'/../services/');
  892. $servidor->addDirectory(dirname(__FILE__) .'/../package/');
  893. ]]>
  894. </programlisting>
  895. <para>
  896. Cuando se llama a servicios remotos, los nombres de los directorios que
  897. contengan las fuentes pueden tener los delimitadores guión bajo (_) y el punto (.).
  898. Cuando se utilize un guión bajo (_) tanto en PEAR como en Zend Framework,
  899. se respetarán los nombres de clases de acuerdo a las convenciones de nomenclatura.
  900. Esto significa que si usted llama al servicio com_Foo_Bar el servidor
  901. buscará el archivo Bar.php en cada una de las rutas incluidas en <code>com/Foo/Bar.php</code>.
  902. Si se usa la notación punto para su servicio remoto como <code>com.Foo.Bar</code>
  903. cada ruta incluida deberá tener <code>com/Foo/Bar.php</code> agregado al final
  904. para autocargar Bar.php.
  905. </para>
  906. <para>
  907. Todos las solicitudes AMF enviadas al script serán manejadas
  908. por el servidor, y este devolverá una respuesta AMF.
  909. </para>
  910. </example>
  911. <note>
  912. <title>Todos los métodos y las funciones agregadas requieren bloques de documentación (docblocks)</title>
  913. <para>
  914. Como todos los demás componentes del servidor en Zend Framework,
  915. debe documentar los métodos de su clase usando PHP docblocks.
  916. Como mínimo, necesita proporcionar anotaciones para cada argumento
  917. así como para el valor de retorno. Como ejemplos:
  918. </para>
  919. <programlisting role="php"><![CDATA[
  920. // Función que agregar:
  921. /**
  922. * @param string $nombre
  923. * @param string $saludo
  924. * @return string
  925. */
  926. function holaMundo($ombre, $saludo = 'Hola')
  927. {
  928. return $saludo . ', ' . $nombre;
  929. }
  930. ]]>
  931. </programlisting>
  932. <programlisting role="php"><![CDATA[
  933. // Clase agregada
  934. class Mundo
  935. {
  936. /**
  937. * @param string $nombre
  938. * @param string $saludo
  939. * @return string
  940. */
  941. public function hola($nombre, $saludo = 'Hola')
  942. {
  943. return $saludo . ', ' . $nombre;
  944. }
  945. }
  946. ]]>
  947. </programlisting>
  948. <para>
  949. Pueden usarse otras anotaciones, pero serán ignoradas.
  950. </para>
  951. </note>
  952. <sect2 id="zend.amf.server.flex">
  953. <title>Conectándose al Servidor desde Flex</title>
  954. <para>
  955. Conectarse a <code>Zend_Amf_Server</code> desde su proyecto Flex
  956. es bastante simple; solo necesita apuntar el final del URI
  957. a su script <code>Zend_Amf_Server</code>.
  958. </para>
  959. <para>
  960. Por ejemplo, digamos que usted ya ha creado su servidor y lo ha
  961. puesto en el fichero <code>server.php</code> en el directorio raíz (root)
  962. de su aplicación, por lo tanto la URI es <code>http://example.com/server.php</code>.
  963. En este caso, usted debería modificar su fichero services-config.xml
  964. poniendo este valor como atributo al punto final del canal uri.
  965. </para>
  966. <para>
  967. Si nunca ha creado un fichero services-config.xml puede hacerlo
  968. abriendo su proyecto en la ventana del navegador.
  969. Haga clic derecho sobre el nombre del proyecto y seleccione 'properties' (propiedades).
  970. En el cuadro de diálogo 'properties' del proyecto ir al menú ‘Flex Build Path' (Crear ruta Flex),
  971. luego en la pestaña ‘Library path’ (ruta de biblioteca) asegúrese
  972. de que el fichero 'rpc.swc' sea añadido a su ruta de proyectos
  973. y pulse Ok (Aceptar) para cerrar la ventana.
  974. </para>
  975. <para>
  976. También necesitará indicarle al compilador que debe usar
  977. services-config.xml para encontrar el punto final de RemoteObject.
  978. Para hacerlo, abra de nuevo el panel de propiedades de su proyecto
  979. haciendo clic en el botón derecho sobre el proyecto en la carpeta del
  980. navegador y seleccione 'properties' (propiedades).
  981. Ahora seleccione ‘Flex Compiler' (Compilador Flex) y añada la cadena:
  982. -services “services-config.xml".
  983. Presione 'Apply' (Aplicar) y luego en OK para volver a actualizar la opción.
  984. Lo que acaba de hacer es decirle al compilador Flex que busque en el fichero
  985. services-config.xml aquellas variables que se usarán en tiempo de
  986. ejecución por la clase RemotingObject.
  987. </para>
  988. <para>
  989. Ahora, para conectarnos a nuestros métodos remotos debemos indicarle a Flex
  990. qué fichero de configuración de servicios utilizar.
  991. Por esta razón creamos un nuevo fichero 'services-config.xml'
  992. en la carpeta src del proyecto Flex.
  993. Con click derecho sobre el proyecto y seleccionando 'new'(nuevo)
  994. 'File' (fichero), se abrirá una nueva ventana.
  995. Seleccione la carpeta del proyecto y luego nombre el archivo
  996. 'services-config.xml' y presione 'finish' (finalizar).
  997. </para>
  998. <para>
  999. Flex ha creado y abierto el nuevo fichero services-config.xml.
  1000. Utilice el siguiente texto de ejemplo para su fichero services-config.xml.
  1001. Asegúrese de actualizar su punto final para que concuerde con el servidor.
  1002. Asegúrese también de guardar el fichero.
  1003. </para>
  1004. <programlisting role="xml"><![CDATA[
  1005. <?xml version="1.0" encoding="UTF-8"?>
  1006. <services-config>
  1007. <services>
  1008. <service id="zend-service"
  1009. class="flex.messaging.services.RemotingService"
  1010. messageTypes="flex.messaging.messages.RemotingMessage">
  1011. <destination id="zend">
  1012. <channels>
  1013. <channel ref="zend-endpoint"/>
  1014. </channels>
  1015. <properties>
  1016. <source>*</source>
  1017. </properties>
  1018. </destination>
  1019. </service>
  1020. </services>
  1021. <channels>
  1022. <channel-definition id="zend-endpoint"
  1023. class="mx.messaging.channels.AMFChannel">
  1024. <endpoint uri="http://example.com/server.php"
  1025. class="flex.messaging.endpoints.AMFEndpoint"/>
  1026. </channel-definition>
  1027. </channels>
  1028. </services-config>
  1029. ]]>
  1030. </programlisting>
  1031. <para>
  1032. Hay dos puntos clave en el ejemplo.
  1033. En primer lugar, pero último en el listado, creamos un canal AMF,
  1034. y especificamos el punto final como la URL a nuestro <code>Zend_Amf_Server</code>:
  1035. </para>
  1036. <programlisting role="xml"><![CDATA[
  1037. <channel-definition id="zend-endpoint"
  1038. <endpoint uri="http://example.com/server.php"
  1039. class="flex.messaging.endpoints.AMFEndpoint"/>
  1040. </channel-definition>
  1041. ]]>
  1042. </programlisting>
  1043. <para>
  1044. Advierta que a este canal le hemos dado un identificador, "zend-endpoint".
  1045. El ejemplo crea un servicio cuyo destino hace referencia a este canal,
  1046. asignándole también un ID, en este caso es "zend".
  1047. </para>
  1048. <para>
  1049. Dentro de nuestros ficheros Flex MXML, necesitamos vincular un RemoteObject al servicio.
  1050. En MXML, esto podría hacerse así:
  1051. </para>
  1052. <programlisting role="xml"><![CDATA[
  1053. <mx:RemoteObject id="myservice"
  1054. fault="faultHandler(event)"
  1055. showBusyCursor="true"
  1056. source="RoundTrip"
  1057. destination="zend">
  1058. ]]>
  1059. </programlisting>
  1060. <para>
  1061. Aquí, hemos definido un nuevo objeto remoto identificado por "myservice"
  1062. vinculado destino de servicio "zend" que hemos definido en el fichero
  1063. <code>services-config.xml</code>. Entonces invocamos sus métodos en
  1064. nuestro ActionScript simplemente llamando a "myservice.&lt;method&gt;".
  1065. (En este caso, el código original "RoundTrip" es el nombre de nuestra
  1066. aplicación Flex). Un ejemplo:
  1067. </para>
  1068. <programlisting role="ActionScript"><![CDATA[
  1069. myservice.hello("Wade");
  1070. ]]>
  1071. </programlisting>
  1072. <para>
  1073. Cuando se usan nombres-de-espacio, puede usarse
  1074. "myservice.&lt;namespace&gt;.&lt;method&gt;":
  1075. </para>
  1076. <programlisting role="ActionScript"><![CDATA[
  1077. myservice.world.hello("Wade");
  1078. ]]>
  1079. </programlisting>
  1080. <para>
  1081. Para más información sobre como invocar a Flex RemoteObject visite el
  1082. sitio de ayuda de Adobe Flex 3 en:<ulink url="http://livedocs.adobe.com/flex/3/html/help.html?content=data_access_4.html"/>.
  1083. </para>
  1084. </sect2>
  1085. <sect2 id="zend.amf.server.errors">
  1086. <title>Manejo de errores</title>
  1087. <para>
  1088. Por defecto, todas las excepciones producidas en sus
  1089. clases o funciones adjuntas serán capturados y devueltas como
  1090. mensajes de error de AMF (AMF ErrorMessages).
  1091. Sin embargo, el contenido de estos objetos de mensajes de error
  1092. variará dependiendo de si el servidor está o no en modo "producción"
  1093. (el estado por defecto).
  1094. </para>
  1095. <para>
  1096. Cuando se está en modo de producción, únicamente el código de excepción será devuelto.
  1097. Si desactiva el modo de producción, algo que debe hacerse sólo
  1098. para probar -- serán devueltos más detalles de la excepción:
  1099. el mensaje de excepción (error), línea y backtrace serán adjuntados.
  1100. </para>
  1101. <para>
  1102. Para desactivar el modo de producción, haga lo siguiente:
  1103. </para>
  1104. <programlisting role="php"><![CDATA[
  1105. $servidor->setProduction(false);
  1106. ]]>
  1107. </programlisting>
  1108. <para>
  1109. Para habilitarlo nuevamente, pase el valor true en su lugar.
  1110. </para>
  1111. <programlisting role="php"><![CDATA[
  1112. $servidor->setProduction(true);
  1113. ]]>
  1114. </programlisting>
  1115. <note>
  1116. <title>¡Deshabilite el modo de producción racionalmente!</title>
  1117. <para>
  1118. Sugerimos deshabilitar el modo de producción solo cuando se está
  1119. en modo de desarrollo.
  1120. Los mensajes de excepción y los backtraces puede contener información
  1121. sensible del sistema, y no desea que se pueda acceder a ellas
  1122. desde el exterior.
  1123. Aunque AMF es un formato binario, ahora al ser abierta la especificación,
  1124. cualquiera puede potencialmente deserializar los datos.
  1125. </para>
  1126. </note>
  1127. <para>
  1128. Un área en la que se debe tener especialmente mucho cuidado son los
  1129. errores propios de PHP.
  1130. Cuando la directiva INI <code>display_errors</code> está habilitada,
  1131. los errores de PHP de cualquier nivel del reporte actual serán
  1132. pasados directamente a la salida, y potencialmente se podrían hacer
  1133. estragos con las respuestas de AMF.
  1134. Para prevenir estos problemas, sugerimos deshabilitar la directiva
  1135. <code>display_errors</code> cuando se está en modo de producción.
  1136. </para>
  1137. </sect2>
  1138. <sect2 id="zend.amf.server.response">
  1139. <title>Respuestas de AMF</title>
  1140. <para>
  1141. En ocasiones es posible que quiera manipular ligeramente el objeto
  1142. respuesta, es bastante usual querer devolver algunas cebeceras
  1143. de mensajes adicionales. Puede hacerlo mediante el método del servidor
  1144. <code>handle()</code> que devuelve el objeto respuesta.
  1145. </para>
  1146. <example id="zend.amf.server.response.messageHeaderExample">
  1147. <title>Agregar cabeceras de mensaje a la respuesta de AMF</title>
  1148. <para>
  1149. En este ejemplo, añadiremos la cabecera de mensaje (MessageHeader)
  1150. "foo" con el valor 'bar' a la respuesta antes de devolverla.
  1151. </para>
  1152. <programlisting role="php"><![CDATA[
  1153. $respuesta = $servidor->handle();
  1154. $respuesta->addAmfHeader(new Zend_Amf_Value_MessageHeader('foo', true, 'bar'))
  1155. echo $respuesta;
  1156. ]]>
  1157. </programlisting>
  1158. </example>
  1159. </sect2>
  1160. <sect2 id="zend.amf.server.typedobjects">
  1161. <title>Objetos tipados</title>
  1162. <para>
  1163. Similarmente a SOAP, AMF permite pasar objetos entre cliente y servidor.
  1164. Esto le da una gran flexibilidad y coherencia a ambos entornos.
  1165. </para>
  1166. <para>
  1167. <code>Zend_Amf</code> ofrece tres métodos para mapear ActionScript
  1168. y objetos PHP.
  1169. </para>
  1170. <itemizedlist>
  1171. <listitem>
  1172. <para>
  1173. Primero, usted puede crear uniones explícitas a nivel del servidor,
  1174. utilizando el método <code>setClassMap()</code>.
  1175. El primer argumento es el nombre de la clase de ActionScript,
  1176. el segundo es el nombre de la clase PHP que lo mapea:
  1177. </para>
  1178. <programlisting role="php"><![CDATA[
  1179. // Mapea la clase ActionScript 'ContactVO' a la clase PHP 'Contact':
  1180. $servidor->setClassMap('ContactVO', 'Contact');
  1181. ]]>
  1182. </programlisting>
  1183. </listitem>
  1184. <listitem>
  1185. <para>
  1186. Segundo, en su clase PHP puede ajustar la propiedad como pública
  1187. mediante <code>$_explicitType</code>, con el valor
  1188. representativo de la clase ActionScript que mapear:
  1189. </para>
  1190. <programlisting role="php"><![CDATA[
  1191. class Contact
  1192. {
  1193. public $_explicitType = 'ContactVO';
  1194. }
  1195. ]]>
  1196. </programlisting>
  1197. </listitem>
  1198. <listitem>
  1199. <para>
  1200. Tercero, en un sentido similar, puede definir como público el método
  1201. <code>getASClassName()</code> dentro de su clase.
  1202. Este método debe devolver la clase ActionScript apropiada:
  1203. </para>
  1204. <programlisting role="php"><![CDATA[
  1205. class Contact
  1206. {
  1207. public function getASClassName()
  1208. {
  1209. return 'ContactVO';
  1210. }
  1211. }
  1212. ]]>
  1213. </programlisting>
  1214. </listitem>
  1215. </itemizedlist>
  1216. <para>
  1217. Aunque hemos creado ContactVO en el servidor,
  1218. ahora tenemos que hacer su clase correspondiente en AS3
  1219. para que el servidor pueda mapear el objeto.
  1220. </para>
  1221. <para>
  1222. Haga clic derecho sobre la carpeta src del proyecto Flex y seleccione New -&gt; ActionScript File.
  1223. Nombre el fichero como ContactVO y pulse 'finish' (finalizar) para verlo.
  1224. Copie el siguiente código en el fichero para terminar de crear la clase.
  1225. </para>
  1226. <programlisting role="as"><![CDATA[
  1227. package
  1228. {
  1229. [Bindable]
  1230. [RemoteClass(alias="ContactVO")]
  1231. public class ContactVO
  1232. {
  1233. public var id:int;
  1234. public var firstname:String;
  1235. public var lastname:String;
  1236. public var email:String;
  1237. public var mobile:String;
  1238. public function ProductVO():void {
  1239. }
  1240. }
  1241. }
  1242. ]]>
  1243. </programlisting>
  1244. <para>
  1245. La clase es sintácticamente equivalente a la de PHP del mismo nombre.
  1246. Los nombres de variables son exactamente los mismos y necesitan estar
  1247. en el mismo contenedor para trabajar correctamente. Hay
  1248. dos meta tags AS3 únicos en esta clase.
  1249. El primero es vinculable y dispara un evento cuando es actualizada.
  1250. El segundo es el tag RemoteClass y define que esta clase puede tener
  1251. mapeado un objeto remoto con un nombre de alias, en este caso <code>ContactVO</code>
  1252. Es obligatorio que en esta etiqueta(tag), el valor que se estableció es la clase PHP
  1253. sea estrictamente equivalente.
  1254. </para>
  1255. <programlisting role="as"><![CDATA[
  1256. [Bindable]
  1257. private var myContact:ContactVO;
  1258. private function getContactHandler(event:ResultEvent):void {
  1259. myContact = ContactVO(event.result);
  1260. }
  1261. ]]>
  1262. </programlisting>
  1263. <para>
  1264. El siguiente resultado del evento debido a la llamada de servicio,
  1265. se incorporó instantáneamente a ContactVO de Flex.
  1266. Cualquier cosa que esté ligada a myContact será actualizada con los
  1267. datos retornados por ContactVO.
  1268. </para>
  1269. </sect2>
  1270. <sect2 id="zend.amf.server.flash">
  1271. <title>Conectándose al servidor desde Flash</title>
  1272. <para>
  1273. La conexión a <code>Zend_Amf_Server</code> desde su proyecto Flash
  1274. es ligeramente distinta a la de Flex. Sin embargo una vez que la conexión
  1275. con Flash funcione con <code>Zend_Amf_Server</code> lo hará igual
  1276. modo que con Flex. El siguiente ejemplo también puede ser utilizado
  1277. desde un fichero Flex AS3. Para nuestra conexión vamos a reutilizar
  1278. la misma configuracion <code>Zend_Amf_Server</code> junto a la clase Mundo.
  1279. </para>
  1280. <para>
  1281. Abra Flash CS y cree un nuevo fichero Flash (ActionScript 3).
  1282. Nombre al documento como ZendExample.fla y guárdelo en una carpeta
  1283. que utilizará para este ejemplo. Cree una nuevo fichero AS3 en el mismo
  1284. directorio y llámelo Main.as. Abra ambos ficheros con su editor.
  1285. Ahora vamos a conectar las dos ficheros a través de la clase documento.
  1286. Seleccione ZendExample y haga clic en el escenario.
  1287. Desde el panel del escenario cambie la propiedad de la clase Document a Main.
  1288. Esto vincula al fichero Main.as con la interfaz de usuario en ZendExample.fla.
  1289. Cuando ejecute el fichero ZendExample de Flash se ejecutará ahora
  1290. la clase Main.as.
  1291. El paso siguiente será añadir ActionScript para hacer una lamada AMF.
  1292. </para>
  1293. <para>
  1294. Ahora vamos a hacer una clase Main(principal) para que podamos enviar
  1295. los datos al servidor y mostrar el resultado.
  1296. Copie el código siguiente en su fichero Main.as y luego vamos a recorrer
  1297. el código para describir cuál es el papel de cada elemento.
  1298. </para>
  1299. <programlisting role="as"><![CDATA[
  1300. package {
  1301. import flash.display.MovieClip;
  1302. import flash.events.*;
  1303. import flash.net.NetConnection;
  1304. import flash.net.Responder;
  1305. public class Main extends MovieClip {
  1306. private var gateway:String = "http://example.com/server.php";
  1307. private var connection:NetConnection;
  1308. private var responder:Responder;
  1309. public function Main() {
  1310. responder = new Responder(onResult, onFault);
  1311. connection = new NetConnection;
  1312. connection.connect(gateway);
  1313. }
  1314. public function onComplete( e:Event ):void{
  1315. var params = "Sent to Server";
  1316. connection.call("World.hello", responder, params);
  1317. }
  1318. private function onResult(result:Object):void {
  1319. // Display the returned data
  1320. trace(String(result));
  1321. }
  1322. private function onFault(fault:Object):void {
  1323. trace(String(fault.description));
  1324. }
  1325. }
  1326. }
  1327. ]]>
  1328. </programlisting>
  1329. <para>
  1330. Primero tenemos que importar dos bibliotecas de ActionScript que realizan
  1331. la mayor parte del trabajo. La primera es NetConnection que actúa como un
  1332. tubo bidireccional entre el cliente y el servidor.
  1333. La segunda es un objeto Responder que maneja los valores de retorno desde
  1334. el servidor, y que están relacionados con el éxito o el fracaso de la llamada.
  1335. </para>
  1336. <programlisting role="as"><![CDATA[
  1337. import flash.net.NetConnection;
  1338. import flash.net.Responder;
  1339. ]]>
  1340. </programlisting>
  1341. <para>
  1342. En la clase necesitaremos tres variables para representar a NetConnection,
  1343. Responder, y la URL del gateway a nuestra instalación <code>Zend_Amf_Server</code>.
  1344. </para>
  1345. <programlisting role="as"><![CDATA[
  1346. private var gateway:String = "http://example.com/server.php";
  1347. private var connection:NetConnection;
  1348. private var responder:Responder;
  1349. ]]>
  1350. </programlisting>
  1351. <para>
  1352. En el constructor Main creamos un Responder(respondedor) y una nueva conexión al
  1353. punto final de <code>Zend_Amf_Server</code>. El respondedor define dos
  1354. diferentes métodos para manejar la respuesta desde el servidor.
  1355. Por simplicidad los hemos llamado onResult y onFault.
  1356. </para>
  1357. <programlisting role="as"><![CDATA[
  1358. responder = new Responder(onResult, onFault);
  1359. connection = new NetConnection;
  1360. connection.connect(gateway);
  1361. ]]>
  1362. </programlisting>
  1363. <para>
  1364. La función onComplete se ejecuta tan pronto como la construcción
  1365. ha concluido, enviando los datos al servidor.
  1366. Necesitamos añadir una línea más que hace una llamada a la función
  1367. <code>Zend_Amf_Server</code> Mundo-&gt;hola.
  1368. </para>
  1369. <programlisting role="as"><![CDATA[
  1370. connection.call("Mundo.hola", responder, params);
  1371. ]]>
  1372. </programlisting>
  1373. <para>
  1374. Cuando creamos la variable responder hemos definido las funciones onResult y onFault
  1375. para manejar la respuesta proveniente del servidor.
  1376. Hemos añadido la función OnResult para el resultado exitoso desde el servidor.
  1377. Cada vez que se ejecuta apropiadamente el manejo de conexión con el
  1378. servidor, el manejador de eventos llama esta función.
  1379. </para>
  1380. <programlisting role="as"><![CDATA[
  1381. private function onResult(result:Object):void {
  1382. // Muestra los datos devueltos
  1383. trace(String(result));
  1384. }
  1385. ]]>
  1386. </programlisting>
  1387. <para>
  1388. La función onFault, se llama si hubo una respuesta nula desde el servidor.
  1389. Esto ocurre cuando hay un error en el servidor, la URL al servidor es inválida,
  1390. el servicio remoto o método no existe o cualquier otra cuestión
  1391. relacionada con la conexión.
  1392. </para>
  1393. <programlisting role="as"><![CDATA[
  1394. private function onFault(fault:Object):void {
  1395. trace(String(fault.description));
  1396. }
  1397. ]]>
  1398. </programlisting>
  1399. <para>
  1400. La inclusión de ActionScript para realizar la conexión remota ha finalizado.
  1401. Al ejecutar el fichero ZendExample, se establece una conexión con Zend_Amf.
  1402. En resumen, se han añadido las variables requeridas para abrir una conexión
  1403. con el servidor remoto, se han definido qué métodos se deben utilizar cuando su aplicación
  1404. recibe una respuesta desde el servidor, y finalmente se han mostrado los datos de salida
  1405. devueltos a través de trace().
  1406. </para>
  1407. </sect2>
  1408. </sect1><!--
  1409. vim:se ts=4 sw=4 et:
  1410. -->
  1411. </chapter>
  1412. <chapter id="zend.auth">
  1413. <title>Zend_Auth</title>
  1414. <sect1 id="zend.auth.introduction" xml:base="module_specs/Zend_Auth.xml">
  1415. <title>Introduction</title>
  1416. <para>
  1417. Zend_Auth provides an API for authentication and includes concrete authentication adapters for
  1418. common use case scenarios.
  1419. </para>
  1420. <para>
  1421. Zend_Auth is concerned only with <emphasis role="strong">authentication</emphasis> and not with
  1422. <emphasis role="strong">authorization</emphasis>. Authentication is loosely defined as determining
  1423. whether an entity actually is what it purports to be (i.e., identification), based on some set of
  1424. credentials. Authorization, the process of deciding whether to allow an entity access to, or to
  1425. perform operations upon, other entities is outside the scope of Zend_Auth. For more information about
  1426. authorization and access control with the Zend Framework, please see
  1427. <link linkend="zend.acl">Zend_Acl</link>.
  1428. </para>
  1429. <note>
  1430. <para>
  1431. The <code>Zend_Auth</code> class implements the Singleton pattern - only one instance of the class is
  1432. available - through its static <code>getInstance()</code> method. This means that using the <code>new</code>
  1433. operator and the <code>clone</code> keyword will not work with the <code>Zend_Auth</code> class; use
  1434. <code>Zend_Auth::getInstance()</code> instead.
  1435. </para>
  1436. </note>
  1437. <sect2 id="zend.auth.introduction.adapters">
  1438. <title>Adapters</title>
  1439. <para>
  1440. A Zend_Auth adapter is used to authenticate against a particular type of authentication service,
  1441. such as LDAP, RDBMS, or file-based storage. Different adapters are likely to have vastly different
  1442. options and behaviors, but some basic things are common among authentication adapters. For example,
  1443. accepting authentication credentials (including a purported identity), performing queries against the
  1444. authentication service, and returning results are common to Zend_Auth adapters.
  1445. </para>
  1446. <para>
  1447. Each Zend_Auth adapter class implements <code>Zend_Auth_Adapter_Interface</code>. This interface defines one
  1448. method, <code>authenticate()</code>, that an adapter class must implement for performing an authentication
  1449. query. Each adapter class must be prepared prior to calling <code>authenticate()</code>. Such adapter
  1450. preparation includes setting up credentials (e.g., username and password) and defining values for adapter-
  1451. specific configuration options, such as database connection settings for a database table adapter.
  1452. </para>
  1453. <para>
  1454. The following is an example authentication adapter that requires a username and password to be set
  1455. for authentication. Other details, such as how the authentication service is queried, have been
  1456. omitted for brevity:
  1457. <programlisting role="php"><![CDATA[
  1458. class MyAuthAdapter implements Zend_Auth_Adapter_Interface
  1459. {
  1460. /**
  1461. * Sets username and password for authentication
  1462. *
  1463. * @return void
  1464. */
  1465. public function __construct($username, $password)
  1466. {
  1467. // ...
  1468. }
  1469. /**
  1470. * Performs an authentication attempt
  1471. *
  1472. * @throws Zend_Auth_Adapter_Exception If authentication cannot
  1473. * be performed
  1474. * @return Zend_Auth_Result
  1475. */
  1476. public function authenticate()
  1477. {
  1478. // ...
  1479. }
  1480. }
  1481. ]]>
  1482. </programlisting>
  1483. As indicated in its docblock, <code>authenticate()</code> must return an instance of
  1484. <code>Zend_Auth_Result</code> (or of a class derived from <code>Zend_Auth_Result</code>). If for some
  1485. reason performing an authentication query is impossible, <code>authenticate()</code> should throw
  1486. an exception that derives from <code>Zend_Auth_Adapter_Exception</code>.
  1487. </para>
  1488. </sect2>
  1489. <sect2 id="zend.auth.introduction.results">
  1490. <title>Results</title>
  1491. <para>
  1492. Zend_Auth adapters return an instance of <code>Zend_Auth_Result</code> with
  1493. <code>authenticate()</code> in order to represent the results of an authentication attempt. Adapters
  1494. populate the <code>Zend_Auth_Result</code> object upon construction, so that the following four methods
  1495. provide a basic set of user-facing operations that are common to the results of Zend_Auth adapters:
  1496. <itemizedlist>
  1497. <listitem>
  1498. <para>
  1499. <code>isValid()</code> - returns true if and only if the result represents a
  1500. successful authentication attempt
  1501. </para>
  1502. </listitem>
  1503. <listitem>
  1504. <para>
  1505. <code>getCode()</code> - returns a <code>Zend_Auth_Result</code> constant identifier for
  1506. determining the type of authentication failure or whether success has occurred. This may be
  1507. used in situations where the developer wishes to distinguish among several authentication
  1508. result types. This allows developers to maintain detailed authentication result statistics,
  1509. for example. Another use of this feature is to provide specific, customized messages to
  1510. users for usability reasons, though developers are encouraged to consider the risks of
  1511. providing such detailed reasons to users, instead of a general authentication failure
  1512. message. For more information, see the notes below.
  1513. </para>
  1514. </listitem>
  1515. <listitem>
  1516. <para>
  1517. <code>getIdentity()</code> - returns the identity of the authentication attempt
  1518. </para>
  1519. </listitem>
  1520. <listitem>
  1521. <para>
  1522. <code>getMessages()</code> - returns an array of messages regarding a failed
  1523. authentication attempt
  1524. </para>
  1525. </listitem>
  1526. </itemizedlist>
  1527. </para>
  1528. <para>
  1529. A developer may wish to branch based on the type of authentication result in order to perform more
  1530. specific operations. Some operations developers might find useful are locking accounts after too many
  1531. unsuccessful password attempts, flagging an IP address after too many nonexistent identities are
  1532. attempted, and providing specific, customized authentication result messages to the user. The following
  1533. result codes are available:
  1534. <programlisting role="php"><![CDATA[
  1535. Zend_Auth_Result::SUCCESS
  1536. Zend_Auth_Result::FAILURE
  1537. Zend_Auth_Result::FAILURE_IDENTITY_NOT_FOUND
  1538. Zend_Auth_Result::FAILURE_IDENTITY_AMBIGUOUS
  1539. Zend_Auth_Result::FAILURE_CREDENTIAL_INVALID
  1540. Zend_Auth_Result::FAILURE_UNCATEGORIZED
  1541. ]]>
  1542. </programlisting>
  1543. </para>
  1544. <para>
  1545. The following example illustrates how a developer may branch on the result code:
  1546. <programlisting role="php"><![CDATA[
  1547. // inside of AuthController / loginAction
  1548. $result = $this->_auth->authenticate($adapter);
  1549. switch ($result->getCode()) {
  1550. case Zend_Auth_Result::FAILURE_IDENTITY_NOT_FOUND:
  1551. /** do stuff for nonexistent identity **/
  1552. break;
  1553. case Zend_Auth_Result::FAILURE_CREDENTIAL_INVALID:
  1554. /** do stuff for invalid credential **/
  1555. break;
  1556. case Zend_Auth_Result::SUCCESS:
  1557. /** do stuff for successful authentication **/
  1558. break;
  1559. default:
  1560. /** do stuff for other failure **/
  1561. break;
  1562. }
  1563. ]]>
  1564. </programlisting>
  1565. </para>
  1566. </sect2>
  1567. <sect2 id="zend.auth.introduction.persistence">
  1568. <title>Identity Persistence</title>
  1569. <para>
  1570. Authenticating a request that includes authentication credentials is useful per se, but it is also
  1571. important to support maintaining the authenticated identity without having to present the
  1572. authentication credentials with each request.
  1573. </para>
  1574. <para>
  1575. HTTP is a stateless protocol, however, and techniques such as cookies and sessions have been
  1576. developed in order to facilitate maintaining state across multiple requests in server-side web
  1577. applications.
  1578. </para>
  1579. <sect3 id="zend.auth.introduction.persistence.default">
  1580. <title>Default Persistence in the PHP Session</title>
  1581. <para>
  1582. By default, <code>Zend_Auth</code> provides persistent storage of the identity from a successful
  1583. authentication attempt using the PHP session. Upon a successful authentication attempt,
  1584. <code>Zend_Auth::authenticate()</code> stores the identity from the authentication result into
  1585. persistent storage. Unless configured otherwise, <code>Zend_Auth</code> uses a storage class named
  1586. <code>Zend_Auth_Storage_Session</code>, which, in turn, uses
  1587. <link linkend="zend.session">Zend_Session</link>. A custom class may instead be used by providing an
  1588. object that implements <code>Zend_Auth_Storage_Interface</code> to
  1589. <code>Zend_Auth::setStorage()</code>.
  1590. </para>
  1591. <note>
  1592. <para>
  1593. If automatic persistent storage of the identity is not appropriate for a particular use case, then
  1594. developers may forgo using the <code>Zend_Auth</code> class altogether, instead using an adapter
  1595. class directly.
  1596. </para>
  1597. </note>
  1598. <example id="zend.auth.introduction.persistence.default.example">
  1599. <title>Modifying the Session Namespace</title>
  1600. <para>
  1601. <code>Zend_Auth_Storage_Session</code> uses a session namespace of <code>'Zend_Auth'</code>. This
  1602. namespace may be overridden by passing a different value to the constructor of
  1603. <code>Zend_Auth_Storage_Session</code>, and this value is internally passed along to the constructor
  1604. of <code>Zend_Session_Namespace</code>. This should occur before authentication is attempted, since
  1605. <code>Zend_Auth::authenticate()</code> performs the automatic storage of the identity.
  1606. <programlisting role="php"><![CDATA[
  1607. // Save a reference to the Singleton instance of Zend_Auth
  1608. $auth = Zend_Auth::getInstance();
  1609. // Use 'someNamespace' instead of 'Zend_Auth'
  1610. $auth->setStorage(new Zend_Auth_Storage_Session('someNamespace'));
  1611. /**
  1612. * @todo Set up the auth adapter, $authAdapter
  1613. */
  1614. // Authenticate, saving the result, and persisting the identity on
  1615. // success
  1616. $result = $auth->authenticate($authAdapter);
  1617. ]]>
  1618. </programlisting>
  1619. </para>
  1620. </example>
  1621. </sect3>
  1622. <sect3 id="zend.auth.introduction.persistence.custom">
  1623. <title>Implementing Customized Storage</title>
  1624. <para>
  1625. Sometimes developers may need to use different identity persistence behavior than that provided by
  1626. <code>Zend_Auth_Storage_Session</code>. For such cases developers may simply implement
  1627. <code>Zend_Auth_Storage_Interface</code> and supply an instance of the class to
  1628. <code>Zend_Auth::setStorage()</code>.
  1629. </para>
  1630. <example id="zend.auth.introduction.persistence.custom.example">
  1631. <title>Using a Custom Storage Class</title>
  1632. <para>
  1633. In order to use an identity persistence storage class other than
  1634. <code>Zend_Auth_Storage_Session</code>, a developer implements
  1635. <code>Zend_Auth_Storage_Interface</code>:
  1636. <programlisting role="php"><![CDATA[
  1637. class MyStorage implements Zend_Auth_Storage_Interface
  1638. {
  1639. /**
  1640. * Returns true if and only if storage is empty
  1641. *
  1642. * @throws Zend_Auth_Storage_Exception If it is impossible to
  1643. * determine whether storage
  1644. * is empty
  1645. * @return boolean
  1646. */
  1647. public function isEmpty()
  1648. {
  1649. /**
  1650. * @todo implementation
  1651. */
  1652. }
  1653. /**
  1654. * Returns the contents of storage
  1655. *
  1656. * Behavior is undefined when storage is empty.
  1657. *
  1658. * @throws Zend_Auth_Storage_Exception If reading contents from
  1659. * storage is impossible
  1660. * @return mixed
  1661. */
  1662. public function read()
  1663. {
  1664. /**
  1665. * @todo implementation
  1666. */
  1667. }
  1668. /**
  1669. * Writes $contents to storage
  1670. *
  1671. * @param mixed $contents
  1672. * @throws Zend_Auth_Storage_Exception If writing $contents to
  1673. * storage is impossible
  1674. * @return void
  1675. */
  1676. public function write($contents)
  1677. {
  1678. /**
  1679. * @todo implementation
  1680. */
  1681. }
  1682. /**
  1683. * Clears contents from storage
  1684. *
  1685. * @throws Zend_Auth_Storage_Exception If clearing contents from
  1686. * storage is impossible
  1687. * @return void
  1688. */
  1689. public function clear()
  1690. {
  1691. /**
  1692. * @todo implementation
  1693. */
  1694. }
  1695. }
  1696. ]]>
  1697. </programlisting>
  1698. </para>
  1699. <para>
  1700. In order to use this custom storage class, <code>Zend_Auth::setStorage()</code> is invoked before an
  1701. authentication query is attempted:
  1702. <programlisting role="php"><![CDATA[
  1703. // Instruct Zend_Auth to use the custom storage class
  1704. Zend_Auth::getInstance()->setStorage(new MyStorage());
  1705. /**
  1706. * @todo Set up the auth adapter, $authAdapter
  1707. */
  1708. // Authenticate, saving the result, and persisting the identity on
  1709. // success
  1710. $result = Zend_Auth::getInstance()->authenticate($authAdapter);
  1711. ]]>
  1712. </programlisting>
  1713. </para>
  1714. </example>
  1715. </sect3>
  1716. </sect2>
  1717. <sect2 id="zend.auth.introduction.using">
  1718. <title>Using Zend_Auth</title>
  1719. <para>
  1720. There are two provided ways to use Zend_Auth adapters:
  1721. <orderedlist>
  1722. <listitem>
  1723. <para>
  1724. indirectly, through <code>Zend_Auth::authenticate()</code>
  1725. </para>
  1726. </listitem>
  1727. <listitem>
  1728. <para>
  1729. directly, through the adapter's <code>authenticate()</code> method
  1730. </para>
  1731. </listitem>
  1732. </orderedlist>
  1733. </para>
  1734. <para>
  1735. The following example illustrates how to use a Zend_Auth adapter indirectly, through the use of
  1736. the <code>Zend_Auth</code> class:
  1737. <programlisting role="php"><![CDATA[
  1738. // Get a reference to the singleton instance of Zend_Auth
  1739. $auth = Zend_Auth::getInstance();
  1740. // Set up the authentication adapter
  1741. $authAdapter = new MyAuthAdapter($username, $password);
  1742. // Attempt authentication, saving the result
  1743. $result = $auth->authenticate($authAdapter);
  1744. if (!$result->isValid()) {
  1745. // Authentication failed; print the reasons why
  1746. foreach ($result->getMessages() as $message) {
  1747. echo "$message\n";
  1748. }
  1749. } else {
  1750. // Authentication succeeded; the identity ($username) is stored
  1751. // in the session
  1752. // $result->getIdentity() === $auth->getIdentity()
  1753. // $result->getIdentity() === $username
  1754. }
  1755. ]]>
  1756. </programlisting>
  1757. </para>
  1758. <para>
  1759. Once authentication has been attempted in a request, as in the above example, it is a simple
  1760. matter to check whether a successfully authenticated identity exists:
  1761. <programlisting role="php"><![CDATA[
  1762. $auth = Zend_Auth::getInstance();
  1763. if ($auth->hasIdentity()) {
  1764. // Identity exists; get it
  1765. $identity = $auth->getIdentity();
  1766. }
  1767. ]]>
  1768. </programlisting>
  1769. </para>
  1770. <para>
  1771. To remove an identity from persistent storage, simply use the <code>clearIdentity()</code> method.
  1772. This typically would be used for implementing an application "logout" operation:
  1773. <programlisting role="php"><![CDATA[
  1774. Zend_Auth::getInstance()->clearIdentity();
  1775. ]]>
  1776. </programlisting>
  1777. </para>
  1778. <para>
  1779. When the automatic use of persistent storage is inappropriate for a particular use case, a
  1780. developer may simply bypass the use of the <code>Zend_Auth</code> class, using an adapter class
  1781. directly. Direct use of an adapter class involves configuring and preparing an adapter object and
  1782. then calling its <code>authenticate()</code> method. Adapter-specific details are discussed in the
  1783. documentation for each adapter. The following example directly utilizes
  1784. <code>MyAuthAdapter</code>:
  1785. <programlisting role="php"><![CDATA[
  1786. // Set up the authentication adapter
  1787. $authAdapter = new MyAuthAdapter($username, $password);
  1788. // Attempt authentication, saving the result
  1789. $result = $authAdapter->authenticate();
  1790. if (!$result->isValid()) {
  1791. // Authentication failed; print the reasons why
  1792. foreach ($result->getMessages() as $message) {
  1793. echo "$message\n";
  1794. }
  1795. } else {
  1796. // Authentication succeeded
  1797. // $result->getIdentity() === $username
  1798. }
  1799. ]]>
  1800. </programlisting>
  1801. </para>
  1802. </sect2>
  1803. </sect1><!--
  1804. vim:se ts=4 sw=4 et:
  1805. -->
  1806. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Auth_Adapter_DbTable.xml"/>
  1807. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Auth_Adapter_Digest.xml"/>
  1808. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Auth_Adapter_Http.xml"/>
  1809. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Auth_Adapter_Ldap.xml"/>
  1810. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Auth_Adapter_OpenId.xml"/>
  1811. </chapter>
  1812. <chapter id="zend.cache">
  1813. <title>Zend_Cache</title>
  1814. <sect1 id="zend.cache.introduction" xml:base="module_specs/Zend_Cache-Introduction.xml">
  1815. <title>Introducción</title>
  1816. <para>
  1817. <code>Zend_Cache</code>
  1818. provee una forma genérica para cualquier caché de datos.
  1819. </para>
  1820. <para>
  1821. El almacenamiento en caché en Zend Framework se opera por
  1822. interfaces, mientras que los registros de caché son almacenados
  1823. a través de adapatadores del backend (
  1824. <code>Archivo</code>
  1825. ,
  1826. <code>Sqlite</code>
  1827. ,
  1828. <code>Memcache</code>
  1829. ...) mediante un sistema flexible de documentos de identidad y
  1830. etiquetas. Utilizando éstas, es fácil en el futuro eliminar
  1831. determinados tipos de registro.(Ejemplo: "eliminar todos los
  1832. registros caché de determinada etiqueta").
  1833. </para>
  1834. <para>
  1835. El módulo principal (
  1836. <code>Zend_Cache_Core</code>
  1837. ) es genérico, flexible y configurable. Aun para sus necesidades
  1838. específicas existen frontends de caché que extienden
  1839. <code>Zend_Cache_Core</code>
  1840. a conveniencia:
  1841. <code>Output</code>
  1842. ,
  1843. <code>File</code>
  1844. ,
  1845. <code>Function</code>
  1846. y
  1847. <code>Class</code>
  1848. .
  1849. </para>
  1850. <example id="zend.cache.introduction.example-1">
  1851. <title>
  1852. Obtener un frontend con
  1853. <code>Zend_Cache::factory()</code>
  1854. </title>
  1855. <para>
  1856. <code>Zend_Cache::factory()</code>
  1857. ejemplifica objetos correctos y los une. En este primer
  1858. ejemplo, usaremos el frontend
  1859. <code>Core</code>
  1860. junto con el backend
  1861. <code>File</code>
  1862. .
  1863. </para>
  1864. <programlisting role="php"><![CDATA[
  1865. $frontendOptions = array(
  1866. 'lifetime' => 7200, // tiempo de vida de caché de 2 horas
  1867. 'automatic_serialization' => true
  1868. );
  1869. $backendOptions = array(
  1870. 'cache_dir' => './tmp/' // Carpeta donde alojar los archivos de caché
  1871. );
  1872. // getting a Zend_Cache_Core object
  1873. $cache = Zend_Cache::factory('Core',
  1874. 'File',
  1875. $frontendOptions,
  1876. $backendOptions);
  1877. ]]>
  1878. </programlisting>
  1879. </example>
  1880. <note>
  1881. <title>
  1882. Frontends y Backends Compuestos de Múltiples Palabras
  1883. </title>
  1884. <para>
  1885. Algunos frontends y backends se nombran usando varias
  1886. palabras, tal como 'ZenPlatform'. Al fabricarlas las
  1887. especificamos, las separamos usando un separador de
  1888. palabras, como un espacio (' '), guión ('-'), o punto ('.').
  1889. </para>
  1890. </note>
  1891. <example id="zend.cache.introduction.example-2">
  1892. <title>Almacenando en caché un resultado de consulta a una base de datos</title>
  1893. <para>
  1894. Ahora que tenemos un frontend, podemos almacenar en caché
  1895. cualquier tipo de dato (hemos activado la serialización). Por
  1896. ejemplo, podemos almacenar en caché un resultado de una
  1897. consulta de base de datos muy costosa. Después de ser
  1898. almacenada en caché, no es necesario ni conectar la base
  1899. de datos; los registros se obtienen del caché de forma no
  1900. serializada.
  1901. </para>
  1902. <programlisting role="php"><![CDATA[
  1903. // $cache initializada en el ejemplo anterior
  1904. // Verificar si la cahce existe:
  1905. if(!$result = $cache->load('myresult')) {
  1906. // no existe cache; conectar a la base de datos
  1907. $db = Zend_Db::factory( [...] );
  1908. $result = $db->fetchAll('SELECT * FROM huge_table');
  1909. $cache->save($result, 'myresult');
  1910. } else {
  1911. // cache existosa!, darlo a conocer
  1912. echo "Éste es de caché!\n\n";
  1913. }
  1914. print_r($result);
  1915. ]]>
  1916. </programlisting>
  1917. </example>
  1918. <example id="zend.cache.introduction.example-3">
  1919. <title>
  1920. El almacenamiento en caché de salida con la interfaz de
  1921. salida
  1922. <code>Zend_Cache</code>
  1923. </title>
  1924. <para>
  1925. ‘Resaltamos’ las secciones en las que deseamos almacenar en
  1926. caché la salida, mediante la adición de algunas condiciones lógicas,
  1927. encapsulamos la sección dentro de los métodos
  1928. <code>start()</code>
  1929. y
  1930. <code>end()</code>
  1931. (esto se parece al primer ejemplo y es la estrategia
  1932. fundamental para el almacenamiento en caché).
  1933. </para>
  1934. <para>
  1935. Dentro, los datos de salida, como siempre – todas las salidas
  1936. serán almacenadas en caché cuando se ordene la ejecución del
  1937. método
  1938. <code>end()</code>
  1939. . En la siguiente ejecución, toda la sección se saltará a
  1940. favor de la búsqueda de datos del caché (tanto tiempo como
  1941. el registro del caché sea válido).
  1942. </para>
  1943. <programlisting role="php"><![CDATA[
  1944. $frontendOptions = array(
  1945. 'lifetime' => 30, // tiempo de vida de caché de 30 segundos
  1946. 'automatic_serialization' => false // éste es el valor por defecto
  1947. );
  1948. $backendOptions = array('cache_dir' => './tmp/');
  1949. $cache = Zend_Cache::factory('Output',
  1950. 'File',
  1951. $frontendOptions,
  1952. $backendOptions);
  1953. // Pasamos un identificador único al método start()
  1954. if(!$cache->start('mypage')) {
  1955. // salida como de costumbre:
  1956. echo 'Hola mundo! ';
  1957. echo 'Esto está en caché ('.time().') ';
  1958. $cache->end(); // la salida es guardada y enviada al navegador
  1959. }
  1960. echo 'Esto no estará en caché nunca ('.time().').';
  1961. ]]>
  1962. </programlisting>
  1963. <para>
  1964. Note que delineamos el resultado de
  1965. <code>time()</code>
  1966. dos veces; esto es algo dinámico para los propósitos de la
  1967. demostración. Trate de ejecutarlo y entonces regenérelo
  1968. muchas veces; notará que el primer número no cambia mientras
  1969. que el segundo cambia a medida que pasa el tiempo. Esto
  1970. es porque el primer número esta delineado en la sección
  1971. caché y esta guardado en medio de otras salidas. Después de
  1972. medio minuto (habremos establecido el tiempo de vida de 30
  1973. segundos) los números deben acoplarse nuevamente porque el
  1974. registro caché ha expirado -- sólo para ser almacenado en
  1975. caché nuevamente. Deberá probarlo en su visualizador o
  1976. consola.
  1977. </para>
  1978. </example>
  1979. <note>
  1980. <para>
  1981. Cuando usamos Zend_Cache, ponemos atención a la importación
  1982. del identificador caché (pasado a
  1983. <code>save()</code>
  1984. y
  1985. <code>start()</code>
  1986. ). Éste deberá ser único para cada recurso que se almacene
  1987. en caché, de otra manera los registros almacenados en caché
  1988. que no se vinculan podrían borrarse unos a otros, o peor
  1989. aún, mostrarse uno en lugar del otro.
  1990. </para>
  1991. </note>
  1992. </sect1><!--
  1993. vim:se ts=4 sw=4 et:
  1994. -->
  1995. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Cache-Theory.xml"/>
  1996. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Cache-Frontends.xml"/>
  1997. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Cache-Backends.xml"/>
  1998. </chapter>
  1999. <chapter id="zend.captcha">
  2000. <title>Zend_Captcha</title>
  2001. <sect1 id="zend.captcha.introduction" xml:base="module_specs/Zend_Captcha.xml">
  2002. <title>Introducción</title>
  2003. <para>
  2004. <ulink url="http://en.wikipedia.org/wiki/Captcha">
  2005. CAPTCHA
  2006. </ulink>
  2007. es el acrónimo de "Completely Automated Public Turing test to
  2008. tell Computers and Humans Apart" (Prueba de Turing pública y
  2009. automática para diferenciar a máquinas y humanos). Es usado como un
  2010. desafío-respuesta para asegurar que la información individual suministrada
  2011. viene de un humano y no de un proceso automatizado. Típicamente,
  2012. un captcha es usado con envío de formularios donde no es necesario que el
  2013. usuario se haya autenticado, pero se desea prevenir el envío de spam.
  2014. </para>
  2015. <para>
  2016. Los Captchas pueden presentarse en multitud de formas, incluyendo
  2017. preguntas lógicas, caracteres trastocados o presentar imágenes y preguntar
  2018. cómo se relacionan. Zend_Captcha intenta proveer una amalgama de backends
  2019. que pueden ser utilizados por separado o en conjunción con
  2020. <code>Zend_Form</code>
  2021. .
  2022. </para>
  2023. </sect1><!--
  2024. vim:se ts=4 sw=4 et:
  2025. -->
  2026. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Captcha-Operation.xml"/>
  2027. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Captcha-Adapters.xml"/>
  2028. </chapter>
  2029. <chapter id="zend.config">
  2030. <title>Zend_Config</title>
  2031. <sect1 id="zend.config.introduction" xml:base="module_specs/Zend_Config-Introduction.xml">
  2032. <title>Introducción</title>
  2033. <para>
  2034. <code class="code">Zend_Config</code>
  2035. está diseñado para simplificar el acceso y el uso de datos de
  2036. configuración dentro de aplicaciones. Provee una interfaz de
  2037. usuario basada en propiedades de objetos anidadas para acceder a
  2038. datos de configuración dentro del código de la aplicación. Los
  2039. datos de configuración pueden venir de multitud de medios que
  2040. soporten almacenamiento de datos de forma jerárquica.
  2041. Actualmente
  2042. <code class="code">Zend_Config</code>
  2043. provee adaptadores para datos de configuración que están
  2044. almacenados en archivos de texto con
  2045. <link linkend="zend.config.adapters.ini">
  2046. <code>Zend_Config_Ini</code>
  2047. </link>
  2048. y
  2049. <link linkend="zend.config.adapters.xml">
  2050. <code>Zend_Config_Xml</code>
  2051. </link>
  2052. .
  2053. </para>
  2054. <example id="zend.config.introduction.example.using">
  2055. <title>Usando Zend_Config Per Se</title>
  2056. <para>
  2057. Normalmente, se espera que los usuarios usen
  2058. una de las clases adaptadoras como
  2059. <link linkend="zend.config.adapters.ini">
  2060. <code>Zend_Config_Ini</code>
  2061. </link>
  2062. o
  2063. <link linkend="zend.config.adapters.xml">
  2064. <code>Zend_Config_Xml</code>
  2065. </link>
  2066. , pero si los datos de configuración están disponibles
  2067. en un array PHP, se puede simplemente pasar los datos al
  2068. constructor
  2069. <code>Zend_Config</code>
  2070. para utilizar una interfaz simple orientada a objetos:
  2071. </para>
  2072. <programlisting role="php"><![CDATA[
  2073. // Dado un array de datos de configuración
  2074. $configArray = array(
  2075. 'webhost' => 'www.example.com',
  2076. 'database' => array(
  2077. 'adapter' => 'pdo_mysql',
  2078. 'params' => array(
  2079. 'host' => 'db.example.com',
  2080. 'username' => 'dbuser',
  2081. 'password' => 'secret',
  2082. 'dbname' => 'mydatabase'
  2083. )
  2084. )
  2085. );
  2086. // Crea el objeto a partir de los datos de configuración
  2087. $config = new Zend_Config($configArray);
  2088. // Muestra un dato de configuración (resultado: 'www.example.com')
  2089. echo $config->webhost;
  2090. // Use los datos de configuración para conectarse a la base de datos
  2091. $db = Zend_Db::factory($config->database->adapter,
  2092. $config->database->params->toArray());
  2093. // Uso alternativo: simplemente pase el objeto Zend_Config.
  2094. // La Zend_Db factory sabe cómo interpretarlo.
  2095. $db = Zend_Db::factory($config->database);
  2096. ]]>
  2097. </programlisting>
  2098. </example>
  2099. <para>
  2100. Como se ilustra en el ejemplo de arriba,
  2101. <code>Zend_Config</code>
  2102. provee una sintáxis de propiedades de objetos anidados para acceder a datos de configuración
  2103. pasados a su constructor.
  2104. </para>
  2105. <para>
  2106. Junto al acceso a valores de datos orientado a objetos,
  2107. <code>Zend_Config</code>
  2108. también tiene el método
  2109. <code>get()</code>
  2110. que devolverá el valor por defecto suministrado si el elemento
  2111. de datos no existe. Por ejemplo:
  2112. </para>
  2113. <programlisting role="php"><![CDATA[
  2114. $host = $config->database->get('host', 'localhost');
  2115. ]]>
  2116. </programlisting>
  2117. <example id="zend.config.introduction.example.file.php">
  2118. <title>Usando Zend_Config con un Archivo de Configuración PHP</title>
  2119. <para>
  2120. A veces, es deseable usar un archivo de configuración
  2121. puramente PHP. El código siguiente ilustra cómo podemos conseguir
  2122. esto fácilmente:
  2123. </para>
  2124. <programlisting role="php"><![CDATA[
  2125. // config.php
  2126. return array(
  2127. 'webhost' => 'www.example.com',
  2128. 'database' => array(
  2129. 'adapter' => 'pdo_mysql',
  2130. 'params' => array(
  2131. 'host' => 'db.example.com',
  2132. 'username' => 'dbuser',
  2133. 'password' => 'secret',
  2134. 'dbname' => 'mydatabase'
  2135. )
  2136. )
  2137. );
  2138. ]]>
  2139. </programlisting>
  2140. <programlisting role="php"><![CDATA[
  2141. // Lectura de la configuración
  2142. $config = new Zend_Config(require 'config.php');
  2143. // Muestra un dato de configuración (resultado: 'www.example.com')
  2144. echo $config->webhost;
  2145. ]]>
  2146. </programlisting>
  2147. </example>
  2148. </sect1><!--
  2149. vim:se ts=4 sw=4 et:
  2150. -->
  2151. <sect1 id="zend.config.theory_of_operation" xml:base="module_specs/Zend_Config-TheoryOfOperation.xml">
  2152. <title>Aspectos Teóricos</title>
  2153. <para>
  2154. Los datos de configuración se hacen accesibles al constructor <code>Zend_Config</code>
  2155. a través de un array asociativo, que puede ser multidimensional, para permitir
  2156. organizar los datos desde lo general a lo específico. Las clases de adaptador concretas
  2157. permiten construir una tabla asociativa para el constructor de <code>Zend_Config</code>
  2158. a partir de un sistema de almacenamiento de datos de configuración. Algunos scripts
  2159. de usuario pueden proveer esos arrays directamente al constructor Zend_Config,
  2160. sin usar una clase adaptador, lo cual puede ser apropiado en ciertas ocasiones.
  2161. </para>
  2162. <para>
  2163. Cada valor del array de datos de configuración se convierte en una propiedad del objeto <code>Zend_Config</code>.
  2164. La clave es usada como el nombre de la propiedad. Si un valor es un array por sí solo, entonces la propiedad
  2165. de objeto resultante es creada como un nuevo objeto
  2166. <code>Zend_Config</code>, cargado con los datos del array. Esto ocurre recursivamente, de forma
  2167. que una jerarquía de datos de configuración puede ser creada con cualquier número de niveles.
  2168. </para>
  2169. <para>
  2170. <code>Zend_Config</code> implementa las interfaces <code>Countable</code> e <code>Iterator</code>
  2171. para facilitar el aceso sencillo a los datos de configuración.
  2172. Así, uno puede usar la función <ulink url="http://php.net/count"><code>count()</code></ulink>
  2173. y constructores PHP como
  2174. <ulink url="http://php.net/foreach"><code>foreach</code></ulink> sobre objetos
  2175. <code>Zend_Config</code>.
  2176. </para>
  2177. <para>
  2178. Por defecto, los datos de configuración permitidos a través de <code>Zend_Config</code>
  2179. son de sólo lectura, y una asignación (e.g.,
  2180. <code>$config-&gt;database-&gt;host = 'example.com'</code>)
  2181. provoca que se lance una excepción. Este comportamiento por defecto puede ser sobrescrito a través
  2182. del constructor, sin embargo, para permitir la modificación de valores de datos. Además, cuando
  2183. las modificaciones están permitidas, <code>Zend_Config</code> soporta el borrado de elementos (unset) (i.e. <code>unset($config-&gt;database-&gt;host);</code>). El método
  2184. <code>readOnly()</code> puede ser usado para determinar si las modificaciones a un objeto <code>Zend_Config</code>
  2185. están permitidas y el método <code>setReadOnly()</code> puede ser usado para evitar cualquier modificación
  2186. posterior a un objeto <code>Zend_Config</code> que fue creado con permiso de modificaciones.
  2187. <note>
  2188. <para>
  2189. Es importante no confundir tales modificaciones en memoria con guardar los datos de configuración a un
  2190. medio de almacenamiento específico. Las herramientas para crear y modificar datos de configuración para
  2191. distintos medios de almacenamiento están fuera del alcance de <code>Zend_Config</code>.
  2192. Existen soluciones third-party de código abierto con el propósito de crear y modificar
  2193. datos de configuración de distintos medios de almacenamiento.
  2194. </para>
  2195. </note>
  2196. </para>
  2197. <para>
  2198. Las clases del adaptador heredan de la clase <code>Zend_Config</code> debido a que utilizan su funcionalidad.
  2199. </para>
  2200. <para>
  2201. La familia de clases <code>Zend_Config</code> permite organizar en secciones
  2202. los datos de configuración. Los objetos de adaptador <code>Zend_Config</code>
  2203. pueden ser cargados con una sola sección especificada, múltiples secciones especificadas,
  2204. o todas las secciones (si no se especifica ninguna).
  2205. </para>
  2206. <para>
  2207. Las clases del adaptador <code>Zend_Config</code> soportan un modelo de herencia única
  2208. que permite que los datos de configuración hereden de una sección de datos de configuración a otra.
  2209. Esto es provisto con el fin de reducir o eliminar la necesidad de duplicar datos de configuración por
  2210. distintos motivos. Una sección heredada puede también sobrescribir los valores que hereda de su sección
  2211. padre. Al igual que la herencia de clases PHP, una sección puede heredar de una sección padre,
  2212. la cual puede heredar de una sección abuela, etc..., pero la herencia múltiple
  2213. (i.e., la sección C heredando directamente de las secciones padre A y B) no está permitida.
  2214. </para>
  2215. <para>
  2216. Si tiene dos objetos <code>Zend_Config</code>, puede combinarlos en un único
  2217. objeto usando la función <code>merge()</code>. Por ejemplo, dados <code>$config</code> y
  2218. <code>$localConfig</code>, puede fusionar datos de <code>$localConfig</code> a <code>$config</code> usando
  2219. <code>$config-&gt;merge($localConfig);</code>. Los ítemes en <code>$localConfig</code> sobrescribirán
  2220. cualquier item con el mismo nombre en <code>$config</code>.
  2221. <note>
  2222. <para>
  2223. El objeto <code>Zend_Config</code> que está ejecutando el merge debe haber sido construido
  2224. para permitir modificaciones, pasando <code>true</code> como el segundo parámetro del constructor.
  2225. El método <code>setReadOnly()</code> puede entonces ser usado para evitar cualquier
  2226. modificación posterior después de que el merge se haya completado.
  2227. </para>
  2228. </note>
  2229. </para>
  2230. </sect1><!--
  2231. vim:se ts=4 sw=4 et:
  2232. -->
  2233. <sect1 id="zend.config.adapters.ini" xml:base="module_specs/Zend_Config_Ini.xml">
  2234. <title>Zend_Config_Ini</title>
  2235. <para>
  2236. <code>Zend_Config_Ini</code>
  2237. permite a los desarrolladores almacenar datos de configuración
  2238. en un formato de datos INI familiar, y leer de ellos en la
  2239. aplicación usando una sintáxis de propiedades de objetos
  2240. anidados. El formato INI se especializa en proveer tanto la
  2241. habilidad de mantener una jerarquía de claves de datos (data
  2242. keys) de configuración como la de mantener una jerarquía entre
  2243. secciones de datos de configuración. Las jerarquías de datos de
  2244. configuración son provistas separando las claves mediante el
  2245. carácter punto (
  2246. <code>.</code>
  2247. ). Una sección puede extender o heredar de otra sección
  2248. indicando el nombre de la sección seguido de dos puntos (
  2249. <code>:</code>
  2250. ) y el nombre de la sección desde la cual se quieren heredar los
  2251. datos.
  2252. </para>
  2253. <note>
  2254. <title>parse_ini_file</title>
  2255. <para>
  2256. <code>Zend_Config_Ini</code>
  2257. utiliza la función
  2258. <ulink url="http://php.net/parse_ini_file">
  2259. <code>parse_ini_file()</code>
  2260. </ulink>
  2261. de PHP. Por favor, revise esta documentación para observar
  2262. sus comportamientos específicos, que se propagan a
  2263. <code>Zend_Config_Ini</code>
  2264. , tales como la forma en que los valores especiales:
  2265. <code>true</code>
  2266. ,
  2267. <code>false</code>
  2268. ,
  2269. <code>yes</code>
  2270. ,
  2271. <code>no</code>
  2272. , y
  2273. <code>null</code>
  2274. son manejados.
  2275. </para>
  2276. </note>
  2277. <note>
  2278. <title>Separador de clave</title>
  2279. <para>
  2280. Por defecto, el carácter separador de clave es el punto (
  2281. <code>.</code>
  2282. ). Puede ser reemplazado, no obstante,cambiando la clave de
  2283. <code>$options</code>
  2284. llamada
  2285. <code>'nestSeparator'</code>
  2286. al construir el objeto
  2287. <code>Zend_Config_Ini</code>
  2288. . Por ejemplo:
  2289. <programlisting role="php"><![CDATA[
  2290. $options['nestSeparator'] = ':';
  2291. $config = new Zend_Config_Ini('/path/to/config.ini',
  2292. 'pruebas',
  2293. $options);
  2294. ]]>
  2295. </programlisting>
  2296. </para>
  2297. </note>
  2298. <example id="zend.config.adapters.ini.example.using">
  2299. <title>Utilizando Zend_Config_Ini</title>
  2300. <para>
  2301. Este ejemplo muestra una forma de uso básica de
  2302. <code>Zend_Config_Ini</code>
  2303. para cargar datos de configuración de un archivo INI. En
  2304. este ejemplo hay datos de configuración tanto para un
  2305. sistema de producción como para un sistema en fase de
  2306. pruebas. Debido a que los datos de la fase de pruebas son
  2307. muy parecidos a los de producción, la sección de pruebas
  2308. hereda de la sección de producción. En este caso, la
  2309. decisión es arbitraria y podría haberse escrito a la
  2310. inversa, con la sección de producción heredando de la
  2311. sección de pruebas, a pesar de que éste no sería el caso
  2312. para situaciones más complejas. Supongamos, entonces, que
  2313. los siguientes datos de configuración están contenidos en
  2314. <code>/path/to/config.ini</code>
  2315. :
  2316. </para>
  2317. <programlisting role="ini"><![CDATA[
  2318. ; Datos de configuración de la web de producción
  2319. [produccion]
  2320. webhost = www.example.com
  2321. database.adapter = pdo_mysql
  2322. database.params.host = db.example.com
  2323. database.params.username = dbuser
  2324. database.params.password = secret
  2325. database.params.dbname = dbname
  2326. ; Los datos de configuración de la fase de pruebas heredan de la producción
  2327. ; y sobreescribren valores si es necesario
  2328. [pruebas : produccion]
  2329. database.params.host = dev.example.com
  2330. database.params.username = devuser
  2331. database.params.password = devsecret
  2332. ]]>
  2333. </programlisting>
  2334. <para>
  2335. Ahora, asuma que el desarrollador de aplicaciones necesita
  2336. los datos de configuración de la etapa de pruebas del
  2337. archivo INI. Resulta fácil cargar estos datos especificando
  2338. el archivo INI en la sección de la etapa de pruebas:
  2339. </para>
  2340. <programlisting role="php"><![CDATA[
  2341. $config = new Zend_Config_Ini('/path/to/config.ini', 'pruebas');
  2342. echo $config->database->params->host; // muestra "dev.example.com"
  2343. echo $config->database->params->dbname; // muestra "dbname"
  2344. ]]>
  2345. </programlisting>
  2346. </example>
  2347. <note>
  2348. <table id="zend.config.adapters.ini.table">
  2349. <title>Parámetros del constructor Zend_Config_Ini</title>
  2350. <tgroup cols="2">
  2351. <thead>
  2352. <row>
  2353. <entry>Parámetros</entry>
  2354. <entry>Notas</entry>
  2355. </row>
  2356. </thead>
  2357. <tbody>
  2358. <row>
  2359. <entry>
  2360. <code>$filename</code>
  2361. </entry>
  2362. <entry>
  2363. El archivo INI que se va a cargar.
  2364. </entry>
  2365. </row>
  2366. <row>
  2367. <entry>
  2368. <code>$section</code>
  2369. </entry>
  2370. <entry>
  2371. La [sección] contenida en el archivo ini que
  2372. se va a cargar. Fijar este parámetro a null
  2373. cargará todas las secciones.
  2374. Alternativamente, se puede introducir un
  2375. array de nombres de sección para cargar
  2376. multiples secciones.
  2377. </entry>
  2378. </row>
  2379. <row>
  2380. <entry>
  2381. <code>$options = false</code>
  2382. </entry>
  2383. <entry>
  2384. Array de opciones. Las siguientes claves
  2385. están aceptadas:
  2386. <itemizedlist>
  2387. <listitem>
  2388. <para>
  2389. <emphasis>
  2390. allowModifications
  2391. </emphasis>
  2392. : Fijar a
  2393. <emphasis>true</emphasis>
  2394. para permitir modificaciones
  2395. subsiguientes del archivo
  2396. cargado. Por defecto es
  2397. <emphasis>false</emphasis>
  2398. </para>
  2399. </listitem>
  2400. <listitem>
  2401. <para>
  2402. <emphasis>
  2403. nestSeparator
  2404. </emphasis>
  2405. : Carácter que utilizar como
  2406. separador de anidamiento. Por
  2407. defecto es "."
  2408. </para>
  2409. </listitem>
  2410. </itemizedlist>
  2411. </entry>
  2412. </row>
  2413. </tbody>
  2414. </tgroup>
  2415. </table>
  2416. </note>
  2417. </sect1><!--
  2418. vim:se ts=4 sw=4 et:
  2419. -->
  2420. <sect1 id="zend.config.adapters.xml" xml:base="module_specs/Zend_Config_Xml.xml">
  2421. <title>Zend_Config_Xml</title>
  2422. <para>
  2423. <code>Zend_Config_Xml</code> permite a los desarrolladores almacenar
  2424. datos de configuración en un formato sencillo XML y leerlos a través de
  2425. una sintáxis de propiedades de objetos anidados. El elemento raíz del
  2426. archivo XML es irrelevante y puede ser nombrado arbitrariamente.
  2427. El primer nivel de elementos XML corresponde con las secciones de datos
  2428. de configuración. El formato XML admite organización jerárquica a
  2429. través del anidamiento de elementos XML bajo los elementos a nivel de
  2430. sección. El contenido de un elemento XML a nivel de hoja corresponde al
  2431. valor de un dato de configuración. La herencia de sección está permitida
  2432. por un atributo XML especial llamado <code>extends</code>, y el valor de
  2433. este atributo se corresponde con la sección de la cual los datos son
  2434. heredados por la sección extendida..
  2435. </para>
  2436. <note>
  2437. <title>Tipo devuelto</title>
  2438. <para>
  2439. Los datos de configuración que se leen en <code>Zend_Config_Xml</code>
  2440. son siempre devueltos como strings.
  2441. La conversión de datos de string a otros tipos se deja en manos de los
  2442. desarrolladores para que se ajuste a sus necesidades particulares.
  2443. </para>
  2444. </note>
  2445. <example id="zend.config.adapters.xml.example.using">
  2446. <title>Usando Zend_Config_Xml</title>
  2447. <para>
  2448. Este ejemplo ilustra un uso básico de <code>Zend_Config_Xml</code>
  2449. para cargar datos de configuración de un archivo XML. En este ejemplo
  2450. hay datos de configuración tanto para un sistema de producción como
  2451. para un sistema de pruebas. Debido a que los datos de configuración del
  2452. sistema de pruebas son muy similares a los de producción, la sección de
  2453. pruebas hereda de la sección de producción. En este caso, la decisión
  2454. es arbitraria y podría haberse escrito a la inversa, con la sección de
  2455. producción heredando de la sección de pruebas, a pesar de que éste no
  2456. sería el caso para situaciones más complejas. Suponga, pues, que los
  2457. datos de configuración siguientes están contenidos
  2458. en <code>/ruta/de/config.xml</code>:
  2459. </para>
  2460. <programlisting role="xml"><![CDATA[
  2461. <?xml version="1.0"?>
  2462. <configdata>
  2463. <production>
  2464. <webhost>www.example.com</webhost>
  2465. <database>
  2466. <adapter>pdo_mysql</adapter>
  2467. <params>
  2468. <host>db.example.com</host>
  2469. <username>dbuser</username>
  2470. <password>secret</password>
  2471. <dbname>dbname</dbname>
  2472. </params>
  2473. </database>
  2474. </production>
  2475. <staging extends="production">
  2476. <database>
  2477. <params>
  2478. <host>dev.example.com</host>
  2479. <username>devuser</username>
  2480. <password>devsecret</password>
  2481. </params>
  2482. </database>
  2483. </staging>
  2484. </configdata>
  2485. ]]>
  2486. </programlisting>
  2487. <para>
  2488. Ahora, asuma que el desarrollador de aplicaciones necesita los datos
  2489. de configuración de la fase de pruebas del archivo XML. Es una tarea
  2490. sencilla cargar estos datos, especificando el archivo XML y la
  2491. sección de pruebas:
  2492. </para>
  2493. <programlisting role="php"><![CDATA[
  2494. $config = new Zend_Config_Xml('/ruta/de/config.xml', 'pruebas');
  2495. echo $config->database->params->host; // muestra "dev.example.com"
  2496. echo $config->database->params->dbname; // muestra "dbname"
  2497. ]]>
  2498. </programlisting>
  2499. </example>
  2500. <example id="zend.config.adapters.xml.example.attributes">
  2501. <title>Usando atributos de etiqueta en Zend_Config_Xml</title>
  2502. <para>
  2503. Zend_Config_Xml también soporta dos formas adicionales de definir
  2504. nodos en la configuración. Ambas hacen uso de atributos. Dado que
  2505. los atributos <code>extends</code> y <code>value</code> son palabras
  2506. reservadas (la última por la segunda manera de usar atributos),
  2507. pueden no ser utilizadas.
  2508. La primera manera de utilizar atributos es añadir atributos en un
  2509. nodo padre, el cual será interpretado como hijo de ese nodo:
  2510. </para>
  2511. <programlisting role="xml"><![CDATA[
  2512. <?xml version="1.0"?>
  2513. <configdata>
  2514. <production webhost="www.example.com">
  2515. <database adapter="pdo_mysql">
  2516. <params host="db.example.com" username="dbuser" password="secret" dbname="dbname"/>
  2517. </database>
  2518. </production>
  2519. <staging extends="production">
  2520. <database>
  2521. <params host="dev.example.com" username="devuser" password="devsecret"/>
  2522. </database>
  2523. </staging>
  2524. </configdata>
  2525. ]]>
  2526. </programlisting>
  2527. <para>
  2528. La otra forma no reduce la configuración, sino que permite mantenerla de
  2529. forma más fácil dado que no es necesario escribir el nombre de la
  2530. etiqueta dos veces. Simplemente, cree una etiqueta vacía con el valor en
  2531. el atributo <code>value</code>:
  2532. </para>
  2533. <programlisting role="xml"><![CDATA[
  2534. <?xml version="1.0"?>
  2535. <configdata>
  2536. <production>
  2537. <webhost>www.example.com</webhost>
  2538. <database>
  2539. <adapter value="pdo_mysql"/>
  2540. <params>
  2541. <host value="db.example.com"/>
  2542. <username value="dbuser"/>
  2543. <password value="secret"/>
  2544. <dbname value="dbname"/>
  2545. </params>
  2546. </database>
  2547. </production>
  2548. <staging extends="production">
  2549. <database>
  2550. <params>
  2551. <host value="dev.example.com"/>
  2552. <username value="devuser"/>
  2553. <password value="devsecret"/>
  2554. </params>
  2555. </database>
  2556. </staging>
  2557. </configdata>
  2558. ]]>
  2559. </programlisting>
  2560. </example>
  2561. </sect1><!--
  2562. vim:se ts=4 sw=4 et:
  2563. -->
  2564. </chapter>
  2565. <chapter id="zend.config.writer">
  2566. <title>Zend_Config_Writer</title>
  2567. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Config_Writer.xml"/>
  2568. </chapter>
  2569. <chapter id="zend.console.getopt">
  2570. <title>Zend_Console_Getopt</title>
  2571. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Console_Getopt-Introduction.xml"/>
  2572. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Console_Getopt-Rules.xml"/>
  2573. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Console_Getopt-Fetching.xml"/>
  2574. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Console_Getopt-Configuration.xml"/>
  2575. </chapter>
  2576. <chapter id="zend.controller">
  2577. <title>Zend_Controller</title>
  2578. <sect1 id="zend.controller.quickstart" xml:base="module_specs/Zend_Controller-QuickStart.xml">
  2579. <title>Zend_Controller Quick Start</title>
  2580. <sect2 id="zend.controller.quickstart.introduction">
  2581. <title>Introducción</title>
  2582. <para>
  2583. <code>Zend_Controller</code>
  2584. es el corazón del sistema de MVC de Zend Framework MVC. MVC
  2585. son las siglas de
  2586. <ulink url="http://en.wikipedia.org/wiki/Model-view-controller">
  2587. Modelo-Vista-Controlador
  2588. </ulink>
  2589. y es un patrón de diseño con el objetivo de separar la
  2590. lógica de la aplicación de la lógica de visualización.
  2591. <code>Zend_Controller_Front</code>
  2592. implementa el patrón
  2593. <ulink url="http://www.martinfowler.com/eaaCatalog/frontController.html">
  2594. Front Controller (Controlador Frontal)
  2595. </ulink>
  2596. en el cual todas las transacciones HTTP (requests) son
  2597. interceptadas por el controlador frontal y despachado a una
  2598. Acción particular de un Controlador según la URL pedida.
  2599. </para>
  2600. <para>
  2601. El sistema
  2602. <code>Zend_Controller</code>
  2603. fue construido con la extensibilidad en mente, ya sea
  2604. heredando las clases existentes, escribiendo nuevas clases
  2605. que implementan varias interfaces o clases abstractas que
  2606. forman la base de la familia de clases del controlador, o
  2607. escribiendo plugins o helpers de las acciones para aumentar
  2608. o manipular la funcionalidad del sistema.
  2609. </para>
  2610. </sect2>
  2611. <sect2 id="zend.controller.quickstart.go">
  2612. <title>Quick Start</title>
  2613. <para>
  2614. Si necesita información más detallada, mire las secciones
  2615. siguientes. Si solamente quiere inicializar y ejecutar una
  2616. aplicación rápidamente, siga leyendo.
  2617. </para>
  2618. <sect3 id="zend.controller.quickstart.go.directory">
  2619. <title>Cree su estructura de archivos</title>
  2620. <para>
  2621. El primer paso es crear su estructura de archivos. La
  2622. estructura típica es la siguiente:
  2623. </para>
  2624. <programlisting role="php"><![CDATA[
  2625. application/
  2626. controllers/
  2627. IndexController.php
  2628. models/
  2629. views/
  2630. scripts/
  2631. index/
  2632. index.phtml
  2633. helpers/
  2634. filters/
  2635. html/
  2636. .htaccess
  2637. index.php
  2638. ]]>
  2639. </programlisting>
  2640. </sect3>
  2641. <sect3 id="zend.controller.quickstart.go.docroot">
  2642. <title>Establezca su document root</title>
  2643. <para>
  2644. Apunte su document root en su servidor web hacia el
  2645. directorio
  2646. <code>html</code>
  2647. de la estrctura de archivos de arriba.
  2648. </para>
  2649. </sect3>
  2650. <sect3 id="zend.controller.quickstart.go.rewrite">
  2651. <title>Cree sus reglas de reescritura</title>
  2652. <para>
  2653. Edite el archivo
  2654. <code>html/.htaccess</code>
  2655. que aparece arriba de la siguiente forma:
  2656. </para>
  2657. <programlisting role="php"><![CDATA[
  2658. RewriteEngine On
  2659. RewriteCond %{REQUEST_FILENAME} -s [OR]
  2660. RewriteCond %{REQUEST_FILENAME} -l [OR]
  2661. RewriteCond %{REQUEST_FILENAME} -d
  2662. RewriteRule ^.*$ - [NC,L]
  2663. RewriteRule ^.*$ index.php [NC,L]
  2664. ]]>
  2665. </programlisting>
  2666. <para>
  2667. La regla de arriba redigirá las peticiones a recuros existentes
  2668. (enlaces simbólicos existentes, archivos no vacíos, o directorios no vacíos)
  2669. en consecuencia, y todas las otras peticiones al front controller.
  2670. </para>
  2671. <note>
  2672. <para>
  2673. Las reglas de arriba pertenecen a Apache. Para ejemplos de reglas
  2674. de rewrite para otros servidores web, mire la
  2675. <link linkend="zend.controller.router.introduction">
  2676. documentación de router
  2677. </link>
  2678. .
  2679. </para>
  2680. </note>
  2681. </sect3>
  2682. <sect3 id="zend.controller.quickstart.go.bootstrap">
  2683. <title>Cree su archivo bootstrap</title>
  2684. <para>
  2685. El archivo bootstrap es la página a la que todas las peticiones
  2686. son redirigidas a través de --
  2687. <code>html/index.php</code>
  2688. en este caso. Abra el archivo
  2689. <code>html/index.php</code>
  2690. en el editor de su elección y añada lo siguiente:
  2691. </para>
  2692. <programlisting role="php"><![CDATA[
  2693. Zend_Controller_Front::run('/path/to/app/controllers');
  2694. ]]>
  2695. </programlisting>
  2696. <para>
  2697. Esto instanciará y hará un dispatch del front controller, que
  2698. redigirá las peticiones a los action controllers.
  2699. </para>
  2700. </sect3>
  2701. <sect3 id="zend.controller.quickstart.go.controller">
  2702. <title>Cree su action controller por defecto</title>
  2703. <para>
  2704. Antes de tratar los action controllers, debe primero
  2705. entender cómo las peticiones son redirigidas en Zend Framework.
  2706. Por defecto, el primero segmento de una ruta URL apunta
  2707. a un controlador, y el segundo a una acción. Por ejemplo,
  2708. dada la URL
  2709. <code>
  2710. http://framework.zend.com/roadmap/components
  2711. </code>
  2712. , la ruta es
  2713. <code>/roadmap/components</code>
  2714. , que apuntará al controlador
  2715. <code>roadmap</code>
  2716. y la acción
  2717. <code>components</code>
  2718. . Si no se suministra una acción, se asume la acción
  2719. <code>index</code>
  2720. , y si no se suministra un controlador, se asume el controlador
  2721. <code>index</code>
  2722. (siguiendo la convención de Apache de apuntar a
  2723. <code>DirectoryIndex</code>
  2724. automáticamente).
  2725. </para>
  2726. <para>
  2727. El dispatcher de <code>Zend_Controller</code>
  2728. toma entonces el valor del controlador y lo apunta
  2729. a una clase. Por defecto, pone en mayúsculas la primera letra
  2730. del nombre de controlador y agrega la palabra
  2731. <code>Controller</code>
  2732. . De esta forma, en nuestro ejemplo de arriba, el controlador
  2733. <code>roadmap</code>
  2734. es dirigido a la clase
  2735. <code>RoadmapController</code>
  2736. .
  2737. </para>
  2738. <para>
  2739. De la misma forma, el valor de action es dirigido
  2740. a un método de la clase controladora. Por defecto, el valor se
  2741. pasa a minúsculas, y la palabra
  2742. <code>Action</code>
  2743. es añadida. De esta forma, en nuestro ejemplo de arriba, la acción
  2744. <code>components</code>
  2745. se convierte en
  2746. <code>componentsAction</code>
  2747. , y el método final llamado es
  2748. <code>RoadmapController::componentsAction()</code>
  2749. .
  2750. </para>
  2751. <para>
  2752. Continuando, creemos ahora un action controller
  2753. y un método de acción por defecto. Como se ha dicho antes,
  2754. el controlador por defecto y la acción llamada son ambos
  2755. <code>index</code>
  2756. . Abra el archivo
  2757. <code>application/controllers/IndexController.php</code>
  2758. , e introduzca lo siguiente:
  2759. </para>
  2760. <programlisting role="php"><![CDATA[
  2761. /** Zend_Controller_Action */
  2762. class IndexController extends Zend_Controller_Action
  2763. {
  2764. public function indexAction()
  2765. {
  2766. }
  2767. }
  2768. ]]>
  2769. </programlisting>
  2770. <para>
  2771. Por defecto, el action helper
  2772. <link linkend="zend.controller.actionhelpers.viewrenderer">
  2773. ViewRenderer
  2774. </link>
  2775. está activado. Esto significa que simplemente
  2776. definiendo un action method y un view script correspondiente,
  2777. tendrá su contenido generado inmediatamente.
  2778. Por defecto,
  2779. <code>Zend_View</code>
  2780. es usado como la capa Vista en el patrón MVC. El
  2781. <code>ViewRenderer</code>
  2782. hace algo de magia, y usa el nombre de controlador (e.g.,
  2783. <code>index</code>
  2784. ) y el nombre de acción actual (e.g.,
  2785. <code>index</code>
  2786. ) para determinar qué plantilla traer. Por defecto,
  2787. las plantillas terminan con la extensión
  2788. <code>.phtml</code>
  2789. , lo que significa que en el ejemplo de arriba, la
  2790. plantilla
  2791. <code>index/index.phtml</code>
  2792. será generada. Adicionalmente, el
  2793. <code>ViewRenderer</code>
  2794. asume automáticamente que la carpeta
  2795. <code>views</code>
  2796. al mismo nivel que la carpeta controller será
  2797. la carpeta raíz de la vista, y que el script de vista actual
  2798. estará en la subcarpeta
  2799. <code>views/scripts/</code>.
  2800. De esta forma, la plantilla generada será encontrada en
  2801. <code>application/views/scripts/index/index.phtml</code>
  2802. .
  2803. </para>
  2804. </sect3>
  2805. <sect3 id="zend.controller.quickstart.go.view">
  2806. <title>Cree su view script</title>
  2807. <para>
  2808. Como hemos mencionado
  2809. <link linkend="zend.controller.quickstart.go.controller">
  2810. en la sección anterior
  2811. </link>
  2812. , los scripts de vista se encuentran en
  2813. <code>application/views/scripts/</code>
  2814. ; el view script para el controlador y la acción por defecto
  2815. está en
  2816. <code>application/views/scripts/index/index.phtml</code>
  2817. . Cree este archivo, y escriba un poco de HTML:
  2818. </para>
  2819. <programlisting role="php"><![CDATA[
  2820. <!DOCTYPE html
  2821. PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
  2822. "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
  2823. <html>
  2824. <head>
  2825. <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  2826. <title>Mi primera aplicación Zend Framework</title>
  2827. </head>
  2828. <body>
  2829. <h1>>¡Hola, Mundo!</h1>
  2830. </body>
  2831. </html>
  2832. ]]>
  2833. </programlisting>
  2834. </sect3>
  2835. <sect3 id="zend.controller.quickstart.go.errorhandler">
  2836. <title>Cree su controlador de errores</title>
  2837. <para>
  2838. Por defecto, está registrado
  2839. <link linkend="zend.controller.plugins.standard.errorhandler">
  2840. el plugin 'error handler'
  2841. </link>. Este plugin espera que exista
  2842. un controlador para manejar los errores.
  2843. Por defecto, asume un
  2844. <code>ErrorController</code>
  2845. en el módulo default con un método
  2846. <code>errorAction</code>
  2847. :
  2848. </para>
  2849. <programlisting role="php"><![CDATA[
  2850. class ErrorController extends Zend_Controller_Action
  2851. {
  2852. public function errorAction()
  2853. {
  2854. }
  2855. }
  2856. ]]>
  2857. </programlisting>
  2858. <para>
  2859. Asumiendo el sistema de carpetas discutido anteriormente,
  2860. este archivo irá en
  2861. <code>application/controllers/ErrorController.php</code>
  2862. . También necesitará crear un view script en
  2863. <code>application/views/scripts/error/error.phtml</code>
  2864. ; el contenido de ejemplo será parecido a:
  2865. </para>
  2866. <programlisting role="php"><![CDATA[
  2867. <!DOCTYPE html
  2868. PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
  2869. "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
  2870. <html>
  2871. <head>
  2872. <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  2873. <title>Error</title>
  2874. </head>
  2875. <body>
  2876. <h1>Ocurrió un error</h1>
  2877. <p>Ocurrió un error; Por favor, inténtelo de nuevo más tarde.</p>
  2878. </body>
  2879. </html>
  2880. ]]>
  2881. </programlisting>
  2882. </sect3>
  2883. <sect3 id="zend.controller.quickstart.go.finish">
  2884. <title>¡Vea el sitio!</title>
  2885. <para>
  2886. Con su primer controlador y vista, ya puede arrancar su navegador y acceder a su sitio.
  2887. Asumiendo que
  2888. <code>example.com</code>
  2889. es su dominio, cualquiera de las siguientes URLs le llevará a
  2890. la página que acaba de crear:
  2891. </para>
  2892. <itemizedlist>
  2893. <listitem>
  2894. <para>
  2895. <code>http://example.com/</code>
  2896. </para>
  2897. </listitem>
  2898. <listitem>
  2899. <para>
  2900. <code>http://example.com/index</code>
  2901. </para>
  2902. </listitem>
  2903. <listitem>
  2904. <para>
  2905. <code>http://example.com/index/index</code>
  2906. </para>
  2907. </listitem>
  2908. </itemizedlist>
  2909. <para>
  2910. Ya está listo para empezar a crear más métodos de controladores y acciones. ¡Felicidades!
  2911. </para>
  2912. </sect3>
  2913. </sect2>
  2914. </sect1><!--
  2915. vim:se ts=4 sw=4 et:
  2916. -->
  2917. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Controller-Basics.xml"/>
  2918. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Controller-FrontController.xml"/>
  2919. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Controller-Request.xml"/>
  2920. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Controller-Router.xml" parse="xml"/>
  2921. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Controller-Dispatcher.xml"/>
  2922. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Controller-ActionController.xml"/>
  2923. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Controller-ActionHelpers.xml" parse="xml"/>
  2924. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Controller-Response.xml"/>
  2925. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Controller-Plugins.xml" parse="xml"/>
  2926. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Controller-Modular.xml"/>
  2927. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Controller-Exceptions.xml"/>
  2928. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Controller-Migration.xml"/>
  2929. </chapter>
  2930. <chapter id="zend.currency">
  2931. <title>Zend_Currency</title>
  2932. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Currency-Introduction.xml"/>
  2933. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Currency-Usage.xml"/>
  2934. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Currency-Migrating.xml"/>
  2935. </chapter>
  2936. <chapter id="zend.date">
  2937. <title>Zend_Date</title>
  2938. <sect1 id="zend.date.introduction" xml:base="module_specs/Zend_Date-Introduction.xml">
  2939. <title>Introducción</title>
  2940. <para>
  2941. El componente
  2942. <code>Zend_Date</code>
  2943. ofrece una API detallada pero simple para manipular fechas y
  2944. horas. Sus métodos aceptan una gran variedad de tipos de
  2945. información, incluyendo partes de fecha, en numerosas
  2946. combinaciones provocando muchas características y posibilidades
  2947. más allá de las funciones de fecha PHP relacionadas. Para
  2948. las últimas actualizaciones manuales, por favor ver el siguiente
  2949. link <ulink>
  2950. url="http://framework.zend.com/wiki/display/ZFDOCDEV/Home"&gt;our
  2951. online manual (sincronizado frecuentemente con Subversion)
  2952. </ulink>
  2953. .
  2954. </para>
  2955. <para>
  2956. Aunque la simplicidad sea el objetivo, trabajar con fechas y
  2957. tiempos localizados mientras se modifican, combinan y comparan
  2958. partes, provoca una complejidad inevitable. Las fechas, así como
  2959. los tiempos, a menudo son escritos de forma diferente en
  2960. zonas locales distintas. Por ejemplo, algunos colocan primero el
  2961. mes, mientras otros escriben el año en primer lugar cuando
  2962. expresan fechas del calendario. Para más información relacionada
  2963. con manejo de localizaciones y normalización, por favor
  2964. vea el manual de
  2965. <link linkend="zend.locale.date.datesandtimes">
  2966. <code>Zend_Locale</code>
  2967. </link>
  2968. .
  2969. </para>
  2970. <para>
  2971. <code>Zend_Date</code>
  2972. también soporta nombres de meses abreviados en varios idiomas.
  2973. <code>Zend_Locale</code>
  2974. facilita la normalización de meses localizados y nombres de días
  2975. de la semana a timestamps, los cuales pueden, a su vez, ser
  2976. mostrados localizados a otras regiones.
  2977. </para>
  2978. <sect2 id="zend.date.setdefaulttimezone">
  2979. <title>Asigne Siempre una Zona Horaria por Defecto</title>
  2980. <para>
  2981. Antes de utilizar funciones relacionadas con fechas en PHP o
  2982. en el Zend Framework, primero debe asegurarse que su
  2983. aplicación tiene una zona horaria correcta por defecto,
  2984. configurando la variable de entorno TZ, usando el
  2985. parametro del php.ini
  2986. <code>date.timezone</code>
  2987. , o usando
  2988. <ulink url="http://php.net/date_default_timezone_set">
  2989. date_default_timezone_set()
  2990. </ulink>
  2991. . En PHP, podemos ajustar todas las funciones relacionadas
  2992. con fechas y hora para trabajar para un usuario particular
  2993. configurando por defecto una zona horaria de acuerdo a las
  2994. expectativas del usuario. Para una lista completa de
  2995. configuraciones de zona horaria, vea el siguiente link
  2996. <ulink url="http://unicode.org/cldr/data/diff/supplemental/territory_containment_un_m_49.html">
  2997. Lista de Identificadores de Zonas Horarias CLDR
  2998. </ulink>
  2999. .
  3000. <example id="zend.date.setdefaulttimezone.example-1">
  3001. <title>Configurando una Zona Horaria por Defecto</title>
  3002. <programlisting role="php"><![CDATA[
  3003. // zona horaria para un estadounidense en California
  3004. date_default_timezone_set('America/Los_Angeles');
  3005. // zona horaria para un alemán en Alemania
  3006. date_default_timezone_set('Europe/Berlin');
  3007. ]]>
  3008. </programlisting>
  3009. </example>
  3010. <emphasis role="strong">¡Al crear instancias de Zend_Date, su zona horaria se convertirá automáticamente
  3011. en la zona horaria por defecto actual!</emphasis> De esta forma, la configuración de zona horaria tendrá
  3012. en cuenta cualquier cambio de hora de invierno/verano (Daylight Saving Time, DST), eliminando la necesidad
  3013. de especificarlo explícitamente.
  3014. </para>
  3015. <para>
  3016. Tenga en cuenta que las zonas horarias <emphasis role="strong">UTC</emphasis> y
  3017. <emphasis role="strong">GMT</emphasis> no incluyen el cambio de hora de invierno/verano (Daylight Saving Time, DST).
  3018. Esto significa que aunque defina a mano que <code>Zend_Date</code> deba trabajar con DST, podría
  3019. ser anulado por las instancias de <code>Zend_Date</code> que han sido fijadas a
  3020. UTC o GMT.
  3021. </para>
  3022. </sect2>
  3023. <sect2 id="zend.date.why">
  3024. <title>¿Por Qué Usar Zend_Date?</title>
  3025. <para>
  3026. <code>Zend_Date</code> ofrece las siguientes prestaciones, las cuales extienden el alcance de las funciones de fecha de PHP:
  3027. </para>
  3028. <itemizedlist mark="opencircle">
  3029. <listitem>
  3030. <para>
  3031. API sencilla
  3032. </para>
  3033. <para>
  3034. <code>Zend_Date</code> aporta una API muy sencilla, que combina lo mejor de la funcionalidad
  3035. fecha/hora de cuatro lenguajes de programación. Es posible, por ejemplo, añadir o comparar dos horas
  3036. dentro de una misma columna.
  3037. </para>
  3038. </listitem>
  3039. <listitem>
  3040. <para>
  3041. Completamente internacionalizado
  3042. </para>
  3043. <para>
  3044. Todos los nombres de meses y días de la semana completos y abreviados están incluidos para más de 130 idiomas.
  3045. Los métodos admiten tanto entrada como salida de fechas usando los nombres localizados de meses y días de la semana.
  3046. </para>
  3047. </listitem>
  3048. <listitem>
  3049. <para>
  3050. Timestamps ilimitados
  3051. </para>
  3052. <para>
  3053. A pesar de que la documentación de PHP 5.2 indice: "El intervalo de valores admitidos de timestamps es
  3054. desde el 13 Dec 1901 20:45:54 GMT al 19 Ene 2038 03:14:07 GMT," <code>Zend_Date</code> admite un rango
  3055. casi ilimitado, con la ayuda de la extensión BCMath. Si BCMath no está disponible, Zend_Date tendrá una
  3056. funcionalidad de timestamps reducida al rango del tipo <code>float</code> soportado por su servidor.
  3057. El tamaño de un float es dependiente de la plataforma, aunque un máximo de ~1.8e308 con una precisión
  3058. de cerca de 14 dígitos decimales es un valor habitual (formato 64 bit IEEE)." [
  3059. <ulink url="http://www.php.net/float">http://www.php.net/float</ulink>
  3060. ]. Adicionalmente, las limitaciones heredadas de los tipos de dato float, y errores de redondeo de números
  3061. flotantes pueden introducir errores en los cálculos. Para evitar estos problemas, los componentes ZF I18n
  3062. usan la extensión BCMath, si está disponible.
  3063. </para>
  3064. </listitem>
  3065. <listitem>
  3066. <para>
  3067. Soporte para especificaciones de fecha ISO_8601
  3068. </para>
  3069. <para>
  3070. Las especificaciones de fecha ISO_8601 están aceptadas. Incluso las especificaciones de fecha ISO_8601
  3071. parcialmente autorizadas serán identificadas. Estos formatos de fecha son particularmente útiles al
  3072. trabajar con bases de datos. Por ejemplo, aunque MsSQL y
  3073. <ulink url="http://dev.mysql.com/doc/refman/5.0/en/date-and-time-functions.html">MySQL</ulink>
  3074. difieren ligeramente uno de otro, ambos tienen soporte por parte de <code>Zend_Date</code> usando la constante
  3075. de especificación de formato
  3076. <link linkend="zend.date.constants.list">Zend_Date::ISO_8601</link>.
  3077. Cuando las cadenas de fecha sean del tipo "Y/m/d" o "Y-m-d H:i:s", de acuerdo con los tokens de formato
  3078. PHP date(), use el soporte integrado de Zend_Date para fechas formateadas ISO 8601.
  3079. </para>
  3080. </listitem>
  3081. <listitem>
  3082. <para>
  3083. Calcular amanecer y puesta de sol
  3084. </para>
  3085. <para>
  3086. Las horas de amanecer y puesta de sol pueden mostrarse para cualquier lugar y día, para que no pierda ni un segundo de luz diurna
  3087. para trabajar en su proyecto PHP favorito :)
  3088. </para>
  3089. </listitem>
  3090. </itemizedlist>
  3091. </sect2>
  3092. </sect1><!--
  3093. vim:se ts=4 sw=4 et:
  3094. -->
  3095. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Date-Theory.xml"/>
  3096. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Date-Basic.xml"/>
  3097. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Date-Overview.xml"/>
  3098. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Date-Creation.xml"/>
  3099. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Date-Constants.xml"/>
  3100. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Date-Additional.xml"/>
  3101. </chapter>
  3102. <chapter id="zend.db">
  3103. <title>Zend_Db</title>
  3104. <sect1 id="zend.db.adapter" xml:base="module_specs/Zend_Db_Adapter.xml">
  3105. <title>Zend_Db_Adapter</title>
  3106. <para>
  3107. Zend_Db y sus clases relacionadas proporcionan una interfaz
  3108. simple de base de datos SQL para Zend Framework. El
  3109. Zend_Db_Adapter es la clase base que se utiliza para conectar su
  3110. aplicación PHP A una base de datos (RDBMS). Existen diferentes
  3111. clases Adapters(Adaptador) para cada tipo de base de datos
  3112. (RDBMS).
  3113. </para>
  3114. <para>
  3115. Las clases
  3116. <code>Adapters</code>
  3117. de Zend_Db crean un puente entre las extensiones de base de
  3118. datos de PHP hacia una interfaz común, para ayudarle a escribir
  3119. aplicaciones PHP una sola vez y poder desplegar múltiples
  3120. tipos de base de datos (RDBMS) con muy poco esfuerzo.
  3121. </para>
  3122. <para>
  3123. La Interfaz de la clase adaptador (adapter) es similar a la
  3124. intefaz de la extensión
  3125. <ulink url="http://www.php.net/pdo">PHP Data Objects</ulink>
  3126. . Zend_Db proporciona clases Adaptadoras para los drivers PDO de
  3127. los siguientes tipos de RDBMS:
  3128. </para>
  3129. <itemizedlist>
  3130. <listitem>
  3131. <para>
  3132. IBM DB2 e Informix Dynamic Server (IDS), usando la
  3133. extensión PHP
  3134. <ulink url="http://www.php.net/pdo-ibm">pdo_ibm</ulink>
  3135. </para>
  3136. </listitem>
  3137. <listitem>
  3138. <para>
  3139. MySQL, usando la extensión PHP
  3140. <ulink url="http://www.php.net/pdo-mysql">
  3141. pdo_mysql
  3142. </ulink>
  3143. </para>
  3144. </listitem>
  3145. <listitem>
  3146. <para>
  3147. Microsoft SQL Server, usando la extensión PHP
  3148. <ulink url="http://www.php.net/pdo-mssql">
  3149. pdo_mssql
  3150. </ulink>
  3151. </para>
  3152. </listitem>
  3153. <listitem>
  3154. <para>
  3155. Oracle, usando la extensión PHP
  3156. <ulink url="http://www.php.net/pdo-oci">pdo_oci</ulink>
  3157. </para>
  3158. </listitem>
  3159. <listitem>
  3160. <para>
  3161. PostgreSQL, usando la extensión PHP
  3162. <ulink url="http://www.php.net/pdo-pgsql">
  3163. pdo_pgsql
  3164. </ulink>
  3165. </para>
  3166. </listitem>
  3167. <listitem>
  3168. <para>
  3169. SQLite, usando la extensión PHP
  3170. <ulink url="http://www.php.net/pdo-sqlite">
  3171. pdo_sqlite
  3172. </ulink>
  3173. </para>
  3174. </listitem>
  3175. </itemizedlist>
  3176. <para>
  3177. Ademas, Zend_Db proporciona clases Adaptadoras que utilizan las
  3178. extensiones de base de datos de PHP de los siguientes tipos:
  3179. </para>
  3180. <itemizedlist>
  3181. <listitem>
  3182. <para>
  3183. MySQL, usando la extensión PHP
  3184. <ulink url="http://www.php.net/mysqli">mysqli</ulink>
  3185. </para>
  3186. </listitem>
  3187. <listitem>
  3188. <para>
  3189. Oracle, usando la extensión PHP
  3190. <ulink url="http://www.php.net/oci8">oci8</ulink>
  3191. </para>
  3192. </listitem>
  3193. <listitem>
  3194. <para>
  3195. IBM DB2, usando la extensión PHP
  3196. <ulink url="http://www.php.net/ibm_db2">ibm_db2</ulink>
  3197. </para>
  3198. </listitem>
  3199. <listitem>
  3200. <para>
  3201. Firebird/Interbase, usando la extensión PHP
  3202. <ulink url="http://www.php.net/ibase">
  3203. php_interbase
  3204. </ulink>
  3205. </para>
  3206. </listitem>
  3207. </itemizedlist>
  3208. <note>
  3209. <para>
  3210. Cada Zend_Db_Adaptador utiliza una extensión PHP. Se debe de
  3211. tener habilitada la respectiva extensión en su entorno PHP
  3212. para utilizar un Zend_Db_Adapter. Por ejemplo, si se utiliza
  3213. una clase Zend_Db_Adapter basada en PDO, tiene que
  3214. habilitar tanto la extensión PDO como el driver PDO del tipo
  3215. de base de datos que se utiliza.
  3216. </para>
  3217. </note>
  3218. <sect2 id="zend.db.adapter.connecting">
  3219. <title>
  3220. Conexión a una Base de Datos utilizando un Adaptador
  3221. </title>
  3222. <para>
  3223. Esta sección describe cómo crear una instancia de un
  3224. Adaptador de base de datos. Esto corresponde a establecer
  3225. una conexión a un servidor de Base de Datos (RDBMS) desde su
  3226. aplicación PHP.
  3227. </para>
  3228. <sect3 id="zend.db.adapter.connecting.constructor">
  3229. <title>Usando un Constructor de Zend_Db Adapter</title>
  3230. <para>
  3231. Se puede crear una instancia de un Adaptador utilizando
  3232. su constructor. Un constructor de adaptador toma un
  3233. argumento, que es un conjunto de parámetros utilizados
  3234. para declarar la conexión.
  3235. </para>
  3236. <example id="zend.db.adapter.connecting.constructor.example">
  3237. <title>Usando el Constructor de un Adaptador</title>
  3238. <programlisting role="php"><![CDATA[
  3239. $db = new Zend_Db_Adapter_Pdo_Mysql(array(
  3240. 'host' => '127.0.0.1',
  3241. 'username' => 'webuser',
  3242. 'password' => 'xxxxxxxx',
  3243. 'dbname' => 'test'
  3244. ));
  3245. ]]>
  3246. </programlisting>
  3247. </example>
  3248. </sect3>
  3249. <sect3 id="zend.db.adapter.connecting.factory">
  3250. <title>Usando el Factory de Zend_Db</title>
  3251. <para>
  3252. Como alternativa a la utilización directa del
  3253. constructor de un adaptador, se puede crear una
  3254. instancia del adaptador que use el método estático
  3255. <code>Zend_Db::factory()</code>
  3256. . Este método carga dinámicamente el archivo de clase
  3257. Adaptador bajo demanda, usando
  3258. <link linkend="zend.loader.load.class">
  3259. Zend_Loader::loadClass()
  3260. </link>
  3261. .
  3262. </para>
  3263. <para>
  3264. El primer argumento es una cadena que nombra al nombre base
  3265. de la clase Adaptador. Por ejemplo, la cadena
  3266. 'Pdo_Mysql' corresponde a la clase
  3267. Zend_Db_Adapter_Pdo_Mysql. El segundo argumento es el
  3268. mismo array de parámetros que hubiera enviado al
  3269. constructor del adaptador.
  3270. </para>
  3271. <example id="zend.db.adapter.connecting.factory.example">
  3272. <title>Usando el Adaptador del método factory</title>
  3273. <programlisting role="php"><![CDATA[
  3274. // No necesitamos la siguiente declaración, porque
  3275. // el archivo Zend_Db_Adapter_Pdo_Mysql será cargado para nosotros por el método
  3276. // factory de Zend_Db.
  3277. // require_once 'Zend/Db/Adapter/Pdo/Mysql.php';
  3278. // carga automaticamente la clase Zend_Db_Adapter_Pdo_Mysql
  3279. // y crea una instancia de la misma
  3280. $db = Zend_Db::factory('Pdo_Mysql', array(
  3281. 'host' => '127.0.0.1',
  3282. 'username' => 'webuser',
  3283. 'password' => 'xxxxxxxx',
  3284. 'dbname' => 'test'
  3285. ));
  3286. ]]>
  3287. </programlisting>
  3288. </example>
  3289. <para>
  3290. Si crea su propia clase que extiende a
  3291. Zend_Db_Adapter_Abstract, pero no nombra su clase con el prefijo
  3292. de paquete "Zend_Db_Adapter", se puede utilizar el método
  3293. <code>factory()</code>
  3294. para cargar su adaptador si se especifica la parte principal
  3295. de la clase del adaptador con la clave "adapterNamespace" en
  3296. el conjunto de parámetros
  3297. </para>
  3298. <example id="zend.db.adapter.connecting.factory.example2">
  3299. <title>
  3300. Usando el método factory para una clase Adaptador
  3301. personalizada
  3302. </title>
  3303. <programlisting role="php"><![CDATA[
  3304. // No tenemos que cargar el archivo de clase Adaptador
  3305. // porque será cargado para nosotros por el método factory de Zend_Db.
  3306. // Automáticamente carga la clase MyProject_Db_Adapter_Pdo_Mysql
  3307. // y crea una instancia de ella.
  3308. $db = Zend_Db::factory('Pdo_Mysql', array(
  3309. 'host' => '127.0.0.1',
  3310. 'username' => 'webuser',
  3311. 'password' => 'xxxxxxxx',
  3312. 'dbname' => 'test',
  3313. 'adapterNamespace' => 'MyProject_Db_Adapter'
  3314. ));
  3315. ]]>
  3316. </programlisting>
  3317. </example>
  3318. </sect3>
  3319. <sect3 id="zend.db.adapter.connecting.factory-config">
  3320. <title>Uso de Zend_Config con Zend_Db Factory</title>
  3321. <para>
  3322. Opcionalmente, se puede especificar cualquier
  3323. argumento del método
  3324. <code>factory()</code>
  3325. como un objeto de tipo
  3326. <link linkend="zend.config">Zend_Config</link>
  3327. .
  3328. </para>
  3329. <para>
  3330. Si el primer argumento es un objeto de configuración, se
  3331. espera que contenga una propiedad llamada
  3332. <code>adapter</code>
  3333. , conteniendo la cadena que da nombre al nombre base de la
  3334. clase de adaptador. Opcionalmente, el objeto puede
  3335. contener una propiedad llamada
  3336. <code>params</code>
  3337. , con subpropiedades correspondientes a nombres de parámetros
  3338. del adaptador. Esto es usado sólo si el segundo
  3339. argumento del método <code>factory()</code> se ha omitido.
  3340. </para>
  3341. <example id="zend.db.adapter.connecting.factory.example1">
  3342. <title>
  3343. Uso del método factory del Adaptador con un objeto Zend_Config
  3344. </title>
  3345. <para>
  3346. En el siguiente ejemplo, un objeto Zend_Config es
  3347. creado usando un array. También puedes cargar los datos de
  3348. un archivo externo, por ejemplo con
  3349. <link linkend="zend.config.adapters.ini">
  3350. Zend_Config_Ini
  3351. </link>
  3352. o
  3353. <link linkend="zend.config.adapters.xml">
  3354. Zend_Config_Xml
  3355. </link>
  3356. .
  3357. </para>
  3358. <programlisting role="php"><![CDATA[
  3359. $config = new Zend_Config(
  3360. array(
  3361. 'database' => array(
  3362. 'adapter' => 'Mysqli',
  3363. 'params' => array(
  3364. 'dbname' => 'test',
  3365. 'username' => 'webuser',
  3366. 'password' => 'secret',
  3367. )
  3368. )
  3369. )
  3370. );
  3371. $db = Zend_Db::factory($config->database);
  3372. ]]>
  3373. </programlisting>
  3374. </example>
  3375. <para>
  3376. El segundo argumento del método
  3377. <code>factory()</code>
  3378. puede ser un array asociativo con entradas
  3379. correspondientes a los parámetros del adaptador. Este argumento es
  3380. opcional. Si el primer argumento es de tipo Zend_Config,
  3381. se asume que tiene todos los parametros, y el segundo
  3382. argumento es ignorado.
  3383. </para>
  3384. </sect3>
  3385. <sect3 id="zend.db.adapter.connecting.parameters">
  3386. <title>Parámetros del Adaptador</title>
  3387. <para>
  3388. El siguiente listado explica parámetros comunes reconocidos por
  3389. Adaptador de clases Zend_Db.
  3390. </para>
  3391. <itemizedlist>
  3392. <listitem>
  3393. <para>
  3394. <emphasis role="strong">host</emphasis>
  3395. : una string conteniendo un nombre de host o dirección IP
  3396. del servidor de base de datos. Si la base de datos está corriendo
  3397. sobre el mismo host que la aplicación PHP,
  3398. usted puede utilizar 'localhost' o '127.0.0.1'.
  3399. </para>
  3400. </listitem>
  3401. <listitem>
  3402. <para>
  3403. <emphasis role="strong">username</emphasis>
  3404. : identificador de cuenta para autenticar una conexión al
  3405. servidor RDBMS.
  3406. </para>
  3407. </listitem>
  3408. <listitem>
  3409. <para>
  3410. <emphasis role="strong">password</emphasis>
  3411. : la contraseña de la cuenta para la autenticación de credenciales
  3412. de conexión con el servidor RDBMS
  3413. </para>
  3414. </listitem>
  3415. <listitem>
  3416. <para>
  3417. <emphasis role="strong">dbname</emphasis>
  3418. : nombre de la base de datos en el servidor RDBMS.
  3419. </para>
  3420. </listitem>
  3421. <listitem>
  3422. <para>
  3423. <emphasis role="strong">port</emphasis>
  3424. : algunos servidores RDBMS pueden aceptar conexiones de red
  3425. sobre un número de puerto específico.
  3426. El parámetro del puerto le permite especificar el puerto al
  3427. que su aplicación PHP se conecta, para que concuerde el puerto
  3428. configurado en el servidor RDBMS.
  3429. </para>
  3430. </listitem>
  3431. <listitem>
  3432. <para>
  3433. <emphasis role="strong">options</emphasis>
  3434. : este parámetro es un array asociativo de
  3435. opciones que son genéricas a todas las clases Zend_Db_Adapter.
  3436. </para>
  3437. </listitem>
  3438. <listitem>
  3439. <para>
  3440. <emphasis role="strong">
  3441. driver_options
  3442. </emphasis>
  3443. : este parámetro es un array asociativo de opciones adicionales
  3444. para una extensión de base de datos dada.
  3445. un uso típico de este parámetro es establecer atributos
  3446. de un driver PDO.
  3447. </para>
  3448. </listitem>
  3449. <listitem>
  3450. <para>
  3451. <emphasis role="strong">
  3452. adapterNamespace
  3453. </emphasis>
  3454. : nombre de la parte inicial del nombre de las clase para el
  3455. adaptador, en lugar de 'Zend_Db_Adapter'. Utilice
  3456. esto si usted necesita usar el método
  3457. <code>factory()</code>
  3458. para cargar un adaptador de clase de base de datos que no sea
  3459. de Zend.
  3460. </para>
  3461. </listitem>
  3462. </itemizedlist>
  3463. <example id="zend.db.adapter.connecting.parameters.example1">
  3464. <title>
  3465. Passing the case-folding option to the factory
  3466. </title>
  3467. <para>
  3468. Usted puede pasar esta opción específica por la constante
  3469. <code>Zend_Db::CASE_FOLDING</code>
  3470. . Este corresponde al atributo
  3471. <code>ATTR_CASE</code>
  3472. en los drivers de base de datos PDO e IBM DB2,
  3473. ajustando la sensibilidad de las claves tipo cadena en los resultados
  3474. de consultas. La opción toma los valores
  3475. <code>Zend_Db::CASE_NATURAL</code>
  3476. (el predeterminado),
  3477. <code>Zend_Db::CASE_UPPER</code>
  3478. , y
  3479. <code>Zend_Db::CASE_LOWER</code>
  3480. .
  3481. </para>
  3482. <programlisting role="php"><![CDATA[
  3483. $options = array(
  3484. Zend_Db::CASE_FOLDING => Zend_Db::CASE_UPPER
  3485. );
  3486. $params = array(
  3487. 'host' => '127.0.0.1',
  3488. 'username' => 'webuser',
  3489. 'password' => 'xxxxxxxx',
  3490. 'dbname' => 'test',
  3491. 'options' => $options
  3492. );
  3493. $db = Zend_Db::factory('Db2', $params);
  3494. ]]>
  3495. </programlisting>
  3496. </example>
  3497. <example id="zend.db.adapter.connecting.parameters.example2">
  3498. <title>
  3499. Passing the auto-quoting option to the factory
  3500. </title>
  3501. <para>
  3502. Usted puede especificar esta opción por la constante
  3503. <code>Zend_Db::AUTO_QUOTE_IDENTIFIERS</code>
  3504. . Si el valor es
  3505. <code>true</code>
  3506. (el predeterminado), los identificadores como nombres de tabla,
  3507. nombres de columna, e incluso los alias son delimitados en la
  3508. sintaxis SQL generada por el Adatador del objeto.
  3509. Esto hace que sea sencillo utilizar identificadores que contengan
  3510. palabras reservadas de SQL, o caracteres especiales. Si el valor es
  3511. <code>false</code>
  3512. , los identificadores no son delimitados automáticamente. Si
  3513. usted necesita delimitar identificadores, debe hacer usted mismo
  3514. utilizando el método
  3515. <code>quoteIdentifier()</code>
  3516. .
  3517. </para>
  3518. <programlisting role="php"><![CDATA[
  3519. $options = array(
  3520. Zend_Db::AUTO_QUOTE_IDENTIFIERS => false
  3521. );
  3522. $params = array(
  3523. 'host' => '127.0.0.1',
  3524. 'username' => 'webuser',
  3525. 'password' => 'xxxxxxxx',
  3526. 'dbname' => 'test',
  3527. 'options' => $options
  3528. );
  3529. $db = Zend_Db::factory('Pdo_Mysql', $params);
  3530. ]]>
  3531. </programlisting>
  3532. </example>
  3533. <example id="zend.db.adapter.connecting.parameters.example3">
  3534. <title>Passing PDO driver options to the factory</title>
  3535. <programlisting role="php"><![CDATA[
  3536. $pdoParams = array(
  3537. PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true
  3538. );
  3539. $params = array(
  3540. 'host' => '127.0.0.1',
  3541. 'username' => 'webuser',
  3542. 'password' => 'xxxxxxxx',
  3543. 'dbname' => 'test',
  3544. 'driver_options' => $pdoParams
  3545. );
  3546. $db = Zend_Db::factory('Pdo_Mysql', $params);
  3547. echo $db->getConnection()
  3548. ->getAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY);
  3549. ]]>
  3550. </programlisting>
  3551. </example>
  3552. </sect3>
  3553. <sect3 id="zend.db.adapter.connecting.getconnection">
  3554. <title>Managing Lazy Connections</title>
  3555. <para>
  3556. Creating an instance of an Adapter class does not
  3557. immediately connect to the RDBMS server. The Adapter
  3558. saves the connection parameters, and makes the actual
  3559. connection on demand, the first time you need to execute
  3560. a query. This ensures that creating an Adapter object is
  3561. quick and inexpensive. You can create an instance of an
  3562. Adapter even if you are not certain that you need to run
  3563. any database queries during the current request your
  3564. application is serving.
  3565. </para>
  3566. <para>
  3567. If you need to force the Adapter to connect to the
  3568. RDBMS, use the
  3569. <code>getConnection()</code>
  3570. method. This method returns an object for the connection
  3571. as represented by the respective PHP database extension.
  3572. For example, if you use any of the Adapter classes for
  3573. PDO drivers, then
  3574. <code>getConnection()</code>
  3575. returns the PDO object, after initiating it as a live
  3576. connection to the specific database.
  3577. </para>
  3578. <para>
  3579. It can be useful to force the connection if you want to
  3580. catch any exceptions it throws as a result of invalid
  3581. account credentials, or other failure to connect to the
  3582. RDBMS server. These exceptions are not thrown until the
  3583. connection is made, so it can help simplify your
  3584. application code if you handle the exceptions in one
  3585. place, instead of at the time of the first query against
  3586. the database.
  3587. </para>
  3588. <example id="zend.db.adapter.connecting.getconnection.example">
  3589. <title>Handling connection exceptions</title>
  3590. <programlisting role="php"><![CDATA[
  3591. try {
  3592. $db = Zend_Db::factory('Pdo_Mysql', $parameters);
  3593. $db->getConnection();
  3594. } catch (Zend_Db_Adapter_Exception $e) {
  3595. // perhaps a failed login credential, or perhaps the RDBMS is not running
  3596. } catch (Zend_Exception $e) {
  3597. // perhaps factory() failed to load the specified Adapter class
  3598. }
  3599. ]]>
  3600. </programlisting>
  3601. </example>
  3602. </sect3>
  3603. </sect2>
  3604. <sect2 id="zend.db.adapter.example-database">
  3605. <title>La base de datos de ejemplo</title>
  3606. <para>
  3607. En la documentación de las clases Zend_Db, usamos un
  3608. conjunto sencillo de tablas para ilustrar el uso de las
  3609. clases y métodos. Estas tablas de ejemplo permiten almacenar
  3610. información para localizar bugs en un proyecto de desarrollo
  3611. de software. La base de datos contiene cuatro tablas:
  3612. </para>
  3613. <itemizedlist>
  3614. <listitem>
  3615. <para>
  3616. <emphasis role="strong">accounts</emphasis>
  3617. almacena información sobre cada usuario que hace el
  3618. seguimiento de bugs.
  3619. </para>
  3620. </listitem>
  3621. <listitem>
  3622. <para>
  3623. <emphasis role="strong">products</emphasis>
  3624. almacena información sobre cada producto para el que
  3625. pueden registrarse bugs.
  3626. </para>
  3627. </listitem>
  3628. <listitem>
  3629. <para>
  3630. <emphasis role="strong">bugs</emphasis>
  3631. almacena información sobre bugs, incluyendo el
  3632. estado actual del bug, la persona que informó sobre
  3633. el bug, la persona que está asignada para corregir
  3634. el bug, y la persona que está asignada para
  3635. verificar la corrección.
  3636. </para>
  3637. </listitem>
  3638. <listitem>
  3639. <para>
  3640. <emphasis role="strong">bugs_products</emphasis>
  3641. stores a relationship between bugs and products.
  3642. This implements a many-to-many relationship, because
  3643. a given bug may be relevant to multiple products,
  3644. and of course a given product can have multiple
  3645. bugs.
  3646. </para>
  3647. </listitem>
  3648. </itemizedlist>
  3649. <para>
  3650. La siguiente definición de datos SQL en lenguaje
  3651. pseudocódigo describe las tablas de esta base de datos de
  3652. ejemplo. Estas tablas de ejemplo son usadas ampliamente por
  3653. los tests unitarios automatizados de Zend_Db.
  3654. </para>
  3655. <programlisting role="sql"><![CDATA[
  3656. CREATE TABLE accounts (
  3657. account_name VARCHAR(100) NOT NULL PRIMARY KEY
  3658. );
  3659. CREATE TABLE products (
  3660. product_id INTEGER NOT NULL PRIMARY KEY,
  3661. product_name VARCHAR(100)
  3662. );
  3663. CREATE TABLE bugs (
  3664. bug_id INTEGER NOT NULL PRIMARY KEY,
  3665. bug_description VARCHAR(100),
  3666. bug_status VARCHAR(20),
  3667. reported_by VARCHAR(100) REFERENCES accounts(account_name),
  3668. assigned_to VARCHAR(100) REFERENCES accounts(account_name),
  3669. verified_by VARCHAR(100) REFERENCES accounts(account_name)
  3670. );
  3671. CREATE TABLE bugs_products (
  3672. bug_id INTEGER NOT NULL REFERENCES bugs,
  3673. product_id INTEGER NOT NULL REFERENCES products,
  3674. PRIMARY KEY (bug_id, product_id)
  3675. );
  3676. ]]>
  3677. </programlisting>
  3678. <para>
  3679. Also notice that the
  3680. <code>bugs</code>
  3681. table contains multiple foreign key references to the
  3682. <code>accounts</code>
  3683. table. Each of these foreign keys may reference a different
  3684. row in the
  3685. <code>accounts</code>
  3686. table for a given bug.
  3687. </para>
  3688. <para>
  3689. The diagram below illustrates the physical data model of the
  3690. example database.
  3691. </para>
  3692. <para>
  3693. <inlinegraphic width="387" scale="100" align="center" valign="middle" fileref="figures/zend.db.adapter.example-database.png" format="PNG"/>
  3694. </para>
  3695. </sect2>
  3696. <sect2 id="zend.db.adapter.select">
  3697. <title>Reading Query Results</title>
  3698. <para>
  3699. This section describes methods of the Adapter class with
  3700. which you can run SELECT queries and retrieve the query
  3701. results.
  3702. </para>
  3703. <sect3 id="zend.db.adapter.select.fetchall">
  3704. <title>Fetching a Complete Result Set</title>
  3705. <para>
  3706. You can run a SQL SELECT query and retrieve its results
  3707. in one step using the
  3708. <code>fetchAll()</code>
  3709. method.
  3710. </para>
  3711. <para>
  3712. The first argument to this method is a string containing
  3713. a SELECT statement. Alternatively, the first argument
  3714. can be an object of class
  3715. <link linkend="zend.db.select">Zend_Db_Select</link>
  3716. . The Adapter automatically converts this object to a
  3717. string representation of the SELECT statement.
  3718. </para>
  3719. <para>
  3720. The second argument to
  3721. <code>fetchAll()</code>
  3722. is an array of values to substitute for parameter
  3723. placeholders in the SQL statement.
  3724. </para>
  3725. <example id="zend.db.adapter.select.fetchall.example">
  3726. <title>Using fetchAll()</title>
  3727. <programlisting role="php"><![CDATA[
  3728. $sql = 'SELECT * FROM bugs WHERE bug_id = ?';
  3729. $result = $db->fetchAll($sql, 2);
  3730. ]]>
  3731. </programlisting>
  3732. </example>
  3733. </sect3>
  3734. <sect3 id="zend.db.adapter.select.fetch-mode">
  3735. <title>Changing the Fetch Mode</title>
  3736. <para>
  3737. By default,
  3738. <code>fetchAll()</code>
  3739. returns an array of rows, each of which is an
  3740. associative array. The keys of the associative array are
  3741. the columns or column aliases named in the select query.
  3742. </para>
  3743. <para>
  3744. You can specify a different style of fetching results
  3745. using the
  3746. <code>setFetchMode()</code>
  3747. method. The modes supported are identified by constants:
  3748. </para>
  3749. <itemizedlist>
  3750. <listitem>
  3751. <para>
  3752. <emphasis role="strong">
  3753. Zend_Db::FETCH_ASSOC
  3754. </emphasis>
  3755. : return data in an array of associative arrays.
  3756. The array keys are column names, as strings.
  3757. This is the default fetch mode for
  3758. Zend_Db_Adapter classes.
  3759. </para>
  3760. <para>
  3761. Note that if your select-list contains more than
  3762. one column with the same name, for example if
  3763. they are from two different tables in a JOIN,
  3764. there can be only one entry in the associative
  3765. array for a given name. If you use the
  3766. FETCH_ASSOC mode, you should specify column
  3767. aliases in your SELECT query to ensure that the
  3768. names result in unique array keys.
  3769. </para>
  3770. <para>
  3771. By default, these strings are returned as they
  3772. are returned by the database driver. This is
  3773. typically the spelling of the column in the
  3774. RDBMS server. You can specify the case for these
  3775. strings, using the
  3776. <code>Zend_Db::CASE_FOLDING</code>
  3777. option. Specify this when instantiating the
  3778. Adapter. See
  3779. <xref linkend="zend.db.adapter.connecting.parameters.example1"/>
  3780. .
  3781. </para>
  3782. </listitem>
  3783. <listitem>
  3784. <para>
  3785. <emphasis role="strong">
  3786. Zend_Db::FETCH_NUM
  3787. </emphasis>
  3788. : return data in an array of arrays. The arrays
  3789. are indexed by integers, corresponding to the
  3790. position of the respective field in the
  3791. select-list of the query.
  3792. </para>
  3793. </listitem>
  3794. <listitem>
  3795. <para>
  3796. <emphasis role="strong">
  3797. Zend_Db::FETCH_BOTH
  3798. </emphasis>
  3799. : return data in an array of arrays. The array
  3800. keys are both strings as used in the FETCH_ASSOC
  3801. mode, and integers as used in the FETCH_NUM
  3802. mode. Note that the number of elements in the
  3803. array is double that which would be in the array
  3804. if you used either FETCH_ASSOC or FETCH_NUM.
  3805. </para>
  3806. </listitem>
  3807. <listitem>
  3808. <para>
  3809. <emphasis role="strong">
  3810. Zend_Db::FETCH_COLUMN
  3811. </emphasis>
  3812. : return data in an array of values. The value
  3813. in each array is the value returned by one
  3814. column of the result set. By default, this is
  3815. the first column, indexed by 0.
  3816. </para>
  3817. </listitem>
  3818. <listitem>
  3819. <para>
  3820. <emphasis role="strong">
  3821. Zend_Db::FETCH_OBJ
  3822. </emphasis>
  3823. : return data in an array of objects. The
  3824. default class is the PHP built-in class
  3825. stdClass. Columns of the result set are
  3826. available as public properties of the object.
  3827. </para>
  3828. </listitem>
  3829. </itemizedlist>
  3830. <example id="zend.db.adapter.select.fetch-mode.example">
  3831. <title>Using setFetchMode()</title>
  3832. <programlisting role="php"><![CDATA[
  3833. $db->setFetchMode(Zend_Db::FETCH_OBJ);
  3834. $result = $db->fetchAll('SELECT * FROM bugs WHERE bug_id = ?', 2);
  3835. // $result is an array of objects
  3836. echo $result[0]->bug_description;
  3837. ]]>
  3838. </programlisting>
  3839. </example>
  3840. </sect3>
  3841. <sect3 id="zend.db.adapter.select.fetchassoc">
  3842. <title>Fetching a Result Set as an Associative Array</title>
  3843. <para>
  3844. The
  3845. <code>fetchAssoc()</code>
  3846. method returns data in an array of associative arrays,
  3847. regardless of what value you have set for the fetch
  3848. mode.
  3849. </para>
  3850. <example id="zend.db.adapter.select.fetchassoc.example">
  3851. <title>Using fetchAssoc()</title>
  3852. <programlisting role="php"><![CDATA[
  3853. $db->setFetchMode(Zend_Db::FETCH_OBJ);
  3854. $result = $db->fetchAssoc('SELECT * FROM bugs WHERE bug_id = ?', 2);
  3855. // $result is an array of associative arrays, in spite of the fetch mode
  3856. echo $result[0]['bug_description'];
  3857. ]]>
  3858. </programlisting>
  3859. </example>
  3860. </sect3>
  3861. <sect3 id="zend.db.adapter.select.fetchcol">
  3862. <title>Fetching a Single Column from a Result Set</title>
  3863. <para>
  3864. The
  3865. <code>fetchCol()</code>
  3866. method returns data in an array of values, regardless of
  3867. the value you have set for the fetch mode. This only
  3868. returns the first column returned by the query. Any
  3869. other columns returned by the query are discarded. If
  3870. you need to return a column other than the first, see
  3871. <xref linkend="zend.db.statement.fetching.fetchcolumn"/>
  3872. .
  3873. </para>
  3874. <example id="zend.db.adapter.select.fetchcol.example">
  3875. <title>Using fetchCol()</title>
  3876. <programlisting role="php"><![CDATA[
  3877. $db->setFetchMode(Zend_Db::FETCH_OBJ);
  3878. $result = $db->fetchCol(
  3879. 'SELECT bug_description, bug_id FROM bugs WHERE bug_id = ?', 2);
  3880. // contains bug_description; bug_id is not returned
  3881. echo $result[0];
  3882. ]]>
  3883. </programlisting>
  3884. </example>
  3885. </sect3>
  3886. <sect3 id="zend.db.adapter.select.fetchpairs">
  3887. <title>Fetching Key-Value Pairs from a Result Set</title>
  3888. <para>
  3889. The
  3890. <code>fetchPairs()</code>
  3891. method returns data in an array of key-value pairs, as
  3892. an associative array with a single entry per row. The
  3893. key of this associative array is taken from the first
  3894. column returned by the SELECT query. The value is taken
  3895. from the second column returned by the SELECT query. Any
  3896. other columns returned by the query are discarded.
  3897. </para>
  3898. <para>
  3899. You should design the SELECT query so that the first
  3900. column returned has unique values. If there are
  3901. duplicates values in the first column, entries in the
  3902. associative array will be overwritten.
  3903. </para>
  3904. <example id="zend.db.adapter.select.fetchpairs.example">
  3905. <title>Using fetchPairs()</title>
  3906. <programlisting role="php"><![CDATA[
  3907. $db->setFetchMode(Zend_Db::FETCH_OBJ);
  3908. $result = $db->fetchPairs('SELECT bug_id, bug_status FROM bugs');
  3909. echo $result[2];
  3910. ]]>
  3911. </programlisting>
  3912. </example>
  3913. </sect3>
  3914. <sect3 id="zend.db.adapter.select.fetchrow">
  3915. <title>Fetching a Single Row from a Result Set</title>
  3916. <para>
  3917. The
  3918. <code>fetchRow()</code>
  3919. method returns data using the current fetch mode, but it
  3920. returns only the first row fetched from the result set.
  3921. </para>
  3922. <example id="zend.db.adapter.select.fetchrow.example">
  3923. <title>Using fetchRow()</title>
  3924. <programlisting role="php"><![CDATA[
  3925. $db->setFetchMode(Zend_Db::FETCH_OBJ);
  3926. $result = $db->fetchRow('SELECT * FROM bugs WHERE bug_id = 2');
  3927. // note that $result is a single object, not an array of objects
  3928. echo $result->bug_description;
  3929. ]]>
  3930. </programlisting>
  3931. </example>
  3932. </sect3>
  3933. <sect3 id="zend.db.adapter.select.fetchone">
  3934. <title>Fetching a Single Scalar from a Result Set</title>
  3935. <para>
  3936. The
  3937. <code>fetchOne()</code>
  3938. method is like a combination of
  3939. <code>fetchRow()</code>
  3940. with
  3941. <code>fetchCol()</code>
  3942. , in that it returns data only for the first row fetched
  3943. from the result set, and it returns only the value of
  3944. the first column in that row. Therefore it returns only
  3945. a single scalar value, not an array or an object.
  3946. </para>
  3947. <example id="zend.db.adapter.select.fetchone.example">
  3948. <title>Using fetchOne()</title>
  3949. <programlisting role="php"><![CDATA[
  3950. $result = $db->fetchOne('SELECT bug_status FROM bugs WHERE bug_id = 2');
  3951. // this is a single string value
  3952. echo $result;
  3953. ]]>
  3954. </programlisting>
  3955. </example>
  3956. </sect3>
  3957. </sect2>
  3958. <sect2 id="zend.db.adapter.write">
  3959. <title>Writing Changes to the Database</title>
  3960. <para>
  3961. You can use the Adapter class to write new data or change
  3962. existing data in your database. This section describes
  3963. methods to do these operations.
  3964. </para>
  3965. <sect3 id="zend.db.adapter.write.insert">
  3966. <title>Inserting Data</title>
  3967. <para>
  3968. You can add new rows to a table in your database using
  3969. the
  3970. <code>insert()</code>
  3971. method. The first argument is a string that names the
  3972. table, and the second argument is an associative array,
  3973. mapping column names to data values.
  3974. </para>
  3975. <example id="zend.db.adapter.write.insert.example">
  3976. <title>Inserting to a table</title>
  3977. <programlisting role="php"><![CDATA[
  3978. $data = array(
  3979. 'created_on' => '2007-03-22',
  3980. 'bug_description' => 'Something wrong',
  3981. 'bug_status' => 'NEW'
  3982. );
  3983. $db->insert('bugs', $data);
  3984. ]]>
  3985. </programlisting>
  3986. </example>
  3987. <para>
  3988. Columns you exclude from the array of data are not
  3989. specified to the database. Therefore, they follow the
  3990. same rules that an SQL INSERT statement follows: if the
  3991. column has a DEFAULT clause, the column takes that value
  3992. in the row created, otherwise the column is left in a
  3993. NULL state.
  3994. </para>
  3995. <para>
  3996. By default, the values in your data array are inserted
  3997. using parameters. This reduces risk of some types of
  3998. security issues. You don't need to apply escaping or
  3999. quoting to values in the data array.
  4000. </para>
  4001. <para>
  4002. You might need values in the data array to be treated as
  4003. SQL expressions, in which case they should not be
  4004. quoted. By default, all data values passed as strings
  4005. are treated as string literals. To specify that the
  4006. value is an SQL expression and therefore should not be
  4007. quoted, pass the value in the data array as an object of
  4008. type Zend_Db_Expr instead of a plain string.
  4009. </para>
  4010. <example id="zend.db.adapter.write.insert.example2">
  4011. <title>Inserting expressions to a table</title>
  4012. <programlisting role="php"><![CDATA[
  4013. $data = array(
  4014. 'created_on' => new Zend_Db_Expr('CURDATE()'),
  4015. 'bug_description' => 'Something wrong',
  4016. 'bug_status' => 'NEW'
  4017. );
  4018. $db->insert('bugs', $data);
  4019. ]]>
  4020. </programlisting>
  4021. </example>
  4022. </sect3>
  4023. <sect3 id="zend.db.adapter.write.lastinsertid">
  4024. <title>Retrieving a Generated Value</title>
  4025. <para>
  4026. Some RDBMS brands support auto-incrementing primary
  4027. keys. A table defined this way generates a primary key
  4028. value automatically during an INSERT of a new row. The
  4029. return value of the
  4030. <code>insert()</code>
  4031. method is
  4032. <emphasis>not</emphasis>
  4033. the last inserted ID, because the table might not have
  4034. an auto-incremented column. Instead, the return value is
  4035. the number of rows affected (usually 1).
  4036. </para>
  4037. <para>
  4038. If your table is defined with an auto-incrementing
  4039. primary key, you can call the
  4040. <code>lastInsertId()</code>
  4041. method after the insert. This method returns the last
  4042. value generated in the scope of the current database
  4043. connection.
  4044. </para>
  4045. <example id="zend.db.adapter.write.lastinsertid.example-1">
  4046. <title>
  4047. Using lastInsertId() for an auto-increment key
  4048. </title>
  4049. <programlisting role="php"><![CDATA[
  4050. $db->insert('bugs', $data);
  4051. // return the last value generated by an auto-increment column
  4052. $id = $db->lastInsertId();
  4053. ]]>
  4054. </programlisting>
  4055. </example>
  4056. <para>
  4057. Some RDBMS brands support a sequence object, which
  4058. generates unique values to serve as primary key values.
  4059. To support sequences, the
  4060. <code>lastInsertId()</code>
  4061. method accepts two optional string arguments. These
  4062. arguments name the table and the column, assuming you
  4063. have followed the convention that a sequence is named
  4064. using the table and column names for which the sequence
  4065. generates values, and a suffix "_seq". This is based on
  4066. the convention used by PostgreSQL when naming sequences
  4067. for SERIAL columns. For example, a table "bugs" with
  4068. primary key column "bug_id" would use a sequence named
  4069. "bugs_bug_id_seq".
  4070. </para>
  4071. <example id="zend.db.adapter.write.lastinsertid.example-2">
  4072. <title>Using lastInsertId() for a sequence</title>
  4073. <programlisting role="php"><![CDATA[
  4074. $db->insert('bugs', $data);
  4075. // return the last value generated by sequence 'bugs_bug_id_seq'.
  4076. $id = $db->lastInsertId('bugs', 'bug_id');
  4077. // alternatively, return the last value generated by sequence 'bugs_seq'.
  4078. $id = $db->lastInsertId('bugs');
  4079. ]]>
  4080. </programlisting>
  4081. </example>
  4082. <para>
  4083. If the name of your sequence object does not follow this
  4084. naming convention, use the
  4085. <code>lastSequenceId()</code>
  4086. method instead. This method takes a single string
  4087. argument, naming the sequence literally.
  4088. </para>
  4089. <example id="zend.db.adapter.write.lastinsertid.example-3">
  4090. <title>Using lastSequenceId()</title>
  4091. <programlisting role="php"><![CDATA[
  4092. $db->insert('bugs', $data);
  4093. // return the last value generated by sequence 'bugs_id_gen'.
  4094. $id = $db->lastSequenceId('bugs_id_gen');
  4095. ]]>
  4096. </programlisting>
  4097. </example>
  4098. <para>
  4099. For RDBMS brands that don't support sequences, including
  4100. MySQL, Microsoft SQL Server, and SQLite, the arguments
  4101. to the lastInsertId() method are ignored, and the value
  4102. returned is the most recent value generated for any
  4103. table by INSERT operations during the current
  4104. connection. For these RDBMS brands, the lastSequenceId()
  4105. method always returns
  4106. <code>null</code>
  4107. .
  4108. </para>
  4109. <note>
  4110. <title>Why not use "SELECT MAX(id) FROM table"?</title>
  4111. <para>
  4112. Sometimes this query returns the most recent primary
  4113. key value inserted into the table. However, this
  4114. technique is not safe to use in an environment where
  4115. multiple clients are inserting records to the
  4116. database. It is possible, and therefore is bound to
  4117. happen eventually, that another client inserts
  4118. another row in the instant between the insert
  4119. performed by your client application and your query
  4120. for the MAX(id) value. Thus the value returned does
  4121. not identify the row you inserted, it identifies the
  4122. row inserted by some other client. There is no way
  4123. to know when this has happened.
  4124. </para>
  4125. <para>
  4126. Using a strong transaction isolation mode such as
  4127. "repeatable read" can mitigate this risk, but some
  4128. RDBMS brands don't support the transaction isolation
  4129. required for this, or else your application may use
  4130. a lower transaction isolation mode by design.
  4131. </para>
  4132. <para>
  4133. Furthermore, using an expression like "MAX(id)+1" to
  4134. generate a new value for a primary key is not safe,
  4135. because two clients could do this query
  4136. simultaneously, and then both use the same
  4137. calculated value for their next INSERT operation.
  4138. </para>
  4139. <para>
  4140. All RDBMS brands provide mechanisms to generate
  4141. unique values, and to return the last value
  4142. generated. These mechanisms necessarily work outside
  4143. of the scope of transaction isolation, so there is
  4144. no chance of two clients generating the same value,
  4145. and there is no chance that the value generated by
  4146. another client could be reported to your client's
  4147. connection as the last value generated.
  4148. </para>
  4149. </note>
  4150. </sect3>
  4151. <sect3 id="zend.db.adapter.write.update">
  4152. <title>Updating Data</title>
  4153. <para>
  4154. You can update rows in a database table using the
  4155. <code>update()</code>
  4156. method of an Adapter. This method takes three arguments:
  4157. the first is the name of the table; the second is an
  4158. associative array mapping columns to change to new
  4159. values to assign to these columns.
  4160. </para>
  4161. <para>
  4162. The values in the data array are treated as string
  4163. literals. See
  4164. <xref linkend="zend.db.adapter.write.insert"/>
  4165. for information on using SQL expressions in the data
  4166. array.
  4167. </para>
  4168. <para>
  4169. The third argument is a string containing an SQL
  4170. expression that is used as criteria for the rows to
  4171. change. The values and identifiers in this argument are
  4172. not quoted or escaped. You are responsible for ensuring
  4173. that any dynamic content is interpolated into this
  4174. string safely. See
  4175. <xref linkend="zend.db.adapter.quoting"/>
  4176. for methods to help you do this.
  4177. </para>
  4178. <para>
  4179. The return value is the number of rows affected by the
  4180. update operation.
  4181. </para>
  4182. <example id="zend.db.adapter.write.update.example">
  4183. <title>Updating rows</title>
  4184. <programlisting role="php"><![CDATA[
  4185. $data = array(
  4186. 'updated_on' => '2007-03-23',
  4187. 'bug_status' => 'FIXED'
  4188. );
  4189. $n = $db->update('bugs', $data, 'bug_id = 2');
  4190. ]]>
  4191. </programlisting>
  4192. </example>
  4193. <para>
  4194. If you omit the third argument, then all rows in the
  4195. database table are updated with the values specified in
  4196. the data array.
  4197. </para>
  4198. <para>
  4199. If you provide an array of strings as the third
  4200. argument, these strings are joined together as terms in
  4201. an expression separated by
  4202. <code>AND</code>
  4203. operators.
  4204. </para>
  4205. <example id="zend.db.adapter.write.update.example-array">
  4206. <title>
  4207. Updating rows using an array of expressions
  4208. </title>
  4209. <programlisting role="php"><![CDATA[
  4210. $data = array(
  4211. 'updated_on' => '2007-03-23',
  4212. 'bug_status' => 'FIXED'
  4213. );
  4214. $where[] = "reported_by = 'goofy'";
  4215. $where[] = "bug_status = 'OPEN'";
  4216. $n = $db->update('bugs', $data, $where);
  4217. // Resulting SQL is:
  4218. // UPDATE "bugs" SET "update_on" = '2007-03-23', "bug_status" = 'FIXED'
  4219. // WHERE ("reported_by" = 'goofy') AND ("bug_status" = 'OPEN')
  4220. ]]>
  4221. </programlisting>
  4222. </example>
  4223. </sect3>
  4224. <sect3 id="zend.db.adapter.write.delete">
  4225. <title>Deleting Data</title>
  4226. <para>
  4227. You can delete rows from a database table using the
  4228. <code>delete()</code>
  4229. method. This method takes two arguments: the first is a
  4230. string naming the table.
  4231. </para>
  4232. <para>
  4233. The second argument is a string containing an SQL
  4234. expression that is used as criteria for the rows to
  4235. delete. The values and identifiers in this argument are
  4236. not quoted or escaped. You are responsible for ensuring
  4237. that any dynamic content is interpolated into this
  4238. string safely. See
  4239. <xref linkend="zend.db.adapter.quoting"/>
  4240. for methods to help you do this.
  4241. </para>
  4242. <para>
  4243. The return value is the number of rows affected by the
  4244. delete operation.
  4245. </para>
  4246. <example id="zend.db.adapter.write.delete.example">
  4247. <title>Deleting rows</title>
  4248. <programlisting role="php"><![CDATA[
  4249. $n = $db->delete('bugs', 'bug_id = 3');
  4250. ]]>
  4251. </programlisting>
  4252. </example>
  4253. <para>
  4254. If you omit the second argument, the result is that all
  4255. rows in the database table are deleted.
  4256. </para>
  4257. <para>
  4258. If you provide an array of strings as the second
  4259. argument, these strings are joined together as terms in
  4260. an expression separated by
  4261. <code>AND</code>
  4262. operators.
  4263. </para>
  4264. </sect3>
  4265. </sect2>
  4266. <sect2 id="zend.db.adapter.quoting">
  4267. <title>Quoting Values and Identifiers</title>
  4268. <para>
  4269. When you form SQL queries, often it is the case that you
  4270. need to include the values of PHP variables in SQL
  4271. expressions. This is risky, because if the value in a PHP
  4272. string contains certain symbols, such as the quote symbol,
  4273. it could result in invalid SQL. For example, notice the
  4274. imbalanced quote characters in the following query:
  4275. <programlisting role="php"><![CDATA[
  4276. $name = "O'Reilly";
  4277. $sql = "SELECT * FROM bugs WHERE reported_by = '$name'";
  4278. echo $sql;
  4279. // SELECT * FROM bugs WHERE reported_by = 'O'Reilly'
  4280. ]]>
  4281. </programlisting>
  4282. </para>
  4283. <para>
  4284. Even worse is the risk that such code mistakes might be
  4285. exploited deliberately by a person who is trying to
  4286. manipulate the function of your web application. If they can
  4287. specify the value of a PHP variable through the use of an
  4288. HTTP parameter or other mechanism, they might be able to
  4289. make your SQL queries do things that you didn't intend them
  4290. to do, such as return data to which the person should not
  4291. have privilege to read. This is a serious and widespread
  4292. technique for violating application security, known as "SQL
  4293. Injection" (see
  4294. <ulink url="http://en.wikipedia.org/wiki/SQL_Injection">
  4295. http://en.wikipedia.org/wiki/SQL_Injection
  4296. </ulink>
  4297. ).
  4298. </para>
  4299. <para>
  4300. The Zend_Db Adapter class provides convenient functions to
  4301. help you reduce vulnerabilities to SQL Injection attacks in
  4302. your PHP code. The solution is to escape special characters
  4303. such as quotes in PHP values before they are interpolated
  4304. into your SQL strings. This protects against both accidental
  4305. and deliberate manipulation of SQL strings by PHP variables
  4306. that contain special characters.
  4307. </para>
  4308. <sect3 id="zend.db.adapter.quoting.quote">
  4309. <title>
  4310. Using
  4311. <code>quote()</code>
  4312. </title>
  4313. <para>
  4314. The
  4315. <code>quote()</code>
  4316. method accepts a single argument, a scalar string value.
  4317. It returns the value with special characters escaped in
  4318. a manner appropriate for the RDBMS you are using, and
  4319. surrounded by string value delimiters. The standard SQL
  4320. string value delimiter is the single-quote (
  4321. <code>'</code>
  4322. ).
  4323. </para>
  4324. <example id="zend.db.adapter.quoting.quote.example">
  4325. <title>Using quote()</title>
  4326. <programlisting role="php"><![CDATA[
  4327. $name = $db->quote("O'Reilly");
  4328. echo $name;
  4329. // 'O\'Reilly'
  4330. $sql = "SELECT * FROM bugs WHERE reported_by = $name";
  4331. echo $sql;
  4332. // SELECT * FROM bugs WHERE reported_by = 'O\'Reilly'
  4333. ]]>
  4334. </programlisting>
  4335. </example>
  4336. <para>
  4337. Note that the return value of
  4338. <code>quote()</code>
  4339. includes the quote delimiters around the string. This is
  4340. different from some functions that escape special
  4341. characters but do not add the quote delimiters, for
  4342. example
  4343. <ulink url="http://www.php.net/mysqli_real_escape_string">
  4344. mysql_real_escape_string()
  4345. </ulink>
  4346. .
  4347. </para>
  4348. <para>
  4349. Values may need to be quoted or not quoted according to
  4350. the SQL datatype context in which they are used. For
  4351. instance, in some RDBMS brands, an integer value must
  4352. not be quoted as a string if it is compared to an
  4353. integer-type column or expression. In other words, the
  4354. following is an error in some SQL implementations,
  4355. assuming
  4356. <code>intColumn</code>
  4357. has a SQL datatype of
  4358. <code>INTEGER</code>
  4359. <programlisting role="php"><![CDATA[
  4360. SELECT * FROM atable WHERE intColumn = '123'
  4361. ]]>
  4362. </programlisting>
  4363. </para>
  4364. <para>
  4365. You can use the optional second argument to the
  4366. <code>quote()</code>
  4367. method to apply quoting selectively for the SQL datatype
  4368. you specify.
  4369. </para>
  4370. <example id="zend.db.adapter.quoting.quote.example-2">
  4371. <title>Using quote() with a SQL type</title>
  4372. <programlisting role="php"><![CDATA[
  4373. $value = '1234';
  4374. $sql = 'SELECT * FROM atable WHERE intColumn = '
  4375. . $db->quote($value, 'INTEGER');
  4376. ]]>
  4377. </programlisting>
  4378. </example>
  4379. <para>
  4380. Each Zend_Db_Adapter class has encoded the names of
  4381. numeric SQL datatypes for the respective brand of RDBMS.
  4382. You can also use the constants
  4383. <code>Zend_Db::INT_TYPE</code>
  4384. ,
  4385. <code>Zend_Db::BIGINT_TYPE</code>
  4386. , and
  4387. <code>Zend_Db::FLOAT_TYPE</code>
  4388. to write code in a more RDBMS-independent way.
  4389. </para>
  4390. <para>
  4391. Zend_Db_Table specifies SQL types to
  4392. <code>quote()</code>
  4393. automatically when generating SQL queries that reference
  4394. a table's key columns.
  4395. </para>
  4396. </sect3>
  4397. <sect3 id="zend.db.adapter.quoting.quote-into">
  4398. <title>
  4399. Using
  4400. <code>quoteInto()</code>
  4401. </title>
  4402. <para>
  4403. The most typical usage of quoting is to interpolate a
  4404. PHP variable into a SQL expression or statement. You can
  4405. use the
  4406. <code>quoteInto()</code>
  4407. method to do this in one step. This method takes two
  4408. arguments: the first argument is a string containing a
  4409. placeholder symbol (
  4410. <code>?</code>
  4411. ), and the second argument is a value or PHP variable
  4412. that should be substituted for that placeholder.
  4413. </para>
  4414. <para>
  4415. The placeholder symbol is the same symbol used by many
  4416. RDBMS brands for positional parameters, but the
  4417. <code>quoteInto()</code>
  4418. method only emulates query parameters. The method simply
  4419. interpolates the value into the string, escapes special
  4420. characters, and applies quotes around it. True query
  4421. parameters maintain the separation between the SQL
  4422. string and the parameters as the statement is parsed in
  4423. the RDBMS server.
  4424. </para>
  4425. <example id="zend.db.adapter.quoting.quote-into.example">
  4426. <title>Using quoteInto()</title>
  4427. <programlisting role="php"><![CDATA[
  4428. $sql = $db->quoteInto("SELECT * FROM bugs WHERE reported_by = ?", "O'Reilly");
  4429. echo $sql;
  4430. // SELECT * FROM bugs WHERE reported_by = 'O\'Reilly'
  4431. ]]>
  4432. </programlisting>
  4433. </example>
  4434. <para>
  4435. You can use the optional third parameter of
  4436. <code>quoteInto()</code>
  4437. to specify the SQL datatype. Numeric datatypes are not
  4438. quoted, and other types are quoted.
  4439. </para>
  4440. <example id="zend.db.adapter.quoting.quote-into.example-2">
  4441. <title>Using quoteInto() with a SQL type</title>
  4442. <programlisting role="php"><![CDATA[
  4443. $sql = $db
  4444. ->quoteInto("SELECT * FROM bugs WHERE bug_id = ?", '1234', 'INTEGER');
  4445. echo $sql;
  4446. // SELECT * FROM bugs WHERE reported_by = 1234
  4447. ]]>
  4448. </programlisting>
  4449. </example>
  4450. </sect3>
  4451. <sect3 id="zend.db.adapter.quoting.quote-identifier">
  4452. <title>
  4453. Using
  4454. <code>quoteIdentifier()</code>
  4455. </title>
  4456. <para>
  4457. Values are not the only part of SQL syntax that might
  4458. need to be variable. If you use PHP variables to name
  4459. tables, columns, or other identifiers in your SQL
  4460. statements, you might need to quote these strings too.
  4461. By default, SQL identifiers have syntax rules like PHP
  4462. and most other programming languages. For example,
  4463. identifiers should not contain spaces, certain
  4464. punctuation or special characters, or international
  4465. characters. Also certain words are reserved for SQL
  4466. syntax, and should not be used as identifiers.
  4467. </para>
  4468. <para>
  4469. However, SQL has a feature called
  4470. <emphasis>delimited identifiers</emphasis>
  4471. , which allows broader choices for the spelling of
  4472. identifiers. If you enclose a SQL identifier in the
  4473. proper types of quotes, you can use identifiers with
  4474. spellings that would be invalid without the quotes.
  4475. Delimited identifiers can contain spaces, punctuation,
  4476. or international characters. You can also use SQL
  4477. reserved words if you enclose them in identifier
  4478. delimiters.
  4479. </para>
  4480. <para>
  4481. The
  4482. <code>quoteIdentifier()</code>
  4483. method works like
  4484. <code>quote()</code>
  4485. , but it applies the identifier delimiter characters to
  4486. the string according to the type of Adapter you use. For
  4487. example, standard SQL uses double-quotes (
  4488. <code>"</code>
  4489. ) for identifier delimiters, and most RDBMS brands use
  4490. that symbol. MySQL uses back-quotes (
  4491. <code>`</code>
  4492. ) by default. The
  4493. <code>quoteIdentifier()</code>
  4494. method also escapes special characters within the string
  4495. argument.
  4496. </para>
  4497. <example id="zend.db.adapter.quoting.quote-identifier.example">
  4498. <title>Using quoteIdentifier()</title>
  4499. <programlisting role="php"><![CDATA[
  4500. // we might have a table name that is an SQL reserved word
  4501. $tableName = $db->quoteIdentifier("order");
  4502. $sql = "SELECT * FROM $tableName";
  4503. echo $sql
  4504. // SELECT * FROM "order"
  4505. ]]>
  4506. </programlisting>
  4507. </example>
  4508. <para>
  4509. SQL delimited identifiers are case-sensitive, unlike
  4510. unquoted identifiers. Therefore, if you use delimited
  4511. identifiers, you must use the spelling of the identifier
  4512. exactly as it is stored in your schema, including the
  4513. case of the letters.
  4514. </para>
  4515. <para>
  4516. In most cases where SQL is generated within Zend_Db
  4517. classes, the default is that all identifiers are
  4518. delimited automatically. You can change this behavior
  4519. with the option
  4520. <code>Zend_Db::AUTO_QUOTE_IDENTIFIERS</code>
  4521. . Specify this when instantiating the Adapter. See
  4522. <xref linkend="zend.db.adapter.connecting.parameters.example2"/>
  4523. .
  4524. </para>
  4525. </sect3>
  4526. </sect2>
  4527. <sect2 id="zend.db.adapter.transactions">
  4528. <title>Controlling Database Transactions</title>
  4529. <para>
  4530. Databases define transactions as logical units of work that
  4531. can be committed or rolled back as a single change, even if
  4532. they operate on multiple tables. All queries to a database
  4533. are executed within the context of a transaction, even if
  4534. the database driver manages them implicitly. This is called
  4535. <emphasis>auto-commit</emphasis>
  4536. mode, in which the database driver creates a transaction for
  4537. every statement you execute, and commits that transaction
  4538. after your SQL statement has been executed. By default, all
  4539. Zend_Db Adapter classes operate in auto-commit mode.
  4540. </para>
  4541. <para>
  4542. Alternatively, you can specify the beginning and resolution
  4543. of a transaction, and thus control how many SQL queries are
  4544. included in a single group that is committed (or rolled
  4545. back) as a single operation. Use the
  4546. <code>beginTransaction()</code>
  4547. method to initiate a transaction. Subsequent SQL statements
  4548. are executed in the context of the same transaction until
  4549. you resolve it explicitly.
  4550. </para>
  4551. <para>
  4552. To resolve the transaction, use either the
  4553. <code>commit()</code>
  4554. or
  4555. <code>rollBack()</code>
  4556. methods. The
  4557. <code>commit()</code>
  4558. method marks changes made during your transaction as
  4559. committed, which means the effects of these changes are
  4560. shown in queries run in other transactions.
  4561. </para>
  4562. <para>
  4563. The
  4564. <code>rollBack()</code>
  4565. method does the opposite: it discards the changes made
  4566. during your transaction. The changes are effectively undone,
  4567. and the state of the data returns to how it was before you
  4568. began your transaction. However, rolling back your
  4569. transaction has no effect on changes made by other
  4570. transactions running concurrently.
  4571. </para>
  4572. <para>
  4573. After you resolve this transaction,
  4574. <code>Zend_Db_Adapter</code>
  4575. returns to auto-commit mode until you call
  4576. <code>beginTransaction()</code>
  4577. again.
  4578. </para>
  4579. <example id="zend.db.adapter.transactions.example">
  4580. <title>Managing a transaction to ensure consistency</title>
  4581. <programlisting role="php"><![CDATA[
  4582. // Start a transaction explicitly.
  4583. $db->beginTransaction();
  4584. try {
  4585. // Attempt to execute one or more queries:
  4586. $db->query(...);
  4587. $db->query(...);
  4588. $db->query(...);
  4589. // If all succeed, commit the transaction and all changes
  4590. // are committed at once.
  4591. $db->commit();
  4592. } catch (Exception $e) {
  4593. // If any of the queries failed and threw an exception,
  4594. // we want to roll back the whole transaction, reversing
  4595. // changes made in the transaction, even those that succeeded.
  4596. // Thus all changes are committed together, or none are.
  4597. $db->rollBack();
  4598. echo $e->getMessage();
  4599. }
  4600. ]]>
  4601. </programlisting>
  4602. </example>
  4603. </sect2>
  4604. <sect2 id="zend.db.adapter.list-describe">
  4605. <title>Listing and Describing Tables</title>
  4606. <para>
  4607. The
  4608. <code>listTables()</code>
  4609. method returns an array of strings, naming all tables in the
  4610. current database.
  4611. </para>
  4612. <para>
  4613. The
  4614. <code>describeTable()</code>
  4615. method returns an associative array of metadata about a
  4616. table. Specify the name of the table as a string in the
  4617. first argument to this method. The second argument is
  4618. optional, and names the schema in which the table exists.
  4619. </para>
  4620. <para>
  4621. The keys of the associative array returned are the column
  4622. names of the table. The value corresponding to each column
  4623. is also an associative array, with the following keys and
  4624. values:
  4625. </para>
  4626. <table frame="all" cellpadding="5" id="zend.db.adapter.list-describe.metadata">
  4627. <title>Metadata fields returned by describeTable()</title>
  4628. <tgroup cols="3" align="left" colsep="1" rowsep="1">
  4629. <thead>
  4630. <row>
  4631. <entry>Key</entry>
  4632. <entry>Type</entry>
  4633. <entry>Description</entry>
  4634. </row>
  4635. </thead>
  4636. <tbody>
  4637. <row>
  4638. <entry>SCHEMA_NAME</entry>
  4639. <entry>(string)</entry>
  4640. <entry>
  4641. Name of the database schema in which this
  4642. table exists.
  4643. </entry>
  4644. </row>
  4645. <row>
  4646. <entry>TABLE_NAME</entry>
  4647. <entry>(string)</entry>
  4648. <entry>
  4649. Name of the table to which this column
  4650. belongs.
  4651. </entry>
  4652. </row>
  4653. <row>
  4654. <entry>COLUMN_NAME</entry>
  4655. <entry>(string)</entry>
  4656. <entry>Name of the column.</entry>
  4657. </row>
  4658. <row>
  4659. <entry>COLUMN_POSITION</entry>
  4660. <entry>(integer)</entry>
  4661. <entry>
  4662. Ordinal position of the column in the table.
  4663. </entry>
  4664. </row>
  4665. <row>
  4666. <entry>DATA_TYPE</entry>
  4667. <entry>(string)</entry>
  4668. <entry>
  4669. RDBMS name of the datatype of the column.
  4670. </entry>
  4671. </row>
  4672. <row>
  4673. <entry>DEFAULT</entry>
  4674. <entry>(string)</entry>
  4675. <entry>
  4676. Default value for the column, if any.
  4677. </entry>
  4678. </row>
  4679. <row>
  4680. <entry>NULLABLE</entry>
  4681. <entry>(boolean)</entry>
  4682. <entry>
  4683. True if the column accepts SQL NULLs, false
  4684. if the column has a NOT NULL constraint.
  4685. </entry>
  4686. </row>
  4687. <row>
  4688. <entry>LENGTH</entry>
  4689. <entry>(integer)</entry>
  4690. <entry>
  4691. Length or size of the column as reported by
  4692. the RDBMS.
  4693. </entry>
  4694. </row>
  4695. <row>
  4696. <entry>SCALE</entry>
  4697. <entry>(integer)</entry>
  4698. <entry>
  4699. Scale of SQL NUMERIC or DECIMAL type.
  4700. </entry>
  4701. </row>
  4702. <row>
  4703. <entry>PRECISION</entry>
  4704. <entry>(integer)</entry>
  4705. <entry>
  4706. Precision of SQL NUMERIC or DECIMAL type.
  4707. </entry>
  4708. </row>
  4709. <row>
  4710. <entry>UNSIGNED</entry>
  4711. <entry>(boolean)</entry>
  4712. <entry>
  4713. True if an integer-based type is reported as
  4714. UNSIGNED.
  4715. </entry>
  4716. </row>
  4717. <row>
  4718. <entry>PRIMARY</entry>
  4719. <entry>(boolean)</entry>
  4720. <entry>
  4721. True if the column is part of the primary
  4722. key of this table.
  4723. </entry>
  4724. </row>
  4725. <row>
  4726. <entry>PRIMARY_POSITION</entry>
  4727. <entry>(integer)</entry>
  4728. <entry>
  4729. Ordinal position (1-based) of the column in
  4730. the primary key.
  4731. </entry>
  4732. </row>
  4733. <row>
  4734. <entry>IDENTITY</entry>
  4735. <entry>(boolean)</entry>
  4736. <entry>
  4737. True if the column uses an auto-generated
  4738. value.
  4739. </entry>
  4740. </row>
  4741. </tbody>
  4742. </tgroup>
  4743. </table>
  4744. <note>
  4745. <title>
  4746. How the IDENTITY metadata field relates to specific
  4747. RDBMS
  4748. </title>
  4749. <para>
  4750. The IDENTITY metadata field was chosen as an 'idiomatic'
  4751. term to represent a relation to surrogate keys. This
  4752. field can be commonly known by the following values:-
  4753. </para>
  4754. <itemizedlist>
  4755. <listitem>
  4756. <para>
  4757. <code>IDENTITY</code>
  4758. - DB2, MSSQL
  4759. </para>
  4760. </listitem>
  4761. <listitem>
  4762. <para>
  4763. <code>AUTO_INCREMENT</code>
  4764. - MySQL
  4765. </para>
  4766. </listitem>
  4767. <listitem>
  4768. <para>
  4769. <code>SERIAL</code>
  4770. - PostgreSQL
  4771. </para>
  4772. </listitem>
  4773. <listitem>
  4774. <para>
  4775. <code>SEQUENCE</code>
  4776. - Oracle
  4777. </para>
  4778. </listitem>
  4779. </itemizedlist>
  4780. </note>
  4781. <para>
  4782. If no table exists matching the table name and optional
  4783. schema name specified, then
  4784. <code>describeTable()</code>
  4785. returns an empty array.
  4786. </para>
  4787. </sect2>
  4788. <sect2 id="zend.db.adapter.closing">
  4789. <title>Closing a Connection</title>
  4790. <para>
  4791. Normally it is not necessary to close a database connection.
  4792. PHP automatically cleans up all resources and the end of a
  4793. request. Database extensions are designed to close the
  4794. connection as the reference to the resource object is
  4795. cleaned up.
  4796. </para>
  4797. <para>
  4798. However, if you have a long-duration PHP script that
  4799. initiates many database connections, you might need to close
  4800. the connection, to avoid exhausting the capacity of your
  4801. RDBMS server. You can use the Adapter's
  4802. <code>closeConnection()</code>
  4803. method to explicitly close the underlying database
  4804. connection.
  4805. </para>
  4806. <example id="zend.db.adapter.closing.example">
  4807. <title>Closing a database connection</title>
  4808. <programlisting role="php"><![CDATA[
  4809. $db->closeConnection();
  4810. ]]>
  4811. </programlisting>
  4812. </example>
  4813. <note>
  4814. <title>Does Zend_Db support persistent connections?</title>
  4815. <para>
  4816. The usage of persistent connections is not supported or
  4817. encouraged in Zend_Db.
  4818. </para>
  4819. <para>
  4820. Using persistent connections can cause an excess of idle
  4821. connections on the RDBMS server, which causes more
  4822. problems than any performance gain you might achieve by
  4823. reducing the overhead of making connections.
  4824. </para>
  4825. <para>
  4826. Database connections have state. That is, some objects
  4827. in the RDBMS server exist in session scope. Examples are
  4828. locks, user variables, temporary tables, and information
  4829. about the most recently executed query, such as rows
  4830. affected, and last generated id value. If you use
  4831. persistent connections, your application could access
  4832. invalid or privileged data that were created in a
  4833. previous PHP request.
  4834. </para>
  4835. </note>
  4836. </sect2>
  4837. <sect2 id="zend.db.adapter.other-statements">
  4838. <title>Running Other Database Statements</title>
  4839. <para>
  4840. There might be cases in which you need to access the
  4841. connection object directly, as provided by the PHP database
  4842. extension. Some of these extensions may offer features that
  4843. are not surfaced by methods of Zend_Db_Adapter_Abstract.
  4844. </para>
  4845. <para>
  4846. For example, all SQL statements run by Zend_Db are prepared,
  4847. then executed. However, some database features are
  4848. incompatible with prepared statements. DDL statements like
  4849. CREATE and ALTER cannot be prepared in MySQL. Also, SQL
  4850. statements don't benefit from the
  4851. <ulink url="http://dev.mysql.com/doc/refman/5.1/en/query-cache-how.html">
  4852. MySQL Query Cache
  4853. </ulink>
  4854. , prior to MySQL 5.1.17.
  4855. </para>
  4856. <para>
  4857. Most PHP database extensions provide a method to execute SQL
  4858. statements without preparing them. For example, in PDO, this
  4859. method is
  4860. <code>exec()</code>
  4861. . You can access the connection object in the PHP extension
  4862. directly using getConnection().
  4863. </para>
  4864. <example id="zend.db.adapter.other-statements.example">
  4865. <title>
  4866. Running a non-prepared statement in a PDO adapter
  4867. </title>
  4868. <programlisting role="php"><![CDATA[
  4869. $result = $db->getConnection()->exec('DROP TABLE bugs');
  4870. ]]>
  4871. </programlisting>
  4872. </example>
  4873. <para>
  4874. Similarly, you can access other methods or properties that
  4875. are specific to PHP database extensions. Be aware, though,
  4876. that by doing this you might constrain your application to
  4877. the interface provided by the extension for a specific brand
  4878. of RDBMS.
  4879. </para>
  4880. <para>
  4881. In future versions of Zend_Db, there will be opportunities
  4882. to add method entry points for functionality that is common
  4883. to the supported PHP database extensions. This will not
  4884. affect backward compatibility.
  4885. </para>
  4886. </sect2>
  4887. <sect2 id="zend.db.adapter.adapter-notes">
  4888. <title>Notes on Specific Adapters</title>
  4889. <para>
  4890. This section lists differences between the Adapter classes
  4891. of which you should be aware.
  4892. </para>
  4893. <sect3 id="zend.db.adapter.adapter-notes.ibm-db2">
  4894. <title>IBM DB2</title>
  4895. <itemizedlist>
  4896. <listitem>
  4897. <para>
  4898. Specify this Adapter to the factory() method
  4899. with the name 'Db2'.
  4900. </para>
  4901. </listitem>
  4902. <listitem>
  4903. <para>
  4904. This Adapter uses the PHP extension ibm_db2.
  4905. </para>
  4906. </listitem>
  4907. <listitem>
  4908. <para>
  4909. IBM DB2 supports both sequences and
  4910. auto-incrementing keys. Therefore the arguments
  4911. to
  4912. <code>lastInsertId()</code>
  4913. are optional. If you give no arguments, the
  4914. Adapter returns the last value generated for an
  4915. auto-increment key. If you give arguments, the
  4916. Adapter returns the last value generated by the
  4917. sequence named according to the convention '
  4918. <emphasis>table</emphasis>
  4919. _
  4920. <emphasis>column</emphasis>
  4921. _seq'.
  4922. </para>
  4923. </listitem>
  4924. </itemizedlist>
  4925. </sect3>
  4926. <sect3 id="zend.db.adapter.adapter-notes.mysqli">
  4927. <title>MySQLi</title>
  4928. <itemizedlist>
  4929. <listitem>
  4930. <para>
  4931. Specify this Adapter to the
  4932. <code>factory()</code>
  4933. method with the name 'Mysqli'.
  4934. </para>
  4935. </listitem>
  4936. <listitem>
  4937. <para>
  4938. This Adapter utilizes the PHP extension mysqli.
  4939. </para>
  4940. </listitem>
  4941. <listitem>
  4942. <para>
  4943. MySQL does not support sequences, so
  4944. <code>lastInsertId()</code>
  4945. ignores its arguments and always returns the
  4946. last value generated for an auto-increment key.
  4947. The
  4948. <code>lastSequenceId()</code>
  4949. method returns
  4950. <code>null</code>
  4951. .
  4952. </para>
  4953. </listitem>
  4954. </itemizedlist>
  4955. </sect3>
  4956. <sect3 id="zend.db.adapter.adapter-notes.oracle">
  4957. <title>Oracle</title>
  4958. <itemizedlist>
  4959. <listitem>
  4960. <para>
  4961. Specify this Adapter to the
  4962. <code>factory()</code>
  4963. method with the name 'Oracle'.
  4964. </para>
  4965. </listitem>
  4966. <listitem>
  4967. <para>
  4968. This Adapter uses the PHP extension oci8.
  4969. </para>
  4970. </listitem>
  4971. <listitem>
  4972. <para>
  4973. Oracle does not support auto-incrementing keys,
  4974. so you should specify the name of a sequence to
  4975. <code>lastInsertId()</code>
  4976. or
  4977. <code>lastSequenceId()</code>
  4978. .
  4979. </para>
  4980. </listitem>
  4981. <listitem>
  4982. <para>
  4983. The Oracle extension does not support positional
  4984. parameters. You must use named parameters.
  4985. </para>
  4986. </listitem>
  4987. <listitem>
  4988. <para>
  4989. Currently the
  4990. <code>Zend_Db::CASE_FOLDING</code>
  4991. option is not supported by the Oracle adapter.
  4992. To use this option with Oracle, you must use the
  4993. PDO OCI adapter.
  4994. </para>
  4995. </listitem>
  4996. </itemizedlist>
  4997. </sect3>
  4998. <sect3 id="zend.db.adapter.adapter-notes.pdo-ibm">
  4999. <title>
  5000. PDO for IBM DB2 and Informix Dynamic Server (IDS)
  5001. </title>
  5002. <itemizedlist>
  5003. <listitem>
  5004. <para>
  5005. Specify this Adapter to the
  5006. <code>factory()</code>
  5007. method with the name 'Pdo_Ibm'.
  5008. </para>
  5009. </listitem>
  5010. <listitem>
  5011. <para>
  5012. This Adapter uses the PHP extensions pdo and
  5013. pdo_ibm.
  5014. </para>
  5015. </listitem>
  5016. <listitem>
  5017. <para>
  5018. You must use at least PDO_IBM extension version
  5019. 1.2.2. If you have an earlier version of this
  5020. extension, you must upgrade the PDO_IBM
  5021. extension from PECL.
  5022. </para>
  5023. </listitem>
  5024. </itemizedlist>
  5025. </sect3>
  5026. <sect3 id="zend.db.adapter.adapter-notes.pdo-mssql">
  5027. <title>PDO Microsoft SQL Server</title>
  5028. <itemizedlist>
  5029. <listitem>
  5030. <para>
  5031. Specify this Adapter to the
  5032. <code>factory()</code>
  5033. method with the name 'Pdo_Mssql'.
  5034. </para>
  5035. </listitem>
  5036. <listitem>
  5037. <para>
  5038. This Adapter uses the PHP extensions pdo and
  5039. pdo_mssql.
  5040. </para>
  5041. </listitem>
  5042. <listitem>
  5043. <para>
  5044. Microsoft SQL Server does not support sequences,
  5045. so
  5046. <code>lastInsertId()</code>
  5047. ignores its arguments and always returns the
  5048. last value generated for an auto-increment key.
  5049. The
  5050. <code>lastSequenceId()</code>
  5051. method returns
  5052. <code>null</code>
  5053. .
  5054. </para>
  5055. </listitem>
  5056. <listitem>
  5057. <para>
  5058. If you are working with unicode strings in an
  5059. encoding other than UCS-2 (such as UTF-8), you
  5060. may have to perform a conversion in your
  5061. application code or store the data in a binary
  5062. column. Please refer to
  5063. <ulink url="http://support.microsoft.com/kb/232580">
  5064. Microsoft's Knowledge Base
  5065. </ulink>
  5066. for more information.
  5067. </para>
  5068. </listitem>
  5069. <listitem>
  5070. <para>
  5071. Zend_Db_Adapter_Pdo_Mssql sets
  5072. <code>QUOTED_IDENTIFIER ON</code>
  5073. immediately after connecting to a SQL Server
  5074. database. This makes the driver use the standard
  5075. SQL identifier delimiter symbol (
  5076. <code>"</code>
  5077. ) instead of the proprietary square-brackets
  5078. syntax SQL Server uses for delimiting
  5079. identifiers.
  5080. </para>
  5081. </listitem>
  5082. <listitem>
  5083. <para>
  5084. You can specify
  5085. <code>pdoType</code>
  5086. as a key in the options array. The value can be
  5087. "mssql" (the default), "dblib", "freetds", or
  5088. "sybase". This option affects the DSN prefix the
  5089. adapter uses when constructing the DSN string.
  5090. Both "freetds" and "sybase" imply a prefix of
  5091. "sybase:", which is used for the
  5092. <ulink url="http://www.freetds.org/">
  5093. FreeTDS
  5094. </ulink>
  5095. set of libraries. See also
  5096. <ulink url="http://www.php.net/manual/en/ref.pdo-dblib.connection.php">
  5097. http://www.php.net/manual/en/ref.pdo-dblib.connection.php
  5098. </ulink>
  5099. for more information on the DSN prefixes used in
  5100. this driver.
  5101. </para>
  5102. </listitem>
  5103. </itemizedlist>
  5104. </sect3>
  5105. <sect3 id="zend.db.adapter.adapter-notes.pdo-mysql">
  5106. <title>PDO MySQL</title>
  5107. <itemizedlist>
  5108. <listitem>
  5109. <para>
  5110. Specify this Adapter to the
  5111. <code>factory()</code>
  5112. method with the name 'Pdo_Mysql'.
  5113. </para>
  5114. </listitem>
  5115. <listitem>
  5116. <para>
  5117. This Adapter uses the PHP extensions pdo and
  5118. pdo_mysql.
  5119. </para>
  5120. </listitem>
  5121. <listitem>
  5122. <para>
  5123. MySQL does not support sequences, so
  5124. <code>lastInsertId()</code>
  5125. ignores its arguments and always returns the
  5126. last value generated for an auto-increment key.
  5127. The
  5128. <code>lastSequenceId()</code>
  5129. method returns
  5130. <code>null</code>
  5131. .
  5132. </para>
  5133. </listitem>
  5134. </itemizedlist>
  5135. </sect3>
  5136. <sect3 id="zend.db.adapter.adapter-notes.pdo-oci">
  5137. <title>PDO Oracle</title>
  5138. <itemizedlist>
  5139. <listitem>
  5140. <para>
  5141. Specify this Adapter to the
  5142. <code>factory()</code>
  5143. method with the name 'Pdo_Oci'.
  5144. </para>
  5145. </listitem>
  5146. <listitem>
  5147. <para>
  5148. This Adapter uses the PHP extensions pdo and
  5149. pdo_oci.
  5150. </para>
  5151. </listitem>
  5152. <listitem>
  5153. <para>
  5154. Oracle does not support auto-incrementing keys,
  5155. so you should specify the name of a sequence to
  5156. <code>lastInsertId()</code>
  5157. or
  5158. <code>lastSequenceId()</code>
  5159. .
  5160. </para>
  5161. </listitem>
  5162. </itemizedlist>
  5163. </sect3>
  5164. <sect3 id="zend.db.adapter.adapter-notes.pdo-pgsql">
  5165. <title>PDO PostgreSQL</title>
  5166. <itemizedlist>
  5167. <listitem>
  5168. <para>
  5169. Specify this Adapter to the
  5170. <code>factory()</code>
  5171. method with the name 'Pdo_Pgsql'.
  5172. </para>
  5173. </listitem>
  5174. <listitem>
  5175. <para>
  5176. This Adapter uses the PHP extensions pdo and
  5177. pdo_pgsql.
  5178. </para>
  5179. </listitem>
  5180. <listitem>
  5181. <para>
  5182. PostgreSQL supports both sequences and
  5183. auto-incrementing keys. Therefore the arguments
  5184. to
  5185. <code>lastInsertId()</code>
  5186. are optional. If you give no arguments, the
  5187. Adapter returns the last value generated for an
  5188. auto-increment key. If you give arguments, the
  5189. Adapter returns the last value generated by the
  5190. sequence named according to the convention '
  5191. <emphasis>table</emphasis>
  5192. _
  5193. <emphasis>column</emphasis>
  5194. _seq'.
  5195. </para>
  5196. </listitem>
  5197. </itemizedlist>
  5198. </sect3>
  5199. <sect3 id="zend.db.adapter.adapter-notes.pdo-sqlite">
  5200. <title>PDO SQLite</title>
  5201. <itemizedlist>
  5202. <listitem>
  5203. <para>
  5204. Specify this Adapter to the
  5205. <code>factory()</code>
  5206. method with the name 'Pdo_Sqlite'.
  5207. </para>
  5208. </listitem>
  5209. <listitem>
  5210. <para>
  5211. This Adapter uses the PHP extensions pdo and
  5212. pdo_sqlite.
  5213. </para>
  5214. </listitem>
  5215. <listitem>
  5216. <para>
  5217. SQLite does not support sequences, so
  5218. <code>lastInsertId()</code>
  5219. ignores its arguments and always returns the
  5220. last value generated for an auto-increment key.
  5221. The
  5222. <code>lastSequenceId()</code>
  5223. method returns
  5224. <code>null</code>
  5225. .
  5226. </para>
  5227. </listitem>
  5228. <listitem>
  5229. <para>
  5230. To connect to an SQLite2 database, specify
  5231. <code>'sqlite2'=&gt;true</code>
  5232. in the array of parameters when creating an
  5233. instance of the Pdo_Sqlite Adapter.
  5234. </para>
  5235. </listitem>
  5236. <listitem>
  5237. <para>
  5238. To connect to an in-memory SQLite database,
  5239. specify
  5240. <code>'dbname'=&gt;':memory:'</code>
  5241. in the array of parameters when creating an
  5242. instance of the Pdo_Sqlite Adapter.
  5243. </para>
  5244. </listitem>
  5245. <listitem>
  5246. <para>
  5247. Older versions of the SQLite driver for PHP do
  5248. not seem to support the PRAGMA commands
  5249. necessary to ensure that short column names are
  5250. used in result sets. If you have problems that
  5251. your result sets are returned with keys of the
  5252. form "tablename.columnname" when you do a join
  5253. query, then you should upgrade to the current
  5254. version of PHP.
  5255. </para>
  5256. </listitem>
  5257. </itemizedlist>
  5258. </sect3>
  5259. <sect3 id="zend.db.adapter.adapter-notes.firebird">
  5260. <title>Firebird/Interbase</title>
  5261. <itemizedlist>
  5262. <listitem>
  5263. <para>
  5264. This Adapter uses the PHP extension
  5265. php_interbase.
  5266. </para>
  5267. </listitem>
  5268. <listitem>
  5269. <para>
  5270. Firebird/interbase does not support
  5271. auto-incrementing keys, so you should specify
  5272. the name of a sequence to
  5273. <code>lastInsertId()</code>
  5274. or
  5275. <code>lastSequenceId()</code>
  5276. .
  5277. </para>
  5278. </listitem>
  5279. <listitem>
  5280. <para>
  5281. Currently the
  5282. <code>Zend_Db::CASE_FOLDING</code>
  5283. option is not supported by the
  5284. Firebird/interbase adapter. Unquoted identifiers
  5285. are automatically returned in upper case.
  5286. </para>
  5287. </listitem>
  5288. </itemizedlist>
  5289. </sect3>
  5290. </sect2>
  5291. </sect1><!--
  5292. vim:se ts=4 sw=4 et:
  5293. -->
  5294. <sect1 id="zend.db.statement" xml:base="module_specs/Zend_Db_Statement.xml">
  5295. <title>Zend_Db_Statement</title>
  5296. <para>
  5297. Además de algunos métodos convenientes tales como
  5298. <code>fetchAll()</code> e <code>insert()</code> documentados en
  5299. <xref linkend="zend.db.adapter"/>, puede usarse un objeto de declaración
  5300. para obtener más opciones al ejecutar consultas y devolver conjuntos de
  5301. resultados. Esta sección describe cómo obtener una instancia de un
  5302. objeto de declaración y como usar sus métodos.
  5303. </para>
  5304. <para>
  5305. Zend_Db_Statement está basado en el objeto PDOStatement en la extensión
  5306. <ulink url="http://www.php.net/pdo">PHP Data Objects</ulink>.
  5307. </para>
  5308. <sect2 id="zend.db.statement.creating">
  5309. <title>Creando una Declaración</title>
  5310. <para>
  5311. Típicamente, un objeto de declaración statement es devuelto por el
  5312. método <code>query()</code> de la clase de Adaptador de la base de
  5313. datos.
  5314. Este método es un modo general de preparar una declaración SQL.
  5315. El primer parámetro es un string conteniendo la declaración SQL.
  5316. El segundo parámetro (opcional) es un array de valores para
  5317. vincular posiciones de parámetros en el string SQL.
  5318. </para>
  5319. <example id="zend.db.statement.creating.example1">
  5320. <title>Crear un objeto de declaración SQL con query()</title>
  5321. <programlisting role="php"><![CDATA[
  5322. $stmt = $db->query(
  5323. 'SELECT * FROM bugs WHERE reported_by = ? AND bug_status = ?',
  5324. array('goofy', 'FIXED')
  5325. );
  5326. ]]>
  5327. </programlisting>
  5328. </example>
  5329. <para>
  5330. El objeto de declaración corresponde a una declaración SQL que ha
  5331. sido preparada, y ejecutada una vez con valores vinculados
  5332. especificados.
  5333. Si la declaración fue una consulta SELECT u otro tipo de declaración
  5334. que devuelve un conjunto de resultados, ahora estará lista para
  5335. extraer resultados.
  5336. </para>
  5337. <para>
  5338. Puede crear una declaración con su constructor, pero este es un
  5339. uso menos típico. No hay un método factory para crear el objeto,
  5340. así que es necesario cargar una clase de declaración específica y llamar a su constructor.
  5341. Pase el objeto Adaptador como el primer parámetro, y un string
  5342. conteniendo la declaración SQL como el segundo parámetro.
  5343. La declaración es preparada pero no ejecutada.
  5344. </para>
  5345. <example id="zend.db.statement.creating.example2">
  5346. <title>Usando un constructor de declaración SQL</title>
  5347. <programlisting role="php"><![CDATA[
  5348. $sql = 'SELECT * FROM bugs WHERE reported_by = ? AND bug_status = ?';
  5349. $stmt = new Zend_Db_Statement_Mysqli($db, $sql);
  5350. ]]>
  5351. </programlisting>
  5352. </example>
  5353. </sect2>
  5354. <sect2 id="zend.db.statement.executing">
  5355. <title>Ejecutando la declaración</title>
  5356. <para>
  5357. Necesita ejecutar un objeto de declaración si lo crea con el
  5358. constructor, o si desea ejecutar la misma declaración varias veces.
  5359. Use el método <code>execute()</code> del mismo objeto de
  5360. declaración. El único parámetro es un array de valores a vincular a
  5361. posiciones de parámetros en la declaración.
  5362. </para>
  5363. <para>
  5364. Si usa <emphasis>parámetros posicionales</emphasis>, o los que
  5365. están marcados por un signo de interrogación (<code>?</code>), pase
  5366. los valores de vinculación en un array plano.
  5367. </para>
  5368. <example id="zend.db.statement.executing.example1">
  5369. <title>Ejecutar una declaración con parámetros posicionales</title>
  5370. <programlisting role="php"><![CDATA[
  5371. $sql = 'SELECT * FROM bugs WHERE reported_by = ? AND bug_status = ?';
  5372. $stmt = new Zend_Db_Statement_Mysqli($db, $sql);
  5373. $stmt->execute(array('goofy', 'FIXED'));
  5374. ]]>
  5375. </programlisting>
  5376. </example>
  5377. <para>
  5378. Si usa <emphasis>parámetros nombrados</emphasis>, o los que son
  5379. indicados por un string identificador precedido por un caracter de
  5380. dos puntos (<code>:</code>), pase el valor en un array asociativo.
  5381. Las claves de este array deben coincidir con el nombre de los
  5382. parámetros.
  5383. </para>
  5384. <example id="zend.db.statement.executing.example2">
  5385. <title>Ejecutando una declaración con parámetros nombrados</title>
  5386. <programlisting role="php"><![CDATA[
  5387. $sql = 'SELECT * FROM bugs WHERE ' .
  5388. 'reported_by = :reporter AND bug_status = :status';
  5389. $stmt = new Zend_Db_Statement_Mysqli($db, $sql);
  5390. $stmt->execute(array(':reporter' => 'goofy', ':status' => 'FIXED'));
  5391. ]]>
  5392. </programlisting>
  5393. </example>
  5394. <para>
  5395. Las declaraciones PDO soportan tanto parámetros posicionales como
  5396. parámetros nombrados, pero no ambos tipos en la misma declaración
  5397. SQL. Algunas clases Zend_Db_Statement para extensiones no-PDO
  5398. soportan solo un tipo de parámetro o el otro.
  5399. </para>
  5400. </sect2>
  5401. <sect2 id="zend.db.statement.fetching">
  5402. <title>Extrayendo Resultados de una declaración <code>SELECT</code></title>
  5403. <para>
  5404. Puede llamar a métodos del objeto de declaración para obtener filas
  5405. desde declaraciones SQL que producen conjuntos de resultados.
  5406. SELECT, SHOW, DESCRIBE y EXPLAIN son ejemplos de declaraciones que
  5407. producen un conjunto de resultados.
  5408. INSERT, UPDATE, and DELETE son ejemplo de declaraciones que
  5409. no producen un conjunto de resultados.
  5410. Puede ejecutar las últimas declaraciones de SQL usando
  5411. Zend_Db_Statement, pero no puede llamar a los métodos que extraen
  5412. filas de resultados desde este.
  5413. </para>
  5414. <sect3 id="zend.db.statement.fetching.fetch">
  5415. <title>Extrayendo una Fila Simple desde un Conjunto de Resultados</title>
  5416. <para>
  5417. Para extraer una fila desde el conjunto de resultados,
  5418. use el método <code>fetch()</code> del objeto de declaración.
  5419. Los tres parámetros de este método son opcionales:
  5420. </para>
  5421. <itemizedlist>
  5422. <listitem>
  5423. <para>
  5424. <emphasis role="strong">Estilo de Extracción</emphasis>
  5425. es el primer parámetro. Éste controla la estructura
  5426. en la que será devuelta la fila.
  5427. Vea <xref linkend="zend.db.adapter.select.fetch-mode"/>
  5428. para la descripción de un valor válido los
  5429. correspondientes formatos de datos.
  5430. </para>
  5431. </listitem>
  5432. <listitem>
  5433. <para>
  5434. <emphasis role="strong">Orientación del Cursor</emphasis>
  5435. es el segundo parámetro. Por omisión es
  5436. Zend_Db::FETCH_ORI_NEXT, lo cual simplemente significa
  5437. que cada llamada a <code>fetch()</code> devuelve la
  5438. siguiente fila del resultado, en el orden devuelto por
  5439. el RDBMS.
  5440. </para>
  5441. </listitem>
  5442. <listitem>
  5443. <para>
  5444. <emphasis role="strong">Compensación</emphasis> es el
  5445. tercer parámetro.
  5446. Si la orientación del cursor es Zend_Db::FETCH_ORI_ABS,
  5447. entonces el offset es el número ordinal
  5448. de las filas que devolver.
  5449. Si la orientación del cursor es Zend_Db::FETCH_ORI_REL,
  5450. entonces el offset es relativo a la posición del
  5451. cursor antes de que <code>fetch()</code> fuera llamado.
  5452. </para>
  5453. </listitem>
  5454. </itemizedlist>
  5455. <para>
  5456. <code>fetch()</code> devuelve <code>false</code> si todas las filas
  5457. del conjunto de resultados han sido extraídas.
  5458. </para>
  5459. <example id="zend.db.statement.fetching.fetch.example">
  5460. <title>Usando fetch() en un bucle</title>
  5461. <programlisting role="php"><![CDATA[
  5462. $stmt = $db->query('SELECT * FROM bugs');
  5463. while ($row = $stmt->fetch()) {
  5464. echo $row['bug_description'];
  5465. }
  5466. ]]>
  5467. </programlisting>
  5468. </example>
  5469. <para>
  5470. Vea también <ulink url="http://www.php.net/PDOStatement-fetch">PDOStatement::fetch()</ulink>.
  5471. </para>
  5472. </sect3>
  5473. <sect3 id="zend.db.statement.fetching.fetchall">
  5474. <title>Extrayendo un Conjunto de Resultados completo</title>
  5475. <para>
  5476. Para extraer todas las filas de un resultado en un solo paso,
  5477. use el método <code>fetchAll()</code>. Esto es equivalente a
  5478. llamar al método <code>fetch()</code> en un bucle devolviendo
  5479. todas las filas en una array. El método <code>fetchAll()</code>
  5480. acepta 2 parámetros. El primero es el estilo de extracción,
  5481. descrito anteriormente, y el segundo indica el número de la
  5482. columa que devolver, cuando el estilo de extracción es
  5483. Zend_Db::FETCH_COLUMN.
  5484. </para>
  5485. <example id="zend.db.statement.fetching.fetchall.example">
  5486. <title>Usando fetchAll()</title>
  5487. <programlisting role="php"><![CDATA[
  5488. $stmt = $db->query('SELECT * FROM bugs');
  5489. $rows = $stmt->fetchAll();
  5490. echo $rows[0]['bug_description'];
  5491. ]]>
  5492. </programlisting>
  5493. </example>
  5494. <para>
  5495. Vea también <ulink url="http://www.php.net/PDOStatement-fetchAll">PDOStatement::fetchAll()</ulink>.
  5496. </para>
  5497. </sect3>
  5498. <sect3 id="zend.db.statement.fetching.fetch-mode">
  5499. <title>Cambiando el Modo de extracción</title>
  5500. <para>
  5501. Por defecto, el objeto de declaración devuelve filas de un
  5502. conjunto de resultados como array asociativo, mapeando los
  5503. nombres de columnas a los valores de la columna.
  5504. Se puede especificar un formato diferente para que la clase de
  5505. declaración devuelva las filas, tal como se puede con la clase
  5506. Adaptadora. Puede usar él método <code>setFetchMode()</code>
  5507. para establecer el modo de extracción. Especifique el modo de
  5508. extracción usando las constantes de la clase
  5509. Zend_Db: FETCH_ASSOC, FETCH_NUM, FETCH_BOTH,
  5510. FETCH_COLUMN, and FETCH_OBJ.
  5511. Vea <xref linkend="zend.db.adapter.select.fetch-mode"/>
  5512. para más información de estos modos.
  5513. Llamadas subsiguientes a los métodos de la declaración
  5514. <code>fetch()</code> o <code>fetchAll()</code> usan el modo de
  5515. extracción especificado.
  5516. </para>
  5517. <example id="zend.db.statement.fetching.fetch-mode.example">
  5518. <title>Configurando un modo de extracción</title>
  5519. <programlisting role="php"><![CDATA[
  5520. $stmt = $db->query('SELECT * FROM bugs');
  5521. $stmt->setFetchMode(Zend_Db::FETCH_NUM);
  5522. $rows = $stmt->fetchAll();
  5523. echo $rows[0][0];
  5524. ]]>
  5525. </programlisting>
  5526. </example>
  5527. <para>
  5528. Vea también <ulink url="http://www.php.net/PDOStatement-setFetchMode">PDOStatement::setFetchMode()</ulink>.
  5529. </para>
  5530. </sect3>
  5531. <sect3 id="zend.db.statement.fetching.fetchcolumn">
  5532. <title>Extrayendo una Única Columna desde un Conjunto de Resultados</title>
  5533. <para>
  5534. Para devolver una única columna de la siguiente fila del
  5535. conjunto de resultados, use <code>fetchColumn()</code>. El
  5536. parámetro opcional es el índice de la columna (integer), y por
  5537. defecto es 0. Este método devuelve un valor escalar, o
  5538. <code>false</code> si todas las filas del conjunto de resultados
  5539. han sido extraídas.
  5540. </para>
  5541. <para>
  5542. Note que este método opera diferente que el método
  5543. <code>fetchCol()</code> de la clase Adaptadora.
  5544. El método <code>fetchColumn()</code> de una declaración devuelve
  5545. un único valor desde una fila.
  5546. El método <code>fetchCol()</code> de un adaptador devuelve un
  5547. array de valores, tomados desde la primera columa de todas las
  5548. del conjunto de resultados.
  5549. </para>
  5550. <example id="zend.db.statement.fetching.fetchcolumn.example">
  5551. <title>Usando fetchColumn()</title>
  5552. <programlisting role="php"><![CDATA[
  5553. $stmt = $db->query('SELECT bug_id, bug_description, bug_status FROM bugs');
  5554. $bug_status = $stmt->fetchColumn(2);
  5555. ]]>
  5556. </programlisting>
  5557. </example>
  5558. <para>
  5559. Vea también <ulink url="http://www.php.net/PDOStatement-fetchColumn">PDOStatement::fetchColumn()</ulink>.
  5560. </para>
  5561. </sect3>
  5562. <sect3 id="zend.db.statement.fetching.fetchobject">
  5563. <title>Extrayendo una Fila como un Objeto</title>
  5564. <para>
  5565. Para extraer una fila desde un conjunto de resultados
  5566. estructurado como un Objeto, use el método
  5567. <code>fetchObject()</code>. Este método tiene 2 parámetros
  5568. opcionales. El primer parámetro es un string con el nombre de
  5569. la clase del objeto que devolver; por defecto será 'stdClass'. El segundo
  5570. parámetro es un array de valores que serán pasados al
  5571. constructor de la clase.
  5572. </para>
  5573. <example id="zend.db.statement.fetching.fetchobject.example">
  5574. <title>Usando fetchObject()</title>
  5575. <programlisting role="php"><![CDATA[
  5576. $stmt = $db->query('SELECT bug_id, bug_description, bug_status FROM bugs');
  5577. $obj = $stmt->fetchObject();
  5578. echo $obj->bug_description;
  5579. ]]>
  5580. </programlisting>
  5581. </example>
  5582. <para>
  5583. Vea también <ulink url="http://www.php.net/PDOStatement-fetchObject">PDOStatement::fetchObject()</ulink>.
  5584. </para>
  5585. </sect3>
  5586. </sect2>
  5587. <!--
  5588. @todo: binding parameters is not working yet.
  5589. <sect2 id="zend.db.statement.binding-param">
  5590. <title>Binding PHP Variables to Parameters</title>
  5591. <para>
  5592. </para>
  5593. <example id="zend.db.statement.binding-param.example">
  5594. <title>Binding parameters from PHP variables</title>
  5595. <programlisting role="php"><![CDATA[
  5596. <?php
  5597. ]]>
  5598. </programlisting>
  5599. </example>
  5600. <para>
  5601. See also <ulink url="http://www.php.net/PDOStatement-bindParam">PDOStatement::bindParam()</ulink>.
  5602. </para>
  5603. </sect2>
  5604. -->
  5605. <!--
  5606. @todo: binding columns is not working yet.
  5607. <sect2 id="zend.db.statement.binding-column">
  5608. <title>Binding PHP Variables to Query Results</title>
  5609. <para>
  5610. </para>
  5611. <example id="zend.db.statement.binding-column.example">
  5612. <title>Binding results to PHP variables</title>
  5613. <programlisting role="php"><![CDATA[
  5614. <?php
  5615. ]]>
  5616. </programlisting>
  5617. </example>
  5618. <para>
  5619. See also <ulink url="http://www.php.net/PDOStatement-bindColumn">PDOStatement::bindColumn()</ulink>.
  5620. </para>
  5621. </sect2>
  5622. -->
  5623. </sect1>
  5624. <sect1 xmlns:xi="http://www.w3.org/2001/XInclude" id="zend.db.profiler" xml:base="module_specs/Zend_Db_Profiler.xml">
  5625. <title>Zend_Db_Profiler</title>
  5626. <sect2 id="zend.db.profiler.introduction">
  5627. <title>Introducción</title>
  5628. <para>
  5629. <code>Zend_Db_Profiler</code> puede ser habilitado para Perfilar las
  5630. consultas. Los Perfiles incluyen la consulta procesada por el adaptador como
  5631. el tiempo as transcurrido en la ejecución de las consultas, permitiendo
  5632. inspeccionar las consultas realizadas win necesidad de agregar información
  5633. de depuración extra en el código de las clases. El uso avanzado también permite
  5634. que el desarrollador filtre las consultas que desea perfilar.
  5635. </para>
  5636. <para>
  5637. Habilite el perfilador pasando una directiva al al constructor del adaptador,
  5638. o pidiendole al adaptador permitirlo más adelante.
  5639. </para>
  5640. <programlisting role="php"><![CDATA[
  5641. $params = array(
  5642. 'host' => '127.0.0.1',
  5643. 'username' => 'webuser',
  5644. 'password' => 'xxxxxxxx',
  5645. 'dbname' => 'test'
  5646. 'profiler' => true // enciende el perfilador
  5647. // establezca false para deshabilitar (está deshabilitado por defecto)
  5648. );
  5649. $db = Zend_Db::factory('PDO_MYSQL', $params);
  5650. // apagar el perfilador:
  5651. $db->getProfiler()->setEnabled(false);
  5652. // encender el perfilador:
  5653. $db->getProfiler()->setEnabled(true);
  5654. ]]>
  5655. </programlisting>
  5656. <para>
  5657. El valor de la opción '<code>profiler</code>' es flexible. Es interpretada de distintas
  5658. formas dependiendo del tipo. Normalmente, debería usar un valor booleano simple, pero
  5659. otros tipos le permiten personalizar el comportamiento del perfilador.
  5660. </para>
  5661. <para>
  5662. Un argumento booleano establece el perfilador como habilitado si el valor es
  5663. <code>true</code>, o deshabilitado si es <code>false</code>. La clase del perfilador
  5664. es el la clase de perfilador por defecto del adaptador, <code>Zend_Db_Profiler</code>.
  5665. <programlisting role="php"><![CDATA[
  5666. $params['profiler'] = true;
  5667. $db = Zend_Db::factory('PDO_MYSQL', $params);
  5668. ]]>
  5669. </programlisting>
  5670. </para>
  5671. <para>
  5672. Una instancia del objeto perfilador hace que el adaptador use ese objeto.
  5673. El tipo del objeto debe ser <code>Zend_Db_Profiler</code> o una subclase de este.
  5674. Habilitar el perfilador se hace por separado.
  5675. <programlisting role="php"><![CDATA[
  5676. $profiler = MyProject_Db_Profiler();
  5677. $profiler->setEnabled(true);
  5678. $params['profiler'] = $profiler;
  5679. $db = Zend_Db::factory('PDO_MYSQL', $params);
  5680. ]]>
  5681. </programlisting>
  5682. </para>
  5683. <para>
  5684. El argumento puede ser un array asociativo conteniendo algunas o todas las claves
  5685. '<code>enabled</code>', '<code>instance</code>', y '<code>class</code>'. Las claves
  5686. '<code>enabled</code>' e '<code>instance</code>' corresponden a los tipos booleano y
  5687. la instancia documentada previamente. La clave '<code>class</code>' es usada para nombrar
  5688. la clase que usará el perfilador personalizado. La clase debe ser
  5689. <code>Zend_Db_Profiler</code> o una subclase. La clase es instanciada sin argumentos
  5690. de constructor. La opción '<code>class</code>' es ignorada cuando la opción
  5691. '<code>instance</code>' está dada.
  5692. <programlisting role="php"><![CDATA[
  5693. $params['profiler'] = array(
  5694. 'enabled' => true,
  5695. 'class' => 'MyProject_Db_Profiler'
  5696. );
  5697. $db = Zend_Db::factory('PDO_MYSQL', $params);
  5698. ]]>
  5699. </programlisting>
  5700. </para>
  5701. <para>
  5702. Finalmente, el argumento puede ser un objeto de tipo <code>Zend_Config</code>
  5703. conteniendo las propiedades, que son tratadas como las claves de array descritas recién.
  5704. Por ejemplo, un archivo "config.ini" puede contener los siguientes datos:
  5705. <programlisting role="ini"><![CDATA[
  5706. [main]
  5707. db.profiler.class = "MyProject_Db_Profiler"
  5708. db.profiler.enabled = true
  5709. ]]>
  5710. </programlisting>
  5711. Esta configuración puede ser aplicada con el siguiente código PHP:
  5712. <programlisting role="php"><![CDATA[
  5713. $config = new Zend_Config_Ini('config.ini', 'main');
  5714. $params['profiler'] = $config->db->profiler;
  5715. $db = Zend_Db::factory('PDO_MYSQL', $params);
  5716. ]]>
  5717. </programlisting>
  5718. La propiedad '<code>instance</code>' debe ser usada como el siguiente ejemplo:
  5719. <programlisting role="php"><![CDATA[
  5720. $profiler = new MyProject_Db_Profiler();
  5721. $profiler->setEnabled(true);
  5722. $configData = array(
  5723. 'instance' => $profiler
  5724. );
  5725. $config = new Zend_Config($configData);
  5726. $params['profiler'] = $config;
  5727. $db = Zend_Db::factory('PDO_MYSQL', $params);
  5728. ]]>
  5729. </programlisting>
  5730. </para>
  5731. </sect2>
  5732. <sect2 id="zend.db.profiler.using">
  5733. <title>Usando el Perfilador</title>
  5734. <para>
  5735. En este punto, obtenemos el perfilador usando el método
  5736. <code>getProfiler()</code> del adaptador:
  5737. </para>
  5738. <programlisting role="php"><![CDATA[
  5739. $profiler = $db->getProfiler();
  5740. ]]>
  5741. </programlisting>
  5742. <para>
  5743. Este retorna una instancia del objeto <code>Zend_Db_Profiler</code>. Con
  5744. esta instancia, el desarrollador puede examinar las consultar usando una variedad
  5745. de métodos:
  5746. </para>
  5747. <itemizedlist>
  5748. <listitem>
  5749. <para>
  5750. <code>getTotalNumQueries()</code> retorna el número total
  5751. de consultas que han sido perfiladas.
  5752. </para>
  5753. </listitem>
  5754. <listitem>
  5755. <para>
  5756. <code>getTotalElapsedSecs()</code> retorna el número total
  5757. de segundos transcurridos en todas las consultas perfiladas.
  5758. </para>
  5759. </listitem>
  5760. <listitem>
  5761. <para>
  5762. <code>getQueryProfiles()</code> retorna un array con todos
  5763. los perfiles de consultas.
  5764. </para>
  5765. </listitem>
  5766. <listitem>
  5767. <para>
  5768. <code>getLastQueryProfile()</code> retorna el último perfil (más
  5769. reciente) de consulta, independientemente de si la consulta ha
  5770. terminado o no (si no lo ha hecho, la hora de finalización será nula).
  5771. </para>
  5772. </listitem>
  5773. <listitem>
  5774. <para>
  5775. <code>clear()</code> limpia los perfiles de consulta de la pila.
  5776. </para>
  5777. </listitem>
  5778. </itemizedlist>
  5779. <para>
  5780. El valor de retorno de <code>getLastQueryProfile()</code> y
  5781. elementos individuales de <code>getQueryProfiles()</code> son
  5782. <code>Zend_Db_Profiler_Query</code> objetos, que proporcionan la
  5783. capacidad para inspeccionar cada una de las consultas:
  5784. </para>
  5785. <itemizedlist>
  5786. <listitem>
  5787. <para>
  5788. <code>getQuery()</code> retorna el texto SQL de la consulta.
  5789. El texto SQL de una declaración preparada con parámetros es el
  5790. texto al tiempo en que la consulta fué preparada, por lo que contiene
  5791. marcadores de posición, no los valores utilizados cuando la
  5792. declaración se ejecuta.
  5793. </para>
  5794. </listitem>
  5795. <listitem>
  5796. <para>
  5797. <code>getQueryParams()</code> retorna un array de
  5798. los valores de los parámetros usados cuando se ejecuta una consulta preparada.
  5799. Este incluye ambos parámetros y argumentos vinculados al método
  5800. <code>execute()</code> de la declaración. Las claves del array
  5801. son las posiciones (basado en 1) o indices de parámetros nombrados (string).
  5802. </para>
  5803. </listitem>
  5804. <listitem>
  5805. <para>
  5806. <code>getElapsedSecs()</code> returna el número de segundos
  5807. que tuvo la consulta al correr.
  5808. </para>
  5809. </listitem>
  5810. </itemizedlist>
  5811. <para>
  5812. La información que <code>Zend_Db_Profiler</code> provee es útil para
  5813. perfilar cuellos de botella en aplicaciones, y para depurar consultas que
  5814. han sido ejecutadas. Por instancia, para ver la consulta exacta que tuvo la
  5815. última ejecución:
  5816. </para>
  5817. <programlisting role="php"><![CDATA[
  5818. $query = $profiler->getLastQueryProfile();
  5819. echo $query->getQuery();
  5820. ]]>
  5821. </programlisting>
  5822. <para>
  5823. Tal vez una página se genera lentamente; use el perfilador para
  5824. determinar primero el número total de segundos de todas las consultas,
  5825. y luego recorrer paso a paso a través de las consultas para encontrar
  5826. la más lenta:
  5827. </para>
  5828. <programlisting role="php"><![CDATA[
  5829. $totalTime = $profiler->getTotalElapsedSecs();
  5830. $queryCount = $profiler->getTotalNumQueries();
  5831. $longestTime = 0;
  5832. $longestQuery = null;
  5833. foreach ($profiler->getQueryProfiles() as $query) {
  5834. if ($query->getElapsedSecs() > $longestTime) {
  5835. $longestTime = $query->getElapsedSecs();
  5836. $longestQuery = $query->getQuery();
  5837. }
  5838. }
  5839. echo 'Ejecutadas ' . $queryCount . ' consultas en ' . $totalTime .
  5840. ' segundos' . "\n";
  5841. echo 'Promedio de tiempo de consulta: ' . $totalTime / $queryCount .
  5842. ' segundos' . "\n";
  5843. echo 'Consultas por segundo: ' . $queryCount / $totalTime . "\n";
  5844. echo 'Tardanza de la consulta más lenta: ' . $longestTime . "\n";
  5845. echo "Consulta más lenta: \n" . $longestQuery . "\n";
  5846. ]]>
  5847. </programlisting>
  5848. </sect2>
  5849. <sect2 id="zend.db.profiler.advanced">
  5850. <title>Uso avanzado del Perfilador</title>
  5851. <para>
  5852. Además de la inspección de consultas, el perfilador también le permite
  5853. al desarrollador filtrar que consultas serán perfiladas. El siguiente método
  5854. opera en una instancia de <code>Zend_Db_Profiler</code>:
  5855. </para>
  5856. <sect3 id="zend.db.profiler.advanced.filtertime">
  5857. <title>Filtrar por tiempo transcurrido en consulta</title>
  5858. <para>
  5859. <code>setFilterElapsedSecs()</code> le permite al desarrolador establecer
  5860. un tiempo mínimo antes de que una consulta se perfile. Para remover el filtro,
  5861. pase un valor null al método.
  5862. </para>
  5863. <programlisting role="php"><![CDATA[
  5864. // Solo perfilar consultas que tardan más de 5 segundos:
  5865. $profiler->setFilterElapsedSecs(5);
  5866. // Perfilar todas las consultas sin importar el tiempo:
  5867. $profiler->setFilterElapsedSecs(null);
  5868. ]]>
  5869. </programlisting>
  5870. </sect3>
  5871. <sect3 id="zend.db.profiler.advanced.filtertype">
  5872. <title>Filtrar por tipo de consulta</title>
  5873. <para>
  5874. <code>setFilterQueryType()</code> le permite al desarrollador
  5875. establecer que tipo de consulta serán perfiladas; para perfilar multiples tipos,
  5876. use un "OR" lógico. Los tipos de consulta se definen como las siguientes
  5877. constantes de <code>Zend_Db_Profiler</code>:
  5878. </para>
  5879. <itemizedlist>
  5880. <listitem>
  5881. <para>
  5882. <code>Zend_Db_Profiler::CONNECT</code>: operaciones de
  5883. conexión o selección de base de datos.
  5884. </para>
  5885. </listitem>
  5886. <listitem>
  5887. <para>
  5888. <code>Zend_Db_Profiler::QUERY</code>: consultas generales
  5889. a la base de datos que no calzan con otros tipos.
  5890. </para>
  5891. </listitem>
  5892. <listitem>
  5893. <para>
  5894. <code>Zend_Db_Profiler::INSERT</code>: cualquier consulta
  5895. que agrega filas a la base de datos, generalmente un SQL INSERT.
  5896. </para>
  5897. </listitem>
  5898. <listitem>
  5899. <para>
  5900. <code>Zend_Db_Profiler::UPDATE</code>: cualquier consulta que
  5901. actualice registros existentes, usualmente un SQL UPDATE.
  5902. </para>
  5903. </listitem>
  5904. <listitem>
  5905. <para>
  5906. <code>Zend_Db_Profiler::DELETE</code>: cualquier consulta
  5907. que elimine datos existentes, usualmente un SQL DELETE.
  5908. </para>
  5909. </listitem>
  5910. <listitem>
  5911. <para>
  5912. <code>Zend_Db_Profiler::SELECT</code>: cualquier consulta que
  5913. retorne datos existentes, usualmente un SQL SELECT.
  5914. </para>
  5915. </listitem>
  5916. <listitem>
  5917. <para>
  5918. <code>Zend_Db_Profiler::TRANSACTION</code>: cualquier
  5919. operación transaccional, tal como iniciar una transacción, confirmar,
  5920. o revertir.
  5921. </para>
  5922. </listitem>
  5923. </itemizedlist>
  5924. <para>
  5925. Asi como con <code>setFilterElapsedSecs()</code>, puedes remover cualquier filtro
  5926. existente pasando un <code>null</code> como único argumento.
  5927. </para>
  5928. <programlisting role="php"><![CDATA[
  5929. // Perfilar solo consultas SELECT
  5930. $profiler->setFilterQueryType(Zend_Db_Profiler::SELECT);
  5931. // Perfila consultas SELECT, INSERT, y UPDATE
  5932. $profiler->setFilterQueryType(Zend_Db_Profiler::SELECT |
  5933. Zend_Db_Profiler::INSERT |
  5934. Zend_Db_Profiler::UPDATE);
  5935. // Perfilar consultas DELETE
  5936. $profiler->setFilterQueryType(Zend_Db_Profiler::DELETE);
  5937. // Remover todos los filtros
  5938. $profiler->setFilterQueryType(null);
  5939. ]]>
  5940. </programlisting>
  5941. </sect3>
  5942. <sect3 id="zend.db.profiler.advanced.getbytype">
  5943. <title>Obtener perfiles por tipo de consulta</title>
  5944. <para>
  5945. Usando <code>setFilterQueryType()</code> puedes reducir los
  5946. perfiles generados. Sin embargo, a veces puede ser más útil
  5947. mantener todos los perfiles, pero ver sólo los que necesita
  5948. en un determinado momento. Otra característica de
  5949. <code>getQueryProfiles()</code> es que puede este filtrado al-vuelo,
  5950. pasando un tipo de consulta(o una combinación lógica de tipos de consulta)
  5951. en el primer; vea <xref linkend="zend.db.profiler.advanced.filtertype"/>
  5952. para una lista las constantes de tipo de consulta.
  5953. </para>
  5954. <programlisting role="php"><![CDATA[
  5955. // Obtiene solo perfiles de consultas SELECT
  5956. $profiles = $profiler->getQueryProfiles(Zend_Db_Profiler::SELECT);
  5957. // Obtiene los perfiles de consultas SELECT, INSERT, y UPDATE
  5958. $profiles = $profiler->getQueryProfiles(Zend_Db_Profiler::SELECT |
  5959. Zend_Db_Profiler::INSERT |
  5960. Zend_Db_Profiler::UPDATE);
  5961. // Obtiene solo perfiles de consultas DELETE
  5962. $profiles = $profiler->getQueryProfiles(Zend_Db_Profiler::DELETE);
  5963. ]]>
  5964. </programlisting>
  5965. </sect3>
  5966. </sect2>
  5967. <sect2 id="zend.db.profiler.profilers">
  5968. <title>Perfiladores Especializados</title>
  5969. <para>
  5970. Un Perfilador Especializado es un objeto que hereda de
  5971. <code>Zend_Db_Profiler</code>. Los Perfiladores Especializados
  5972. tratan la información de perfilado de maneras más especificas.
  5973. </para>
  5974. <sect3 id="zend.db.profiler.profilers.firebug">
  5975. <title>Perfilando con Firebug</title>
  5976. <para>
  5977. <code>Zend_Db_Profiler_Firebug</code> envía información de
  5978. perfilado a la <ulink url="http://getfirebug.com/logging.html">Consola</ulink> de
  5979. <ulink url="http://www.getfirebug.com/">Firebug</ulink>.
  5980. </para>
  5981. <para>
  5982. Todos los datos son enviados a través del componente
  5983. <code>Zend_Wildfire_Channel_HttpHeaders</code> que usa cabeceras HTTP
  5984. para asegurar que el contenido de la página no sea alterado.
  5985. Depurar peticiones AJAX que requieren respuestas JSON y XML
  5986. es perfectamente posible con este enfoque.
  5987. </para>
  5988. <para>
  5989. Requerimientos:
  5990. </para>
  5991. <itemizedlist>
  5992. <listitem><para>
  5993. Navegador web Firefox idealmente versión 3, pero la versión 2
  5994. tambien está soportada.
  5995. </para></listitem>
  5996. <listitem> <para>
  5997. Extensión Firebug para Firefox, la cual puede descargarse desde
  5998. <ulink url="https://addons.mozilla.org/en-US/firefox/addon/1843">https://addons.
  5999. mozilla .org/en-US/firefox/addon/1843</ulink>.
  6000. </para></listitem>
  6001. <listitem><para>
  6002. Extensión FirePHP para Firefox, la cual puede descargarse desde
  6003. <ulink url="https://addons.mozilla.org/en-US/firefox/addon/6149">https://addons.mozilla.org/en-US/firefox/addon/6149</ulink>.
  6004. </para></listitem>
  6005. </itemizedlist>
  6006. <example id="zend.db.profiler.profilers.firebug.example.with_front_controller">
  6007. <title>Perfilando DB con <code>Zend_Controller_Front</code></title>
  6008. <programlisting role="php"><![CDATA[
  6009. // En tu archivo bootstrap
  6010. $profiler = new Zend_Db_Profiler_Firebug('All DB Queries');
  6011. $profiler->setEnabled(true);
  6012. // Anexar el perfilador a tu adaptador de base de datos
  6013. $db->setProfiler($profiler)
  6014. // Despachar el controlador frontal
  6015. // Todas las consultas a la base de datos en tus archivos modelo, vista y controlador
  6016. // ahora serán perfilados y enviados a Firebug
  6017. ]]>
  6018. </programlisting>
  6019. </example>
  6020. <example id="zend.db.profiler.profilers.firebug.example.without_front_controller">
  6021. <title>Perfilar DB sin <code>Zend_Controller_Front</code></title>
  6022. <programlisting role="php"><![CDATA[
  6023. $profiler = new Zend_Db_Profiler_Firebug('All DB Queries');
  6024. $profiler->setEnabled(true);
  6025. // Anexar el perfilador a tu adaptador de base de datos
  6026. $db->setProfiler($profiler)
  6027. $request = new Zend_Controller_Request_Http();
  6028. $response = new Zend_Controller_Response_Http();
  6029. $channel = Zend_Wildfire_Channel_HttpHeaders::getInstance();
  6030. $channel->setRequest($request);
  6031. $channel->setResponse($response);
  6032. // Iniciar un buffer de las salidas
  6033. ob_start();
  6034. // Ahora se pueden ejecutar las consultas a la Base de Datos para ser perfiladas
  6035. // Enviar los datos de perfilado al navegador
  6036. $channel->flush();
  6037. $response->sendHeaders();
  6038. ]]>
  6039. </programlisting>
  6040. </example>
  6041. </sect3><!--
  6042. vim:se ts=4 sw=4 et:
  6043. -->
  6044. </sect2>
  6045. </sect1><!--
  6046. vim:se ts=4 sw=4 et:
  6047. -->
  6048. <sect1 id="zend.db.select" xml:base="module_specs/Zend_Db_Select.xml">
  6049. <title>Zend_Db_Select</title>
  6050. <sect2 id="zend.db.select.introduction">
  6051. <title>Descripción del Objeto Select</title>
  6052. <para>
  6053. El objeto Zend_Db_Select object representa una declaración de consulta
  6054. <code>SELECT</code> de SQL. La clase tiene métodos para agregar partes
  6055. individuales a la consulta. Puedes especificar algunas partes de la consulta
  6056. usando los métodos en PHP y sus estructuras de datos, y la clase forma la sintaxis
  6057. SLQ correcta. Despues de construir la consulta, puedes ejecutarla como si
  6058. se hubiera escrito como un string.
  6059. </para>
  6060. <para>
  6061. El valor entregado por Zend_Db_Select incluye:
  6062. </para>
  6063. <itemizedlist>
  6064. <listitem>
  6065. <para>
  6066. Métodos Orientados a objetos para especificar consultas SQL
  6067. de manera pieza-a-pieza;
  6068. </para>
  6069. </listitem>
  6070. <listitem>
  6071. <para>
  6072. Abstracción de partes de las consultas SQL, independiente de la
  6073. Base de datos;
  6074. </para>
  6075. </listitem>
  6076. <listitem>
  6077. <para>
  6078. Entrecomillado automático de identificadores de metadatos en
  6079. la mayoría de los casos, soportanto identificadores que contienen palabras
  6080. reservadas de SQL y caracteres especiales;
  6081. </para>
  6082. </listitem>
  6083. <listitem>
  6084. <para>
  6085. Entrecomillado de identificadores y valores, para ayudar a reducir el
  6086. riesgo de ataque de inyección SQL.
  6087. </para>
  6088. </listitem>
  6089. </itemizedlist>
  6090. <para>
  6091. El uso de Zend_Db_Select no es obligatorio. Para consultas SELECT muy simples,
  6092. es usualmente más simple especificar la consulta completa como un string
  6093. y ejecutarla usando un método del Adapter como <code>query()</code> o
  6094. <code>fetchAll()</code>. Usar Zend_Db_Select es util si se necesita ensamblar
  6095. una consulta SELECT proceduralmente, o basado en condiciones lógicas en
  6096. la aplicación.
  6097. </para>
  6098. </sect2>
  6099. <sect2 id="zend.db.select.creating">
  6100. <title>Creando un Objeto Select</title>
  6101. <para>
  6102. Puedes crear un a instancia del objeto Zend_Db_Select usando el método
  6103. <code>select()</code> de un objeto Zend_Db_Adapter_Abstract.
  6104. </para>
  6105. <example id="zend.db.select.creating.example-db">
  6106. <title>Ejemplo del método select() del adaptador</title>
  6107. <programlisting role="php"><![CDATA[
  6108. $db = Zend_Db::factory( ...options... );
  6109. $select = $db->select();
  6110. ]]>
  6111. </programlisting>
  6112. </example>
  6113. <para>
  6114. Otra manera de crear el objeto Zend_Db_Select es con su constructor,
  6115. especificando el adaptador de base de datos como un argumento.
  6116. </para>
  6117. <example id="zend.db.select.creating.example-new">
  6118. <title>Ejemplo de creación de un nuevo objeto Select</title>
  6119. <programlisting role="php"><![CDATA[
  6120. $db = Zend_Db::factory( ...options... );
  6121. $select = new Zend_Db_Select($db);
  6122. ]]>
  6123. </programlisting>
  6124. </example>
  6125. </sect2>
  6126. <sect2 id="zend.db.select.building">
  6127. <title>Construyendo consultas Select</title>
  6128. <para>Cuando se construye una consulta, puede agregar clausulas a esta, una por una.
  6129. Hay un método separado para agregar cada al objeto Zend_Db_Select.</para>
  6130. <example id="zend.db.select.building.example">
  6131. <title>Ejemplo de uso de métodos que agregan cláusulas</title>
  6132. <programlisting role="php"><![CDATA[
  6133. // Crear el objeto Zend_Db_Select
  6134. $select = $db->select();
  6135. // Agregar una cláusula FROM
  6136. $select->from( ...specify table and columns... )
  6137. // Agregar una cláusula WHERE
  6138. $select->where( ...specify search criteria... )
  6139. // Agregar una cláusula ORDER BY
  6140. $select->order( ...specify sorting criteria... );
  6141. ]]>
  6142. </programlisting>
  6143. </example>
  6144. <para>También puede utilizar la mayoría de los métodos del objeto Zend_Db_Select con una
  6145. interfaz fluida. Una interfaz fluida significa que cada método retorna una referencia
  6146. al objeto que se ha llamado, así puedes llamar inmediatamente a otro método.</para>
  6147. <example id="zend.db.select.building.example-fluent">
  6148. <title>Ejemplo de uso de la interfaz fluida.</title>
  6149. <programlisting role="php"><![CDATA[
  6150. $select = $db->select()
  6151. ->from( ...specify table and columns... )
  6152. ->where( ...specify search criteria... )
  6153. ->order( ...specify sorting criteria... );
  6154. ]]>
  6155. </programlisting>
  6156. </example>
  6157. <para>Los ejemplos en esta sección muestran el uso de la interfaz fluída, pero también
  6158. puedes usar la interfaz no-fluída en todos los casos. A menudo es necesario
  6159. utilizar la interfaz no-fluída, por ejemplo, si su aplicación necesita realizar
  6160. cierta lógica antes de añadir una cláusula a la consulta.</para>
  6161. <sect3 id="zend.db.select.building.from">
  6162. <title>Agregando una cláusula FROM</title>
  6163. <para>
  6164. Especifica la tabla para esta consulta usando el método <code>from()</code>.
  6165. Puedes especificar el nombre de la tabla como un simple string. Zend_Db_Select
  6166. aplica el identificador entrecomillando el nombre de la tabla, así puedes
  6167. usar caracteres especiales.
  6168. </para>
  6169. <example id="zend.db.select.building.from.example">
  6170. <title>Ejemplo del método from()</title>
  6171. <programlisting role="php"><![CDATA[
  6172. // Construye la consulta:
  6173. // SELECT *
  6174. // FROM "products"
  6175. $select = $db->select()
  6176. ->from( 'products' );
  6177. ]]>
  6178. </programlisting>
  6179. </example>
  6180. <para>
  6181. Puedes especificar un nombre correlacionado (también llamado a veces
  6182. "alias de tabla") para una tabla. En lugar de un simple string, se usa un
  6183. array asociativo que mapee el nombre de la correlación con el nombre de la tabla.
  6184. En otras cláusulas de consulta SQL, se usa esta correlación de nombre.
  6185. si su consulta se une con más de una tabla, Zend_Db_Select generatiza una
  6186. correlación unica de nombres basados en el nombre de la tabla, para una tabla
  6187. a la cual no se le espicifique un nombre correlacionado.
  6188. </para>
  6189. <example id="zend.db.select.building.from.example-cname">
  6190. <title>Ejemplo especificando una tabla con nombre correlacionado</title>
  6191. <programlisting role="php"><![CDATA[
  6192. // Construye esta consulta:
  6193. // SELECT p.*
  6194. // FROM "products" AS p
  6195. $select = $db->select()
  6196. ->from( array('p' => 'products') );
  6197. ]]>
  6198. </programlisting>
  6199. </example>
  6200. <para>
  6201. Algunos RDBMS apoyan el uso de un especificador de esquema para una tabla.
  6202. Puedes especificar el nombre de la tabla como
  6203. "<code>nombreDeEsquema.nombre DeTabla</code>", donde Zend_Db_Select entrecomillará
  6204. cada parte individualmente, o tambien puedes especificar el nombre de esquema
  6205. por separado. Un nombre de esquema especificado en el nombre de la tabla toma
  6206. precedencia en sobre un esquema dado por separado en el caso de que ambos
  6207. sean dados.
  6208. </para>
  6209. <example id="zend.db.select.building.from.example-schema">
  6210. <title>Ejemplo especificando un nombre de esquema</title>
  6211. <programlisting role="php"><![CDATA[
  6212. // Construye esta consulta:
  6213. // SELECT *
  6214. // FROM "myschema"."products"
  6215. $select = $db->select()
  6216. ->from( 'myschema.products' );
  6217. // o
  6218. $select = $db->select()
  6219. ->from('products', '*', 'myschema');
  6220. ]]>
  6221. </programlisting>
  6222. </example>
  6223. </sect3>
  6224. <sect3 id="zend.db.select.building.columns">
  6225. <title>Agregando Columnas</title>
  6226. <para>
  6227. En el segundo argumento del método <code>from()</code>, puedes especificar
  6228. las columnas a seleccionar desde la respectiva tabla.
  6229. Si no especificas columns, por defecto será "<code>*</code>",
  6230. el comodín SQL para "todas las columnas".
  6231. </para>
  6232. <para>
  6233. Puedes listar las columnas en un simple array de strings, o en un
  6234. array asociativo mapeando los alias de columnas a su nombre de tabla.
  6235. Si solo se especifica una columna en la consulta y no necesitas especificar un
  6236. alias de columna, puedes listarla solo con un string plano de lugar de un array.
  6237. </para>
  6238. <para>
  6239. Si se entrega un array vacío como el argumento de las tablas, no se incluirán
  6240. columnas en el resultado. Vea un
  6241. <link linkend="zend.db.select.building.join.example-no-columns">codigo de ejemplo</link>
  6242. bajo la sección del método <code>join()</code>.
  6243. </para>
  6244. <para>
  6245. Puedes especificar el nombre de columna como
  6246. "<code>nombreCorrelacionado.nombreDeColumna</code>".
  6247. Zend_Db_Select entrecomullará cada parte individualmente. Si no especificas
  6248. un nombre correlacionado para una columna, se usará el nombre correlacionado
  6249. para la tabla nombrada en el actual método <code>from()</code>.
  6250. </para>
  6251. <example id="zend.db.select.building.columns.example">
  6252. <title>Ejemplos especificando columnas</title>
  6253. <programlisting role="php"><![CDATA[
  6254. // Construir esta consulta:
  6255. // SELECT p."product_id", p."product_name"
  6256. // FROM "products" AS p
  6257. $select = $db->select()
  6258. ->from(array('p' => 'products'),
  6259. array('product_id', 'product_name'));
  6260. // Construir la misma consulta, especificando nombres correlacionados:
  6261. // SELECT p."product_id", p."product_name"
  6262. // FROM "products" AS p
  6263. $select = $db->select()
  6264. ->from(array('p' => 'products'),
  6265. array('p.product_id', 'p.product_name'));
  6266. // Construir esta consulta con una alias para una columna:
  6267. // SELECT p."product_id" AS prodno, p."product_name"
  6268. // FROM "products" AS p
  6269. $select = $db->select()
  6270. ->from(array('p' => 'products'),
  6271. array('prodno' => 'product_id', 'product_name'));
  6272. ]]>
  6273. </programlisting>
  6274. </example>
  6275. </sect3>
  6276. <sect3 id="zend.db.select.building.columns-expr">
  6277. <title>Agregando una Expresión en las Columns</title>
  6278. <para>
  6279. Las columnas en consultas SQL a veces son expresiones, no simples columnas
  6280. de una tabla. Las expresiones no deberían tener nombres correlacionados o entrecomillado aplicado.
  6281. Si sus columnas contienen parentesis, Zend_Db_Select las reconoce como una expresión.
  6282. </para>
  6283. <para>
  6284. Tambien puedes crear un objeto de tipo Zend_Db_Expr explícitamente, para prevenir
  6285. que el string sea tratado como columna. Zend_Db_Expr es una clase mínima, que contiene
  6286. un simple string. Zend_Db_Select reconoce el objeto de tipo Zend_Db_Expr y
  6287. lo convierte de vuelta en el string, pero no le aplica ninguna alteración,
  6288. tal como el entrecomillado o la correlación de nombres.
  6289. </para>
  6290. <note>
  6291. <para>
  6292. El Uso de Zend_Db_Expr para nombres de columnas no es necesario si
  6293. la expresión de la columna contiene parentesis; Zend_Db_Select reconoce
  6294. y trata el string como expresión, saltándose el entrcomillado y la
  6295. correlación de nombres.
  6296. </para>
  6297. </note>
  6298. <example id="zend.db.select.building.columns-expr.example">
  6299. <title>Ejemplos especificando columnas que contienen expresiones</title>
  6300. <programlisting role="php"><![CDATA[
  6301. // Construye esta consulta:
  6302. // SELECT p."product_id", LOWER(product_name)
  6303. // FROM "products" AS p
  6304. // Una expresion con parentesis implicitamente se transforma en
  6305. // un Zend_Db_Expr.
  6306. $select = $db->select()
  6307. ->from(array('p' => 'products'),
  6308. array('product_id', 'LOWER(product_name)'));
  6309. // Construye esta consulta:
  6310. // SELECT p."product_id", (p.cost * 1.08) AS cost_plus_tax
  6311. // FROM "products" AS p
  6312. $select = $db->select()
  6313. ->from(array('p' => 'products'),
  6314. array('product_id',
  6315. 'cost_plus_tax' => '(p.cost * 1.08)')
  6316. );
  6317. // Construye esta consulta usando Zend_Db_Expr explícitamente:
  6318. // SELECT p."product_id", p.cost * 1.08 AS cost_plus_tax
  6319. // FROM "products" AS p
  6320. $select = $db->select()
  6321. ->from(array('p' => 'products'),
  6322. array('product_id',
  6323. 'cost_plus_tax' =>
  6324. new Zend_Db_Expr('p.cost * 1.08'))
  6325. );
  6326. ]]>
  6327. </programlisting>
  6328. </example>
  6329. <para>
  6330. En los casos anteriores, Zend_Db_Select no altera el string para aplicar
  6331. correlación de nombres o entrecomillado de identificadores. Si estos
  6332. cambios son necesarios para resolver ambigüedades, deberías realizar
  6333. cambios manualmente en el string.
  6334. </para>
  6335. <para>
  6336. Si el nombre de su columna es alguna palabra reservada de SQL o
  6337. contiene caracteres especiales, debería usar el método
  6338. <code>quoteIdentifier()</code> del Adapdator e interpolar el resultado en un
  6339. string. El método <code>quoteIdentifier()</code> usa entrecomillado SQL para
  6340. delimitar el identificador,
  6341. the identifier, dejando en claro que es un identificador de tabla o columna y no
  6342. otra parte de la sintaxis SQL.
  6343. </para>
  6344. <para>
  6345. Su código es más independiente de la base de datos si se usa el método
  6346. <code>quoteIdentifier()</code> en vez de las excribir literalmente las comillas
  6347. en la cadena, debido a que algunos RDBMS no usan simbolos estándar para entrecomillar
  6348. identificadores.
  6349. El método <code>quoteIdentifier()</code> está diseñado para usar los símbolos
  6350. apropiados para entrecomillar basado en el tipo del adaptador.
  6351. El método <code>quoteIdentifier()</code> también escapa
  6352. cual caracter de comilla que aparezca en el nombre del identificador mismo.
  6353. </para>
  6354. <example id="zend.db.select.building.columns-quoteid.example">
  6355. <title>Ejemplo de entrecomillado de columnas en una expresión</title>
  6356. <programlisting role="php"><![CDATA[
  6357. // Construye esta consulta, entrecomillando el nombre
  6358. // especial de la columna llamada "from" en la expresión:
  6359. // SELECT p."from" + 10 AS origin
  6360. // FROM "products" AS p
  6361. $select = $db->select()
  6362. ->from(array('p' => 'products'),
  6363. array('origin' =>
  6364. '(p.' . $db->quoteIdentifier('from') . ' + 10)')
  6365. );
  6366. ]]>
  6367. </programlisting>
  6368. </example>
  6369. </sect3>
  6370. <sect3 id="zend.db.select.building.columns-atomic">
  6371. <title>Agregar columnas a una tabla FROM o JOIN existente</title>
  6372. <para>
  6373. Puede haber casos en los que desea agregar columnas a una tabla FROM o JOIN
  6374. después de que estos métodos han sido llamados. El método <code>columns()</code>
  6375. permite agregar columnas en cualquier punto antes de ejecutar la consulta.
  6376. Puedes pasar las columnas bien como un string, un <code>Zend_Db_Expr</code> o
  6377. un array de estos elementos. El segundo argumento para este método puede ser omitido,
  6378. implicando que las columnas serán agregadas a una tabla FROM, en otro caso
  6379. debería usarse un nombre de correlación existente.
  6380. </para>
  6381. <example id="zend.db.select.building.columns-atomic.example">
  6382. <title>Ejemplos agregando columnas con el método<code>columns()</code></title>
  6383. <programlisting role="php"><![CDATA[
  6384. // Construir la consulta:
  6385. // SELECT p."product_id", p."product_name"
  6386. // FROM "products" AS p
  6387. $select = $db->select()
  6388. ->from(array('p' => 'products'), 'product_id')
  6389. ->columns('product_name');
  6390. // Construir la misma consulta, especificando correlación de nombres:
  6391. // SELECT p."product_id", p."product_name"
  6392. // FROM "products" AS p
  6393. $select = $db->select()
  6394. ->from(array('p' => 'products'), 'p.product_id')
  6395. ->columns('product_name', 'p');
  6396. // Alternativamente puede usar columns('p.product_name')]]>
  6397. </programlisting>
  6398. </example>
  6399. </sect3>
  6400. <sect3 id="zend.db.select.building.join">
  6401. <title>Agregar Otra Tabla a la Consulta Query con JOIN</title>
  6402. <para>
  6403. Muchas consultas útiles involucran el uso de un <code>JOIN</code> para
  6404. combinar filas de multiples tablas. Puedes agregar tablas a una consulta Zend_Db_Select
  6405. usando el método <code>join()</code>. Usar este método, es similar
  6406. al método <code>from()</code>, excepto que puedes especificar una condición de unión
  6407. en la mayoría de los casos.
  6408. </para>
  6409. <example id="zend.db.select.building.join.example">
  6410. <title>Ejemplo del método join()</title>
  6411. <programlisting role="php"><![CDATA[
  6412. // Construye esta consulta:
  6413. // SELECT p."product_id", p."product_name", l.*
  6414. // FROM "products" AS p JOIN "line_items" AS l
  6415. // ON p.product_id = l.product_id
  6416. $select = $db->select()
  6417. ->from(array('p' => 'products'),
  6418. array('product_id', 'product_name'))
  6419. ->join(array('l' => 'line_items'),
  6420. 'p.product_id = l.product_id');
  6421. ]]>
  6422. </programlisting>
  6423. </example>
  6424. <para>
  6425. El segundo argumento <code>join()</code> es un string que es usado como condición de unión.
  6426. Esta es una expresión que declara un criterio por el cual las filas en una tabla concuerdan con
  6427. las filas de la otra tabla. Puedes especificar correlación de nombres en esta expresión.
  6428. </para>
  6429. <note>
  6430. <para>
  6431. No se aplica entrecomillado en la expresión especificada para la condición de unión;
  6432. si tienes problemas con nombres que necesitan ser entrecomillados, deberás usar
  6433. <code>quoteIdentifier()</code> para formar el string de condición de unión.
  6434. </para>
  6435. </note>
  6436. <para>
  6437. El tercer argumento <code>join()</code> es un array de nombres de columnas, como
  6438. al usar el método <code>from()</code>. Este es por defecto "<code>*</code>", soporta
  6439. correlación de nombres, expresiones, y Zend_Db_Expr de la misma manera que el array de
  6440. nombres de columnas en el método <code>from()</code>.
  6441. </para>
  6442. <para>
  6443. Para no seleccionar columnas de una tabla, use un array vacío para la lista de columnas.
  6444. El uso de esto trabaja con el método <code>from()</code> también, pero en general
  6445. deseará algunas columnas de la tabla primaria en sus consultas, a la vez que no se desean
  6446. columnas de la tabla unida.
  6447. </para>
  6448. <example id="zend.db.select.building.join.example-no-columns">
  6449. <title>Ejemplo especificando ninguna columna</title>
  6450. <programlisting role="php"><![CDATA[
  6451. // Construye esta consulta:
  6452. // SELECT p."product_id", p."product_name"
  6453. // FROM "products" AS p JOIN "line_items" AS l
  6454. // ON p.product_id = l.product_id
  6455. $select = $db->select()
  6456. ->from(array('p' => 'products'),
  6457. array('product_id', 'product_name'))
  6458. ->join(array('l' => 'line_items'),
  6459. 'p.product_id = l.product_id',
  6460. array() ); // empty list of columns
  6461. ]]>
  6462. </programlisting>
  6463. <para>
  6464. Note el array vacío <code>array()</code> en el ejemplo anterior
  6465. en lugar de una lista de columnas de la tabla unida.
  6466. </para>
  6467. </example>
  6468. <para>
  6469. SQL tiene muchos tipos de uniones. Vea una lista a continuación para los métodos
  6470. que soportan cada tipo de unión en Zend_Db_Select.
  6471. </para>
  6472. <itemizedlist>
  6473. <listitem>
  6474. <para>
  6475. <command>INNER JOIN</command> con los métodos
  6476. <code>join(table, join, [columns])</code> o
  6477. <code>joinInner(table, join, [columns])</code>.
  6478. </para>
  6479. <para>
  6480. Esta es el tipo de unión más comun. Las filas de cada tabla son comparadas
  6481. usando la condición de unión especificada. El resultado incluye solo las filas
  6482. que satisfacen la condición. El resultado puede ser vacio si no hay filas que
  6483. satisfagan la condición.
  6484. </para>
  6485. <para>
  6486. Todos los RDBMS soportan este tipo de unión.
  6487. </para>
  6488. </listitem>
  6489. <listitem>
  6490. <para>
  6491. <command>LEFT JOIN</command> con el método
  6492. <code>joinLeft(table, condition, [columns])</code>.
  6493. </para>
  6494. <para>
  6495. Todas las filas de tabla a la izquierda del operando son incluídas,
  6496. pareando las filas de la tabla a la derecha del operando,
  6497. y las columnas de la tabla a la derecha del operando son rellenadas con
  6498. NULLs si no existen filas que calcen con la tabla a la izquierda.
  6499. </para>
  6500. <para>
  6501. Todos los RDBMS soportan este tipo de unión.
  6502. </para>
  6503. </listitem>
  6504. <listitem>
  6505. <para>
  6506. <command>RIGHT JOIN</command> con el método
  6507. <code>joinRight(table, condition, [columns])</code>.
  6508. </para>
  6509. <para>
  6510. Unión exterior por la derecha es un complemento de la unión exterior por la
  6511. izquierda. Todas las filas de la tabla a la derecha del operando son incluídos,
  6512. pareando las filas de la tabla a la izquierda del operando incluídos, y las
  6513. columnas de la tabla a la izquierda del operando son rellenadas con NULLs si
  6514. no existen filas que calcen con la tabla de la derecha.
  6515. </para>
  6516. <para>
  6517. Algunos RDBMS no soportan'este tipo de join, pero en general, cualquier unión
  6518. por la derecha puede representarse por una unión por la derecha invirtiendo
  6519. el orden de las tablas.
  6520. </para>
  6521. </listitem>
  6522. <listitem>
  6523. <para>
  6524. <command>FULL JOIN</command> con el método
  6525. <code>joinFull(table, condition, [columns])</code>.
  6526. </para>
  6527. <para>
  6528. Una unión externa total es como una combinación de una unión exterior por
  6529. la izquierda y una unión exterior por la derecha.
  6530. Todas las filas de ambas tablas son incluídas, vinculadas entre sí
  6531. en la misma fila si estos satisfacen la condición de unión, y en otro
  6532. caso se vinculan con valores nulos en lugar de columnas de la otra tabla.
  6533. </para>
  6534. <para>
  6535. Algunos RDBMS no soportan este tipo de unión.
  6536. </para>
  6537. </listitem>
  6538. <listitem>
  6539. <para>
  6540. <command>CROSS JOIN</command> con el método
  6541. <code>joinCross(table, [columns])</code>.
  6542. </para>
  6543. <para>
  6544. Una unión cruzada es un Producto Cartesiano. Cada fila en la primera tabla
  6545. es pareada con cada una en la segunda tabla.
  6546. Por lo tanto, el número de filas en el resultado es igual al producto del
  6547. número de filas en cada tabla.
  6548. Puede filtrar el conjunto de resultados con el uso de condiciones en una
  6549. cláusula WHERE; de esta forma una unión cruzada es similar a la antigua
  6550. sintaxis de unión en SQL-89.
  6551. </para>
  6552. <para>
  6553. El método <code>joinCross()</code> no tiene parámetros para especificar una
  6554. condición de unión. Algunos RDBMS no soportan este tipo de unión.
  6555. </para>
  6556. </listitem>
  6557. <listitem>
  6558. <para>
  6559. <command>NATURAL JOIN</command> con el método
  6560. <code>joinNatural(table, [columns])</code>.
  6561. </para>
  6562. <para>
  6563. Una unión natural compara cualquier columa(s) que aparezca con el nombre
  6564. en ambas tablas. La comparación es el equivalente de todas las columna(s);
  6565. comparando las columnas usando desigualdad no es una unión natural.
  6566. Solo la unión interna natural es soportada por este API, aun cuando SQL
  6567. permita una unión externa natural.
  6568. </para>
  6569. <para>
  6570. El método <code>joinNatural()</code> no tiene parámetros para especificar una condición.
  6571. </para>
  6572. </listitem>
  6573. </itemizedlist>
  6574. <para>
  6575. Además de los métodos de unión, puedes simplificar las consultas
  6576. usando métodos JoinUsing. En vez de proveer una condición completa a la unión,
  6577. simplemente pasas el nombre de columna en la que se hará la uninón y
  6578. el objeto Zend_Db_Select completa la condición por ti.
  6579. </para>
  6580. <example id="zend.db.select.building.joinusing.example">
  6581. <title>Ejemplo de método joinUsing()</title>
  6582. <programlisting role="php"><![CDATA[
  6583. // Construye esta consulta:
  6584. // SELECT *
  6585. // FROM "table1"
  6586. // JOIN "table2"
  6587. // ON "table1".column1 = "table2".column1
  6588. // WHERE column2 = 'foo'
  6589. $select = $db->select()
  6590. ->from('table1')
  6591. ->joinUsing('table2', 'column1')
  6592. ->where('column2 = ?', 'foo');]]>
  6593. </programlisting>
  6594. </example>
  6595. <para>
  6596. Cada uno de los métodos aplicables para uniones en el componente
  6597. Zend_Db_Select tiene su correspondiente método 'usando'.
  6598. </para>
  6599. <itemizedlist>
  6600. <listitem>
  6601. <para>
  6602. <code>joinUsing(table, join, [columns])</code> y
  6603. <code>joinInnerUsing(table, join, [columns])</code>
  6604. </para>
  6605. </listitem>
  6606. <listitem>
  6607. <para>
  6608. <code>joinLeftUsing(table, join, [columns])</code>
  6609. </para>
  6610. </listitem>
  6611. <listitem>
  6612. <para>
  6613. <code>joinRightUsing(table, join, [columns])</code>
  6614. </para>
  6615. </listitem>
  6616. <listitem>
  6617. <para>
  6618. <code>joinFullUsing(table, join, [columns])</code>
  6619. </para>
  6620. </listitem>
  6621. </itemizedlist>
  6622. </sect3>
  6623. <sect3 id="zend.db.select.building.where">
  6624. <title>Agregar una cláusula WHERE</title>
  6625. <para>
  6626. Puede especificar un criterio para restringir las filas de resultado
  6627. usando el método <code>where()</code>. El primer argumento de este método
  6628. es una expresión SQL, y esta expresión es usada como una expresión SQL
  6629. <code>WHERE</code> en la consulta.
  6630. </para>
  6631. <example id="zend.db.select.building.where.example">
  6632. <title>Ejemplo del método where()</title>
  6633. <programlisting role="php"><![CDATA[
  6634. // Construye esta consulta:
  6635. // SELECT product_id, product_name, price
  6636. // FROM "products"
  6637. // WHERE price > 100.00
  6638. $select = $db->select()
  6639. ->from('products',
  6640. array('product_id', 'product_name', 'price'))
  6641. ->where('price > 100.00');]]>
  6642. </programlisting>
  6643. </example>
  6644. <note>
  6645. <para>
  6646. No se aplica entrecomillado en una expresión dada en el método <code>where()</code> u
  6647. <code>orWhere()</code>. Si tienes nombres de columnas que necesitan ser entrecomillada,
  6648. debe usar el método <code>quoteIdentifier()</code> para formar el string de la condición.
  6649. </para>
  6650. </note>
  6651. <para>
  6652. El segundo argumento del método <code>where()</code> es opcional.
  6653. Es un valor a sustituir en la expresión. Zend_Db_Select entrecomilla el valor
  6654. y sustituye por un signo de interrogación ("<code>?</code>") en la expresión.
  6655. </para>
  6656. <para>
  6657. Este método acepta solo un parámetro. Si tienes una expresión
  6658. en la cual necesitas sustituir multiples variables, deberás formar
  6659. el string manualmente, interpolando variables y realizando entrecomillado
  6660. tu mismo.
  6661. </para>
  6662. <example id="zend.db.select.building.where.example-param">
  6663. <title>Ejemplo de parámetro en el método where()</title>
  6664. <programlisting role="php"><![CDATA[
  6665. // Construye esta consulta:
  6666. // SELECT product_id, product_name, price
  6667. // FROM "products"
  6668. // WHERE (price > 100.00)
  6669. $minimumPrice = 100;
  6670. $select = $db->select()
  6671. ->from('products',
  6672. array('product_id', 'product_name', 'price'))
  6673. ->where('price > ?', $minimumPrice);
  6674. ]]>
  6675. </programlisting>
  6676. </example>
  6677. <para>
  6678. Puedes invocar el método <code>where()</code> multiples veces en el mismo objeto
  6679. Zend_Db_Select. La consulta resultante combina los multiples terminos
  6680. juntos usando <code>AND</code> entre ellos.
  6681. </para>
  6682. <example id="zend.db.select.building.where.example-and">
  6683. <title>Ejemplo de multiples métodos where()</title>
  6684. <programlisting role="php"><![CDATA[
  6685. // Construye esta consulta:
  6686. // SELECT product_id, product_name, price
  6687. // FROM "products"
  6688. // WHERE (price > 100.00)
  6689. // AND (price < 500.00)
  6690. $minimumPrice = 100;
  6691. $maximumPrice = 500;
  6692. $select = $db->select()
  6693. ->from('products',
  6694. array('product_id', 'product_name', 'price'))
  6695. ->where('price > ?', $minimumPrice)
  6696. ->where('price < ?', $maximumPrice);
  6697. ]]>
  6698. </programlisting>
  6699. </example>
  6700. <para>
  6701. Si necesitas combinar terminos juntos uando <code>OR</code>, use el método
  6702. <code>orWhere()</code>. Este mñetodo se usa del mismo modo que el método
  6703. <code>where()</code>, excepto que el termino especificado es precedido por
  6704. <code>OR</code>, en lugar de <code>AND</code>.
  6705. </para>
  6706. <example id="zend.db.select.building.where.example-or">
  6707. <title>Ejemplo del método orWhere()</title>
  6708. <programlisting role="php"><![CDATA[
  6709. // Construye esta consulta:
  6710. // SELECT product_id, product_name, price
  6711. // FROM "products"
  6712. // WHERE (price < 100.00)
  6713. // OR (price > 500.00)
  6714. $minimumPrice = 100;
  6715. $maximumPrice = 500;
  6716. $select = $db->select()
  6717. ->from('products',
  6718. array('product_id', 'product_name', 'price'))
  6719. ->where('price < ?', $minimumPrice)
  6720. ->orWhere('price > ?', $maximumPrice);
  6721. ]]>
  6722. </programlisting>
  6723. </example>
  6724. <para>
  6725. Zend_Db_Select automáticamente pone paréntesis alrededor de cada expresión
  6726. que especifiques usandp el método <code>where()</code> u <code>orWhere()</code>.
  6727. Esto ayuda a asegurar que la precedencia del operador Booleano no cause resultados
  6728. inesperados.
  6729. </para>
  6730. <example id="zend.db.select.building.where.example-parens">
  6731. <title>Ejemplos de Expresiones Booleanas con parentesis</title>
  6732. <programlisting role="php"><![CDATA[
  6733. // Construye esta consulta:
  6734. // SELECT product_id, product_name, price
  6735. // FROM "products"
  6736. // WHERE (price < 100.00 OR price > 500.00)
  6737. // AND (product_name = 'Apple')
  6738. $minimumPrice = 100;
  6739. $maximumPrice = 500;
  6740. $prod = 'Apple';
  6741. $select = $db->select()
  6742. ->from('products',
  6743. array('product_id', 'product_name', 'price'))
  6744. ->where("price < $minimumPrice OR price > $maximumPrice")
  6745. ->where('product_name = ?', $prod);
  6746. ]]>
  6747. </programlisting>
  6748. </example>
  6749. <para>
  6750. En el ejemplo anterior, los resultados deberían ser diferentes sin paréntesis,
  6751. porque <code>AND</code> tiene alta precedencia respecto a <code>OR</code>.
  6752. Zend_Db_Select aplica el parentesis con un efecto tal que la expresión en sucesivas
  6753. llamadas al método <code>where()</code> vincule más estrechamente el <code>AND</code>
  6754. que combina las expresiones.
  6755. </para>
  6756. </sect3>
  6757. <sect3 id="zend.db.select.building.group">
  6758. <title>Agregando una cláusula GROUP BY</title>
  6759. <para>
  6760. En SQL, la cláusula <code>GROUP BY</code> permite reducir el número
  6761. de filas del resultado de una consulta a una fila por cada valor único
  6762. encontrado en la(s) columna(s) nombrada(s) en la cláusula
  6763. <code>GROUP BY</code>.
  6764. </para>
  6765. <para>
  6766. En Zend_Db_Select, puedes especificar la(s) columna(s) a usar para el
  6767. cálculo de grupos de filas usando el método <code>group()</code>.
  6768. El argumento de este método es una columna o un array de columnas
  6769. que se usarán en la cláusula <code>GROUP BY</code>.
  6770. </para>
  6771. <example id="zend.db.select.building.group.example">
  6772. <title>Ejemplo del método groups group()</title>
  6773. <programlisting role="php"><![CDATA[
  6774. // Construye esta consulta:
  6775. // SELECT p."product_id", COUNT(*) AS line_items_per_product
  6776. // FROM "products" AS p JOIN "line_items" AS l
  6777. // ON p.product_id = l.product_id
  6778. // GROUP BY p.product_id
  6779. $select = $db->select()
  6780. ->from(array('p' => 'products'),
  6781. array('product_id'))
  6782. ->join(array('l' => 'line_items'),
  6783. 'p.product_id = l.product_id',
  6784. array('line_items_per_product' => 'COUNT(*)'))
  6785. ->group('p.product_id');
  6786. ]]>
  6787. </programlisting>
  6788. </example>
  6789. <para>
  6790. Como el array de columnas del método <code>from()</code>, peudes usar
  6791. correlación de nombres en el string de nombre de columna, y la conlumna será
  6792. entrecomillada como un identificador, salvo que el string contenga paréntesis
  6793. o sea un objeto de tipo Zend_Db_Expr.
  6794. </para>
  6795. </sect3>
  6796. <sect3 id="zend.db.select.building.having">
  6797. <title>Agregando una cláusula HAVING</title>
  6798. <para>
  6799. En SQL, la cláusula <code>HAVING</code> aplica una condición de restricción
  6800. en grupos de filas. Es similar a una cláusula <code>WHERE</code>
  6801. aplicando una condición de restricción a las filas. Pero las 2 cláusulas
  6802. son diferentes porque las condiciones <code>WHERE</code>
  6803. son aplicadas antes que definan los grupos, mientras que las condiciones
  6804. <code>HAVING</code> son aplicadas después que los grupos son definidos.
  6805. </para>
  6806. <para>
  6807. En Zend_Db_Select, puedes especificar condiciones para restringir
  6808. grupos usando el método <code>having()</code>. Su uso es similar al
  6809. del método <code>where()</code>. El primer agumento es un string
  6810. conteniendo una expresión SQL. El segundo argumento es un valor
  6811. que es usado para reemplazar un parámetro marcador de posición en la
  6812. expresión SQL. Las expresiones dadas en multiples invocaciones al método
  6813. <code>having()</code> son combinados usando el operador Booleano
  6814. <code>AND</code>, o el operador <code>OR</code> si usas el método
  6815. <code>orHaving()</code>.
  6816. </para>
  6817. <example id="zend.db.select.building.having.example">
  6818. <title>Ejemplo del método having()</title>
  6819. <programlisting role="php"><![CDATA[
  6820. // Construye esta consulta:
  6821. // SELECT p."product_id", COUNT(*) AS line_items_per_product
  6822. // FROM "products" AS p JOIN "line_items" AS l
  6823. // ON p.product_id = l.product_id
  6824. // GROUP BY p.product_id
  6825. // HAVING line_items_per_product > 10
  6826. $select = $db->select()
  6827. ->from(array('p' => 'products'),
  6828. array('product_id'))
  6829. ->join(array('l' => 'line_items'),
  6830. 'p.product_id = l.product_id',
  6831. array('line_items_per_product' => 'COUNT(*)'))
  6832. ->group('p.product_id')
  6833. ->having('line_items_per_product > 10');
  6834. ]]>
  6835. </programlisting>
  6836. </example>
  6837. <note>
  6838. <para>
  6839. No se aplica entrecomillado a expresiones dadas al método <code>having()</code> u
  6840. <code>orHaving()</code>. Si tienes nombres de columnas que deban ser
  6841. entrecomillados, deberás usar <code>quoteIdentifier()</code> para
  6842. formar el string de la condición.
  6843. </para>
  6844. </note>
  6845. </sect3>
  6846. <sect3 id="zend.db.select.building.order">
  6847. <title>Agregar una cláusula ORDER BY</title>
  6848. <para>
  6849. En SQL, la cláusula <code>ORDER BY</code> especifica una o más
  6850. columnas o expresiones por el cual el resultado de la consulta
  6851. será ordenado. Si multiples columnas son listadas, las columnas secundarias
  6852. serán usadas para resolver relaciones; el orden de clasificación es determinado
  6853. por columnas secundarias si la columna anterior contiene valores identicos.
  6854. El orden por defecto es del menor valor al mayor valor. Puedes también
  6855. ordenar de mayor a menor valor para una columna dada en la lista espeificando
  6856. la palabra clave <code>DESC</code> despues de la columna.
  6857. </para>
  6858. <para>
  6859. En Zend_Db_Select, puedes usar el método el método <code>order()</code>
  6860. para especificar una columna o un array de columnas por el cual ordenar.
  6861. Cada elemento del array es un string nombrando la columna. Opcionalmente con la
  6862. palabra reservada <code>ASC</code> o <code>DESC</code> siguiendola, deparada
  6863. por un espacio.
  6864. </para>
  6865. <para>
  6866. Como en el método <code>from()</code> y <code>group()</code>, los nombres de columnas
  6867. son entrecomillados como identificadores, a menos que contengan paréntesis
  6868. o sean un obheto de tipo Zend_Db_Expr.
  6869. </para>
  6870. <example id="zend.db.select.building.order.example">
  6871. <title>Ejemplo del método order()</title>
  6872. <programlisting role="php"><![CDATA[
  6873. // Construye esta consulta:
  6874. // SELECT p."product_id", COUNT(*) AS line_items_per_product
  6875. // FROM "products" AS p JOIN "line_items" AS l
  6876. // ON p.product_id = l.product_id
  6877. // GROUP BY p.product_id
  6878. // ORDER BY "line_items_per_product" DESC, "product_id"
  6879. $select = $db->select()
  6880. ->from(array('p' => 'products'),
  6881. array('product_id'))
  6882. ->join(array('l' => 'line_items'),
  6883. 'p.product_id = l.product_id',
  6884. array('line_items_per_product' => 'COUNT(*)'))
  6885. ->group('p.product_id')
  6886. ->order(array('line_items_per_product DESC',
  6887. 'product_id'));
  6888. ]]>
  6889. </programlisting>
  6890. </example>
  6891. </sect3>
  6892. <sect3 id="zend.db.select.building.limit">
  6893. <title>Agregando una cláusula LIMIT</title>
  6894. <para>
  6895. Algunos RDBMS extienden una consulta SQL con una cláusula conocida como <code>LIMIT</code>.
  6896. Esta cláusuala reduce el número de filas en el resultado a no más de un número
  6897. especificado. También puedes especificar saltar el número de filas antes
  6898. de empezar la salida. Esta característica hace más fácil tomar un subconjunto de
  6899. resultados, por ejemplo cuando mostramos los resultados de una consulta en
  6900. progresivas páginas de salida.
  6901. </para>
  6902. <para>
  6903. En Zend_Db_Select, puedes usar el método <code>limit()</code> para especificar
  6904. la cantidad de filas y el número de filas a saltar. El primer argumento es
  6905. el método es el número de filas deseado. El segundo argument es el númerp de filas a saltar.
  6906. </para>
  6907. <example id="zend.db.select.building.limit.example">
  6908. <title>Ejemplo del método limit()</title>
  6909. <programlisting role="php"><![CDATA[
  6910. // Construye esta consulta:
  6911. // SELECT p."product_id", p."product_name"
  6912. // FROM "products" AS p
  6913. // LIMIT 10, 20
  6914. $select = $db->select()
  6915. ->from(array('p' => 'products'),
  6916. array('product_id', 'product_name'))
  6917. ->limit(10, 20);
  6918. ]]>
  6919. </programlisting>
  6920. </example>
  6921. <note>
  6922. <para>
  6923. La sintaxis de <code>LIMIT</code> no está soportada por todos los RDBMS brands.
  6924. Algunos RDBMS requieren diferente sintaxis para soportar una funcionalidad simialr.
  6925. Cada clase Zend_Db_Adapter_Abstract incluye un método
  6926. para producir el SQL apropiado para cada RDBMS.
  6927. </para>
  6928. </note>
  6929. <para>
  6930. Use el método <code>limitPage()</code> como un modo alternativa de
  6931. especificar la cantidad de filas y compensación.
  6932. Este método permite limitar el conjunto resultado a una serie de subconjuntos
  6933. de tamaño fijo de filas del total del resultado de la consulta.
  6934. En otras palabras, puedes especificar el tamaño de una "página" de resultados,
  6935. y el número ordinal de la página simple donde se espera que retorne la consulta.
  6936. El número de página es el primer argumento del método <code>limitPage()</code>,
  6937. y la longitud de la página es el segundo argumento.
  6938. Ambos son argumentos requeridos; no tienen valores por omisión.
  6939. </para>
  6940. <example id="zend.db.select.building.limit.example2">
  6941. <title>Ejemplo del método limitPage()</title>
  6942. <programlisting role="php"><![CDATA[
  6943. // Construye esta consulta:
  6944. // SELECT p."product_id", p."product_name"
  6945. // FROM "products" AS p
  6946. // LIMIT 10, 20
  6947. $select = $db->select()
  6948. ->from(array('p' => 'products'),
  6949. array('product_id', 'product_name'))
  6950. ->limitPage(2, 10);
  6951. ]]>
  6952. </programlisting>
  6953. </example>
  6954. </sect3>
  6955. <sect3 id="zend.db.select.building.distinct">
  6956. <title>Agregar el modificador DISTINCT a la consulta</title>
  6957. <para>
  6958. El método <code>distinct()</code> permite agregar la palabra
  6959. clave a la consulta <code>DISTINCT</code> a su consulta SQL.
  6960. </para>
  6961. <example id="zend.db.select.building.distinct.example">
  6962. <title>Ejemplo del método distinct()</title>
  6963. <programlisting role="php"><![CDATA[
  6964. // Construye esta consulta:
  6965. // SELECT DISTINCT p."product_name"
  6966. // FROM "products" AS p
  6967. $select = $db->select()
  6968. ->distinct()
  6969. ->from(array('p' => 'products'), 'product_name');
  6970. ]]>
  6971. </programlisting>
  6972. </example>
  6973. </sect3>
  6974. <sect3 id="zend.db.select.building.for-update">
  6975. <title>Agregar el modificador FOR UPDATE</title>
  6976. <para>
  6977. El método <code>forUpdate()</code> permite agregar el modificador
  6978. <code>FOR UPDATE</code> a su consulta SQL.
  6979. </para>
  6980. <example id="zend.db.select.building.for-update.example">
  6981. <title>Example of forUpdate() method</title>
  6982. <programlisting role="php"><![CDATA[
  6983. // Construye esta consulta:
  6984. // SELECT FOR UPDATE p.*
  6985. // FROM "products" AS p
  6986. $select = $db->select()
  6987. ->forUpdate()
  6988. ->from(array('p' => 'products'));
  6989. ]]>
  6990. </programlisting>
  6991. </example>
  6992. </sect3>
  6993. </sect2>
  6994. <sect2 id="zend.db.select.execute">
  6995. <title>Ejecutando consultas Select</title>
  6996. <para>
  6997. Esta sección se describe como ejecutar una consulta representada por
  6998. un objeto Zend_Db_Select.
  6999. </para>
  7000. <sect3 id="zend.db.select.execute.query-adapter">
  7001. <title>Ejecutando Consultas SelectExecuting desde el Adaptador de Base de Datos</title>
  7002. <para>
  7003. Puedes ejecutar la consulta representada por el objeto Zend_Db_Select pasandolo
  7004. como primer argumento al método <code>query()</code> de un objeto Zend_Db_Adapter_Abstract.
  7005. Use objetos Zend_Db_Select en lugar de un string de consulta.
  7006. </para>
  7007. <para>
  7008. El método <code>query()</code> retorna un objeto de tipo
  7009. Zend_Db_Statement o PDOStatement, dependiendo del tipo de adaptador.
  7010. </para>
  7011. <example id="zend.db.select.execute.query-adapter.example">
  7012. <title>Ejemplo usando el método adaptador query() del Adaptador de Base de datos</title>
  7013. <programlisting role="php"><![CDATA[
  7014. $select = $db->select()
  7015. ->from('products');
  7016. $stmt = $db->query($select);
  7017. $result = $stmt->fetchAll();
  7018. ]]>
  7019. </programlisting>
  7020. </example>
  7021. </sect3>
  7022. <sect3 id="zend.db.select.execute.query-select">
  7023. <title>Ejecutando Consultas Select desde el Objeto</title>
  7024. <para>
  7025. Como alternativa al uso del método <code>query()</code> del objeto adaptador,
  7026. puedes usar el método <code>query()</code> del objeto Zend_Db_Select. Ambos
  7027. métodos retornan un objeto de tipo Zend_Db_Statement o PDOStatement, dependiendo
  7028. del tipo de adaptador.
  7029. </para>
  7030. <example id="zend.db.select.execute.query-select.example">
  7031. <title>Ejempo usando el método query() del objeto Select</title>
  7032. <programlisting role="php"><![CDATA[
  7033. $select = $db->select()
  7034. ->from('products');
  7035. $stmt = $select->query();
  7036. $result = $stmt->fetchAll();
  7037. ]]>
  7038. </programlisting>
  7039. </example>
  7040. </sect3>
  7041. <sect3 id="zend.db.select.execute.tostring">
  7042. <title>Convertiendo un Objeto Select a un String SQL</title>
  7043. <para>
  7044. Si necesitas acceder a una represantación en un string de la
  7045. consulta SQL correspondiente al objeto Zend_Db_Select,
  7046. use el método <code>__toString()</code>.
  7047. </para>
  7048. <example id="zend.db.select.execute.tostring.example">
  7049. <title>Ejemplo del método __toString()</title>
  7050. <programlisting role="php"><![CDATA[
  7051. $select = $db->select()
  7052. ->from('products');
  7053. $sql = $select->__toString();
  7054. echo "$sql\n";
  7055. // The output is the string:
  7056. // SELECT * FROM "products"
  7057. ]]>
  7058. </programlisting>
  7059. </example>
  7060. </sect3>
  7061. </sect2>
  7062. <sect2 id="zend.db.select.other">
  7063. <title>Otros Métodos</title>
  7064. <para>
  7065. Esta sección describe otros métodos de Zend_Db_Select que no han
  7066. sido cubiertos antes: <code>getPart()</code> y <code>reset()</code>.
  7067. </para>
  7068. <sect3 id="zend.db.select.other.get-part">
  7069. <title>Obtener Partes de un Objeto Select</title>
  7070. <para>
  7071. El método <code>getPart()</code> retorna una representación de
  7072. una parte de su consulta SQL. Por ejemplo, puedes usar este
  7073. método para retornar un array de expresiones para la cláusula
  7074. <code>WHERE</code>, o el array de columnas (o expresiones de
  7075. columnas) que estan en la lista del <code>SELECT</code>, o los
  7076. valores de la cantidad y comienzo para la cláusula
  7077. <code>LIMIT</code>.
  7078. </para>
  7079. <para>
  7080. El valor de retorno no es un string conteniendo un fragmento
  7081. de la sintaxis SQL. El valor de retorno es una representación,
  7082. típicamente un array con una estructura que contiene valores y
  7083. expresiones. Cada parte de la consulta tiene una estructura
  7084. diferente.
  7085. </para>
  7086. <para>
  7087. El único argumento del método <code>getPart()</code> es un
  7088. string que identifica que parte del la consulta Select va a
  7089. retornar. Por ejemplo, el string <code>'from'</code> identifica
  7090. la parte del objeto Select que almacena la información de las
  7091. tablas de la cláusula <code>FROM</code>, incluyendo uniones de
  7092. tablas.
  7093. </para>
  7094. <para>
  7095. La clase Zend_Db_Select define constantes que puedes usar para
  7096. las partes de la consulta SQL.
  7097. Puedes usar estas definiciones de constantes, o los strings
  7098. literales.
  7099. </para>
  7100. <table id="zend.db.select.other.get-part.table">
  7101. <title>Constantes usedas por getPart() y reset()</title>
  7102. <tgroup cols="2">
  7103. <thead>
  7104. <row>
  7105. <entry>Constante</entry>
  7106. <entry>Valor del String</entry>
  7107. </row>
  7108. </thead>
  7109. <tbody>
  7110. <row>
  7111. <entry><code>Zend_Db_Select::DISTINCT</code></entry>
  7112. <entry><code>'distinct'</code></entry>
  7113. </row>
  7114. <row>
  7115. <entry><code>Zend_Db_Select::FOR_UPDATE</code></entry>
  7116. <entry><code>'forupdate'</code></entry>
  7117. </row>
  7118. <row>
  7119. <entry><code>Zend_Db_Select::COLUMNS</code></entry>
  7120. <entry><code>'columns'</code></entry>
  7121. </row>
  7122. <row>
  7123. <entry><code>Zend_Db_Select::FROM</code></entry>
  7124. <entry><code>'from'</code></entry>
  7125. </row>
  7126. <row>
  7127. <entry><code>Zend_Db_Select::WHERE</code></entry>
  7128. <entry><code>'where'</code></entry>
  7129. </row>
  7130. <row>
  7131. <entry><code>Zend_Db_Select::GROUP</code></entry>
  7132. <entry><code>'group'</code></entry>
  7133. </row>
  7134. <row>
  7135. <entry><code>Zend_Db_Select::HAVING</code></entry>
  7136. <entry><code>'having'</code></entry>
  7137. </row>
  7138. <row>
  7139. <entry><code>Zend_Db_Select::ORDER</code></entry>
  7140. <entry><code>'order'</code></entry>
  7141. </row>
  7142. <row>
  7143. <entry><code>Zend_Db_Select::LIMIT_COUNT</code></entry>
  7144. <entry><code>'limitcount'</code></entry>
  7145. </row>
  7146. <row>
  7147. <entry><code>Zend_Db_Select::LIMIT_OFFSET</code></entry>
  7148. <entry><code>'limitoffset'</code></entry>
  7149. </row>
  7150. </tbody>
  7151. </tgroup>
  7152. </table>
  7153. <example id="zend.db.select.other.get-part.example">
  7154. <title>Ejemplo del método getPart()</title>
  7155. <programlisting role="php"><![CDATA[
  7156. $select = $db->select()
  7157. ->from('products')
  7158. ->order('product_id');
  7159. // Puedes especificar un string string literal para especificar la parte
  7160. $orderData = $select->getPart( 'order' );
  7161. // Puedes usar una constante para especificar la misma parte
  7162. $orderData = $select->getPart( Zend_Db_Select::ORDER );
  7163. // El valor de retorno puede ser una estructura en un array, no un string.
  7164. // Cada parte tiene distinta estructura.
  7165. print_r( $orderData );
  7166. ]]>
  7167. </programlisting>
  7168. </example>
  7169. </sect3>
  7170. <sect3 id="zend.db.select.other.reset">
  7171. <title>Restableciendo Partes de un Objeto</title>
  7172. <para>
  7173. El método <code>reset()</code> permite limpiar una parte
  7174. específica de la consulta SQL, o limpia todas las partes de la
  7175. consulta SQL si omites el argumento.
  7176. </para>
  7177. <para>
  7178. El argumento es opcional. Puedes especificar la parte de la
  7179. consulta que será limpiada, usando los mismos strings que usa el
  7180. argumento del método <code>getPart()</code>. La parte de la
  7181. consulta que especifiques se reestablecerá a su estado por
  7182. omisión.
  7183. </para>
  7184. <para>
  7185. Si omites el parámetro, <code>reset()</code> cambia todas las
  7186. partes de la consulta a su estado por omisión. Esto hace que
  7187. el objeto Zend_Db_Select sea equivalente a crear un nuevo
  7188. objeto, como si acabases de instanciarlo.
  7189. </para>
  7190. <example id="zend.db.select.other.reset.example">
  7191. <title>Ejemplo del método reset()</title>
  7192. <programlisting role="php"><![CDATA[
  7193. // Construye esta consulta:
  7194. // SELECT p.*
  7195. // FROM "products" AS p
  7196. // ORDER BY "product_name"
  7197. $select = $db->select()
  7198. ->from(array('p' => 'products')
  7199. ->order('product_name');
  7200. // Requisito cambiado, en su lugar un orden diferente de columnas:
  7201. // SELECT p.*
  7202. // FROM "products" AS p
  7203. // ORDER BY "product_id"
  7204. // Limpia una parte para poder redefinirla
  7205. $select->reset( Zend_Db_Select::ORDER );
  7206. // Y especificar una columna diferente
  7207. $select->order('product_id');
  7208. // Limpia todas las partes de la consulta
  7209. $select->reset();
  7210. ]]>
  7211. </programlisting>
  7212. </example>
  7213. </sect3>
  7214. </sect2>
  7215. </sect1><!--
  7216. vim:se ts=4 sw=4 et:
  7217. -->
  7218. <sect1 id="zend.db.table" xml:base="module_specs/Zend_Db_Table.xml">
  7219. <title>Zend_Db_Table</title>
  7220. <sect2 id="zend.db.table.introduction">
  7221. <title>Introduction to Table Class</title>
  7222. <para>
  7223. The Zend_Db_Table class is an object-oriented interface to database tables. It provides
  7224. methods for many common operations on tables. The base class is extensible, so you can
  7225. add custom logic.
  7226. </para>
  7227. <para>
  7228. The Zend_Db_Table solution is an implementation of the
  7229. <ulink url="http://www.martinfowler.com/eaaCatalog/tableDataGateway.html">Table Data
  7230. Gateway</ulink> pattern. The solution also includes a class that implements the
  7231. <ulink url="http://www.martinfowler.com/eaaCatalog/rowDataGateway.html">Row Data
  7232. Gateway</ulink> pattern.
  7233. </para>
  7234. </sect2>
  7235. <sect2 id="zend.db.table.defining">
  7236. <title>Defining a Table Class</title>
  7237. <para>
  7238. For each table in your database that you want to access, define a class that extends
  7239. Zend_Db_Table_Abstract.
  7240. </para>
  7241. <sect3 id="zend.db.table.defining.table-schema">
  7242. <title>Defining the Table Name and Schema</title>
  7243. <para>
  7244. Declare the database table for which this class is defined, using the protected
  7245. variable <code>$_name</code>. This is a string, and must contain the name of the
  7246. table spelled as it appears in the database.
  7247. </para>
  7248. <example id="zend.db.table.defining.table-schema.example1">
  7249. <title>Declaring a table class with explicit table name</title>
  7250. <programlisting role="php"><![CDATA[
  7251. class Bugs extends Zend_Db_Table_Abstract
  7252. {
  7253. protected $_name = 'bugs';
  7254. }
  7255. ]]>
  7256. </programlisting>
  7257. </example>
  7258. <para>
  7259. If you don't specify the table name, it defaults to the name of the class. If you
  7260. rely on this default, the class name must match the spelling of the table name as
  7261. it appears in the database.
  7262. </para>
  7263. <example id="zend.db.table.defining.table-schema.example">
  7264. <title>Declaring a table class with implicit table name</title>
  7265. <programlisting role="php"><![CDATA[
  7266. class bugs extends Zend_Db_Table_Abstract
  7267. {
  7268. // table name matches class name
  7269. }
  7270. ]]>
  7271. </programlisting>
  7272. </example>
  7273. <para>
  7274. You can also declare the schema for the table, either with the protected variable
  7275. <code>$_schema</code>, or with the schema prepended to the table name in the
  7276. <code>$_name</code> property. Any schema specified with the <code>$_name</code>
  7277. property takes precedence over a schema specified with the <code>$_schema</code>
  7278. property. In some RDBMS brands, the term for schema is "database" or "tablespace,"
  7279. but it is used similarly.
  7280. </para>
  7281. <example id="zend.db.table.defining.table-schema.example3">
  7282. <title>Declaring a table class with schema</title>
  7283. <programlisting role="php"><![CDATA[
  7284. // First alternative:
  7285. class Bugs extends Zend_Db_Table_Abstract
  7286. {
  7287. protected $_schema = 'bug_db';
  7288. protected $_name = 'bugs';
  7289. }
  7290. // Second alternative:
  7291. class Bugs extends Zend_Db_Table_Abstract
  7292. {
  7293. protected $_name = 'bug_db.bugs';
  7294. }
  7295. // If schemas are specified in both $_name and $_schema, the one
  7296. // specified in $_name takes precedence:
  7297. class Bugs extends Zend_Db_Table_Abstract
  7298. {
  7299. protected $_name = 'bug_db.bugs';
  7300. protected $_schema = 'ignored';
  7301. }
  7302. ]]>
  7303. </programlisting>
  7304. </example>
  7305. <para>
  7306. The schema and table names may also be specified via constructor configuration
  7307. directives, which override any default values specified with the
  7308. <code>$_name</code> and <code>$_schema</code> properties. A schema specification
  7309. given with the <code>name</code> directive overrides any value provided with the
  7310. <code>schema</code> option.
  7311. </para>
  7312. <example id="zend.db.table.defining.table-schema.example.constructor">
  7313. <title>Declaring table and schema names upon instantiation</title>
  7314. <programlisting role="php"><![CDATA[
  7315. class Bugs extends Zend_Db_Table_Abstract
  7316. {
  7317. }
  7318. // First alternative:
  7319. $tableBugs = new Bugs(array('name' => 'bugs', 'schema' => 'bug_db'));
  7320. // Second alternative:
  7321. $tableBugs = new Bugs(array('name' => 'bug_db.bugs');
  7322. // If schemas are specified in both 'name' and 'schema', the one
  7323. // specified in 'name' takes precedence:
  7324. $tableBugs = new Bugs(array('name' => 'bug_db.bugs',
  7325. 'schema' => 'ignored');
  7326. ]]>
  7327. </programlisting>
  7328. </example>
  7329. <para>
  7330. If you don't specify the schema name, it defaults to the schema to which your
  7331. database adapter instance is connected.
  7332. </para>
  7333. </sect3>
  7334. <sect3 id="zend.db.table.defining.primary-key">
  7335. <title>Defining the Table Primary Key</title>
  7336. <para>
  7337. Every table must have a primary key. You can declare the column for the primary key
  7338. using the protected variable <code>$_primary</code>. This is either a string that
  7339. names the single column for the primary key, or else it is an array of column names
  7340. if your primary key is a compound key.
  7341. </para>
  7342. <example id="zend.db.table.defining.primary-key.example">
  7343. <title>Example of specifying the primary key</title>
  7344. <programlisting role="php"><![CDATA[
  7345. class Bugs extends Zend_Db_Table_Abstract
  7346. {
  7347. protected $_name = 'bugs';
  7348. protected $_primary = 'bug_id';
  7349. }
  7350. ]]>
  7351. </programlisting>
  7352. </example>
  7353. <para>
  7354. If you don't specify the primary key, Zend_Db_Table_Abstract tries to discover the
  7355. primary key based on the information provided by the <code>describeTable()</code>´
  7356. method.
  7357. </para>
  7358. <note>
  7359. <para>
  7360. Every table class must know which column(s) can be used to address rows
  7361. uniquely. If no primary key column(s) are specified in the table class
  7362. definition or the table constructor arguments, or discovered in the table
  7363. metadata provided by <code>describeTable()</code>, then the table cannot be
  7364. used with Zend_Db_Table.
  7365. </para>
  7366. </note>
  7367. </sect3>
  7368. <sect3 id="zend.db.table.defining.setup">
  7369. <title>Overriding Table Setup Methods</title>
  7370. <para>
  7371. When you create an instance of a Table class, the constructor calls a set of
  7372. protected methods that initialize metadata for the table. You can extend any of
  7373. these methods to define metadata explicitly. Remember to call the method of the
  7374. same name in the parent class at the end of your method.
  7375. </para>
  7376. <example id="zend.db.table.defining.setup.example">
  7377. <title>Example of overriding the _setupTableName() method</title>
  7378. <programlisting role="php"><![CDATA[
  7379. class Bugs extends Zend_Db_Table_Abstract
  7380. {
  7381. protected function _setupTableName()
  7382. {
  7383. $this->_name = 'bugs';
  7384. parent::_setupTableName();
  7385. }
  7386. }
  7387. ]]>
  7388. </programlisting>
  7389. </example>
  7390. <para>
  7391. The setup methods you can override are the following:
  7392. </para>
  7393. <itemizedlist>
  7394. <listitem>
  7395. <para>
  7396. <code>_setupDatabaseAdapter()</code> checks that an adapter has been
  7397. provided; gets a default adapter from the registry if needed. By overriding
  7398. this method, you can set a database adapter from some other source.
  7399. </para>
  7400. </listitem>
  7401. <listitem>
  7402. <para>
  7403. <code>_setupTableName()</code> defaults the table name to the name of the
  7404. class. By overriding this method, you can set the table name before this
  7405. default behavior runs.
  7406. </para>
  7407. </listitem>
  7408. <listitem>
  7409. <para>
  7410. <code>_setupMetadata()</code> sets the schema if the table name contains
  7411. the pattern "schema.table"; calls <code>describeTable()</code> to get
  7412. metadata information; defaults the <code>$_cols</code> array to the columns
  7413. reported by <code>describeTable()</code>. By overriding this method, you
  7414. can specify the columns.
  7415. </para>
  7416. </listitem>
  7417. <listitem>
  7418. <para>
  7419. <code>_setupPrimaryKey()</code> defaults the primary key columns to those
  7420. reported by <code>describeTable()</code>; checks that the primary key
  7421. columns are included in the <code>$_cols</code> array. By overriding this
  7422. method, you can specify the primary key columns.
  7423. </para>
  7424. </listitem>
  7425. </itemizedlist>
  7426. </sect3>
  7427. <sect3 id="zend.db.table.initialization">
  7428. <title>Table initialization</title>
  7429. <para>
  7430. If application-specific logic needs to be initialized when a Table class is
  7431. constructed, you can select to move your tasks to the <code>init()</code> method,
  7432. which is called after all Table metadata has been processed. This is recommended
  7433. over the <code>__construct</code> method if you do not need to alter the metadata
  7434. in any programmatic way.
  7435. <example id="zend.db.table.defining.init.usage.example">
  7436. <title>Example usage of init() method</title>
  7437. <programlisting role="php"><![CDATA[
  7438. class Bugs extends Zend_Db_Table_Abstract
  7439. {
  7440. protected $_observer;
  7441. protected function init()
  7442. {
  7443. $this->_observer = new MyObserverClass();
  7444. }
  7445. }
  7446. ]]>
  7447. </programlisting>
  7448. </example>
  7449. </para>
  7450. </sect3>
  7451. </sect2>
  7452. <sect2 id="zend.db.table.constructing">
  7453. <title>Creating an Instance of a Table</title>
  7454. <para>
  7455. Before you use a Table class, create an instance using its constructor. The
  7456. constructor's argument is an array of options. The most important option to a Table
  7457. constructor is the database adapter instance, representing a live connection to an
  7458. RDBMS. There are three ways of specifying the database adapter to a Table class, and
  7459. these three ways are described below:
  7460. </para>
  7461. <sect3 id="zend.db.table.constructing.adapter">
  7462. <title>Specifying a Database Adapter</title>
  7463. <para>
  7464. The first way to provide a database adapter to a Table class is by passing it as an
  7465. object of type Zend_Db_Adapter_Abstract in the options array, identified by the key
  7466. <code>'db'</code>.
  7467. </para>
  7468. <example id="zend.db.table.constructing.adapter.example">
  7469. <title>Example of constructing a Table using an Adapter object</title>
  7470. <programlisting role="php"><![CDATA[
  7471. $db = Zend_Db::factory('PDO_MYSQL', $options);
  7472. $table = new Bugs(array('db' => $db));
  7473. ]]>
  7474. </programlisting>
  7475. </example>
  7476. </sect3>
  7477. <sect3 id="zend.db.table.constructing.default-adapter">
  7478. <title>Setting a Default Database Adapter</title>
  7479. <para>
  7480. The second way to provide a database adapter to a Table class is by declaring an
  7481. object of type Zend_Db_Adapter_Abstract to be a default database adapter for all
  7482. subsequent instances of Tables in your application. You can do this with the static
  7483. method <code>Zend_Db_Table_Abstract::setDefaultAdapter()</code>. The argument is an
  7484. object of type Zend_Db_Adapter_Abstract.
  7485. </para>
  7486. <example id="zend.db.table.constructing.default-adapter.example">
  7487. <title>Example of constructing a Table using a the Default Adapter</title>
  7488. <programlisting role="php"><![CDATA[
  7489. $db = Zend_Db::factory('PDO_MYSQL', $options);
  7490. Zend_Db_Table_Abstract::setDefaultAdapter($db);
  7491. // Later...
  7492. $table = new Bugs();
  7493. ]]>
  7494. </programlisting>
  7495. </example>
  7496. <para>
  7497. It can be convenient to create the database adapter object in a central place of
  7498. your application, such as the bootstrap, and then store it as the default adapter.
  7499. This gives you a means to ensure that the adapter instance is the same throughout
  7500. your application. However, setting a default adapter is limited to a single adapter
  7501. instance.
  7502. </para>
  7503. </sect3>
  7504. <sect3 id="zend.db.table.constructing.registry">
  7505. <title>Storing a Database Adapter in the Registry</title>
  7506. <para>
  7507. The third way to provide a database adapter to a Table class is by passing a string
  7508. in the options array, also identified by the <code>'db'</code> key. The string is
  7509. used as a key to the static Zend_Registry instance, where the entry at that key is
  7510. an object of type Zend_Db_Adapter_Abstract.
  7511. </para>
  7512. <example id="zend.db.table.constructing.registry.example">
  7513. <title>Example of constructing a Table using a Registry key</title>
  7514. <programlisting role="php"><![CDATA[
  7515. $db = Zend_Db::factory('PDO_MYSQL', $options);
  7516. Zend_Registry::set('my_db', $db);
  7517. // Later...
  7518. $table = new Bugs(array('db' => 'my_db'));
  7519. ]]>
  7520. </programlisting>
  7521. </example>
  7522. <para>
  7523. Like setting the default adapter, this gives you the means to ensure that the same
  7524. adapter instance is used throughout your application. Using the registry is more
  7525. flexible, because you can store more than one adapter instance. A given adapter
  7526. instance is specific to a certain RDBMS brand and database instance. If your
  7527. application needs access to multiple databases or even multiple database brands,
  7528. then you need to use multiple adapters.
  7529. </para>
  7530. </sect3>
  7531. </sect2>
  7532. <sect2 id="zend.db.table.insert">
  7533. <title>Inserting Rows to a Table</title>
  7534. <para>
  7535. You can use the Table object to insert rows into the database table on which the Table
  7536. object is based. Use the <code>insert()</code> method of your Table object. The
  7537. argument is an associative array, mapping column names to values.
  7538. </para>
  7539. <example id="zend.db.table.insert.example">
  7540. <title>Example of inserting to a Table</title>
  7541. <programlisting role="php"><![CDATA[
  7542. $table = new Bugs();
  7543. $data = array(
  7544. 'created_on' => '2007-03-22',
  7545. 'bug_description' => 'Something wrong',
  7546. 'bug_status' => 'NEW'
  7547. );
  7548. $table->insert($data);
  7549. ]]>
  7550. </programlisting>
  7551. </example>
  7552. <para>
  7553. By default, the values in your data array are inserted as literal values, using
  7554. parameters. If you need them to be treated as SQL expressions, you must make sure they
  7555. are distinct from plain strings. Use an object of type Zend_Db_Expr to do this.
  7556. </para>
  7557. <example id="zend.db.table.insert.example-expr">
  7558. <title>Example of inserting expressions to a Table</title>
  7559. <programlisting role="php"><![CDATA[
  7560. $table = new Bugs();
  7561. $data = array(
  7562. 'created_on' => new Zend_Db_Expr('CURDATE()'),
  7563. 'bug_description' => 'Something wrong',
  7564. 'bug_status' => 'NEW'
  7565. );
  7566. ]]>
  7567. </programlisting>
  7568. </example>
  7569. <para>
  7570. In the examples of inserting rows above, it is assumed that the table has an
  7571. auto-incrementing primary key. This is the default behavior of Zend_Db_Table_Abstract,
  7572. but there are other types of primary keys as well. The following sections describe how
  7573. to support different types of primary keys.
  7574. </para>
  7575. <sect3 id="zend.db.table.insert.key-auto">
  7576. <title>Using a Table with an Auto-incrementing Key</title>
  7577. <para>
  7578. An auto-incrementing primary key generates a unique integer value for you if you
  7579. omit the primary key column from your SQL <code>INSERT</code> statement.
  7580. </para>
  7581. <para>
  7582. In Zend_Db_Table_Abstract, if you define the protected variable
  7583. <code>$_sequence</code> to be the Boolean value <code>true</code>, then the class
  7584. assumes that the table has an auto-incrementing primary key.
  7585. </para>
  7586. <example id="zend.db.table.insert.key-auto.example">
  7587. <title>Example of declaring a Table with auto-incrementing primary key</title>
  7588. <programlisting role="php"><![CDATA[
  7589. class Bugs extends Zend_Db_Table_Abstract
  7590. {
  7591. protected $_name = 'bugs';
  7592. // This is the default in the Zend_Db_Table_Abstract class;
  7593. // you do not need to define this.
  7594. protected $_sequence = true;
  7595. }
  7596. ]]>
  7597. </programlisting>
  7598. </example>
  7599. <para>
  7600. MySQL, Microsoft SQL Server, and SQLite are examples of RDBMS brands that support
  7601. auto-incrementing primary keys.
  7602. </para>
  7603. <para>
  7604. PostgreSQL has a <code>SERIAL</code> notation that implicitly defines a sequence
  7605. based on the table and column name, and uses the sequence to generate key values
  7606. for new rows. IBM DB2 has an <code>IDENTITY</code> notation that works similarly.
  7607. If you use either of these notations, treat your Zend_Db_Table class as having an
  7608. auto-incrementing column with respect to declaring the <code>$_sequence</code>
  7609. member as <code>true</code>.
  7610. </para>
  7611. </sect3>
  7612. <sect3 id="zend.db.table.insert.key-sequence">
  7613. <title>Using a Table with a Sequence</title>
  7614. <para>
  7615. A sequence is a database object that generates a unique value, which can be used
  7616. as a primary key value in one or more tables of the database.
  7617. </para>
  7618. <para>
  7619. If you define <code>$_sequence</code> to be a string, then Zend_Db_Table_Abstract
  7620. assumes the string to name a sequence object in the database. The sequence is
  7621. invoked to generate a new value, and this value is used in the <code>INSERT</code>
  7622. operation.
  7623. </para>
  7624. <example id="zend.db.table.insert.key-sequence.example">
  7625. <title>Example of declaring a Table with a sequence</title>
  7626. <programlisting role="php"><![CDATA[
  7627. class Bugs extends Zend_Db_Table_Abstract
  7628. {
  7629. protected $_name = 'bugs';
  7630. protected $_sequence = 'bug_sequence';
  7631. }
  7632. ]]>
  7633. </programlisting>
  7634. </example>
  7635. <para>
  7636. Oracle, PostgreSQL, and IBM DB2 are examples of RDBMS brands that support sequence
  7637. objects in the database.
  7638. </para>
  7639. <para>
  7640. PostgreSQL and IBM DB2 also have syntax that defines sequences implicitly and
  7641. associated with columns. If you use this notation, treat the table as having an
  7642. auto-incrementing key column. Define the sequence name as a string only in cases
  7643. where you would invoke the sequence explicitly to get the next key value.
  7644. </para>
  7645. </sect3>
  7646. <sect3 id="zend.db.table.insert.key-natural">
  7647. <title>Using a Table with a Natural Key</title>
  7648. <para>
  7649. Some tables have a natural key. This means that the key is not automatically
  7650. generated by the table or by a sequence. You must specify the value for the primary
  7651. key in this case.
  7652. </para>
  7653. <para>
  7654. If you define the <code>$_sequence</code> to be the Boolean value
  7655. <code>false</code>, then Zend_Db_Table_Abstract assumes that the table has a
  7656. natural primary key. You must provide values for the primary key columns in the
  7657. array of data to the <code>insert()</code> method, or else this method throws a
  7658. Zend_Db_Table_Exception.
  7659. </para>
  7660. <example id="zend.db.table.insert.key-natural.example">
  7661. <title>Example of declaring a Table with a natural key</title>
  7662. <programlisting role="php"><![CDATA[
  7663. class BugStatus extends Zend_Db_Table_Abstract
  7664. {
  7665. protected $_name = 'bug_status';
  7666. protected $_sequence = false;
  7667. }
  7668. ]]>
  7669. </programlisting>
  7670. </example>
  7671. <note>
  7672. <para>
  7673. All RDBMS brands support tables with natural keys. Examples of tables that are
  7674. often declared as having natural keys are lookup tables, intersection tables in
  7675. many-to-many relationships, or most tables with compound primary keys.
  7676. </para>
  7677. </note>
  7678. </sect3>
  7679. </sect2>
  7680. <sect2 id="zend.db.table.update">
  7681. <title>Updating Rows in a Table</title>
  7682. <para>
  7683. You can update rows in a database table using the <code>update</code> method of a Table
  7684. class. This method takes two arguments: an associative array of columns to change and
  7685. new values to assign to these columns; and an SQL expression that is used in a
  7686. <code>WHERE</code> clause, as criteria for the rows to change in the
  7687. <code>UPDATE</code> operation.
  7688. </para>
  7689. <example id="zend.db.table.update.example">
  7690. <title>Example of updating rows in a Table</title>
  7691. <programlisting role="php"><![CDATA[
  7692. $table = new Bugs();
  7693. $data = array(
  7694. 'updated_on' => '2007-03-23',
  7695. 'bug_status' => 'FIXED'
  7696. );
  7697. $where = $table->getAdapter()->quoteInto('bug_id = ?', 1234);
  7698. $table->update($data, $where);
  7699. ]]>
  7700. </programlisting>
  7701. </example>
  7702. <para>
  7703. Since the table <code>update()</code> method proxies to the database adapter
  7704. <link linkend="zend.db.adapter.write.update"><code>update()</code></link> method, the
  7705. second argument can be an array of SQL expressions. The expressions are combined as
  7706. Boolean terms using an <code>AND</code> operator.
  7707. </para>
  7708. <note>
  7709. <para>
  7710. The values and identifiers in the SQL expression are not quoted for you. If you
  7711. have values or identifiers that require quoting, you are responsible for doing
  7712. this. Use the <code>quote()</code>, <code>quoteInto()</code>, and
  7713. <code>quoteIdentifier()</code> methods of the database adapter.
  7714. </para>
  7715. </note>
  7716. </sect2>
  7717. <sect2 id="zend.db.table.delete">
  7718. <title>Deleting Rows from a Table</title>
  7719. <para>
  7720. You can delete rows from a database table using the <code>delete()</code> method. This
  7721. method takes one argument, which is an SQL expression that is used in a
  7722. <code>WHERE</code> clause, as criteria for the rows to delete.
  7723. </para>
  7724. <example id="zend.db.table.delete.example">
  7725. <title>Example of deleting rows from a Table</title>
  7726. <programlisting role="php"><![CDATA[
  7727. $table = new Bugs();
  7728. $where = $table->getAdapter()->quoteInto('bug_id = ?', 1235);
  7729. $table->delete($where);
  7730. ]]>
  7731. </programlisting>
  7732. </example>
  7733. <para>
  7734. The second argument can be an array of SQL expressions. The expressions are combined as
  7735. Boolean terms using an <code>AND</code> operator.
  7736. </para>
  7737. <para>
  7738. Since the table <code>delete()</code> method proxies to the database adapter
  7739. <link linkend="zend.db.adapter.write.delete"><code>delete()</code></link> method, the
  7740. second argument can be an array of SQL expressions. The expressions are combined as
  7741. Boolean terms using an <code>AND</code> operator.
  7742. </para>
  7743. <note>
  7744. <para>
  7745. The values and identifiers in the SQL expression are not quoted for you. If you
  7746. have values or identifiers that require quoting, you are responsible for doing
  7747. this. Use the <code>quote()</code>, <code>quoteInto()</code>, and
  7748. <code>quoteIdentifier()</code> methods of the database adapter.
  7749. </para>
  7750. </note>
  7751. </sect2>
  7752. <sect2 id="zend.db.table.find">
  7753. <title>Finding Rows by Primary Key</title>
  7754. <para>
  7755. You can query the database table for rows matching specific values in the primary key,
  7756. using the <code>find()</code> method. The first argument of this method is either a
  7757. single value or an array of values to match against the primary key of the table.
  7758. </para>
  7759. <example id="zend.db.table.find.example">
  7760. <title>Example of finding rows by primary key values</title>
  7761. <programlisting role="php"><![CDATA[
  7762. $table = new Bugs();
  7763. // Find a single row
  7764. // Returns a Rowset
  7765. $rows = $table->find(1234);
  7766. // Find multiple rows
  7767. // Also returns a Rowset
  7768. $rows = $table->find(array(1234, 5678));
  7769. ]]>
  7770. </programlisting>
  7771. </example>
  7772. <para>
  7773. If you specify a single value, the method returns at most one row, because a primary
  7774. key cannot have duplicate values and there is at most one row in the database table
  7775. matching the value you specify. If you specify multiple values in an array, the method
  7776. returns at most as many rows as the number of distinct values you specify.
  7777. </para>
  7778. <para>
  7779. The <code>find()</code> method might return fewer rows than the number of values you
  7780. specify for the primary key, if some of the values don't match any rows in the database
  7781. table. The method even may return zero rows. Because the number of rows returned is
  7782. variable, the <code>find()</code> method returns an object of type
  7783. <classname>Zend_Db_Table_Rowset_Abstract</classname>.
  7784. </para>
  7785. <para>
  7786. If the primary key is a compound key, that is, it consists of multiple columns, you can
  7787. specify the additional columns as additional arguments to the <code>find()</code>
  7788. method. You must provide as many arguments as the number of columns in the table's
  7789. primary key.
  7790. </para>
  7791. <para>
  7792. To find multiple rows from a table with a compound primary key, provide an array for
  7793. each of the arguments. All of these arrays must have the same number of elements. The
  7794. values in each array are formed into tuples in order; for example, the first element
  7795. in all the array arguments define the first compound primary key value, then the second
  7796. elements of all the arrays define the second compound primary key value, and so on.
  7797. </para>
  7798. <example id="zend.db.table.find.example-compound">
  7799. <title>Example of finding rows by compound primary key values</title>
  7800. <para>
  7801. The call to <code>find()</code> below to match multiple rows can match two rows in
  7802. the database. The first row must have primary key value (1234, 'ABC'), and the
  7803. second row must have primary key value (5678, 'DEF').
  7804. </para>
  7805. <programlisting role="php"><![CDATA[
  7806. class BugsProducts extends Zend_Db_Table_Abstract
  7807. {
  7808. protected $_name = 'bugs_products';
  7809. protected $_primary = array('bug_id', 'product_id');
  7810. }
  7811. $table = new BugsProducts();
  7812. // Find a single row with a compound primary key
  7813. // Returns a Rowset
  7814. $rows = $table->find(1234, 'ABC');
  7815. // Find multiple rows with compound primary keys
  7816. // Also returns a Rowset
  7817. $rows = $table->find(array(1234, 5678), array('ABC', 'DEF'));
  7818. ]]>
  7819. </programlisting>
  7820. </example>
  7821. </sect2>
  7822. <sect2 id="zend.db.table.fetch-all">
  7823. <title>Querying for a Set of Rows</title>
  7824. <sect3 id="zend.db.table.fetch-all.select">
  7825. <title>Select API</title>
  7826. <para>
  7827. <warning>
  7828. <para>
  7829. The API for fetch operations has been superseded to allow a
  7830. <code>Zend_Db_Table_Select</code> object to modify the query. However, the
  7831. deprecated usage of the <code>fetchRow()</code> and <code>fetchAll()</code>
  7832. methods will continue to work without modification.
  7833. </para>
  7834. <para>
  7835. The following statements are all legal and functionally identical, however
  7836. it is recommended to update your code to take advantage of the new usage
  7837. where possible.
  7838. </para>
  7839. <para>
  7840. <programlisting role="php"><![CDATA[
  7841. // Fetching a rowset
  7842. $rows = $table->fetchAll('bug_status = "NEW"', 'bug_id ASC', 10, 0);
  7843. $rows = $table->fetchAll($table->select()->where('bug_status = ?', 'NEW')
  7844. ->order('bug_id ASC')
  7845. ->limit(10, 0));
  7846. // Fetching a single row
  7847. $row = $table->fetchRow('bug_status = "NEW"', 'bug_id ASC');
  7848. $row = $table->fetchRow($table->select()->where('bug_status = ?', 'NEW')
  7849. ->order('bug_id ASC'));
  7850. ]]>
  7851. </programlisting>
  7852. </para>
  7853. </warning>
  7854. </para>
  7855. <para>
  7856. The <classname>Zend_Db_Table_Select</classname> object is an extension of the
  7857. <classname>Zend_Db_Select</classname> object that applies specific restrictions to
  7858. a query. The enhancements and restrictions are:
  7859. </para>
  7860. <itemizedlist>
  7861. <listitem>
  7862. <para>
  7863. You <emphasis>can</emphasis> elect to return a subset of columns within a
  7864. fetchRow or fetchAll query. This can provide optimization benefits where
  7865. returning a large set of results for all columns is not desirable.
  7866. </para>
  7867. </listitem>
  7868. <listitem>
  7869. <para>
  7870. You <emphasis>can</emphasis> specify columns that evaluate expressions from
  7871. within the selected table. However this will mean that the returned row or
  7872. rowset will be <property>readOnly</property> and cannot be used for save()
  7873. operations. A <code>Zend_Db_Table_Row</code> with
  7874. <property>readOnly</property> status will throw an exception if a
  7875. <code>save()</code> operation is attempted.
  7876. </para>
  7877. </listitem>
  7878. <listitem>
  7879. <para>
  7880. You <emphasis>can</emphasis> allow JOIN clauses on a select to allow
  7881. multi-table lookups.
  7882. </para>
  7883. </listitem>
  7884. <listitem>
  7885. <para>
  7886. You <emphasis>can not</emphasis> specify columns from a JOINed tabled to be
  7887. returned in a row/rowset. Doing so will trigger a PHP error. This was done
  7888. to ensure the integrity of the <code>Zend_Db_Table is retained</code>. i.e.
  7889. A <code>Zend_Db_Table_Row</code> should only reference columns derived from
  7890. its parent table.
  7891. </para>
  7892. </listitem>
  7893. </itemizedlist>
  7894. <para>
  7895. <example id="zend.db.table.qry.rows.set.simple.usage.example">
  7896. <title>Simple usage</title>
  7897. <programlisting role="php"><![CDATA[
  7898. $table = new Bugs();
  7899. $select = $table->select();
  7900. $select->where('bug_status = ?', 'NEW');
  7901. $rows = $table->fetchAll($select);
  7902. ]]>
  7903. </programlisting>
  7904. </example>
  7905. </para>
  7906. <para>
  7907. Fluent interfaces are implemented across the component, so this can be rewritten
  7908. this in a more abbreviated form.
  7909. </para>
  7910. <para>
  7911. <example id="zend.db.table.qry.rows.set.fluent.interface.example">
  7912. <title>Example of fluent interface</title>
  7913. <programlisting role="php"><![CDATA[
  7914. $table = new Bugs();
  7915. $rows =
  7916. $table->fetchAll($table->select()->where('bug_status = ?', 'NEW'));
  7917. ]]>
  7918. </programlisting>
  7919. </example>
  7920. </para>
  7921. </sect3>
  7922. <sect3 id="zend.db.table.fetch-all.usage">
  7923. <title>Fetching a rowset</title>
  7924. <para>
  7925. You can query for a set of rows using any criteria other than the primary key
  7926. values, using the <code>fetchAll()</code> method of the Table class. This method
  7927. returns an object of type <code>Zend_Db_Table_Rowset_Abstract</code>.
  7928. </para>
  7929. <example id="zend.db.table.qry.rows.set.finding.row.example">
  7930. <title>Example of finding rows by an expression</title>
  7931. <programlisting role="php"><![CDATA[
  7932. $table = new Bugs();
  7933. $select = $table->select()->where('bug_status = ?', 'NEW');
  7934. $rows = $table->fetchAll($select);
  7935. ]]>
  7936. </programlisting>
  7937. </example>
  7938. <para>
  7939. You may also pass sorting criteria in an <code>ORDER BY</code> clause, as well as
  7940. count and offset integer values, used to make the query return a specific subset of
  7941. rows. These values are used in a <code>LIMIT</code> clause, or in equivalent logic
  7942. for RDBMS brands that do not support the <code>LIMIT</code> syntax.
  7943. </para>
  7944. <example id="zend.db.table.fetch-all.example2">
  7945. <title>Example of finding rows by an expression</title>
  7946. <programlisting role="php"><![CDATA[
  7947. $table = new Bugs();
  7948. $order = 'bug_id';
  7949. // Return the 21st through 30th rows
  7950. $count = 10;
  7951. $offset = 20;
  7952. $select = $table->select()->where(array('bug_status = ?' => 'NEW'))
  7953. ->order($order)
  7954. ->limit($count, $offset);
  7955. $rows = $table->fetchAll($select);
  7956. ]]>
  7957. </programlisting>
  7958. </example>
  7959. <para>
  7960. All of the arguments above are optional. If you omit the ORDER clause, the result
  7961. set includes rows from the table in an unpredictable order. If no LIMIT clause is
  7962. set, you retrieve every row in the table that matches the WHERE clause.
  7963. </para>
  7964. </sect3>
  7965. <sect3 id="zend.db.table.advanced.usage">
  7966. <title>Advanced usage</title>
  7967. <para>
  7968. For more specific and optimized requests, you may wish to limit the number of
  7969. columns returned in a row/rowset. This can be achieved by passing a FROM clause to
  7970. the select object. The first argument in the FROM clause is identical to that of a
  7971. Zend_Db_Select object with the addition of being able to pass an instance of
  7972. Zend_Db_Table_Abstract and have it automatically determine the table name.
  7973. </para>
  7974. <para>
  7975. <example id="zend.db.table.qry.rows.set.retrieving.a.example">
  7976. <title>Retrieving specific columns</title>
  7977. <programlisting role="php"><![CDATA[
  7978. $table = new Bugs();
  7979. $select = $table->select();
  7980. $select->from($table, array('bug_id', 'bug_description'))
  7981. ->where('bug_status = ?', 'NEW');
  7982. $rows = $table->fetchAll($select);
  7983. ]]>
  7984. </programlisting>
  7985. </example>
  7986. </para>
  7987. <para>
  7988. <important>
  7989. <para>
  7990. The rowset contains rows that are still 'valid' - they simply contain a
  7991. subset of the columns of a table. If a save() method is called on a partial
  7992. row then only the fields available will be modified.
  7993. </para>
  7994. </important>
  7995. You can also specify expressions within a FROM clause and have these returned as a
  7996. readOnly row/rowset. In this example we will return a rows from the bugs table that
  7997. show an aggregate of the number of new bugs reported by individuals. Note the GROUP
  7998. clause. The 'count' column will be made available to the row for evaluation and can
  7999. be accessed as if it were part of the schema.
  8000. </para>
  8001. <para>
  8002. <example id="zend.db.table.qry.rows.set.retrieving.b.example">
  8003. <title>Retrieving expressions as columns</title>
  8004. <programlisting role="php"><![CDATA[
  8005. $table = new Bugs();
  8006. $select = $table->select();
  8007. $select->from($table,
  8008. array('COUNT(reported_by) as `count`', 'reported_by'))
  8009. ->where('bug_status = ?', 'NEW')
  8010. ->group('reported_by');
  8011. $rows = $table->fetchAll($select);
  8012. ]]>
  8013. </programlisting>
  8014. </example>
  8015. You can also use a lookup as part of your query to further refine your fetch
  8016. operations. In this example the accounts table is queried as part of a search for
  8017. all new bugs reported by 'Bob'.
  8018. </para>
  8019. <para>
  8020. <example id="zend.db.table.qry.rows.set.refine.example">
  8021. <title>Using a lookup table to refine the results of fetchAll()</title>
  8022. <programlisting role="php"><![CDATA[
  8023. $table = new Bugs();
  8024. $select = $table->select();
  8025. $select->where('bug_status = ?', 'NEW')
  8026. ->join('accounts', 'accounts.account_name = bugs.reported_by')
  8027. ->where('accounts.account_name = ?', 'Bob');
  8028. $rows = $table->fetchAll($select);
  8029. ]]>
  8030. </programlisting>
  8031. </example>
  8032. </para>
  8033. <para>
  8034. The <classname>Zend_Db_Table_Select</classname> is primarily used to constrain and
  8035. validate so that it may enforce the criteria for a legal SELECT query. However
  8036. there may be certain cases where you require the flexibility of the
  8037. Zend_Db_Table_Row component and do not require a writable or deletable row. For
  8038. this specific user case, it is possible to retrieve a row/rowset by passing a false
  8039. value to setIntegrityCheck. The resulting row/rowset will be returned as a 'locked'
  8040. row (meaning the save(), delete() and any field-setting methods will throw an
  8041. exception).
  8042. </para>
  8043. <example id="zend.db.table.qry.rows.set.integrity.example">
  8044. <title>Removing the integrity check on Zend_Db_Table_Select to allow JOINed rows</title>
  8045. <programlisting><![CDATA[
  8046. $table = new Bugs();
  8047. $select = $table->select()->setIntegrityCheck(false);
  8048. $select->where('bug_status = ?', 'NEW')
  8049. ->join('accounts',
  8050. 'accounts.account_name = bugs.reported_by',
  8051. 'account_name')
  8052. ->where('accounts.account_name = ?', 'Bob');
  8053. $rows = $table->fetchAll($select);
  8054. ]]>
  8055. </programlisting>
  8056. </example>
  8057. </sect3>
  8058. </sect2>
  8059. <sect2 id="zend.db.table.fetch-row">
  8060. <title>Querying for a Single Row</title>
  8061. <para>
  8062. You can query for a single row using criteria similar to that of the
  8063. <code>fetchAll()</code> method.
  8064. </para>
  8065. <example id="zend.db.table.fetch-row.example1">
  8066. <title>Example of finding a single row by an expression</title>
  8067. <programlisting role="php"><![CDATA[
  8068. $table = new Bugs();
  8069. $select = $table->select()->where('bug_status = ?', 'NEW')
  8070. ->order('bug_id');
  8071. $row = $table->fetchRow($select);
  8072. ]]>
  8073. </programlisting>
  8074. </example>
  8075. <para>
  8076. This method returns an object of type Zend_Db_Table_Row_Abstract. If the search
  8077. criteria you specified match no rows in the database table, then
  8078. <code>fetchRow()</code> returns PHP's <code>null</code> value.
  8079. </para>
  8080. </sect2>
  8081. <sect2 id="zend.db.table.info">
  8082. <title>Retrieving Table Metadata Information</title>
  8083. <para>
  8084. The Zend_Db_Table_Abstract class provides some information about its metadata. The
  8085. <code>info()</code> method returns an array structure with information about the table,
  8086. its columns and primary key, and other metadata.
  8087. </para>
  8088. <example id="zend.db.table.info.example">
  8089. <title>Example of getting the table name</title>
  8090. <programlisting role="php"><![CDATA[
  8091. $table = new Bugs();
  8092. $info = $table->info();
  8093. echo "The table name is " . $info['name'] . "\n";
  8094. ]]>
  8095. </programlisting>
  8096. </example>
  8097. <para>
  8098. The keys of the array returned by the <code>info()</code> method are described below:
  8099. </para>
  8100. <itemizedlist>
  8101. <listitem>
  8102. <para>
  8103. <emphasis role="strong">name</emphasis> =&gt; the name of the table.
  8104. </para>
  8105. </listitem>
  8106. <listitem>
  8107. <para>
  8108. <emphasis role="strong">cols</emphasis> =&gt; an array, naming the column(s) of
  8109. the table.
  8110. </para>
  8111. </listitem>
  8112. <listitem>
  8113. <para>
  8114. <emphasis role="strong">primary</emphasis> =&gt; an array, naming the column(s) in
  8115. the primary key.
  8116. </para>
  8117. </listitem>
  8118. <listitem>
  8119. <para>
  8120. <emphasis role="strong">metadata</emphasis> =&gt; an associative array, mapping
  8121. column names to information about the columns. This is the information returned
  8122. by the <code>describeTable()</code> method.
  8123. </para>
  8124. </listitem>
  8125. <listitem>
  8126. <para>
  8127. <emphasis role="strong">rowClass</emphasis> =&gt; the name of the concrete class
  8128. used for Row objects returned by methods of this table instance. This defaults
  8129. to Zend_Db_Table_Row.
  8130. </para>
  8131. </listitem>
  8132. <listitem>
  8133. <para>
  8134. <emphasis role="strong">rowsetClass</emphasis> =&gt; the name of the concrete
  8135. class used for Rowset objects returned by methods of this table instance. This
  8136. defaults to Zend_Db_Table_Rowset.
  8137. </para>
  8138. </listitem>
  8139. <listitem>
  8140. <para>
  8141. <emphasis role="strong">referenceMap</emphasis> =&gt; an associative array, with
  8142. information about references from this table to any parent tables. See
  8143. <xref linkend="zend.db.table.relationships.defining"/>.
  8144. </para>
  8145. </listitem>
  8146. <listitem>
  8147. <para>
  8148. <emphasis role="strong">dependentTables</emphasis> =&gt; an array of class names
  8149. of tables that reference this table. See
  8150. <xref linkend="zend.db.table.relationships.defining"/>.
  8151. </para>
  8152. </listitem>
  8153. <listitem>
  8154. <para>
  8155. <emphasis role="strong">schema</emphasis> =&gt; the name of the schema (or
  8156. database or tablespace) for this table.
  8157. </para>
  8158. </listitem>
  8159. </itemizedlist>
  8160. </sect2>
  8161. <sect2 id="zend.db.table.metadata.caching">
  8162. <title>Caching Table Metadata</title>
  8163. <para>
  8164. By default, <code>Zend_Db_Table_Abstract</code> queries the
  8165. underlying database for <link linkend="zend.db.table.info">table
  8166. metadata</link> whenever that data is needed to perform table
  8167. operations. The table object fetches the table metadata from the
  8168. database using the adapter's <code>describeTable()</code> method.
  8169. Operations requiring this introspection include:
  8170. </para>
  8171. <itemizedlist>
  8172. <listitem><para><code>insert()</code></para></listitem>
  8173. <listitem><para><code>find()</code></para></listitem>
  8174. <listitem><para><code>info()</code></para></listitem>
  8175. </itemizedlist>
  8176. <para>
  8177. In some circumstances, particularly when many table objects are instantiated against
  8178. the same database table, querying the database for the table metadata for each instance
  8179. may be undesirable from a performance standpoint. In such cases, users may benefit by
  8180. caching the table metadata retrieved from the database.
  8181. </para>
  8182. <para>
  8183. There are two primary ways in which a user may take advantage of table metadata
  8184. caching:
  8185. <itemizedlist>
  8186. <listitem>
  8187. <para>
  8188. <emphasis role="strong">Call
  8189. Zend_Db_Table_Abstract::setDefaultMetadataCache()</emphasis> - This allows
  8190. a developer to once set the default cache object to be used for all table
  8191. classes.
  8192. </para>
  8193. </listitem>
  8194. <listitem>
  8195. <para>
  8196. <emphasis role="strong">Configure
  8197. Zend_Db_Table_Abstract::__construct()</emphasis> - This allows a developer
  8198. to set the cache object to be used for a particular table class instance.
  8199. </para>
  8200. </listitem>
  8201. </itemizedlist>
  8202. In both cases, the cache specification must be either <code>null</code> (i.e., no cache
  8203. used) or an instance of
  8204. <link linkend="zend.cache.frontends.core"><code>Zend_Cache_Core</code></link>. The
  8205. methods may be used in conjunction when it is desirable to have both a default metadata
  8206. cache and the ability to change the cache for individual table objects.
  8207. </para>
  8208. <example id="zend.db.table.metadata.caching-default">
  8209. <title>Using a Default Metadata Cache for all Table Objects</title>
  8210. <para>
  8211. The following code demonstrates how to set a default metadata cache to be used for
  8212. all table objects:
  8213. </para>
  8214. <programlisting role="php"><![CDATA[<
  8215. // First, set up the Cache
  8216. $frontendOptions = array(
  8217. 'automatic_serialization' => true
  8218. );
  8219. $backendOptions = array(
  8220. 'cache_dir' => 'cacheDir'
  8221. );
  8222. $cache = Zend_Cache::factory('Core',
  8223. 'File',
  8224. $frontendOptions,
  8225. $backendOptions);
  8226. // Next, set the cache to be used with all table objects
  8227. Zend_Db_Table_Abstract::setDefaultMetadataCache($cache);
  8228. // A table class is also needed
  8229. class Bugs extends Zend_Db_Table_Abstract
  8230. {
  8231. // ...
  8232. }
  8233. // Each instance of Bugs now uses the default metadata cache
  8234. $bugs = new Bugs();
  8235. ]]>
  8236. </programlisting>
  8237. </example>
  8238. <example id="zend.db.table.metadata.caching-instance">
  8239. <title>Using a Metadata Cache for a Specific Table Object</title>
  8240. <para>
  8241. The following code demonstrates how to set a metadata cache for a specific table
  8242. object instance:
  8243. </para>
  8244. <programlisting role="php"><![CDATA[
  8245. // First, set up the Cache
  8246. $frontendOptions = array(
  8247. 'automatic_serialization' => true
  8248. );
  8249. $backendOptions = array(
  8250. 'cache_dir' => 'cacheDir'
  8251. );
  8252. $cache = Zend_Cache::factory('Core',
  8253. 'File',
  8254. $frontendOptions,
  8255. $backendOptions);
  8256. // A table class is also needed
  8257. class Bugs extends Zend_Db_Table_Abstract
  8258. {
  8259. // ...
  8260. }
  8261. // Configure an instance upon instantiation
  8262. $bugs = new Bugs(array('metadataCache' => $cache));
  8263. ]]>
  8264. </programlisting>
  8265. </example>
  8266. <note>
  8267. <title>Automatic Serialization with the Cache Frontend</title>
  8268. <para>
  8269. Since the information returned from the adapter's describeTable() method is an
  8270. array, ensure that the <code>automatic_serialization</code> option is set to
  8271. <code>true</code> for the <code>Zend_Cache_Core</code> frontend.
  8272. </para>
  8273. </note>
  8274. <para>
  8275. Though the above examples use <code>Zend_Cache_Backend_File</code>, developers may use
  8276. whatever cache backend is appropriate for the situation. Please see
  8277. <link linkend="zend.cache">Zend_Cache</link> for more information.
  8278. </para>
  8279. <sect3 id="zend.db.table.metadata.caching.hardcoding">
  8280. <title>Hardcoding Table Metadata</title>
  8281. <para>
  8282. To take metadata caching a step further, you can also choose to
  8283. hardcode metadata. In this particular case, however, any changes
  8284. to the table schema will require a change in your code. As such,
  8285. it is only recommended for those who are optimizing for
  8286. production usage.
  8287. </para>
  8288. <para>
  8289. The metadata structure is as follows:
  8290. </para>
  8291. <programlisting role="php"><![CDATA[
  8292. protected $_metadata = array(
  8293. '<column_name>' => array(
  8294. 'SCHEMA_NAME' => <string>,
  8295. 'TABLE_NAME' => <string>,
  8296. 'COLUMN_NAME' => <string>,
  8297. 'COLUMN_POSITION' => <int>,
  8298. 'DATA_TYPE' => <string>,
  8299. 'DEFAULT' => NULL|<value>,
  8300. 'NULLABLE' => <bool>,
  8301. 'LENGTH' => <string - length>,
  8302. 'SCALE' => NULL|<value>,
  8303. 'PRECISION' => NULL|<value>,
  8304. 'UNSIGNED' => NULL|<bool>,
  8305. 'PRIMARY' => <bool>,
  8306. 'PRIMARY_POSITION' => <int>,
  8307. 'IDENTITY' => <bool>,
  8308. ),
  8309. // additional columns...
  8310. );
  8311. ]]></programlisting>
  8312. <para>
  8313. An easy way to get the appropriate values is to use the metadata
  8314. cache, and then to deserialize values stored in the cache.
  8315. </para>
  8316. <para>
  8317. You can disable this optimization by turning of the
  8318. <code>metadataCacheInClass</code> flag:
  8319. </para>
  8320. <programlisting role="php"><![CDATA[
  8321. // At instantiation:
  8322. $bugs = new Bugs(array('metadataCacheInClass' => false));
  8323. // Or later:
  8324. $bugs->setMetadataCacheInClass(false);
  8325. ]]></programlisting>
  8326. <para>
  8327. The flag is enabled by default, which ensures that the
  8328. <code>$_metadata</code> array is only populated once per
  8329. instance.
  8330. </para>
  8331. </sect3>
  8332. </sect2>
  8333. <sect2 id="zend.db.table.extending">
  8334. <title>Customizing and Extending a Table Class</title>
  8335. <sect3 id="zend.db.table.extending.row-rowset">
  8336. <title>Using Custom Row or Rowset Classes</title>
  8337. <para>
  8338. By default, methods of the Table class return a Rowset in instances of the concrete
  8339. class Zend_Db_Table_Rowset, and Rowsets contain a collection of instances of the
  8340. concrete class Zend_Db_Table_Row. You can specify an alternative class to use for
  8341. either of these, but they must be classes that extend Zend_Db_Table_Rowset_Abstract
  8342. and Zend_Db_Table_Row_Abstract, respectively.
  8343. </para>
  8344. <para>
  8345. You can specify Row and Rowset classes using the Table constructor's options array,
  8346. in keys <code>'rowClass'</code> and <code>'rowsetClass'</code> respectively.
  8347. Specify the names of the classes using strings.
  8348. </para>
  8349. <example id="zend.db.table.extending.row-rowset.example">
  8350. <title>Example of specifying the Row and Rowset classes</title>
  8351. <programlisting role="php"><![CDATA[
  8352. class My_Row extends Zend_Db_Table_Row_Abstract
  8353. {
  8354. ...
  8355. }
  8356. class My_Rowset extends Zend_Db_Table_Rowset_Abstract
  8357. {
  8358. ...
  8359. }
  8360. $table = new Bugs(
  8361. array(
  8362. 'rowClass' => 'My_Row',
  8363. 'rowsetClass' => 'My_Rowset'
  8364. )
  8365. );
  8366. $where = $table->getAdapter()->quoteInto('bug_status = ?', 'NEW')
  8367. // Returns an object of type My_Rowset,
  8368. // containing an array of objects of type My_Row.
  8369. $rows = $table->fetchAll($where);
  8370. ]]>
  8371. </programlisting>
  8372. </example>
  8373. <para>
  8374. You can change the classes by specifying them with the <code>setRowClass()</code>
  8375. and <code>setRowsetClass()</code> methods. This applies to rows and rowsets created
  8376. subsequently; it does not change the class of any row or rowset objects you have
  8377. created previously.
  8378. </para>
  8379. <example id="zend.db.table.extending.row-rowset.example2">
  8380. <title>Example of changing the Row and Rowset classes</title>
  8381. <programlisting role="php"><![CDATA[
  8382. $table = new Bugs();
  8383. $where = $table->getAdapter()->quoteInto('bug_status = ?', 'NEW')
  8384. // Returns an object of type Zend_Db_Table_Rowset
  8385. // containing an array of objects of type Zend_Db_Table_Row.
  8386. $rowsStandard = $table->fetchAll($where);
  8387. $table->setRowClass('My_Row');
  8388. $table->setRowsetClass('My_Rowset');
  8389. // Returns an object of type My_Rowset,
  8390. // containing an array of objects of type My_Row.
  8391. $rowsCustom = $table->fetchAll($where);
  8392. // The $rowsStandard object still exists, and it is unchanged.
  8393. ]]>
  8394. </programlisting>
  8395. </example>
  8396. <para>
  8397. For more information on the Row and Rowset classes, see
  8398. <xref linkend="zend.db.table.row"/> and <xref linkend="zend.db.table.rowset"/>.
  8399. </para>
  8400. </sect3>
  8401. <sect3 id="zend.db.table.extending.insert-update">
  8402. <title>Defining Custom Logic for Insert, Update, and Delete</title>
  8403. <para>
  8404. You can override the <code>insert()</code> and <code>update()</code> methods in
  8405. your Table class. This gives you the opportunity to implement custom code that is
  8406. executed before performing the database operation. Be sure to call the parent class
  8407. method when you are done.
  8408. </para>
  8409. <example id="zend.db.table.extending.insert-update.example">
  8410. <title>Custom logic to manage timestamps</title>
  8411. <programlisting role="php"><![CDATA[
  8412. class Bugs extends Zend_Db_Table_Abstract
  8413. {
  8414. protected $_name = 'bugs';
  8415. public function insert(array $data)
  8416. {
  8417. // add a timestamp
  8418. if (empty($data['created_on'])) {
  8419. $data['created_on'] = time();
  8420. }
  8421. return parent::insert($data);
  8422. }
  8423. public function update(array $data, $where)
  8424. {
  8425. // add a timestamp
  8426. if (empty($data['updated_on'])) {
  8427. $data['updated_on'] = time();
  8428. }
  8429. return parent::update($data, $where);
  8430. }
  8431. }
  8432. ]]>
  8433. </programlisting>
  8434. </example>
  8435. <para>
  8436. You can also override the <code>delete()</code> method.
  8437. </para>
  8438. </sect3>
  8439. <sect3 id="zend.db.table.extending.finders">
  8440. <title>Define Custom Search Methods in Zend_Db_Table</title>
  8441. <para>
  8442. You can implement custom query methods in your Table class, if you have frequent
  8443. need to do queries against this table with specific criteria. Most queries can be
  8444. written using <code>fetchAll()</code>, but this requires that you duplicate code to
  8445. form the query conditions if you need to run the query in several places in your
  8446. application. Therefore it can be convenient to implement a method in the Table
  8447. class to perform frequently-used queries against this table.
  8448. </para>
  8449. <example id="zend.db.table.extending.finders.example">
  8450. <title>Custom method to find bugs by status</title>
  8451. <programlisting role="php"><![CDATA[
  8452. class Bugs extends Zend_Db_Table_Abstract
  8453. {
  8454. protected $_name = 'bugs';
  8455. public function findByStatus($status)
  8456. {
  8457. $where = $this->getAdapter()->quoteInto('bug_status = ?', $status);
  8458. return $this->fetchAll($where, 'bug_id');
  8459. }
  8460. }
  8461. ]]>
  8462. </programlisting>
  8463. </example>
  8464. </sect3>
  8465. <sect3 id="zend.db.table.extending.inflection">
  8466. <title>Define Inflection in Zend_Db_Table</title>
  8467. <para>
  8468. Some people prefer that the table class name match a table name in the RDBMS by
  8469. using a string transformation called <emphasis>inflection</emphasis>.
  8470. </para>
  8471. <para>
  8472. For example, if your table class name is "<code>BugsProducts</code>", it would
  8473. match the physical table in the database called "<code>bugs_products</code>," if
  8474. you omit the explicit declaration of the <code>$_name</code> class property. In
  8475. this inflection mapping, the class name spelled in "CamelCase" format would be
  8476. transformed to lower case, and words are separated with an underscore.
  8477. </para>
  8478. <para>
  8479. You can specify the database table name independently from the class name by
  8480. declaring the table name with the <code>$_name</code> class property in each of
  8481. your table classes.
  8482. </para>
  8483. <para>
  8484. Zend_Db_Table_Abstract performs no inflection to map the class name to the table
  8485. name. If you omit the declaration of <code>$_name</code> in your table class, the
  8486. class maps to a database table that matches the spelling of the class name exactly.
  8487. </para>
  8488. <para>
  8489. It is inappropriate to transform identifiers from the database, because this can
  8490. lead to ambiguity or make some identifiers inaccessible. Using the SQL identifiers
  8491. exactly as they appear in the database makes Zend_Db_Table_Abstract both simpler
  8492. and more flexible.
  8493. </para>
  8494. <para>
  8495. If you prefer to use inflection, then you must implement the transformation
  8496. yourself, by overriding the <code>_setupTableName()</code> method in your Table
  8497. classes. One way to do this is to define an abstract class that extends
  8498. Zend_Db_Table_Abstract, and then the rest of your tables extend your new abstract
  8499. class.
  8500. </para>
  8501. <example id="zend.db.table.extending.inflection.example">
  8502. <title>Example of an abstract table class that implements inflection</title>
  8503. <programlisting role="php"><![CDATA[
  8504. abstract class MyAbstractTable extends Zend_Db_Table_Abstract
  8505. {
  8506. protected function _setupTableName()
  8507. {
  8508. if (!$this->_name) {
  8509. $this->_name = myCustomInflector(get_class($this));
  8510. }
  8511. parent::_setupTableName();
  8512. }
  8513. }
  8514. class BugsProducts extends MyAbstractTable
  8515. {
  8516. }
  8517. ]]>
  8518. </programlisting>
  8519. </example>
  8520. <para>
  8521. You are responsible for writing the functions to perform inflection transformation.
  8522. Zend Framework does not provide such a function.
  8523. </para>
  8524. </sect3>
  8525. </sect2>
  8526. </sect1><!--
  8527. vim:se ts=4 sw=4 et:
  8528. -->
  8529. <sect1 id="zend.db.table.row" xml:base="module_specs/Zend_Db_Table_Row.xml">
  8530. <title>Zend_Db_Table_Row</title>
  8531. <sect2 id="zend.db.table.row.introduction">
  8532. <title>Introduction</title>
  8533. <para>
  8534. Zend_Db_Table_Row is a class that contains an individual row of a Zend_Db_Table object.
  8535. When you run a query against a Table class, the result is returned in a set of
  8536. Zend_Db_Table_Row objects. You can also use this object to create new rows and add them
  8537. to the database table.
  8538. </para>
  8539. <para>
  8540. Zend_Db_Table_Row is an implementation of the <ulink url="http://www.martinfowler.com/eaaCatalog/rowDataGateway.html">Row Data Gateway</ulink>
  8541. pattern.
  8542. </para>
  8543. </sect2>
  8544. <sect2 id="zend.db.table.row.read">
  8545. <title>Fetching a Row</title>
  8546. <para>
  8547. Zend_Db_Table_Abstract provides methods <code>find()</code> and
  8548. <code>fetchAll()</code>, which each return an object of type Zend_Db_Table_Rowset, and
  8549. the method <code>fetchRow()</code>, which returns an object of type Zend_Db_Table_Row.
  8550. </para>
  8551. <example id="zend.db.table.row.read.example">
  8552. <title>Example of fetching a row</title>
  8553. <programlisting role="php"><![CDATA[
  8554. $bugs = new Bugs();
  8555. $row = $bugs->fetchRow($bugs->select()->where('bug_id = ?', 1));
  8556. ]]>
  8557. </programlisting>
  8558. </example>
  8559. <para>
  8560. A Zend_Db_Table_Rowset object contains a collection of Zend_Db_Table_Row objects. See
  8561. <xref linkend="zend.db.table.rowset"/>.
  8562. </para>
  8563. <example id="zend.db.table.row.read.example-rowset">
  8564. <title>Example of reading a row in a rowset</title>
  8565. <programlisting role="php"><![CDATA[
  8566. $bugs = new Bugs();
  8567. $rowset = $bugs->fetchAll($bugs->select()->where('bug_status = ?', 1));
  8568. $row = $rowset->current();
  8569. ]]>
  8570. </programlisting>
  8571. </example>
  8572. <sect3 id="zend.db.table.row.read.get">
  8573. <title>Reading column values from a row</title>
  8574. <para>
  8575. Zend_Db_Table_Row_Abstract provides accessor methods so you can reference columns
  8576. in the row as object properties.
  8577. </para>
  8578. <example id="zend.db.table.row.read.get.example">
  8579. <title>Example of reading a column in a row</title>
  8580. <programlisting role="php"><![CDATA[
  8581. $bugs = new Bugs();
  8582. $row = $bugs->fetchRow($bugs->select()->where('bug_id = ?', 1));
  8583. // Echo the value of the bug_description column
  8584. echo $row->bug_description;
  8585. ]]>
  8586. </programlisting>
  8587. </example>
  8588. <note>
  8589. <para>
  8590. Earlier versions of Zend_Db_Table_Row mapped these column accessors to the
  8591. database column names using a string transformation called
  8592. <emphasis>inflection</emphasis>.
  8593. </para>
  8594. <para>
  8595. Currently, Zend_Db_Table_Row does not implement inflection. Accessed property
  8596. names need to match the spelling of the column names as they appear in your
  8597. database.
  8598. </para>
  8599. </note>
  8600. </sect3>
  8601. <sect3 id="zend.db.table.row.read.to-array">
  8602. <title>Retrieving Row Data as an Array</title>
  8603. <para>
  8604. You can access the row's data as an array using the <code>toArray()</code> method
  8605. of the Row object. This returns an associative array of the column names to the
  8606. column values.
  8607. </para>
  8608. <example id="zend.db.table.row.read.to-array.example">
  8609. <title>Example of using the toArray() method</title>
  8610. <programlisting role="php"><![CDATA[
  8611. $bugs = new Bugs();
  8612. $row = $bugs->fetchRow($bugs->select()->where('bug_id = ?', 1));
  8613. // Get the column/value associative array from the Row object
  8614. $rowArray = $row->toArray();
  8615. // Now use it as a normal array
  8616. foreach ($rowArray as $column => $value) {
  8617. echo "Column: $column\n";
  8618. echo "Value: $value\n";
  8619. }
  8620. ]]>
  8621. </programlisting>
  8622. </example>
  8623. <para>
  8624. The array returned from <code>toArray()</code> is not updateable. You can modify
  8625. values in the array as you can with any array, but you cannot save changes to this
  8626. array to the database directly.
  8627. </para>
  8628. </sect3>
  8629. <sect3 id="zend.db.table.row.read.relationships">
  8630. <title>Fetching data from related tables</title>
  8631. <para>
  8632. The Zend_Db_Table_Row_Abstract class provides methods for fetching rows and rowsets
  8633. from related tables. See <xref linkend="zend.db.table.relationships"/> for more
  8634. information on table relationships.
  8635. </para>
  8636. </sect3>
  8637. </sect2>
  8638. <sect2 id="zend.db.table.row.write">
  8639. <title>Writing rows to the database</title>
  8640. <sect3 id="zend.db.table.row.write.set">
  8641. <title>Changing column values in a row</title>
  8642. <para>
  8643. You can set individual column values using column accessors, similar to how the
  8644. columns are read as object properties in the example above.
  8645. </para>
  8646. <para>
  8647. Using a column accessor to set a value changes the column value of the row object
  8648. in your application, but it does not commit the change to the database yet. You can
  8649. do that with the <code>save()</code> method.
  8650. </para>
  8651. <example id="zend.db.table.row.write.set.example">
  8652. <title>Example of changing a column in a row</title>
  8653. <programlisting role="php"><![CDATA[
  8654. $bugs = new Bugs();
  8655. $row = $bugs->fetchRow($bugs->select()->where('bug_id = ?', 1));
  8656. // Change the value of one or more columns
  8657. $row->bug_status = 'FIXED';
  8658. // UPDATE the row in the database with new values
  8659. $row->save();
  8660. ]]>
  8661. </programlisting>
  8662. </example>
  8663. </sect3>
  8664. <sect3 id="zend.db.table.row.write.insert">
  8665. <title>Inserting a new row</title>
  8666. <para>
  8667. You can create a new row for a given table with the <code>createRow()</code> method
  8668. of the table class. You can access fields of this row with the object-oriented
  8669. interface, but the row is not stored in the database until you call the
  8670. <code>save()</code> method.
  8671. </para>
  8672. <example id="zend.db.table.row.write.insert.example">
  8673. <title>Example of creating a new row for a table</title>
  8674. <programlisting role="php"><![CDATA[
  8675. $bugs = new Bugs();
  8676. $newRow = $bugs->createRow();
  8677. // Set column values as appropriate for your application
  8678. $newRow->bug_description = '...description...';
  8679. $newRow->bug_status = 'NEW';
  8680. // INSERT the new row to the database
  8681. $newRow->save();
  8682. ]]>
  8683. </programlisting>
  8684. </example>
  8685. <para>
  8686. The optional argument to the createRow() method is an associative array, with which
  8687. you can populate fields of the new row.
  8688. </para>
  8689. <example id="zend.db.table.row.write.insert.example2">
  8690. <title>Example of populating a new row for a table</title>
  8691. <programlisting role="php"><![CDATA[
  8692. $data = array(
  8693. 'bug_description' => '...description...',
  8694. 'bug_status' => 'NEW'
  8695. );
  8696. $bugs = new Bugs();
  8697. $newRow = $bugs->createRow($data);
  8698. // INSERT the new row to the database
  8699. $newRow->save();
  8700. ]]>
  8701. </programlisting>
  8702. </example>
  8703. <note>
  8704. <para>
  8705. The <code>createRow()</code> method was called <code>fetchNew()</code> in
  8706. earlier releases of Zend_Db_Table. You are encouraged to use the new method
  8707. name, even though the old name continues to work for the sake of backward
  8708. compatibility.
  8709. </para>
  8710. </note>
  8711. </sect3>
  8712. <sect3 id="zend.db.table.row.write.set-from-array">
  8713. <title>Changing values in multiple columns</title>
  8714. <para>
  8715. Zend_Db_Table_Row_Abstract provides the <code>setFromArray()</code> method to
  8716. enable you to set several columns in a single row at once, specified in an
  8717. associative array that maps the column names to values. You may find this method
  8718. convenient for setting values both for new rows and for rows you need to update.
  8719. </para>
  8720. <example id="zend.db.table.row.write.set-from-array.example">
  8721. <title>Example of using setFromArray() to set values in a new Row</title>
  8722. <programlisting role="php"><![CDATA[
  8723. $bugs = new Bugs();
  8724. $newRow = $bugs->createRow();
  8725. // Data are arranged in an associative array
  8726. $data = array(
  8727. 'bug_description' => '...description...',
  8728. 'bug_status' => 'NEW'
  8729. );
  8730. // Set all the column values at once
  8731. $newRow->setFromArray($data);
  8732. // INSERT the new row to the database
  8733. $newRow->save();
  8734. ]]>
  8735. </programlisting>
  8736. </example>
  8737. </sect3>
  8738. <sect3 id="zend.db.table.row.write.delete">
  8739. <title>Deleting a row</title>
  8740. <para>
  8741. You can call the <code>delete()</code> method on a Row object. This deletes rows in
  8742. the database matching the primary key in the Row object.
  8743. </para>
  8744. <example id="zend.db.table.row.write.delete.example">
  8745. <title>Example of deleting a row</title>
  8746. <programlisting role="php"><![CDATA[
  8747. $bugs = new Bugs();
  8748. $row = $bugs->fetchRow('bug_id = 1');
  8749. // DELETE this row
  8750. $row->delete();
  8751. ]]>
  8752. </programlisting>
  8753. </example>
  8754. <para>
  8755. You do not have to call <code>save()</code> to apply the delete; it is executed
  8756. against the database immediately.
  8757. </para>
  8758. </sect3>
  8759. </sect2>
  8760. <sect2 id="zend.db.table.row.serialize">
  8761. <title>Serializing and unserializing rows</title>
  8762. <para>
  8763. It is often convenient to save the contents of a database row to be used later.
  8764. <emphasis>Serialization</emphasis> is the name for the operation that converts an
  8765. object into a form that is easy to save in offline storage (for example, a file).
  8766. Objects of type Zend_Db_Table_Row_Abstract are serializable.
  8767. </para>
  8768. <sect3 id="zend.db.table.row.serialize.serializing">
  8769. <title>Serializing a Row</title>
  8770. <para>
  8771. Simply use PHP's <code>serialize()</code> function to create a string containing a
  8772. byte-stream representation of the Row object argument.
  8773. </para>
  8774. <example id="zend.db.table.row.serialize.serializing.example">
  8775. <title>Example of serializing a row</title>
  8776. <programlisting role="php"><![CDATA[
  8777. $bugs = new Bugs();
  8778. $row = $bugs->fetchRow('bug_id = 1');
  8779. // Convert object to serialized form
  8780. $serializedRow = serialize($row);
  8781. // Now you can write $serializedRow to a file, etc.
  8782. ]]>
  8783. </programlisting>
  8784. </example>
  8785. </sect3>
  8786. <sect3 id="zend.db.table.row.serialize.unserializing">
  8787. <title>Unserializing Row Data</title>
  8788. <para>
  8789. Use PHP's <code>unserialize()</code> function to restore a string containing a
  8790. byte-stream representation of an object. The function returns the original object.
  8791. </para>
  8792. <para>
  8793. Note that the Row object returned is in a <emphasis>disconnected</emphasis> state.
  8794. You can read the Row object and its properties, but you cannot change values in the
  8795. Row or execute other methods that require a database connection (for example,
  8796. queries against related tables).
  8797. </para>
  8798. <example id="zend.db.table.row.serialize.unserializing.example">
  8799. <title>Example of unserializing a serialized row</title>
  8800. <programlisting role="php"><![CDATA[
  8801. $rowClone = unserialize($serializedRow);
  8802. // Now you can use object properties, but read-only
  8803. echo $rowClone->bug_description;
  8804. ]]>
  8805. </programlisting>
  8806. </example>
  8807. <note>
  8808. <title>Why do Rows unserialize in a disconnected state?</title>
  8809. <para>
  8810. A serialized object is a string that is readable to anyone who possesses it. It
  8811. could be a security risk to store parameters such as database account and
  8812. password in plain, unencrypted text in the serialized string. You would not
  8813. want to store such data to a text file that is not protected, or send it in an
  8814. email or other medium that is easily read by potential attackers. The reader of
  8815. the serialized object should not be able to use it to gain access to your
  8816. database without knowing valid credentials.
  8817. </para>
  8818. </note>
  8819. </sect3>
  8820. <sect3 id="zend.db.table.row.serialize.set-table">
  8821. <title>Reactivating a Row as Live Data</title>
  8822. <para>
  8823. You can reactivate a disconnected Row, using the <code>setTable()</code> method.
  8824. The argument to this method is a valid object of type Zend_Db_Table_Abstract, which
  8825. you create. Creating a Table object requires a live connection to the database, so
  8826. by reassociating the Table with the Row, the Row gains access to the database.
  8827. Subsequently, you can change values in the Row object and save the changes to the
  8828. database.
  8829. </para>
  8830. <example id="zend.db.table.row.serialize.set-table.example">
  8831. <title>Example of reactivating a row</title>
  8832. <programlisting role="php"><![CDATA[
  8833. $rowClone = unserialize($serializedRow);
  8834. $bugs = new Bugs();
  8835. // Reconnect the row to a table, and
  8836. // thus to a live database connection
  8837. $rowClone->setTable($bugs);
  8838. // Now you can make changes to the row and save them
  8839. $rowClone->bug_status = 'FIXED';
  8840. $rowClone->save();
  8841. ]]>
  8842. </programlisting>
  8843. </example>
  8844. </sect3>
  8845. </sect2>
  8846. <sect2 id="zend.db.table.row.extending">
  8847. <title>Extending the Row class</title>
  8848. <para>
  8849. Zend_Db_Table_Row is the default concrete class that extends
  8850. Zend_Db_Table_Row_Abstract. You can define your own concrete class for instances of Row
  8851. by extending Zend_Db_Table_Row_Abstract. To use your new Row class to store results of
  8852. Table queries, specify the custom Row class by name either in the
  8853. <code>$_rowClass</code> protected member of a Table class, or in the array argument of
  8854. the constructor of a Table object.
  8855. </para>
  8856. <example id="zend.db.table.row.extending.example">
  8857. <title>Specifying a custom Row class</title>
  8858. <programlisting role="php"><![CDATA[
  8859. class MyRow extends Zend_Db_Table_Row_Abstract
  8860. {
  8861. // ...customizations
  8862. }
  8863. // Specify a custom Row to be used by default
  8864. // in all instances of a Table class.
  8865. class Products extends Zend_Db_Table_Abstract
  8866. {
  8867. protected $_name = 'products';
  8868. protected $_rowClass = 'MyRow';
  8869. }
  8870. // Or specify a custom Row to be used in one
  8871. // instance of a Table class.
  8872. $bugs = new Bugs(array('rowClass' => 'MyRow'));
  8873. ]]>
  8874. </programlisting>
  8875. </example>
  8876. <sect3 id="zend.db.table.row.extending.overriding">
  8877. <title>Row initialization</title>
  8878. <para>
  8879. If application-specific logic needs to be initialized when a row is constructed,
  8880. you can select to move your tasks to the <code>init()</code> method, which is
  8881. called after all row metadata has been processed. This is recommended over the
  8882. <code>__construct</code> method if you do not need to alter the metadata in any
  8883. programmatic way.
  8884. <example id="zend.db.table.row.init.usage.example">
  8885. <title>Example usage of init() method</title>
  8886. <programlisting role="php"><![CDATA[
  8887. class MyApplicationRow extends Zend_Db_Table_Row_Abstract
  8888. {
  8889. protected $_role;
  8890. public function init()
  8891. {
  8892. $this->_role = new MyRoleClass();
  8893. }
  8894. }
  8895. ]]>
  8896. </programlisting>
  8897. </example>
  8898. </para>
  8899. </sect3>
  8900. <sect3 id="zend.db.table.row.extending.insert-update">
  8901. <title>Defining Custom Logic for Insert, Update, and Delete in Zend_Db_Table_Row</title>
  8902. <para>
  8903. The Row class calls protected methods <code>_insert()</code>,
  8904. <code>_update()</code>, and <code>_delete()</code> before performing the
  8905. corresponding operations <code>INSERT</code>, <code>UPDATE</code>, and
  8906. <code>DELETE</code>. You can add logic to these methods in your custom Row
  8907. subclass.
  8908. </para>
  8909. <para>
  8910. If you need to do custom logic in a specific table, and the custom logic must occur
  8911. for every operation on that table, it may make more sense to implement your custom
  8912. code in the <code>insert()</code>, <code>update()</code> and <code>delete()</code>
  8913. methods of your Table class. However, sometimes it may be necessary to do custom
  8914. logic in the Row class.
  8915. </para>
  8916. <para>
  8917. Below are some example cases where it might make sense to implement custom logic in
  8918. a Row class instead of in the Table class:
  8919. </para>
  8920. <example id="zend.db.table.row.extending.overriding-example1">
  8921. <title>Example of custom logic in a Row class</title>
  8922. <para>
  8923. The custom logic may not apply in all cases of operations on the respective
  8924. Table. You can provide custom logic on demand by implementing it in a Row class
  8925. and creating an instance of the Table class with that custom Row class
  8926. specified. Otherwise, the Table uses the default Row class.
  8927. </para>
  8928. <para>
  8929. You need data operations on this table to record the operation to a
  8930. Zend_Log object, but only if the application configuration has enabled this
  8931. behavior.
  8932. </para>
  8933. <programlisting role="php"><![CDATA[
  8934. class MyLoggingRow extends Zend_Db_Table_Row_Abstract
  8935. {
  8936. protected function _insert()
  8937. {
  8938. $log = Zend_Registry::get('database_log');
  8939. $log->info(Zend_Debug::dump($this->_data,
  8940. "INSERT: $this->_tableClass",
  8941. false)
  8942. );
  8943. }
  8944. }
  8945. // $loggingEnabled is an example property that depends
  8946. // on your application configuration
  8947. if ($loggingEnabled) {
  8948. $bugs = new Bugs(array('rowClass' => 'MyLoggingRow'));
  8949. } else {
  8950. $bugs = new Bugs();
  8951. }
  8952. ]]>
  8953. </programlisting>
  8954. </example>
  8955. <example id="zend.db.table.row.extending.overriding-example2">
  8956. <title>Example of a Row class that logs insert data for multiple tables</title>
  8957. <para>
  8958. The custom logic may be common to multiple tables. Instead of implementing the
  8959. same custom logic in every one of your Table classes, you can implement the
  8960. code for such actions in the definition of a Row class, and use this Row in
  8961. each of your Table classes.
  8962. </para>
  8963. <para>
  8964. In this example, the logging code is identical in all table classes.
  8965. </para>
  8966. <programlisting role="php"><![CDATA[
  8967. class MyLoggingRow extends Zend_Db_Table_Row_Abstract
  8968. {
  8969. protected function _insert()
  8970. {
  8971. $log = Zend_Registry::get('database_log');
  8972. $log->info(Zend_Debug::dump($this->_data,
  8973. "INSERT: $this->_tableClass",
  8974. false)
  8975. );
  8976. }
  8977. }
  8978. class Bugs extends Zend_Db_Table_Abstract
  8979. {
  8980. protected $_name = 'bugs';
  8981. protected $_rowClass = 'MyLoggingRow';
  8982. }
  8983. class Products extends Zend_Db_Table_Abstract
  8984. {
  8985. protected $_name = 'products';
  8986. protected $_rowClass = 'MyLoggingRow';
  8987. }
  8988. ]]>
  8989. </programlisting>
  8990. </example>
  8991. </sect3>
  8992. <sect3 id="zend.db.table.row.extending.inflection">
  8993. <title>Define Inflection in Zend_Db_Table_Row</title>
  8994. <para>
  8995. Some people prefer that the table class name match a table name in the RDBMS by
  8996. using a string transformation called <emphasis>inflection</emphasis>.
  8997. </para>
  8998. <para>
  8999. Zend_Db classes do not implement inflection by default. See
  9000. <xref linkend="zend.db.table.extending.inflection"/> for an explanation of this
  9001. policy.
  9002. </para>
  9003. <para>
  9004. If you prefer to use inflection, then you must implement the transformation yourself,
  9005. by overriding the <code>_transformColumn()</code> method in a custom Row class, and
  9006. using that custom Row class when you perform queries against your Table class.
  9007. </para>
  9008. <example id="zend.db.table.row.extending.inflection.example">
  9009. <title>Example of defining an inflection transformation</title>
  9010. <para>
  9011. This allows you to use an inflected version of the column name in the
  9012. accessors. The Row class uses the <code>_transformColumn()</code> method to
  9013. change the name you use to the native column name in the database table.
  9014. </para>
  9015. <programlisting role="php"><![CDATA[
  9016. class MyInflectedRow extends Zend_Db_Table_Row_Abstract
  9017. {
  9018. protected function _transformColumn($columnName)
  9019. {
  9020. $nativeColumnName = myCustomInflector($columnName);
  9021. return $nativeColumnName;
  9022. }
  9023. }
  9024. class Bugs extends Zend_Db_Table_Abstract
  9025. {
  9026. protected $_name = 'bugs';
  9027. protected $_rowClass = 'MyInflectedRow';
  9028. }
  9029. $bugs = new Bugs();
  9030. $row = $bugs->fetchNew();
  9031. // Use camelcase column names, and rely on the
  9032. // transformation function to change it into the
  9033. // native representation.
  9034. $row->bugDescription = 'New description';
  9035. ]]>
  9036. </programlisting>
  9037. </example>
  9038. <para>
  9039. You are responsible for writing the functions to perform inflection transformation.
  9040. Zend Framework does not provide such a function.
  9041. </para>
  9042. </sect3>
  9043. </sect2>
  9044. </sect1><!--
  9045. vim:se ts=4 sw=4 et:
  9046. -->
  9047. <sect1 id="zend.db.table.rowset" xml:base="module_specs/Zend_Db_Table_Rowset.xml">
  9048. <title>Zend_Db_Table_Rowset</title>
  9049. <sect2 id="zend.db.table.rowset.introduction">
  9050. <title>Introduction</title>
  9051. <para>
  9052. When you run a query against a Table class using the <code>find()</code> or <code>fetchAll()</code>
  9053. methods, the result is returned in an object of type <code>Zend_Db_Table_Rowset_Abstract</code>. A Rowset
  9054. contains a collection of objects descending from <code>Zend_Db_Table_Row_Abstract</code>. You can iterate
  9055. through the Rowset and access individual Row objects, reading or modifying data in the Rows.
  9056. </para>
  9057. </sect2>
  9058. <sect2 id="zend.db.table.rowset.fetch">
  9059. <title>Fetching a Rowset</title>
  9060. <para>
  9061. <code>Zend_Db_Table_Abstract</code> provides methods <code>find()</code> and <code>fetchAll()</code>, each
  9062. of which returns an object of type <code>Zend_Db_Table_Rowset_Abstract</code>.
  9063. </para>
  9064. <example id="zend.db.table.rowset.fetch.example">
  9065. <title>Example of fetching a rowset</title>
  9066. <programlisting role="php"><![CDATA[
  9067. $bugs = new Bugs();
  9068. $rowset = $bugs->fetchAll("bug_status = 'NEW'");
  9069. ]]>
  9070. </programlisting>
  9071. </example>
  9072. </sect2>
  9073. <sect2 id="zend.db.table.rowset.rows">
  9074. <title>Retrieving Rows from a Rowset</title>
  9075. <para>
  9076. The Rowset itself is usually less interesting than the Rows that it contains. This section illustrates how
  9077. to get the Rows that comprise the Rowset.
  9078. </para>
  9079. <para>
  9080. A legitimate query returns zero rows when no rows in the database match the query conditions. Therefore, a
  9081. Rowset object might contain zero Row objects. Since <code>Zend_Db_Table_Rowset_Abstract</code> implements
  9082. the <code>Countable</code> interface, you can use <code>count()</code> to determine the number of Rows in
  9083. the Rowset.
  9084. </para>
  9085. <example id="zend.db.table.rowset.rows.counting.example">
  9086. <title>Counting the Rows in a Rowset</title>
  9087. <programlisting role="php"><![CDATA[
  9088. $rowset = $bugs->fetchAll("bug_status = 'FIXED'");
  9089. $rowCount = count($rowset);
  9090. if ($rowCount > 0) {
  9091. echo "found $rowCount rows";
  9092. } else {
  9093. echo 'no rows matched the query';
  9094. }
  9095. ]]>
  9096. </programlisting>
  9097. </example>
  9098. <example id="zend.db.table.rowset.rows.current.example">
  9099. <title>Reading a Single Row from a Rowset</title>
  9100. <para>
  9101. The simplest way to access a Row from a Rowset is to use the <code>current()</code> method. This is
  9102. particularly appropriate when the Rowset contains exactly one Row.
  9103. </para>
  9104. <programlisting role="php"><![CDATA[
  9105. $bugs = new Bugs();
  9106. $rowset = $bugs->fetchAll("bug_id = 1");
  9107. $row = $rowset->current();
  9108. ]]>
  9109. </programlisting>
  9110. </example>
  9111. <para>
  9112. If the Rowset contains zero rows, <code>current()</code> returns
  9113. PHP's <code>null</code> value.
  9114. </para>
  9115. <example id="zend.db.table.rowset.rows.iterate.example">
  9116. <title>Iterating through a Rowset</title>
  9117. <para>
  9118. Objects descending from <code>Zend_Db_Table_Rowset_Abstract</code> implement the <code>SeekableIterator</code>
  9119. interface, which means you can loop through them using the <code>foreach</code> construct. Each value
  9120. you retrieve this way is a <code>Zend_Db_Table_Row_Abstract</code> object that corresponds to one
  9121. record from the table.
  9122. </para>
  9123. <programlisting role="php"><![CDATA[
  9124. $bugs = new Bugs();
  9125. // fetch all records from the table
  9126. $rowset = $bugs->fetchAll();
  9127. foreach ($rowset as $row) {
  9128. // output 'Zend_Db_Table_Row' or similar
  9129. echo get_class($row) . "\n";
  9130. // read a column in the row
  9131. $status = $row->bug_status;
  9132. // modify a column in the current row
  9133. $row->assigned_to = 'mmouse';
  9134. // write the change to the database
  9135. $row->save();
  9136. }
  9137. ]]>
  9138. </programlisting>
  9139. </example>
  9140. <example id="zend.db.table.rowset.rows.seek.example">
  9141. <title>Seeking to a known position into a Rowset</title>
  9142. <para>
  9143. <code>SeekableIterator</code> allows you to seek to a position that you would like the iterator to jump to.
  9144. Simply use the <code>seek()</code> method for that. Pass it an integer representing the number of the Row
  9145. you would like your Rowset to point to next, don't forget that it starts with index 0. If the index is wrong,
  9146. ie doesn't exist, an exception will be thrown. You should use <code>count()</code> to check the number of
  9147. results before seeking to a position.
  9148. </para>
  9149. <programlisting role="php"><![CDATA[
  9150. $bugs = new Bugs();
  9151. // fetch all records from the table
  9152. $rowset = $bugs->fetchAll();
  9153. // takes the iterator to the 9th element (zero is one element) :
  9154. $rowset->seek(8);
  9155. // retrive it
  9156. $row9 = $rowset->current();
  9157. // and use it
  9158. $row9->assigned_to = 'mmouse';
  9159. $row9->save();
  9160. ]]>
  9161. </programlisting>
  9162. </example>
  9163. <para>
  9164. <code>getRow()</code> allows you to get a specific row in the Rowset, knowing its position; don't forget
  9165. however that positions start with index zero. The first parameter for <code>getRow()</code> is an integer
  9166. for the position asked. The second optional parameter is a boolean; it tells the Rowset iterator if it must
  9167. seek to that position in the same time, or not (default is false). This method returns a Zend_Db_Table_Row
  9168. object by default. If the position requested does not exist, an exception will be thrown. Here is an example :
  9169. </para>
  9170. <programlisting role="php"><![CDATA[
  9171. $bugs = new Bugs();
  9172. // fetch all records from the table
  9173. $rowset = $bugs->fetchAll();
  9174. // retrieve the 9th element immediately:
  9175. $row9->getRow(8);
  9176. // and use it:
  9177. $row9->assigned_to = 'mmouse';
  9178. $row9->save();
  9179. ]]>
  9180. </programlisting>
  9181. <para>
  9182. After you have access to an individual Row object, you can manipulate the Row using methods described in
  9183. <xref linkend="zend.db.table.row"/>.
  9184. </para>
  9185. </sect2>
  9186. <sect2 id="zend.db.table.rowset.to-array">
  9187. <title>Retrieving a Rowset as an Array</title>
  9188. <para>
  9189. You can access all the data in the Rowset as an array using the <code>toArray()</code> method of the Rowset
  9190. object. This returns an array containing one entry per Row. Each entry is an associative array having keys
  9191. that correspond to column names and elements that correspond to the respective column values.
  9192. </para>
  9193. <example id="zend.db.table.rowset.to-array.example">
  9194. <title>Using toArray()</title>
  9195. <programlisting role="php"><![CDATA[
  9196. $bugs = new Bugs();
  9197. $rowset = $bugs->fetchAll();
  9198. $rowsetArray = $rowset->toArray();
  9199. $rowCount = 1;
  9200. foreach ($rowsetArray as $rowArray) {
  9201. echo "row #$rowCount:\n";
  9202. foreach ($rowArray as $column => $value) {
  9203. echo "\t$column => $value\n";
  9204. }
  9205. ++$rowCount;
  9206. echo "\n";
  9207. }
  9208. ]]>
  9209. </programlisting>
  9210. </example>
  9211. <para>
  9212. The array returned from <code>toArray()</code> is not updateable. That is, you can modify values in the
  9213. array as you can with any array, but changes to the array data are not propagated to the database.
  9214. </para>
  9215. </sect2>
  9216. <sect2 id="zend.db.table.rowset.serialize">
  9217. <title>Serializing and Unserializing a Rowset</title>
  9218. <para>
  9219. Objects of type <code>Zend_Db_Table_Rowset_Abstract</code> are serializable. In a similar fashion to
  9220. serializing an individual Row object, you can serialize a Rowset and unserialize it later.
  9221. </para>
  9222. <example id="zend.db.table.rowset.serialize.example.serialize">
  9223. <title>Serializing a Rowset</title>
  9224. <para>
  9225. Simply use PHP's <code>serialize()</code> function to create a string containing a byte-stream
  9226. representation of the Rowset object argument.
  9227. </para>
  9228. <programlisting role="php"><![CDATA[
  9229. $bugs = new Bugs();
  9230. $rowset = $bugs->fetchAll();
  9231. // Convert object to serialized form
  9232. $serializedRowset = serialize($rowset);
  9233. // Now you can write $serializedRowset to a file, etc.
  9234. ]]>
  9235. </programlisting>
  9236. </example>
  9237. <example id="zend.db.table.rowset.serialize.example.unserialize">
  9238. <title>Unserializing a Serialized Rowset</title>
  9239. <para>
  9240. Use PHP's <code>unserialize()</code> function to restore a string containing a byte-stream
  9241. representation of an object. The function returns the original object.
  9242. </para>
  9243. <para>
  9244. Note that the Rowset object returned is in a <emphasis>disconnected</emphasis> state. You can iterate
  9245. through the Rowset and read the Row objects and their properties, but you cannot change values in the
  9246. Rows or execute other methods that require a database connection (for example, queries against related
  9247. tables).
  9248. </para>
  9249. <programlisting role="php"><![CDATA[
  9250. $rowsetDisconnected = unserialize($serializedRowset);
  9251. // Now you can use object methods and properties, but read-only
  9252. $row = $rowsetDisconnected->current();
  9253. echo $row->bug_description;
  9254. ]]>
  9255. </programlisting>
  9256. </example>
  9257. <note>
  9258. <title>Why do Rowsets unserialize in a disconnected state?</title>
  9259. <para>
  9260. A serialized object is a string that is readable to anyone who possesses it. It could be a security
  9261. risk to store parameters such as database account and password in plain, unencrypted text in the
  9262. serialized string. You would not want to store such data to a text file that is not protected, or send
  9263. it in an email or other medium that is easily read by potential attackers. The reader of the serialized
  9264. object should not be able to use it to gain access to your database without knowing valid credentials.
  9265. </para>
  9266. </note>
  9267. <para>
  9268. You can reactivate a disconnected Rowset using the <code>setTable()</code> method. The argument to this
  9269. method is a valid object of type <code>Zend_Db_Table_Abstract</code>, which you create. Creating a Table
  9270. object requires a live connection to the database, so by reassociating the Table with the Rowset, the
  9271. Rowset gains access to the database. Subsequently, you can change values in the Row objects contained in
  9272. the Rowset and save the changes to the database.
  9273. </para>
  9274. <example id="zend.db.table.rowset.serialize.example.set-table">
  9275. <title>Reactivating a Rowset as Live Data</title>
  9276. <programlisting role="php"><![CDATA[
  9277. $rowset = unserialize($serializedRowset);
  9278. $bugs = new Bugs();
  9279. // Reconnect the rowset to a table, and
  9280. // thus to a live database connection
  9281. $rowset->setTable($bugs);
  9282. $row = $rowset->current();
  9283. // Now you can make changes to the row and save them
  9284. $row->bug_status = 'FIXED';
  9285. $row->save();
  9286. ]]>
  9287. </programlisting>
  9288. </example>
  9289. <para>
  9290. Reactivating a Rowset with <code>setTable()</code> also reactivates all the Row objects contained in that
  9291. Rowset.
  9292. </para>
  9293. </sect2>
  9294. <sect2 id="zend.db.table.rowset.extending">
  9295. <title>Extending the Rowset class</title>
  9296. <para>
  9297. You can use an alternative concrete class for instances of Rowsets
  9298. by extending Zend_Db_Table_Rowset_Abstract. Specify the custom
  9299. Rowset class by name either in the <code>$_rowsetClass</code>
  9300. protected member of a Table class, or in the array argument of the
  9301. constructor of a Table object.
  9302. </para>
  9303. <example id="zend.db.table.rowset.extending.example">
  9304. <title>Specifying a custom Rowset class</title>
  9305. <programlisting role="php"><![CDATA[
  9306. class MyRowset extends Zend_Db_Table_Rowset_Abstract
  9307. {
  9308. // ...customizations
  9309. }
  9310. // Specify a custom Rowset to be used by default
  9311. // in all instances of a Table class.
  9312. class Products extends Zend_Db_Table_Abstract
  9313. {
  9314. protected $_name = 'products';
  9315. protected $_rowsetClass = 'MyRowset';
  9316. }
  9317. // Or specify a custom Rowset to be used in one
  9318. // instance of a Table class.
  9319. $bugs = new Bugs(array('rowsetClass' => 'MyRowset'));
  9320. ]]>
  9321. </programlisting>
  9322. </example>
  9323. <para>
  9324. Typically, the standard Zend_Db_Rowset concrete class is
  9325. sufficient for most usage. However, you might find it useful
  9326. to add new logic to a Rowset, specific to a given Table.
  9327. For example, a new method could calculate an aggregate
  9328. over all the Rows in the Rowset.
  9329. </para>
  9330. <example id="zend.db.table.rowset.extending.example-aggregate">
  9331. <title>Example of Rowset class with a new method</title>
  9332. <programlisting role="php"><![CDATA[
  9333. class MyBugsRowset extends Zend_Db_Table_Rowset_Abstract
  9334. {
  9335. /**
  9336. * Find the Row in the current Rowset with the
  9337. * greatest value in its 'updated_at' column.
  9338. */
  9339. public function getLatestUpdatedRow()
  9340. {
  9341. $max_updated_at = 0;
  9342. $latestRow = null;
  9343. foreach ($this as $row) {
  9344. if ($row->updated_at > $max_updated_at) {
  9345. $latestRow = $row;
  9346. }
  9347. }
  9348. return $latestRow;
  9349. }
  9350. }
  9351. class Bugs extends Zend_Db_Table_Abstract
  9352. {
  9353. protected $_name = 'bugs';
  9354. protected $_rowsetClass = 'MyBugsRowset';
  9355. }
  9356. ]]>
  9357. </programlisting>
  9358. </example>
  9359. </sect2>
  9360. </sect1><!--
  9361. vim:se ts=4 sw=4 et:
  9362. -->
  9363. <sect1 id="zend.db.table.relationships" xml:base="module_specs/Zend_Db_Table-Relationships.xml">
  9364. <title>Zend_Db_Table Relationships</title>
  9365. <sect2 id="zend.db.table.relationships.introduction">
  9366. <title>Introduction</title>
  9367. <para>
  9368. Tables have relationships to each other in a relational database. An entity in one
  9369. table can be linked to one or more entities in another table by using referential
  9370. integrity constraints defined in the database schema.
  9371. </para>
  9372. <para>
  9373. The Zend_Db_Table_Row class has methods for querying related rows in other tables.
  9374. </para>
  9375. </sect2>
  9376. <sect2 id="zend.db.table.relationships.defining">
  9377. <title>Defining Relationships</title>
  9378. <para>
  9379. Define classes for each of your tables, extending the abstract class
  9380. Zend_Db_Table_Abstract, as described in <xref linkend="zend.db.table.defining"/>. Also
  9381. see <xref linkend="zend.db.adapter.example-database"/> for a description of the
  9382. example database for which the following example code is designed.
  9383. </para>
  9384. <para>
  9385. Below are the PHP class definitions for these tables:
  9386. </para>
  9387. <programlisting role="php"><![CDATA[
  9388. class Accounts extends Zend_Db_Table_Abstract
  9389. {
  9390. protected $_name = 'accounts';
  9391. protected $_dependentTables = array('Bugs');
  9392. }
  9393. class Products extends Zend_Db_Table_Abstract
  9394. {
  9395. protected $_name = 'products';
  9396. protected $_dependentTables = array('BugsProducts');
  9397. }
  9398. class Bugs extends Zend_Db_Table_Abstract
  9399. {
  9400. protected $_name = 'bugs';
  9401. protected $_dependentTables = array('BugsProducts');
  9402. protected $_referenceMap = array(
  9403. 'Reporter' => array(
  9404. 'columns' => 'reported_by',
  9405. 'refTableClass' => 'Accounts',
  9406. 'refColumns' => 'account_name'
  9407. ),
  9408. 'Engineer' => array(
  9409. 'columns' => 'assigned_to',
  9410. 'refTableClass' => 'Accounts',
  9411. 'refColumns' => 'account_name'
  9412. ),
  9413. 'Verifier' => array(
  9414. 'columns' => array('verified_by'),
  9415. 'refTableClass' => 'Accounts',
  9416. 'refColumns' => array('account_name')
  9417. )
  9418. );
  9419. }
  9420. class BugsProducts extends Zend_Db_Table_Abstract
  9421. {
  9422. protected $_name = 'bugs_products';
  9423. protected $_referenceMap = array(
  9424. 'Bug' => array(
  9425. 'columns' => array('bug_id'),
  9426. 'refTableClass' => 'Bugs',
  9427. 'refColumns' => array('bug_id')
  9428. ),
  9429. 'Product' => array(
  9430. 'columns' => array('product_id'),
  9431. 'refTableClass' => 'Products',
  9432. 'refColumns' => array('product_id')
  9433. )
  9434. );
  9435. }
  9436. ]]>
  9437. </programlisting>
  9438. <para>
  9439. If you use Zend_Db_Table to emulate cascading UPDATE and DELETE operations, declare the
  9440. <code>$_dependentTables</code> array in the class for the parent table. List the class
  9441. name for each dependent table. Use the class name, not the physical name of the SQL
  9442. table.
  9443. </para>
  9444. <note>
  9445. <para>
  9446. Skip declaration of <code>$_dependentTables</code> if you use referential integrity
  9447. constraints in the RDBMS server to implement cascading operations. See
  9448. <xref linkend="zend.db.table.relationships.cascading"/> for more information.
  9449. </para>
  9450. </note>
  9451. <para>
  9452. Declare the <code>$_referenceMap</code> array in the class for each dependent table.
  9453. This is an associative array of reference "rules". A reference rule identifies which
  9454. table is the parent table in the relationship, and also lists which columns in the
  9455. dependent table reference which columns in the parent table.
  9456. </para>
  9457. <para>
  9458. The rule key is a string used as an index to the <code>$_referenceMap</code> array.
  9459. This rule key is used to identify each reference relationship. Choose a descriptive
  9460. name for this rule key. It's best to use a string that can be part of a PHP method
  9461. name, as you will see later.
  9462. </para>
  9463. <para>
  9464. In the example PHP code above, the rule keys in the Bugs table class are:
  9465. <code>'Reporter'</code>, <code>'Engineer'</code>, <code>'Verifier'</code>, and
  9466. <code>'Product'</code>.
  9467. </para>
  9468. <para>
  9469. The value of each rule entry in the <code>$_referenceMap</code> array is also an
  9470. associative array. The elements of this rule entry are described below:
  9471. </para>
  9472. <itemizedlist>
  9473. <listitem>
  9474. <para>
  9475. <emphasis role="strong">columns</emphasis> =&gt; A string or an array of strings
  9476. naming the foreign key column name(s) in the dependent table.
  9477. </para>
  9478. <para>
  9479. It's common for this to be a single column, but some tables have multi-column
  9480. keys.
  9481. </para>
  9482. </listitem>
  9483. <listitem>
  9484. <para>
  9485. <emphasis role="strong">refTableClass</emphasis> =&gt; The class name of the
  9486. parent table. Use the class name, not the physical name of the SQL table.
  9487. </para>
  9488. <para>
  9489. It's common for a dependent table to have only one reference to its parent
  9490. table, but some tables have multiple references to the same parent table. In
  9491. the example database, there is one reference from the <code>bugs</code> table
  9492. to the <code>products</code> table, but three references from the
  9493. <code>bugs</code> table to the <code>accounts</code> table. Put each reference
  9494. in a separate entry in the <code>$_referenceMap</code> array.
  9495. </para>
  9496. </listitem>
  9497. <listitem>
  9498. <para>
  9499. <emphasis role="strong">refColumns</emphasis> =&gt; A string or an array of
  9500. strings naming the primary key column name(s) in the parent table.
  9501. </para>
  9502. <para>
  9503. It's common for this to be a single column, but some tables have multi-column
  9504. keys. If the reference uses a multi-column key, the order of columns in the
  9505. <code>'columns'</code> entry must match the order of columns in the
  9506. <code>'refColumns'</code> entry.
  9507. </para>
  9508. <para>
  9509. It is optional to specify this element. If you don't specify the
  9510. <code>refColumns</code>, the column(s) reported as the primary key columns of
  9511. the parent table are used by default.
  9512. </para>
  9513. </listitem>
  9514. <listitem>
  9515. <para>
  9516. <emphasis role="strong">onDelete</emphasis> =&gt; The rule for an action to
  9517. execute if a row is deleted in the parent table. See
  9518. <xref linkend="zend.db.table.relationships.cascading"/> for more information.
  9519. </para>
  9520. </listitem>
  9521. <listitem>
  9522. <para>
  9523. <emphasis role="strong">onUpdate</emphasis> =&gt; The rule for an action to
  9524. execute if values in primary key columns are updated in the parent table. See
  9525. <xref linkend="zend.db.table.relationships.cascading"/> for more information.
  9526. </para>
  9527. </listitem>
  9528. </itemizedlist>
  9529. </sect2>
  9530. <sect2 id="zend.db.table.relationships.fetching.dependent">
  9531. <title>Fetching a Dependent Rowset</title>
  9532. <para>
  9533. If you have a Row object as the result of a query on a parent table, you can fetch rows
  9534. from dependent tables that reference the current row. Use the method:
  9535. </para>
  9536. <programlisting role="php"><![CDATA[
  9537. $row->findDependentRowset($table, [$rule]);
  9538. ]]>
  9539. </programlisting>
  9540. <para>
  9541. This method returns a Zend_Db_Table_Rowset_Abstract object, containing a set of rows
  9542. from the dependent table <code>$table</code> that refer to the row identified by the
  9543. <code>$row</code> object.
  9544. </para>
  9545. <para>
  9546. The first argument <code>$table</code> can be a string that specifies the dependent
  9547. table by its class name. You can also specify the dependent table by using an object of
  9548. that table class.
  9549. </para>
  9550. <example id="zend.db.table.relationships.fetching.dependent.example">
  9551. <title>Fetching a Dependent Rowset</title>
  9552. <para>
  9553. This example shows getting a Row object from the table <code>Accounts</code>, and
  9554. finding the <code>Bugs</code> reported by that account.
  9555. </para>
  9556. <programlisting role="php"><![CDATA[
  9557. $accountsTable = new Accounts();
  9558. $accountsRowset = $accountsTable->find(1234);
  9559. $user1234 = $accountsRowset->current();
  9560. $bugsReportedByUser = $user1234->findDependentRowset('Bugs');
  9561. ]]>
  9562. </programlisting>
  9563. </example>
  9564. <para>
  9565. The second argument <code>$rule</code> is optional. It is a string that names the rule
  9566. key in the <code>$_referenceMap</code> array of the dependent table class. If you don't
  9567. specify a rule, the first rule in the array that references the parent table is used.
  9568. If you need to use a rule other than the first, you need to specify the key.
  9569. </para>
  9570. <para>
  9571. In the example code above, the rule key is not specified, so the rule used by default
  9572. is the first one that matches the parent table. This is the rule
  9573. <code>'Reporter'</code>.
  9574. </para>
  9575. <example id="zend.db.table.relationships.fetching.dependent.example-by">
  9576. <title>Fetching a Dependent Rowset By a Specific Rule</title>
  9577. <para>
  9578. This example shows getting a Row object from the table <code>Accounts</code>, and
  9579. finding the <code>Bugs</code> assigned to be fixed by the user of that account. The
  9580. rule key string that corresponds to this reference relationship in this example is
  9581. <code>'Engineer'</code>.
  9582. </para>
  9583. <programlisting role="php"><![CDATA[
  9584. $accountsTable = new Accounts();
  9585. $accountsRowset = $accountsTable->find(1234);
  9586. $user1234 = $accountsRowset->current();
  9587. $bugsAssignedToUser = $user1234->findDependentRowset('Bugs', 'Engineer');
  9588. ]]>
  9589. </programlisting>
  9590. </example>
  9591. <para>
  9592. You can also add criteria, ordering and limits to your relationships using the parent
  9593. row's select object.
  9594. </para>
  9595. <para>
  9596. <example id="zend.db.table.relationships.fetching.dependent.example-by-select">
  9597. <title>Fetching a Dependent Rowset using a Zend_Db_Table_Select</title>
  9598. <para>
  9599. This example shows getting a Row object from the table <code>Accounts</code>,
  9600. and finding the <code>Bugs</code> assigned to be fixed by the user of that
  9601. account, limited only to 3 rows and ordered by name.
  9602. </para>
  9603. <programlisting role="php"><![CDATA[
  9604. $accountsTable = new Accounts();
  9605. $accountsRowset = $accountsTable->find(1234);
  9606. $user1234 = $accountsRowset->current();
  9607. $select = $accountsTable->select()->order('name ASC')
  9608. ->limit(3);
  9609. $bugsAssignedToUser = $user1234->findDependentRowset('Bugs',
  9610. 'Engineer',
  9611. $select);
  9612. ]]>
  9613. </programlisting>
  9614. </example>
  9615. Alternatively, you can query rows from a dependent table using a special mechanism
  9616. called a "magic method". Zend_Db_Table_Row_Abstract invokes the method:
  9617. <code>findDependentRowset('&lt;TableClass&gt;', '&lt;Rule&gt;')</code> if you invoke a method on
  9618. the Row object matching either of the following patterns:
  9619. </para>
  9620. <itemizedlist>
  9621. <listitem>
  9622. <para>
  9623. <code>$row-&gt;find&lt;TableClass&gt;()</code>
  9624. </para>
  9625. </listitem>
  9626. <listitem>
  9627. <para>
  9628. <code>$row-&gt;find&lt;TableClass&gt;By&lt;Rule&gt;()</code>
  9629. </para>
  9630. </listitem>
  9631. </itemizedlist>
  9632. <para>
  9633. In the patterns above, <code>&lt;TableClass&gt;</code> and <code>&lt;Rule&gt;</code> are strings
  9634. that correspond to the class name of the dependent table, and the dependent table's
  9635. rule key that references the parent table.
  9636. </para>
  9637. <note>
  9638. <para>
  9639. Some application frameworks, such as Ruby on Rails, use a mechanism called
  9640. "inflection" to allow the spelling of identifiers to change depending on usage. For
  9641. simplicity, Zend_Db_Table_Row does not provide any inflection mechanism. The table
  9642. identity and the rule key named in the method call must match the spelling of the
  9643. class and rule key exactly.
  9644. </para>
  9645. </note>
  9646. <example id="zend.db.table.relationships.fetching.dependent.example-magic">
  9647. <title>Fetching Dependent Rowsets using the Magic Method</title>
  9648. <para>
  9649. This example shows finding dependent Rowsets equivalent to those in the previous
  9650. examples. In this case, the application uses the magic method invocation instead of
  9651. specifying the table and rule as strings.
  9652. </para>
  9653. <programlisting role="php"><![CDATA[
  9654. $accountsTable = new Accounts();
  9655. $accountsRowset = $accountsTable->find(1234);
  9656. $user1234 = $accountsRowset->current();
  9657. // Use the default reference rule
  9658. $bugsReportedBy = $user1234->findBugs();
  9659. // Specify the reference rule
  9660. $bugsAssignedTo = $user1234->findBugsByEngineer();
  9661. ]]>
  9662. </programlisting>
  9663. </example>
  9664. </sect2>
  9665. <sect2 id="zend.db.table.relationships.fetching.parent">
  9666. <title>Fetching a Parent Row</title>
  9667. <para>
  9668. If you have a Row object as the result of a query on a dependent table, you can fetch
  9669. the row in the parent to which the dependent row refers. Use the method:
  9670. </para>
  9671. <programlisting role="php"><![CDATA[
  9672. $row->findParentRow($table, [$rule]);
  9673. ]]>
  9674. </programlisting>
  9675. <para>
  9676. There always should be exactly one row in the parent table referenced by a dependent
  9677. row, therefore this method returns a Row object, not a Rowset object.
  9678. </para>
  9679. <para>
  9680. The first argument <code>$table</code> can be a string that specifies the parent table
  9681. by its class name. You can also specify the parent table by using an object of that
  9682. table class.
  9683. </para>
  9684. <example id="zend.db.table.relationships.fetching.parent.example">
  9685. <title>Fetching the Parent Row</title>
  9686. <para>
  9687. This example shows getting a Row object from the table <code>Bugs</code> (for
  9688. example one of those bugs with status 'NEW'), and finding the row in the
  9689. <code>Accounts</code> table for the user who reported the bug.
  9690. </para>
  9691. <programlisting role="php"><![CDATA[
  9692. $bugsTable = new Bugs();
  9693. $bugsRowset = $bugsTable->fetchAll(array('bug_status = ?' => 'NEW'));
  9694. $bug1 = $bugsRowset->current();
  9695. $reporter = $bug1->findParentRow('Accounts');
  9696. ]]>
  9697. </programlisting>
  9698. </example>
  9699. <para>
  9700. The second argument <code>$rule</code> is optional. It is a string that names the rule
  9701. key in the <code>$_referenceMap</code> array of the dependent table class. If you don't
  9702. specify a rule, the first rule in the array that references the parent table is used.
  9703. If you need to use a rule other than the first, you need to specify the key.
  9704. </para>
  9705. <para>
  9706. In the example above, the rule key is not specified, so the rule used by default is the
  9707. first one that matches the parent table. This is the rule <code>'Reporter'</code>.
  9708. </para>
  9709. <example id="zend.db.table.relationships.fetching.parent.example-by">
  9710. <title>Fetching a Parent Row By a Specific Rule</title>
  9711. <para>
  9712. This example shows getting a Row object from the table <code>Bugs</code>, and
  9713. finding the account for the engineer assigned to fix that bug. The rule key string
  9714. that corresponds to this reference relationship in this example is
  9715. <code>'Engineer'</code>.
  9716. </para>
  9717. <programlisting role="php"><![CDATA[
  9718. $bugsTable = new Bugs();
  9719. $bugsRowset = $bugsTable->fetchAll(array('bug_status = ?', 'NEW'));
  9720. $bug1 = $bugsRowset->current();
  9721. $engineer = $bug1->findParentRow('Accounts', 'Engineer');
  9722. ]]>
  9723. </programlisting>
  9724. </example>
  9725. <para>
  9726. Alternatively, you can query rows from a parent table using a "magic method".
  9727. Zend_Db_Table_Row_Abstract invokes the method:
  9728. <code>findParentRow('&lt;TableClass&gt;', '&lt;Rule&gt;')</code> if you invoke a method
  9729. on the Row object matching either of the following patterns:
  9730. </para>
  9731. <itemizedlist>
  9732. <listitem>
  9733. <para>
  9734. <code>$row-&gt;findParent&lt;TableClass&gt;([Zend_Db_Table_Select $select])</code>
  9735. </para>
  9736. </listitem>
  9737. <listitem>
  9738. <para>
  9739. <code>$row-&gt;findParent&lt;TableClass&gt;By&lt;Rule&gt;([Zend_Db_Table_Select
  9740. $select])</code>
  9741. </para>
  9742. </listitem>
  9743. </itemizedlist>
  9744. <para>
  9745. In the patterns above, <code>&lt;TableClass&gt;</code> and <code>&lt;Rule&gt;</code>
  9746. are strings that correspond to the class name of the parent table, and the dependent
  9747. table's rule key that references the parent table.
  9748. </para>
  9749. <note>
  9750. <para>
  9751. The table identity and the rule key named in the method call must match the
  9752. spelling of the class and rule key exactly.
  9753. </para>
  9754. </note>
  9755. <example id="zend.db.table.relationships.fetching.parent.example-magic">
  9756. <title>Fetching the Parent Row using the Magic Method</title>
  9757. <para>
  9758. This example shows finding parent Rows equivalent to those in the previous
  9759. examples. In this case, the application uses the magic method invocation instead of
  9760. specifying the table and rule as strings.
  9761. </para>
  9762. <programlisting role="php"><![CDATA[
  9763. $bugsTable = new Bugs();
  9764. $bugsRowset = $bugsTable->fetchAll(array('bug_status = ?', 'NEW'));
  9765. $bug1 = $bugsRowset->current();
  9766. // Use the default reference rule
  9767. $reporter = $bug1->findParentAccounts();
  9768. // Specify the reference rule
  9769. $engineer = $bug1->findParentAccountsByEngineer();
  9770. ]]>
  9771. </programlisting>
  9772. </example>
  9773. </sect2>
  9774. <sect2 id="zend.db.table.relationships.fetching.many-to-many">
  9775. <title>Fetching a Rowset via a Many-to-many Relationship</title>
  9776. <para>
  9777. If you have a Row object as the result of a query on one table in a many-to-many
  9778. relationship (for purposes of the example, call this the "origin" table), you can
  9779. fetch corresponding rows in the other table (call this the "destination" table) via an
  9780. intersection table. Use the method:
  9781. </para>
  9782. <programlisting role="php"><![CDATA[
  9783. $row->findManyToManyRowset($table,
  9784. $intersectionTable,
  9785. [$rule1,
  9786. [$rule2,
  9787. [Zend_Db_Table_Select $select]
  9788. ]
  9789. ]);
  9790. ]]>
  9791. </programlisting>
  9792. <para>
  9793. This method returns a Zend_Db_Table_Rowset_Abstract containing rows from the table
  9794. <code>$table</code>, satisfying the many-to-many relationship. The current Row object
  9795. <code>$row</code> from the origin table is used to find rows in the intersection table,
  9796. and that is joined to the destination table.
  9797. </para>
  9798. <para>
  9799. The first argument <code>$table</code> can be a string that specifies the destination
  9800. table in the many-to-many relationship by its class name. You can also specify the
  9801. destination table by using an object of that table class.
  9802. </para>
  9803. <para>
  9804. The second argument <code>$intersectionTable</code> can be a string that specifies the
  9805. intersection table between the two tables in the the many-to-many relationship by its
  9806. class name. You can also specify the intersection table by using an object of that
  9807. table class.
  9808. </para>
  9809. <example id="zend.db.table.relationships.fetching.many-to-many.example">
  9810. <title>Fetching a Rowset with the Many-to-many Method</title>
  9811. <para>
  9812. This example shows getting a Row object from from the origin table
  9813. <code>Bugs</code>, and finding rows from the destination table
  9814. <code>Products</code>, representing products related to that bug.
  9815. </para>
  9816. <programlisting role="php"><![CDATA[
  9817. $bugsTable = new Bugs();
  9818. $bugsRowset = $bugsTable->find(1234);
  9819. $bug1234 = $bugsRowset->current();
  9820. $productsRowset = $bug1234->findManyToManyRowset('Products',
  9821. 'BugsProducts');
  9822. ]]>
  9823. </programlisting>
  9824. </example>
  9825. <para>
  9826. The third and fourth arguments <code>$rule1</code> and <code>$rule2</code> are
  9827. optional. These are strings that name the rule keys in the <code>$_referenceMap</code>
  9828. array of the intersection table.
  9829. </para>
  9830. <para>
  9831. The <code>$rule1</code> key names the rule for the relationship from the intersection
  9832. table to the origin table. In this example, this is the relationship from
  9833. <code>BugsProducts</code> to <code>Bugs</code>.
  9834. </para>
  9835. <para>
  9836. The <code>$rule2</code> key names the rule for the relationship from the intersection
  9837. table to the destination table. In this example, this is the relationship from
  9838. <code>Bugs</code> to <code>Products</code>.
  9839. </para>
  9840. <para>
  9841. Similarly to the methods for finding parent and dependent rows, if you don't specify a
  9842. rule, the method uses the first rule in the <code>$_referenceMap</code> array that
  9843. matches the tables in the relationship. If you need to use a rule other than the first,
  9844. you need to specify the key.
  9845. </para>
  9846. <para>
  9847. In the example code above, the rule key is not specified, so the rules used by default
  9848. are the first ones that match. In this case, <code>$rule1</code> is
  9849. <code>'Reporter'</code> and <code>$rule2</code> is <code>'Product'</code>.
  9850. </para>
  9851. <example id="zend.db.table.relationships.fetching.many-to-many.example-by">
  9852. <title>Fetching a Rowset with the Many-to-many Method By a Specific Rule</title>
  9853. <para>
  9854. This example shows geting a Row object from from the origin table
  9855. <code>Bugs</code>, and finding rows from the destination table
  9856. <code>Products</code>, representing products related to that bug.
  9857. </para>
  9858. <programlisting role="php"><![CDATA[
  9859. $bugsTable = new Bugs();
  9860. $bugsRowset = $bugsTable->find(1234);
  9861. $bug1234 = $bugsRowset->current();
  9862. $productsRowset = $bug1234->findManyToManyRowset('Products',
  9863. 'BugsProducts',
  9864. 'Bug');
  9865. ]]>
  9866. </programlisting>
  9867. </example>
  9868. <para>
  9869. Alternatively, you can query rows from the destination table in a many-to-many
  9870. relationship using a "magic method." Zend_Db_Table_Row_Abstract invokes the method:
  9871. <code>findManyToManyRowset('&lt;TableClass&gt;', '&lt;IntersectionTableClass&gt;',
  9872. '&lt;Rule1&gt;', '&lt;Rule2&gt;')</code> if you invoke a method matching any of the
  9873. following patterns:
  9874. </para>
  9875. <itemizedlist>
  9876. <listitem>
  9877. <para>
  9878. <code>$row-&gt;find&lt;TableClass&gt;Via&lt;IntersectionTableClass&gt;
  9879. ([Zend_Db_Table_Select $select])</code>
  9880. </para>
  9881. </listitem>
  9882. <listitem>
  9883. <para>
  9884. <code>$row-&gt;find&lt;TableClass&gt;Via&lt;IntersectionTableClass&gt;By&lt;Rule1&gt;
  9885. ([Zend_Db_Table_Select $select])</code>
  9886. </para>
  9887. </listitem>
  9888. <listitem>
  9889. <para>
  9890. <code>$row-&gt;find&lt;TableClass&gt;Via&lt;IntersectionTableClass&gt;By&lt;Rule1&gt;And&lt;Rule2&gt;
  9891. ([Zend_Db_Table_Select $select])</code>
  9892. </para>
  9893. </listitem>
  9894. </itemizedlist>
  9895. <para>
  9896. In the patterns above, <code>&lt;TableClass&gt;</code> and
  9897. <code>&lt;IntersectionTableClass&gt;</code> are strings that correspond to the class
  9898. names of the destination table and the intersection table, respectively.
  9899. <code>&lt;Rule1&gt;</code> and <code>&lt;Rule2&gt;</code> are strings that correspond
  9900. to the rule keys in the intersection table that reference the origin table and the
  9901. destination table, respectively.
  9902. </para>
  9903. <note>
  9904. <para>
  9905. The table identities and the rule keys named in the method call must match the
  9906. spelling of the class and rule key exactly.
  9907. </para>
  9908. </note>
  9909. <example id="zend.db.table.relationships.fetching.many-to-many.example-magic">
  9910. <title>Fetching Rowsets using the Magic Many-to-many Method</title>
  9911. <para>
  9912. This example shows finding rows in the destination table of a many-to-many
  9913. relationship representing products related to a given bug.
  9914. </para>
  9915. <programlisting role="php"><![CDATA[
  9916. $bugsTable = new Bugs();
  9917. $bugsRowset = $bugsTable->find(1234);
  9918. $bug1234 = $bugsRowset->current();
  9919. // Use the default reference rule
  9920. $products = $bug1234->findProductsViaBugsProducts();
  9921. // Specify the reference rule
  9922. $products = $bug1234->findProductsViaBugsProductsByBug();
  9923. ]]>
  9924. </programlisting>
  9925. </example>
  9926. </sect2>
  9927. <sect2 id="zend.db.table.relationships.cascading">
  9928. <title>Cascading Write Operations</title>
  9929. <note>
  9930. <title>Declare DRI in the database:</title>
  9931. <para>
  9932. Declaring cascading operations in Zend_Db_Table is intended
  9933. <emphasis role="strong">only</emphasis> for RDBMS brands that do not support
  9934. declarative referential integrity (DRI).
  9935. </para>
  9936. <para>
  9937. For example, if you use MySQL's MyISAM storage engine, or SQLite, these solutions
  9938. do not support DRI. You may find it helpful to declare the cascading operations
  9939. with Zend_Db_Table.
  9940. </para>
  9941. <para>
  9942. If your RDBMS implements DRI and the <code>ON DELETE</code> and
  9943. <code>ON UPDATE</code> clauses, you should declare these clauses in your database
  9944. schema, instead of using the cascading feature in Zend_Db_Table. Declaring
  9945. cascading DRI rules in the RDBMS is better for database performance, consistency,
  9946. and integrity.
  9947. </para>
  9948. <para>
  9949. Most importantly, do not declare cascading operations both in the RDBMS and in your
  9950. Zend_Db_Table class.
  9951. </para>
  9952. </note>
  9953. <para>
  9954. You can declare cascading operations to execute against a dependent table when you
  9955. apply an <code>UPDATE</code> or a <code>DELETE</code> to a row in a parent table.
  9956. </para>
  9957. <example id="zend.db.table.relationships.cascading.example-delete">
  9958. <title>Example of a Cascading Delete</title>
  9959. <para>
  9960. This example shows deleting a row in the <code>Products</code> table, which is
  9961. configured to automatically delete dependent rows in the <code>Bugs</code> table.
  9962. </para>
  9963. <programlisting role="php"><![CDATA[
  9964. $productsTable = new Products();
  9965. $productsRowset = $productsTable->find(1234);
  9966. $product1234 = $productsRowset->current();
  9967. $product1234->delete();
  9968. // Automatically cascades to Bugs table
  9969. // and deletes dependent rows.
  9970. ]]>
  9971. </programlisting>
  9972. </example>
  9973. <para>
  9974. Similarly, if you use <code>UPDATE</code> to change the value of a primary key in a
  9975. parent table, you may want the value in foreign keys of dependent tables to be updated
  9976. automatically to match the new value, so that such references are kept up to date.
  9977. </para>
  9978. <para>
  9979. It's usually not necessary to update the value of a primary key that was generated by a
  9980. sequence or other mechanism. But if you use a <emphasis>natural key</emphasis> that may
  9981. change value occasionally, it is more likely that you need to apply cascading updates
  9982. to dependent tables.
  9983. </para>
  9984. <para>
  9985. To declare a cascading relationship in the Zend_Db_Table, edit the rules in the
  9986. <code>$_referenceMap</code>. Set the associative array keys <code>'onDelete'</code> and
  9987. <code>'onUpdate'</code> to the string 'cascade' (or the constant
  9988. <code>self::CASCADE</code>). Before a row is deleted from the parent table, or its
  9989. primary key values updated, any rows in the dependent table that refer to the parent's
  9990. row are deleted or updated first.
  9991. </para>
  9992. <example id="zend.db.table.relationships.cascading.example-declaration">
  9993. <title>Example Declaration of Cascading Operations</title>
  9994. <para>
  9995. In the example below, rows in the <code>Bugs</code> table are automatically deleted
  9996. if the row in the <code>Products</code> table to which they refer is deleted. The
  9997. <code>'onDelete'</code> element of the reference map entry is set to
  9998. <code>self::CASCADE</code>.
  9999. </para>
  10000. <para>
  10001. No cascading update is done in the example below if the primary key value in the
  10002. parent class is changed. The <code>'onUpdate'</code> element of the reference map
  10003. entry is <code>self::RESTRICT</code>. You can get the same result using the value
  10004. <code>self::NO_ACTION</code>, or by omitting the <code>'onUpdate'</code> entry.
  10005. </para>
  10006. <programlisting role="php"><![CDATA[
  10007. class BugsProducts extends Zend_Db_Table_Abstract
  10008. {
  10009. ...
  10010. protected $_referenceMap = array(
  10011. 'Product' => array(
  10012. 'columns' => array('product_id'),
  10013. 'refTableClass' => 'Products',
  10014. 'refColumns' => array('product_id'),
  10015. 'onDelete' => self::CASCADE,
  10016. 'onUpdate' => self::RESTRICT
  10017. ),
  10018. ...
  10019. );
  10020. }
  10021. ]]>
  10022. </programlisting>
  10023. </example>
  10024. <sect3 id="zend.db.table.relationships.cascading.notes">
  10025. <title>Notes Regarding Cascading Operations</title>
  10026. <para>
  10027. <emphasis role="strong">Cascading operations invoked by Zend_Db_Table are not
  10028. atomic.</emphasis>
  10029. </para>
  10030. <para>
  10031. This means that if your database implements and enforces referential integrity
  10032. constraints, a cascading <code>UPDATE</code> executed by a Zend_Db_Table class
  10033. conflicts with the constraint, and results in a referential integrity violation.
  10034. You can use cascading <code>UPDATE</code> in Zend_Db_Table
  10035. <emphasis>only</emphasis> if your database does not enforce that referential
  10036. integrity constraint.
  10037. </para>
  10038. <para>
  10039. Cascading <code>DELETE</code> suffers less from the problem of referential
  10040. integrity violations. You can delete dependent rows as a non-atomic action before
  10041. deleting the parent row that they reference.
  10042. </para>
  10043. <para>
  10044. However, for both <code>UPDATE</code> and <code>DELETE</code>, changing the
  10045. database in a non-atomic way also creates the risk that another database user can
  10046. see the data in an inconsistent state. For example, if you delete a row and all its
  10047. dependent rows, there is a small chance that another database client program can
  10048. query the database after you have deleted the dependent rows, but before you delete
  10049. the parent row. That client program may see the parent row with no dependent rows,
  10050. and assume this is the intended state of the data. There is no way for that client
  10051. to know that its query read the database in the middle of a change.
  10052. </para>
  10053. <para>
  10054. The issue of non-atomic change can be mitigated by using transactions to isolate
  10055. your change. But some RDBMS brands don't support transactions, or allow clients to
  10056. read "dirty" changes that have not been committed yet.
  10057. </para>
  10058. <para>
  10059. <emphasis role="strong">Cascading operations in Zend_Db_Table are invoked only by
  10060. Zend_Db_Table.</emphasis>
  10061. </para>
  10062. <para>
  10063. Cascading deletes and updates defined in your Zend_Db_Table classes are applied if
  10064. you execute the <code>save()</code> or <code>delete()</code> methods on the Row
  10065. class. However, if you update or delete data using another interface, such as a
  10066. query tool or another application, the cascading operations are not applied. Even
  10067. when using <code>update()</code> and <code>delete()</code> methods in the
  10068. Zend_Db_Adapter class, cascading operations defined in your Zend_Db_Table classes
  10069. are not executed.
  10070. </para>
  10071. <para>
  10072. <emphasis role="strong">No Cascading <code>INSERT</code>.</emphasis>
  10073. </para>
  10074. <para>
  10075. There is no support for a cascading <code>INSERT</code>. You must insert a row to a
  10076. parent table in one operation, and insert row(s) to a dependent table in a separate
  10077. operation.
  10078. </para>
  10079. </sect3>
  10080. </sect2>
  10081. </sect1><!--
  10082. vim:se ts=4 sw=4 et:
  10083. -->
  10084. </chapter>
  10085. <chapter id="zend.debug">
  10086. <title>Zend_Debug</title>
  10087. <!-- versión 11089 --><sect1 id="zend.debug.dumping" xml:base="module_specs/Zend_Debug.xml">
  10088. <title>Mostrar información de variables(Dumping Variables)</title>
  10089. <para>
  10090. El método estático <code>Zend_Debug::dump()</code> imprime o devuelve
  10091. información sobre una expresión. Esta sencilla técnica de depuración es
  10092. común, porque es fácil de utilizar en caliente y no requiere
  10093. inicialización, herramientas especiales, o la depuración del entorno.
  10094. </para>
  10095. <example id="zend.debug.dumping.example">
  10096. <title>Ejemplo del método dump()</title>
  10097. <programlisting role="php"><![CDATA[
  10098. Zend_Debug::dump($var, $label=null, $echo=true);
  10099. ]]>
  10100. </programlisting>
  10101. </example>
  10102. <para>
  10103. El argumento <code>$var</code> especifica la expresión o variable sobre
  10104. la cual el método <code>Zend_Debug::dump()</code> generará información.
  10105. </para>
  10106. <para>
  10107. El argumento boleano <code>$echo</code> especifica si la salida de
  10108. <code>Zend_Debug::dump()</code> es o no mostrada. Si es
  10109. <code>verdadera</code>, la salida es mostrada. A pesar del valor del
  10110. argumento <code>$echo</code>, el retorno de este método contiene la
  10111. salida.
  10112. </para>
  10113. <para>
  10114. Puede ser útil comprender que el método <code>Zend_Debug::dump()</code>
  10115. envuelve la función de PHP
  10116. <ulink url="http://php.net/var_dump"><code>var_dump()</code></ulink>.
  10117. Si el flujo de salida es detectado como una presentación de la web, la
  10118. salida de <code>var_dump()</code> es escapada usando
  10119. <ulink url="http://php.net/htmlspecialchars"><code>htmlspecialchars()</code></ulink>
  10120. y envuelta con el tag (X)HTML <code>pre</code>.
  10121. </para>
  10122. <tip>
  10123. <title>Depurando con Zend_Log</title>
  10124. <para>
  10125. Usar <code>Zend_Debug::dump()</code> es lo mejor para la depuración
  10126. en caliente durante el desarrollo de software. Puede añadir el código para
  10127. volcar una variable y después quitar el código fácilmente.
  10128. </para>
  10129. <para>
  10130. También considere el componente <link linkend="zend.log.overview">
  10131. Zend_Log</link> escribiendo el código de depuración más
  10132. permanente. Por ejemplo, puede utilizar el nivel de log de
  10133. <code>DEPURACIÓN</code> y el Stream log writer, para mostrar la
  10134. cadena de salida de <code>Zend_Debug::dump()</code>.
  10135. </para>
  10136. </tip>
  10137. </sect1><!--
  10138. vim:se ts=4 sw=4 et:
  10139. -->
  10140. </chapter>
  10141. <chapter id="zend.dojo">
  10142. <title>Zend_Dojo</title>
  10143. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Dojo.xml"/>
  10144. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Dojo-Data.xml"/>
  10145. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Dojo-View.xml" parse="xml"/>
  10146. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Dojo-Form.xml" parse="xml"/>
  10147. </chapter>
  10148. <chapter id="zend.dom">
  10149. <title>Zend_Dom</title>
  10150. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Dom.xml"/>
  10151. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Dom-Query.xml"/>
  10152. </chapter>
  10153. <chapter id="zend.exception">
  10154. <title>Zend_Exception</title>
  10155. <sect1 id="zend.exception.using" xml:base="module_specs/Zend_Exception.xml">
  10156. <title>Usando Excepciones</title>
  10157. <para>
  10158. Todas las excepciones lanzadas por las clases de Zend Framework
  10159. deberian arrojar una excepción que deriva de la clase base
  10160. Zend_Exception.
  10161. </para>
  10162. <example id="zend.exception.using.example">
  10163. <title>Ejemplo de catching de una excepción</title>
  10164. <programlisting role="php"><![CDATA[
  10165. try {
  10166. Zend_Loader::loadClass('clasenoexistente');
  10167. } catch (Zend_Exception $e) {
  10168. echo "Recibida excepción: " . get_class($e) . "\n";
  10169. echo "Mensaje: " . $e->getMessage() . "\n";
  10170. // código para recuperar el fallo.
  10171. }
  10172. ]]>
  10173. </programlisting>
  10174. </example>
  10175. <para>
  10176. Consulte la documentación de cada uno de los componente de Zend
  10177. Framework para obtener información más específica sobre los
  10178. métodos que lanzan excepciones, las circunstancias de las
  10179. excepciones, y qué clases derivan de Zend_Exception.
  10180. </para>
  10181. </sect1><!--
  10182. vim:se ts=4 sw=4 et:
  10183. -->
  10184. </chapter>
  10185. <chapter id="zend.feed">
  10186. <title>Zend_Feed</title>
  10187. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Feed-Introduction.xml"/>
  10188. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Feed-Importing.xml"/>
  10189. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Feed-FindFeeds.xml"/>
  10190. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Feed-ConsumingRss.xml"/>
  10191. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Feed-ConsumingAtom.xml"/>
  10192. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Feed-ConsumingAtomSingle.xml"/>
  10193. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Feed-ModifyingFeed.xml"/>
  10194. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Feed-CustomFeed.xml"/>
  10195. </chapter>
  10196. <chapter id="zend.file">
  10197. <title>Zend_File</title>
  10198. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_File_Transfer-Introduction.xml"/>
  10199. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_File_Transfer-Validators.xml"/>
  10200. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_File_Transfer-Filters.xml"/>
  10201. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_File_Transfer-Migration.xml"/>
  10202. </chapter>
  10203. <chapter id="zend.filter">
  10204. <title>Zend_Filter</title>
  10205. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Filter.xml"/>
  10206. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Filter-Set.xml"/>
  10207. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Filter-FilterChains.xml"/>
  10208. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Filter-WritingFilters.xml"/>
  10209. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Filter_Input.xml"/>
  10210. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Filter-Inflector.xml"/>
  10211. </chapter>
  10212. <chapter id="zend.form">
  10213. <title>Zend_Form</title>
  10214. <sect1 id="zend.form.introduction" xml:base="module_specs/Zend_Form-Introduction.xml">
  10215. <title>Zend_Form</title>
  10216. <para>
  10217. Zend_Form simplifica la creación y manejo de formularios en sus
  10218. aplicaciones web. Cumple los siguientes objetivos:
  10219. </para>
  10220. <itemizedlist>
  10221. <listitem><para>Validación y filtrado de la información suministrada</para></listitem>
  10222. <listitem><para>Ordenado de elementos</para></listitem>
  10223. <listitem><para>Elementos y su presentación, incluyendo su escape</para></listitem>
  10224. <listitem><para>Agrupación de elementos y formularios</para></listitem>
  10225. <listitem><para>Configuración de componentes a nivel de formulario</para></listitem>
  10226. </itemizedlist>
  10227. <para>
  10228. Se aprovecha en gran medida de otros componentes de Zend Framework para lograr sus objetivos,
  10229. incluyendo <code>Zend_Config</code>, <code>Zend_Validate</code>, <code>Zend_Filter</code>,
  10230. <code>Zend_Loader_PluginLoader</code> y, opcionalmente, <code>Zend_View</code>.
  10231. </para>
  10232. </sect1><!--
  10233. vim:se ts=4 sw=4 et:
  10234. -->
  10235. <sect1 id="zend.form.quickstart" xml:base="module_specs/Zend_Form-QuickStart.xml">
  10236. <title>Inicio rápido a Zend_Form</title>
  10237. <para>
  10238. Esta guía rápida pretende cubrir los fundamentos para
  10239. crear, validar y presentar formularios usando <code>Zend_Form</code>
  10240. </para>
  10241. <sect2 id="zend.form.quickstart.create">
  10242. <title>Creando un objeto formulario</title>
  10243. <para>
  10244. Crear un objeto de formulario es muy simple: solo instancíe
  10245. <code>Zend_Form</code>
  10246. </para>
  10247. <programlisting role="php"><![CDATA[
  10248. $form = new Zend_Form;
  10249. ]]>
  10250. </programlisting>
  10251. <para>
  10252. Para casos de uso avanzados, es posible desee crear una subclase de
  10253. <code>Zend_Form</code>, pero para formularios simples, puede
  10254. programar la creación de un formulario usando un objeto
  10255. <code>Zend_Form</code>
  10256. </para>
  10257. <para>
  10258. Si desea especificar el action y method del formulario (siempre
  10259. buenas ideas), puede hacer uso de los accesos
  10260. <code>setAction()</code> y <code>setMethod()</code>:
  10261. </para>
  10262. <programlisting role="php"><![CDATA[
  10263. $form->setAction('/resource/process')
  10264. ->setMethod('post');
  10265. ]]>
  10266. </programlisting>
  10267. <para>
  10268. El código de arriba establece el action del formulario a la URL
  10269. parcial "/resource/process" y como method HTTP POST. Esto se
  10270. mostrará en la presentación final.
  10271. </para>
  10272. <para>
  10273. Usted puede establecer atributos HTML adicionales para la etiqueta
  10274. <code>&lt;form&gt;</code> mediante el uso de los métodos
  10275. setAttrib() o setAttribs(). Por ejemplo, si desea especificar el id
  10276. establezca el atributo "id":
  10277. </para>
  10278. <programlisting role="php"><![CDATA[
  10279. $form->setAttrib('id', 'login');
  10280. ]]>
  10281. </programlisting>
  10282. </sect2>
  10283. <sect2 id="zend.form.quickstart.elements">
  10284. <title>Añadir elementos al formulario</title>
  10285. <para>
  10286. Un formulario no es nada sin sus elementos. <code>Zend_Form</code>
  10287. contiene de manera predeterminada algunos elementos que generan
  10288. XHTML vía auxiliares <code>Zend_View</code>. Son los
  10289. siguientes:
  10290. </para>
  10291. <itemizedlist>
  10292. <listitem><para>
  10293. button
  10294. </para></listitem>
  10295. <listitem><para>
  10296. checkbox (o varios checkboxes a la vez con multiCheckbox)
  10297. </para></listitem>
  10298. <listitem><para>
  10299. hidden
  10300. </para></listitem>
  10301. <listitem><para>
  10302. image
  10303. </para></listitem>
  10304. <listitem><para>
  10305. password
  10306. </para></listitem>
  10307. <listitem><para>
  10308. radio
  10309. </para></listitem>
  10310. <listitem><para>
  10311. reset
  10312. </para></listitem>
  10313. <listitem><para>
  10314. select (tanto regulares como de multi-selección)
  10315. </para></listitem>
  10316. <listitem><para>
  10317. submit
  10318. </para></listitem>
  10319. <listitem><para>
  10320. text
  10321. </para></listitem>
  10322. <listitem><para>
  10323. textarea
  10324. </para></listitem>
  10325. </itemizedlist>
  10326. <para>
  10327. Tiene dos opciones para añadir elementos a un formulario; puede
  10328. instanciar elementos concretos y pasarlos como objetos, o
  10329. simplemente puede pasar el tipo de elemento y <code>Zend_Form</code>
  10330. instaciará por usted un objeto del tipo correspondiente.
  10331. </para>
  10332. <para>
  10333. Algunos ejemplos:
  10334. </para>
  10335. <programlisting role="php"><![CDATA[
  10336. // Instanciando un elemento y pasandolo al objeto form:
  10337. $form->addElement(new Zend_Form_Element_Text('username'));
  10338. // Pasando el tipo de elemento del formulario al objeto form:
  10339. $form->addElement('text', 'username');
  10340. ]]>
  10341. </programlisting>
  10342. <para>
  10343. De manera predeterminada, éstos no tienen validadores o filtros.
  10344. Esto significa que tendrá que configurar sus elementos con un
  10345. mínimo de validadores, y potencialmente filtros. Puede hacer esto
  10346. (a) antes de pasar el elemento al formulario, (b) vía opciones de
  10347. configuración pasadas cuando crea un elemento a través de
  10348. <code>Zend_Form</code>, o (c) recuperar el elemento del objeto form
  10349. y configurándolo posteriormente.
  10350. </para>
  10351. <para>
  10352. Veamos primero la creación de validadores para la instancia de
  10353. un elemento concreto. Puede pasar objetos
  10354. <code>Zend_Validate_*</code> o el nombre de un validador para utilizar:
  10355. </para>
  10356. <programlisting role="php"><![CDATA[
  10357. $username = new Zend_Form_Element_Text('username');
  10358. // Pasando un objeto Zend_Validate_*:
  10359. $username->addValidator(new Zend_Validate_Alnum());
  10360. // Pasando el nombre de un validador:
  10361. $username->addValidator('alnum');
  10362. ]]>
  10363. </programlisting>
  10364. <para>
  10365. Cuando se utiliza esta segunda opción, si el constructor del
  10366. validador acepta argumentos, se pueden pasar en un array
  10367. como tercer parámetro:
  10368. </para>
  10369. <programlisting role="php"><![CDATA[
  10370. // Pasando un patrón
  10371. $username->addValidator('regex', false, array('/^[a-z]/i'));
  10372. ]]>
  10373. </programlisting>
  10374. <para>
  10375. (El segundo parámetro se utiliza para indicar si el fallo
  10376. debería prevenir la ejecución de validadores posteriores o no; por
  10377. defecto, el valor es false.)
  10378. </para>
  10379. <para>
  10380. Puede también desear especificar un elemento como requerido. Esto
  10381. puede hacerse utilizando un método de acceso o pasando una opción al
  10382. crear el elemento. En el primer caso:
  10383. </para>
  10384. <programlisting role="php"><![CDATA[
  10385. // Hace este elemento requerido:
  10386. $username->setRequired(true);
  10387. ]]>
  10388. </programlisting>
  10389. <para>
  10390. Cuando un elemento es requerido, un validador 'NotEmpty' (NoVacio)
  10391. es añadido a la parte superior de la cadena de validaciones,
  10392. asegurando que el elemento tenga algún valor cuando sea requerido.
  10393. </para>
  10394. <para>
  10395. Los filtros son registrados básicamente de la misma manera que los
  10396. validadores. Para efectos ilustrativos, vamos a agregar un filtro
  10397. para poner en minúsculas el valor final:
  10398. </para>
  10399. <programlisting role="php"><![CDATA[
  10400. $username->addFilter('StringtoLower');
  10401. ]]>
  10402. </programlisting>
  10403. <para>
  10404. Entonces, la configuración final de nuestro elemento queda así:
  10405. </para>
  10406. <programlisting role="php"><![CDATA[
  10407. $username->addValidator('alnum')
  10408. ->addValidator('regex', false, array('/^[a-z]/'))
  10409. ->setRequired(true)
  10410. ->addFilter('StringToLower');
  10411. // o, de manera más compacta:
  10412. $username->addValidators(array('alnum',
  10413. array('regex', false, '/^[a-z]/i')
  10414. ))
  10415. ->setRequired(true)
  10416. ->addFilters(array('StringToLower'));
  10417. ]]>
  10418. </programlisting>
  10419. <para>
  10420. Tan simple como esto, realizarlo para cada uno de los elementos
  10421. del formulario puede resultar un poco tedioso. Intentemos la opción
  10422. (b) arriba mencionada. Cuando creamos un nuevo elemento utilizando
  10423. <code>Zend_Form::addElement()</code> como fábrica, opcionalmente
  10424. podemos pasar las opciones de configuración. Éstas pueden incluir
  10425. validadores y los filtros que se van a utilizar. Por lo tanto, para hacer todo
  10426. lo anterior implícitamente, intente lo siguiente:
  10427. </para>
  10428. <programlisting role="php"><![CDATA[
  10429. $form->addElement('text', 'username', array(
  10430. 'validators' => array(
  10431. 'alnum',
  10432. array('regex', false, '/^[a-z]/i')
  10433. ),
  10434. 'required' => true,
  10435. 'filters' => array('StringToLower'),
  10436. ));
  10437. ]]>
  10438. </programlisting>
  10439. <note><para>
  10440. Si encuentra que está asignando elementos con las mismas opciones en
  10441. varios lugares, podría considerar crear su propia subclase de
  10442. <code>Zend_Form_Element</code> y utilizar ésta; a largo plazo le
  10443. permitirá escribir menos.
  10444. </para></note>
  10445. </sect2>
  10446. <sect2 id="zend.form.quickstart.render">
  10447. <title>Generar un formulario</title>
  10448. <para>
  10449. Generar un formulario es simple. La mayoría de los elementos
  10450. utilizan un auxiliar de <code>Zend_View</code> para generarse a sí
  10451. mismos, por lo tanto necesitan un objeto vista con el fin de
  10452. generarse. Además, tiene dos opciones: usar el método render()
  10453. del formulario, o simplemente mostrarlo con echo.
  10454. </para>
  10455. <programlisting role="php"><![CDATA[
  10456. // Llamando a render() explicitamente, y pasando un objeto vista opcional:
  10457. echo $form->render($view);
  10458. // Suponiendo un objeto vista ha sido previamente establecido vía setView():
  10459. echo $form;
  10460. ]]>
  10461. </programlisting>
  10462. <para>
  10463. De manera predeterminada, <code>Zend_Form</code> y
  10464. <code>Zend_Form_Element</code> intentarán utilizar el objeto vista
  10465. inicializado en el <code>ViewRenderer</code>, lo que significa que
  10466. no tendrá que establecer la vista manualmente cuando use el MVC de
  10467. Zend Framework. Generar un formulario en un script vista es tan
  10468. simple como:
  10469. </para>
  10470. <programlisting role="php"><![CDATA[
  10471. <?php echo $this->form ?>
  10472. ]]>
  10473. </programlisting>
  10474. <para>
  10475. Detrás del telón, <code>Zend_Form</code> utiliza "decoradores"
  10476. (decorators) para generar la salida. Estos decoradores pueden
  10477. reemplazar, añadir o anteponer contenido, y tienen plena
  10478. introspección al elemento que les es pasado. Como resultado, puede
  10479. combinar múltiples decoradores para lograr efectos personalizados.
  10480. Predeterminadamente, <code>Zend_Form_Element</code> actualmente
  10481. combina cuatro decoradores para obtener su salida; la configuración
  10482. sería como sigue:
  10483. </para>
  10484. <programlisting role="php"><![CDATA[
  10485. $element->addDecorators(array(
  10486. 'ViewHelper',
  10487. 'Errors',
  10488. array('HtmlTag', array('tag' => 'dd')),
  10489. array('Label', array('tag' => 'dt')),
  10490. ));
  10491. ]]>
  10492. </programlisting>
  10493. <para>
  10494. (Donde &lt;HELPERNAME&gt; es el nombre de un view helper que
  10495. utilizar, y varía según el elemento)
  10496. </para>
  10497. <para>
  10498. Lo anterior crea una salida como la siguiente:
  10499. </para>
  10500. <programlisting role="html"><![CDATA[
  10501. <dt><label for="username" class="required">Username</dt>
  10502. <dd>
  10503. <input type="text" name="username" value="123-abc" />
  10504. <ul class="errors">
  10505. <li>'123-abc' has not only alphabetic and digit characters</li>
  10506. <li>'123-abc' does not match against pattern '/^[a-z]/i'</li>
  10507. </ul>
  10508. </dd>
  10509. ]]>
  10510. </programlisting>
  10511. <para>
  10512. (Aunque no con el mismo formato.)
  10513. </para>
  10514. <para>
  10515. Puede cambiar los decoradores usados para un elemento si desea tener
  10516. diferente salida; véase la sección sobre decoradores para mayor
  10517. información.
  10518. </para>
  10519. <para>
  10520. El propio formulario simplemente itera sobre los elementos y
  10521. los cubre en un &lt;form&gt; HTML. El action y method que
  10522. proporcionó cuando definió el formulario se pasan a la etiqueta
  10523. <code>&lt;form&gt;</code>, como cualquier atributo que establezca
  10524. vía <code>setAttribs()</code> y familia.
  10525. </para>
  10526. <para>
  10527. Elementos son desplegados en el orden en el que fueron registrados,
  10528. o, si el elemento contienen un atributo de orden, ese orden será
  10529. utilizado. Usted puede fijar el orden de un elemento usando:
  10530. </para>
  10531. <programlisting role="php"><![CDATA[
  10532. $element->setOrder(10);
  10533. ]]>
  10534. </programlisting>
  10535. <para>
  10536. O, cuando crea un elemento, pasándolo como una opción:
  10537. </para>
  10538. <programlisting role="php"><![CDATA[
  10539. $form->addElement('text', 'username', array('order' => 10));
  10540. ]]>
  10541. </programlisting>
  10542. </sect2>
  10543. <sect2 id="zend.form.quickstart.validate">
  10544. <title>Comprobar si un formulario es válido</title>
  10545. <para>
  10546. Después que un formulario es enviado, necesitará comprobar y ver si
  10547. pasa las validaciones. Cada elemento es valuado contra los datos
  10548. provistos; si una clave no está presente y el campo fue marcado como
  10549. requerido, la validación se ejecuta contra un valor nulo.
  10550. </para>
  10551. <para>
  10552. ¿De dónde provienen los datos?. Puede usar <code>$_POST</code> o
  10553. <code>$_GET</code>, o cualquier otra fuente de datos que tenga a
  10554. mano (solicitud de un servicio web, por ejemplo):
  10555. </para>
  10556. <programlisting role="php"><![CDATA[
  10557. if ($form->isValid($_POST)) {
  10558. // ¡Correcto!
  10559. } else {
  10560. // ¡Fallo!
  10561. }
  10562. ]]>
  10563. </programlisting>
  10564. <para>
  10565. Con solicitudes AJAX, a veces puede ignorar la validación de un solo
  10566. elemento, o grupo de elementos.
  10567. <code>isValidPartial()</code> validará parcialmente el formulario.
  10568. A diferencia de <code>isValid()</code>, que como sea, si alguna
  10569. clave no esta presente, no ejecutará las validaciones para ese
  10570. elemento en particular.
  10571. </para>
  10572. <programlisting role="php"><![CDATA[
  10573. if ($form->isValidPartial($_POST)) {
  10574. // de los elementos presentes, todos pasaron las validaciones
  10575. } else {
  10576. // uno u más elementos probados no pasaron las validaciones
  10577. }
  10578. ]]>
  10579. </programlisting>
  10580. <para>
  10581. Un método adicional, <code>processAjax()</code>, puede también ser
  10582. usado para validar formularios parciales. A diferencia de
  10583. <code>isValidPartial()</code>, regresa una cadena en formato JSON
  10584. conteniendo mensajes de error en caso de fallo.
  10585. </para>
  10586. <para>
  10587. Asumiendo que sus validaciones han pasado, ahora puede obtener los
  10588. valores filtrados:
  10589. </para>
  10590. <programlisting role="php"><![CDATA[
  10591. $values = $form->getValues();
  10592. ]]>
  10593. </programlisting>
  10594. <para>
  10595. Si necesita los valores sin filtrar en algún punto, utilice:
  10596. </para>
  10597. <programlisting role="php"><![CDATA[
  10598. $unfiltered = $form->getUnfilteredValues();
  10599. ]]>
  10600. </programlisting>
  10601. </sect2>
  10602. <sect2 id="zend.form.quickstart.errorstatus">
  10603. <title>Obteniendo el estado de error</title>
  10604. <para>
  10605. Entonces, ¿su formulario no es válido? En la mayoría de los casos,
  10606. simplemente puede generar el formulario nuevamente y los errores se
  10607. mostrarán cuando se usen los decoradores predeterminados:
  10608. </para>
  10609. <programlisting role="php"><![CDATA[
  10610. if (!$form->isValid($_POST)) {
  10611. echo $form;
  10612. // o asigne al objeto vista y genere una vista...
  10613. $this->view->form = $form;
  10614. return $this->render('form');
  10615. }
  10616. ]]>
  10617. </programlisting>
  10618. <para>
  10619. Si quiere inspeccionar los errores, tiene dos métodos.
  10620. <code>getErrors()</code> regresa una matriz asociativa de nombres /
  10621. códigos de elementos (donde códigos es una matriz de códigos de
  10622. error). <code>getMessages()</code> regresa una matriz asociativa
  10623. de nombres / mensajes de elementos (donde mensajes es una matriz
  10624. asociativa de pares código de error / mensaje de error). Si un
  10625. elemento no tiene ningún error, no será incluido en la matriz.
  10626. </para>
  10627. </sect2>
  10628. <sect2 id="zend.form.quickstart.puttingtogether">
  10629. <title>Poniendo todo junto</title>
  10630. <para>
  10631. Construyamos un simple formulario de login. Necesitaremos
  10632. elementos que representen:
  10633. </para>
  10634. <itemizedlist>
  10635. <listitem><para>usuario</para></listitem>
  10636. <listitem><para>contraseña</para></listitem>
  10637. <listitem><para>Botón de ingreso</para></listitem>
  10638. </itemizedlist>
  10639. <para>
  10640. Para nuestros propósitos, vamos a suponer que un usuario válido
  10641. cumplirá con tener solo caracteres alfanuméricos, comenzar con una
  10642. letra, tener una longitud mínima de 6 caracteres y una longitud
  10643. máxima de 20 caracteres; se normalizarán en minúsculas. Las
  10644. contraseñas deben tener un mínimo de 6 caracteres. Cuando se procese
  10645. vamos simplemente a mostrar el valor, por lo que puede permanecer
  10646. inválido.
  10647. </para>
  10648. <para>
  10649. Usaremos el poder de la opciones de configuración de
  10650. <code>Zend_Form</code> para crear el formulario:
  10651. </para>
  10652. <programlisting role="php"><![CDATA[
  10653. $form = new Zend_Form();
  10654. $form->setAction('/user/login')
  10655. ->setMethod('post');
  10656. // Crea un y configura el elemento username
  10657. $username = $form->createElement('text', 'username');
  10658. $username->addValidator('alnum')
  10659. ->addValidator('regex', false, array('/^[a-z]+/'))
  10660. ->addValidator('stringLength', false, array(6, 20))
  10661. ->setRequired(true)
  10662. ->addFilter('StringToLower');
  10663. // Crea y configura el elemento password:
  10664. $password = $form->createElement('password', 'password');
  10665. $password->addValidator('StringLength', false, array(6))
  10666. ->setRequired(true);
  10667. // Añade los elementos al formulario:
  10668. $form->addElement($username)
  10669. ->addElement($password)
  10670. // uso de addElement() como fábrica para crear el botón 'Login':
  10671. ->addElement('submit', 'login', array('label' => 'Login'));
  10672. ]]>
  10673. </programlisting>
  10674. <para>
  10675. A continuación, vamos a crear un controlador para manejar esto:
  10676. </para>
  10677. <programlisting role="php"><![CDATA[
  10678. class UserController extends Zend_Controller_Action
  10679. {
  10680. public function getForm()
  10681. {
  10682. // crea el formulario como se indicó arriba
  10683. return $form;
  10684. }
  10685. public function indexAction()
  10686. {
  10687. // genera user/form.phtml
  10688. $this->view->form = $this->getForm();
  10689. $this->render('form');
  10690. }
  10691. public function loginAction()
  10692. {
  10693. if (!$this->getRequest()->isPost()) {
  10694. return $this->_forward('index');
  10695. }
  10696. $form = $this->getForm();
  10697. if (!$form->isValid($_POST)) {
  10698. // Falla la validación; Se vuelve a mostrar el formulario
  10699. $this->view->form = $form;
  10700. return $this->render('form');
  10701. }
  10702. $values = $form->getValues();
  10703. // ahora intenta y autentica...
  10704. }
  10705. }
  10706. ]]>
  10707. </programlisting>
  10708. <para>
  10709. Y un script para la vista que muestra el formulario:
  10710. </para>
  10711. <programlisting role="php"><![CDATA[
  10712. <h2>Please login:</h2>
  10713. <?= $this->form ?>
  10714. ]]>
  10715. </programlisting>
  10716. <para>
  10717. Como notará en el código del controlador, hay más trabajo por hacer:
  10718. mientras la información enviada sea válida, necesitará todavía
  10719. realizar la autenticación usando <code>Zend_Auth</code>, por
  10720. ejemplo.
  10721. </para>
  10722. </sect2>
  10723. <sect2 id="zend.form.quickstart.config">
  10724. <title>Usando un objeto Zend_Config</title>
  10725. <para>
  10726. Todas las clases <code>Zend_Form</code> son configurables mediante
  10727. <code>Zend_Config</code>; puede incluso pasar un objeto al
  10728. constructor o pasarlo a través de <code>setConfig()</code>. Veamos
  10729. cómo podemos crear el formulario anterior usando un archivo INI.
  10730. Primero, vamos a seguir las recomendaciones, y colocaremos nuestras
  10731. configuraciones dentro de secciones reflejando su objetivo y
  10732. y enfocándonos en la sección 'development'. A continuación,
  10733. pondremos en una sección de configuración para el controlador dado
  10734. ('user'), y una clave para el formulario ('login'):
  10735. </para>
  10736. <programlisting role="ini"><![CDATA[
  10737. [development]
  10738. ; metainformación general del formulario
  10739. user.login.action = "/user/login"
  10740. user.login.method = "post"
  10741. ; elemento username
  10742. user.login.elements.username.type = "text"
  10743. user.login.elements.username.options.validators.alnum.validator = "alnum"
  10744. user.login.elements.username.options.validators.regex.validator = "regex"
  10745. user.login.elements.username.options.validators.regex.options.pattern = "/^[a-z]/i"
  10746. user.login.elements.username.options.validators.strlen.validator = "StringLength"
  10747. user.login.elements.username.options.validators.strlen.options.min = "6"
  10748. user.login.elements.username.options.validators.strlen.options.max = "20"
  10749. user.login.elements.username.options.required = true
  10750. user.login.elements.username.options.filters.lower.filter = "StringToLower"
  10751. ; elemento password
  10752. user.login.elements.password.type = "password"
  10753. user.login.elements.password.options.validators.strlen.validator = "StringLength"
  10754. user.login.elements.password.options.validators.strlen.options.min = "6"
  10755. user.login.elements.password.options.required = true
  10756. ; elemento submit
  10757. user.login.elements.submit.type = "submit"
  10758. ]]>
  10759. </programlisting>
  10760. <para>
  10761. Entonces puede pasarlo al constructor del formulario:
  10762. </para>
  10763. <programlisting role="php"><![CDATA[
  10764. $config = new Zend_Config_Ini($configFile, 'development');
  10765. $form = new Zend_Form($config->user->login);
  10766. ]]>
  10767. </programlisting>
  10768. <para>
  10769. y el formulario entero será definido.
  10770. </para>
  10771. </sect2>
  10772. <sect2 id="zend.form.quickstart.conclusion">
  10773. <title>Conclusión</title>
  10774. <para>
  10775. Esperamos que después de este pequeño tutorial sea capaz de descubrir
  10776. el poder y flexibilidad de <code>Zend_Form</code>. Continúe leyendo
  10777. para profundizar más en el tema.
  10778. </para>
  10779. </sect2>
  10780. </sect1><!--
  10781. vim:se ts=4 sw=4 et:
  10782. -->
  10783. <sect1 id="zend.form.elements" xml:base="module_specs/Zend_Form-Elements.xml">
  10784. <title>Creando elementos de formulario usando Zend_Form_Element</title>
  10785. <para>
  10786. Un formulario esta compuesto de elementos, que normalmente corresponden
  10787. al elemento HTML input. <code>Zend_Form_Element</code> encapsula
  10788. elementos de formulario individualmente, con las siguientes áreas de
  10789. responsabilidad:
  10790. </para>
  10791. <itemizedlist>
  10792. <listitem>
  10793. <para>
  10794. validación (¿los datos enviados son válidos?)
  10795. </para>
  10796. <itemizedlist>
  10797. <listitem><para>captura de códigos y mensajes de error</para></listitem>
  10798. </itemizedlist>
  10799. </listitem>
  10800. <listitem><para>
  10801. filtrado (¿cómo es escapado y normalizado el elemento para su
  10802. validación y/o salida?
  10803. </para></listitem>
  10804. <listitem><para>
  10805. generación (¿cómo es mostrado el elemento?)
  10806. </para></listitem>
  10807. <listitem><para>
  10808. metadatos y atributos (¿qué información amplía la definición del
  10809. elemento?)
  10810. </para></listitem>
  10811. </itemizedlist>
  10812. <para>
  10813. La clase base, <code>Zend_Form_Element</code>, funciona por defecto para
  10814. varios casos, pero es mejor extender la clase para elementos con fines
  10815. especiales de uso común. Adicionalmente, Zend Framework contiene un
  10816. número de elementos XHTML estándar; puede leer de ellos <link linkend="zend.form.standarElements">en el capítulo Elementos
  10817. Estándares</link>
  10818. </para>
  10819. <sect2 id="zend.form.elements.loaders">
  10820. <title>Cargadores de Plugin</title>
  10821. <para>
  10822. <code>Zend_Form_Element</code> hace uso de <link linkend="zend.loader.pluginloader">Zend_Loader_PluginLoader</link>
  10823. para permitir a los desarrolladores especificar ubicaciones de
  10824. validadores, filtros y decoradores alternos. Cada uno tiene su
  10825. propio cargador de plugin asociado a él y métodos de acceso
  10826. generales usados para su recuperación y modificación.
  10827. </para>
  10828. <para>
  10829. Los siguientes tipos de cargadores son usados con los varios métodos
  10830. del cargador de plugin: 'validate', 'filter', y 'decorator'. Los
  10831. nombres son sensibles a mayúsculas y minúsculas.
  10832. </para>
  10833. <para>
  10834. Los métodos usados para interactuar con los cargadores de plugin son
  10835. los siguientes:
  10836. </para>
  10837. <itemizedlist>
  10838. <listitem><para>
  10839. <code>setPluginLoader($loader, $type)</code>:
  10840. <code>$loader</code> es el propio objeto cargador, mientras
  10841. <code>$type</code> es uno de los tipos arriba mencionados. Esto
  10842. establece el cargador de plugin para el tipo dado en el objeto
  10843. cargador recién especificado.
  10844. </para></listitem>
  10845. <listitem><para>
  10846. <code>getPluginLoader($type)</code>: obtiene el cargador de
  10847. plugin asociado con <code>$type</code>.
  10848. </para></listitem>
  10849. <listitem><para>
  10850. <code>addPrefixPath($prefix, $path, $type = null)</code>: agrega
  10851. una asociación prefijo/ruta para el cargador especificado por
  10852. <code>$type</code>. Si <code>$type</code> es null, se intentará
  10853. agregar la ruta a todos los cargadores, añadiendo el prefijo a
  10854. cada "_Validate", "_Filter" y "_Decorator"; y agregandole
  10855. "Validate/", "Filter/" y "Decorator/" a la ruta. Si tiene todas
  10856. sus clases extras para elementos de formulario dentro de
  10857. una jerarquía común, este método es conveniente para establecer
  10858. el prefijo para todas ellas.
  10859. </para></listitem>
  10860. <listitem><para>
  10861. <code>addPrefixPaths(array $spec)</code>: le permite añadir
  10862. varias rutas de una sola vez a uno o más cargadores de plugin.
  10863. Se espera cada elemento de la matriz sea un array con claves
  10864. 'path', 'prefix', y 'type'.
  10865. </para></listitem>
  10866. </itemizedlist>
  10867. <para>
  10868. Validadores, filtros y decoradores personalizados son una manera
  10869. simple de compartir funcionalidad entre formularios y encapsular
  10870. funcionalidad personalizada.
  10871. </para>
  10872. <example id="zend.form.elements.loaders.customLabel">
  10873. <title>Etiqueta personalizada</title>
  10874. <para>
  10875. Un uso común de los plugins es proveer reemplazos para las
  10876. clases estándares. Por ejemplo, si desea proveer una implementación diferente
  10877. del decorador 'Label' -- por ejemplo, para
  10878. añadir siempre dos puntos -- puede crear su propio decorador
  10879. 'Label' con su propio prefijo de clase, y entonces añadirlo a su
  10880. prefijo de ruta.
  10881. </para>
  10882. <para>
  10883. Comencemos con un decorador de etiqueta personalizado. Le
  10884. daremos el prefijo "My_Decorator", y la clase estará en el
  10885. archivo "My/Decorator/Label.php".
  10886. </para>
  10887. <programlisting role="php"><![CDATA[
  10888. class My_Decorator_Label extends Zend_Form_Decorator_Abstract
  10889. {
  10890. protected $_placement = 'PREPEND';
  10891. public function render($content)
  10892. {
  10893. if (null === ($element = $this->getElement())) {
  10894. return $content;
  10895. }
  10896. if (!method_exists($element, 'getLabel')) {
  10897. return $content;
  10898. }
  10899. $label = $element->getLabel() . ':';
  10900. if (null === ($view = $element->getView())) {
  10901. return $this->renderLabel($content, $label);
  10902. }
  10903. $label = $view->formLabel($element->getName(), $label);
  10904. return $this->renderLabel($content, $label);
  10905. }
  10906. public function renderLabel($content, $label)
  10907. {
  10908. $placement = $this->getPlacement();
  10909. $separator = $this->getSeparator();
  10910. switch ($placement) {
  10911. case 'APPEND':
  10912. return $content . $separator . $label;
  10913. case 'PREPEND':
  10914. default:
  10915. return $label . $separator . $content;
  10916. }
  10917. }
  10918. }
  10919. ]]>
  10920. </programlisting>
  10921. <para>
  10922. Ahora diremos al elemento que use esta ruta cuando busque por
  10923. decoradores:
  10924. </para>
  10925. <programlisting role="php"><![CDATA[
  10926. $element->addPrefixPath('My_Decorator', 'My/Decorator/', 'decorator');
  10927. ]]>
  10928. </programlisting>
  10929. <para>
  10930. Alternativamente, podemos hacerlo en el formulario para asegurar
  10931. que todos los decoradores usen esta ruta:
  10932. </para>
  10933. <programlisting role="php"><![CDATA[
  10934. $form->addElementPrefixPath('My_Decorator', 'My/Decorator/', 'decorator');
  10935. ]]>
  10936. </programlisting>
  10937. <para>
  10938. Con esta ruta añadida, cuando agregue un decorador, la ruta
  10939. 'My/Decorator' será consultada primero en búsqueda de la
  10940. existencia del decorador en este lugar. Como resultado,
  10941. 'My_Decorator_Label' ahora será utilizado cuando el decorador
  10942. 'Label' sea requerido.
  10943. </para>
  10944. </example>
  10945. </sect2>
  10946. <sect2 id="zend.form.elements.filters">
  10947. <title>Filters</title>
  10948. <para>
  10949. A menudo es útil y/o necesario realizar alguna normalización en la
  10950. entrada antes de la validación – por ejemplo, puede querer eliminar
  10951. todo el HTML, pero realizar las validaciones sobre lo restante para
  10952. asegurarse que el envío es válido. O puede eliminar los espacios en
  10953. blanco al inicio o fin de la entrada para asegurarse de que un validador
  10954. StringLenth (longitud de la cadena) no regrese un positivo falso. Estas
  10955. operaciones pueden realizarse usando <code>Zend_Filter</code>, y
  10956. <code>Zend_Form_Element</code> que soportan cadenas de filtros,
  10957. permitiéndole especificar múltiples filtros secuenciales a utilizar.
  10958. El filtrado sucede tanto en la validación como cuando recupera el
  10959. valor del elemento vía <code>getValue()</code>:
  10960. </para>
  10961. <programlisting role="php"><![CDATA[
  10962. $filtered = $element->getValue();
  10963. ]]>
  10964. </programlisting>
  10965. <para>
  10966. Los filtros pueden ser agregados a la pila de dos maneras:
  10967. </para>
  10968. <itemizedlist>
  10969. <listitem><para>
  10970. pasándolo en una instancia de filtro específica
  10971. </para></listitem>
  10972. <listitem><para>
  10973. proveyendo un nombre de filtro – el correspondiente nombre
  10974. corto o completo de la clase
  10975. </para></listitem>
  10976. </itemizedlist>
  10977. <para>
  10978. Veamos algunos ejemplos:
  10979. </para>
  10980. <programlisting role="php"><![CDATA[
  10981. // Instancia específica del filtro
  10982. $element->addFilter(new Zend_Filter_Alnum());
  10983. // El correspondiente nombre completo de la clase:
  10984. $element->addFilter('Zend_Filter_Alnum');
  10985. // Nombre corto del filtro:
  10986. $element->addFilter('Alnum');
  10987. $element->addFilter('alnum');
  10988. ]]>
  10989. </programlisting>
  10990. <para>
  10991. Los nombres cortos son típicamente el nombre del filtro sin el
  10992. prefijo. En el caso predeterminado, esto se refiere a sin el prefijo
  10993. 'Zend_Filter_'. Además, la primera letra no necesita estar en
  10994. mayúscula.
  10995. </para>
  10996. <note>
  10997. <title>Usando clases de filtros personalizados</title>
  10998. <para>
  10999. Si tiene su propio conjunto de clases de filtro, puede
  11000. informarle de ellas a <code>Zend_Form_Element</code> usando
  11001. <code>addPrefixPath()</code>. Por ejemplo, si tiene filtros
  11002. con el prefijo 'My_Filter', puede indicárselo a
  11003. <code>Zend_Form_Element</code> de la siguiente manera:
  11004. </para>
  11005. <programlisting role="php"><![CDATA[
  11006. $element->addPrefixPath('My_Filter', 'My/Filter/', 'filter');
  11007. ]]>
  11008. </programlisting>
  11009. <para>
  11010. (Recuerde que el tercer argumento indica el cargador de plugin
  11011. sobre el cual ha de ejecutarse la acción.)
  11012. </para>
  11013. </note>
  11014. <para>
  11015. Si en algún momento necesita un valor no filtrado, use el método
  11016. <code>getUnfilteredValue()</code>:
  11017. </para>
  11018. <programlisting role="php"><![CDATA[
  11019. $unfiltered = $element->getUnfilteredValue();
  11020. ]]>
  11021. </programlisting>
  11022. <para>
  11023. Para mayor información sobre filtros, vea la <link linkend="zend.filter.introduction">documentación de
  11024. Zend_Filter</link>.
  11025. </para>
  11026. <para>
  11027. Métodos asociados con filtros incluyen:
  11028. </para>
  11029. <itemizedlist>
  11030. <listitem><para>
  11031. <code>addFilter($nameOfFilter, array $options = null)</code>
  11032. </para></listitem>
  11033. <listitem><para>
  11034. <code>addFilters(array $filters)</code>
  11035. </para></listitem>
  11036. <listitem><para>
  11037. <code>setFilters(array $filters)</code> (sobreescribe todos los
  11038. filtros)
  11039. </para></listitem>
  11040. <listitem><para>
  11041. <code>getFilter($name)</code> (recupera un objeto filtro por su
  11042. nombre)
  11043. </para></listitem>
  11044. <listitem><para>
  11045. <code>getFilters()</code> (recupera todos los filtros)
  11046. </para></listitem>
  11047. <listitem><para>
  11048. <code>removeFilter($name)</code> (elimina un filtro por su
  11049. nombre)
  11050. </para></listitem>
  11051. <listitem><para>
  11052. <code>clearFilters()</code> (elimina todos los filtros)
  11053. </para></listitem>
  11054. </itemizedlist>
  11055. </sect2>
  11056. <sect2 id="zend.form.elements.validators">
  11057. <title>Validadores</title>
  11058. <para>
  11059. Si sigue el mantra de seguridad "filtrar la entrada, escapar la
  11060. salida" querrá validar ("filtrar la entrada") los datos de los
  11061. formularios. En <code>Zend_Form</code> cada elemento contiene su
  11062. propia cadena de validadores, consistente en validadores
  11063. <code>Zend_Validate_*</code>.
  11064. </para>
  11065. <para>
  11066. Los validadores pueden ser agregados de dos maneras:
  11067. </para>
  11068. <itemizedlist>
  11069. <listitem><para>
  11070. pasándolo en una instancia de validador específica
  11071. </para></listitem>
  11072. <listitem><para>
  11073. proveyendo un nombre de validador – el correspondiente nombre
  11074. corto o completo de clase
  11075. </para></listitem>
  11076. </itemizedlist>
  11077. <para>
  11078. Veamos algunos ejemplos:
  11079. </para>
  11080. <programlisting role="php"><![CDATA[
  11081. // Instancia específica del validador:
  11082. $element->addValidator(new Zend_Validate_Alnum());
  11083. // El correspondiente nombre completo de la clase:
  11084. $element->addValidator('Zend_Validate_Alnum');
  11085. // Nombre corto del validador:
  11086. $element->addValidator('Alnum');
  11087. $element->addValidator('alnum');
  11088. ]]>
  11089. </programlisting>
  11090. <para>
  11091. Los nombres cortos son típicamente el nombre del validador sin el
  11092. prefijo. En el caso predeterminado, esto se refiere a sin el prefijo
  11093. 'Zend_Validate_'. Además, la primera letra no necesita estar en
  11094. mayúscula.
  11095. </para>
  11096. <note>
  11097. <title>Usando clases de validación personalizadas</title>
  11098. <para>
  11099. Si tiene su propio conjunto de clases de validación, puede
  11100. informarle de ellas a <code>Zend_Form_Element</code> usando
  11101. <code>addPrefixPath()</code>. Por ejemplo, si tiene validadores
  11102. con el prefijo 'My_Validator', puede indicárselo a
  11103. <code>Zend_Form_Element</code> de la siguiente manera:
  11104. </para>
  11105. <programlisting role="php"><![CDATA[
  11106. $element->addPrefixPath('My_Validator', 'My/Validator/', 'validate');
  11107. ]]>
  11108. </programlisting>
  11109. <para>
  11110. (Recuerde que el tercer argumento indica el cargador de plugin
  11111. sobre el cual ha de ejecutarse la acción.)
  11112. </para>
  11113. </note>
  11114. <para>
  11115. Si el fallo de un validador debe evitar validaciones posteriores,
  11116. pase el boleano <code>true</code> como segundo parámetro:
  11117. </para>
  11118. <programlisting role="php"><![CDATA[
  11119. $element->addValidator('alnum', true);
  11120. ]]>
  11121. </programlisting>
  11122. <para>
  11123. Si está usando la cadena nombre para añadir el validador, y la clase
  11124. del validador acepta argumentos para su constructor, puede pasarlos
  11125. a el tercer parámetro de <code>addValidator()</code> como un
  11126. array:
  11127. </para>
  11128. <programlisting role="php"><![CDATA[
  11129. $element->addValidator('StringLength', false, array(6, 20));
  11130. ]]>
  11131. </programlisting>
  11132. <para>
  11133. Los argumentos pasados de esta manera deben estar en el orden en el
  11134. cual son definidos en el constructor. El ejemplo de arriba
  11135. instanciará la clase <code>Zend_Validate_StringLenth</code> con los
  11136. parámetros <code>$min</code> y <code>$max</code>:
  11137. </para>
  11138. <programlisting role="php"><![CDATA[
  11139. $validator = new Zend_Validate_StringLength(6, 20);
  11140. ]]>
  11141. </programlisting>
  11142. <note>
  11143. <title>Estipulando mensajes de error de validación personalizados</title>
  11144. <para>
  11145. Algunos desarrolladores querrán estipular mensajes de error
  11146. personalizados para un validador. El argumento
  11147. <code>$options</code> de
  11148. <code>Zend_Form_Element::addValidator()</code> le permite
  11149. hacerlo proporcionando la clave 'messages' y estableciendolos en
  11150. un array de pares clave/valor para especificar las plantillas
  11151. de mensaje. Necesitará conocer los códigos de error de los
  11152. diferentes tipos de error de un validador en particular.
  11153. </para>
  11154. <para>
  11155. Una opción mejor es usar <code>Zend_Translate_Adapter</code>
  11156. con su formulario. Los códigos de error son automáticamente
  11157. pasados al adaptador por el decorador Errors por defecto; puede
  11158. especificar su propias cadenas de mensaje de error mediante la
  11159. creación de traducciones para los varios códigos de error de
  11160. sus validadores.
  11161. </para>
  11162. </note>
  11163. <para>
  11164. Puede también establecer varios validadores a la vez, usando
  11165. <code>addValidators()</code>. Su uso básico es pasar una matriz de
  11166. arrays, donde cada array contenga de 1 a 3 valores,
  11167. correspondientes al constructor de <code>addValidator()</code>:
  11168. </para>
  11169. <programlisting role="php"><![CDATA[
  11170. $element->addValidators(array(
  11171. array('NotEmpty', true),
  11172. array('alnum'),
  11173. array('stringLength', false, array(6, 20)),
  11174. ));
  11175. ]]>
  11176. </programlisting>
  11177. <para>
  11178. Si quiere ser más detallado o explícito, puede utilizar las claves
  11179. 'validator', 'breakChainOnFailure', y 'options' en el array:
  11180. </para>
  11181. <programlisting role="php"><![CDATA[
  11182. $element->addValidators(array(
  11183. array(
  11184. 'validator' => 'NotEmpty',
  11185. 'breakChainOnFailure' => true),
  11186. array('validator' => 'alnum'),
  11187. array(
  11188. 'validator' => 'stringLength',
  11189. 'options' => array(6, 20)),
  11190. ));
  11191. ]]>
  11192. </programlisting>
  11193. <para>
  11194. Este uso es bueno para ilustrar cómo puede configurar validadores
  11195. en un archivo de configuración:
  11196. </para>
  11197. <programlisting role="ini"><![CDATA[
  11198. element.validators.notempty.validator = "NotEmpty"
  11199. element.validators.notempty.breakChainOnFailure = true
  11200. element.validators.alnum.validator = "Alnum"
  11201. element.validators.strlen.validator = "StringLength"
  11202. element.validators.strlen.options.min = 6
  11203. element.validators.strlen.options.max = 20
  11204. ]]>
  11205. </programlisting>
  11206. <para>
  11207. Note que cada elemento tiene una clave, la necesite o no; esta es
  11208. una limitación del uso de archivos de configuración -- pero también
  11209. ayuda a hacer más explicito el para qué son usados los argumentos.
  11210. Sólo recuerde que cualesquiera opciones del validador deben ser
  11211. especificadas en orden.
  11212. </para>
  11213. <para>
  11214. Para validar un elemento, pase el valor a
  11215. <code>isValid()</code>:
  11216. </para>
  11217. <programlisting role="php"><![CDATA[
  11218. if ($element->isValid($value)) {
  11219. // válido
  11220. } else {
  11221. // no válido
  11222. }
  11223. ]]>
  11224. </programlisting>
  11225. <note>
  11226. <title>Validación operando en valores filtrados</title>
  11227. <para>
  11228. <code>Zend_Form_Element::isValid()</code> siempre filtra los
  11229. valores antes de la validación a través de la cadena de filtros.
  11230. Vea <link linkend="zend.form.elements.filters">la sección de
  11231. filtros</link> para más información.
  11232. </para>
  11233. </note>
  11234. <note>
  11235. <title>Contexto de validación</title>
  11236. <para>
  11237. <code>Zend_Form_Element::isValid()</code> soporta un argumento
  11238. adicional, <code>$context</code>.
  11239. <code>Zend_Form::isValid()</code> pasa todo el conjunto de datos
  11240. procesados a <code>$context</code> cuando valida un formulario,
  11241. y <code>Zend_Form_Element::isValid()</code>, a su vez, lo pasa a
  11242. cada validador. Esto significa que puede escribir validadores
  11243. que son conscientes de los datos pasados a otros elementos del
  11244. formulario. Como ejemplo, considere un formulario de registro
  11245. estándar que tiene campos para la contraseña y la confirmación
  11246. de la contraseña; una validación sería que los dos campos
  11247. coincidan. Este validador puede tener un aspecto como el
  11248. siguiente:
  11249. </para>
  11250. <programlisting role="php"><![CDATA[
  11251. class My_Validate_PasswordConfirmation extends Zend_Validate_Abstract
  11252. {
  11253. const NOT_MATCH = 'notMatch';
  11254. protected $_messageTemplates = array(
  11255. self::NOT_MATCH => 'Password confirmation does not match'
  11256. );
  11257. public function isValid($value, $context = null)
  11258. {
  11259. $value = (string) $value;
  11260. $this->_setValue($value);
  11261. if (is_array($context)) {
  11262. if (isset($context['password_confirm'])
  11263. && ($value == $context['password_confirm']))
  11264. {
  11265. return true;
  11266. }
  11267. } elseif (is_string($context) && ($value == $context)) {
  11268. return true;
  11269. }
  11270. $this->_error(self::NOT_MATCH);
  11271. return false;
  11272. }
  11273. }
  11274. ]]>
  11275. </programlisting>
  11276. </note>
  11277. <para>
  11278. Los validadores son procesados en orden. Cada validador es
  11279. procesado, a menos que un validador creado con un valor true para
  11280. <code>breakChainOnFailure</code> falle su validación. Asegúrese de
  11281. especificar sus validadores en un orden razonable.
  11282. </para>
  11283. <para>
  11284. Después de una validación fallida, puede recuperar los códigos y
  11285. mensajes de error de la cadena del validador:
  11286. </para>
  11287. <programlisting role="php"><![CDATA[
  11288. $errors = $element->getErrors();
  11289. $messages = $element->getMessages();
  11290. ]]>
  11291. </programlisting>
  11292. <para>
  11293. (Nota: los mensajes de error retornados son un array asociativo de
  11294. pares código / mensaje de error.)
  11295. </para>
  11296. <para>
  11297. En adición a los validadores, puede especificar que un elemento es
  11298. necesario, usando <code>setRequired(true)</code>. Por defecto, esta
  11299. bandera es false, lo que significa que pasará su cadena de
  11300. validadores si ningún valor es pasado a <code>isValid()</code>.
  11301. Puede modificar este comportamiento en un número de maneras:
  11302. </para>
  11303. <itemizedlist>
  11304. <listitem>
  11305. <para>
  11306. Por defecto, cuando un elemento es requerido, una bandera,
  11307. 'allowEmpty', también es true. Esto quiere decir que si un
  11308. valor empty es evaluado pasándolo a <code>isValid()</code>,
  11309. los validadores serán saltados. Puede intercalar esta
  11310. bandera usando el método de acceso
  11311. <code>setAllowEmpty($flag)</code>; cuando la bandera es
  11312. false, si un valor es pasado, los validadores seguirán
  11313. ejecutándose.
  11314. </para>
  11315. </listitem>
  11316. <listitem>
  11317. <para>
  11318. Por defecto, si un elemento es requerido, pero no contiene
  11319. un validador 'NotEmpty', <code>isValid()</code> añadirá uno
  11320. en la cima de la pila, con la bandera
  11321. <code>breakChainOnFailure</code> establecido. Esto hace que
  11322. la bandera requerida tenga un significado semántico: si
  11323. ningún valor es pasado, inmediatamente invalidamos el envío
  11324. y se le notifica al usuario, e impedimos que otros
  11325. validadores se ejecuten en lo que ya sabemos son datos
  11326. inválidos.
  11327. </para>
  11328. <para>
  11329. Si no quiere este comportamiento, puede desactivarlo pasando
  11330. un valor false a
  11331. <code>setAutoInsertNotEmptyValidator($flag)</code>; esto
  11332. prevendrá a <code>isValid()</code> de colocar un validador
  11333. 'NotEmpty' en la cadena de validaciones.
  11334. </para>
  11335. </listitem>
  11336. </itemizedlist>
  11337. <para>
  11338. Para mayor información sobre validadores, vea la <link linkend="zend.validate.introduction">documentación de
  11339. Zend_Validate</link>.
  11340. </para>
  11341. <note>
  11342. <title>Usando Zend_Form_Elements como validador de propósito general</title>
  11343. <para>
  11344. <code>Zend_Form_Element</code> implementa
  11345. <code>Zend_Validate_Interface</code>, significando un elemento
  11346. puede también usarse como un validador en otro, cadenas de
  11347. validación no relacionadas al formulario.
  11348. </para>
  11349. </note>
  11350. <para>
  11351. Métodos asociados con validación incluyen:
  11352. </para>
  11353. <itemizedlist>
  11354. <listitem><para>
  11355. <code>setRequired($flag)</code> y
  11356. <code>isRequired()</code> permiten establecer y recuperar el
  11357. estado de la bandera 'required'. Cuando se le asigna un
  11358. booleano <code>true</code>, esta bandera requiere que el
  11359. elemento esté presente en la información procesada por
  11360. <code>Zend_Form</code>.
  11361. </para></listitem>
  11362. <listitem><para>
  11363. <code>setAllowEmpty($flag)</code> y
  11364. <code>getAllowEmpty()</code> permiten modificar el
  11365. comportamiento de elementos opcionales (p.e., elementos
  11366. donde la bandera required es false). Cuando la bandera
  11367. 'allow empty' es true, valores vacíos no pasarán la cadena
  11368. de validadores.
  11369. </para></listitem>
  11370. <listitem><para>
  11371. <code>setAutoInsertNotEmptyValidator($flag)</code> permite
  11372. especificar si realmente un validador 'NotEmpty' será
  11373. añadido el inicio de la cadena de validaciones cuando un
  11374. elemento es requerido. Por defecto, esta bandera es true.
  11375. </para></listitem>
  11376. <listitem><para>
  11377. <code>addValidator($nameOrValidator, $breakChainOnFailure = false, array $options = null)</code>
  11378. </para></listitem>
  11379. <listitem><para>
  11380. <code>addValidators(array $validators)</code>
  11381. </para></listitem>
  11382. <listitem><para>
  11383. <code>setValidators(array $validators)</code> (sobreescribe todos los validadores)
  11384. </para></listitem>
  11385. <listitem><para>
  11386. <code>getValidator($name)</code> (recupera un objeto validador por nombre)
  11387. </para></listitem>
  11388. <listitem><para>
  11389. <code>getValidators()</code> (recupera todos los validadores)
  11390. </para></listitem>
  11391. <listitem><para>
  11392. <code>removeValidator($name)</code> (elimina un validador por nombre)
  11393. </para></listitem>
  11394. <listitem><para>
  11395. <code>clearValidators()</code> (elimina todos los validadores)
  11396. </para></listitem>
  11397. </itemizedlist>
  11398. <sect3 id="zend.form.elements.validators.errors">
  11399. <title>Errores de mensaje personalizados</title>
  11400. <para>
  11401. Alguna veces, querrá especificar uno o más mensajes de error para
  11402. usarlos en lugar de los mensajes de error generados por los
  11403. validadores adjuntos a los elementos. Adicionalmente, algunas
  11404. veces usted mismo querrá marcar al elemento como inválido. A
  11405. partir de 1.6.0, esta funcionalidad es posible vía los
  11406. siguientes métodos.
  11407. </para>
  11408. <itemizedlist>
  11409. <listitem><para>
  11410. <code>addErrorMessage($message)</code>: añade un mensaje de
  11411. error para mostrarlos en forma de errores de validación. Puede
  11412. llamarlo más de una vez, y los nuevos mensajes nuevos son
  11413. añadidos a la pila.
  11414. </para></listitem>
  11415. <listitem><para>
  11416. <code>addErrorMessages(array $messages)</code>: añade
  11417. múltiples mensajes de error para mostrarlos en forma de errores de
  11418. validación.
  11419. </para></listitem>
  11420. <listitem><para>
  11421. <code>setErrorMessages(array $messages)</code>: añade
  11422. múltiples mensajes de error para mostrarlos en forma de errores de
  11423. validación, sobreescribiendo todos los mensajes de error
  11424. previamente establecidos.
  11425. </para></listitem>
  11426. <listitem><para>
  11427. <code>getErrorMessages()</code>: recupera la lista de
  11428. mensajes de error personalizados que fueron definidos.
  11429. </para></listitem>
  11430. <listitem><para>
  11431. <code>clearErrorMessages()</code>: remueve todos los
  11432. mensajes de error personalizados que hayan sido definidos.
  11433. </para></listitem>
  11434. <listitem><para>
  11435. <code>markAsError()</code>: marca al elemento como que falló
  11436. la validación.
  11437. </para></listitem>
  11438. <listitem><para>
  11439. <code>hasErrors()</code>: determina si el elemento ha
  11440. fallado la validación o ha sido marcado como inválido.
  11441. </para></listitem>
  11442. <listitem><para>
  11443. <code>addError($message)</code>: añade un mensaje a la pila
  11444. de mensaje de error personalizados y marca al elemento como
  11445. inválido.
  11446. </para></listitem>
  11447. <listitem><para>
  11448. <code>addErrors(array $messages)</code>: añade varios
  11449. mensajes a la pila de mensajes de error personalizados y
  11450. marca al elemento como inválido.
  11451. </para></listitem>
  11452. <listitem><para>
  11453. <code>setErrors(array $messages)</code>: sobreescribe el
  11454. mensaje de error personalizado en la pila con los mensajes
  11455. previstos y marca al elemento como inválido.
  11456. </para></listitem>
  11457. </itemizedlist>
  11458. <para>
  11459. Todos los errores establecidos de este modo pueden ser
  11460. traducidos. Adicionalmente, puede insertar el marcador "%value%"
  11461. para representar el valor del elemento; este valor actual del
  11462. elemento será sustituido cuando el mensaje de error sea
  11463. recuperado.
  11464. </para>
  11465. </sect3>
  11466. </sect2>
  11467. <sect2 id="zend.form.elements.decorators">
  11468. <title>Decoradores</title>
  11469. <para>
  11470. Una dolencia particular para muchos desarrolladores web es la creación
  11471. del XHTML para formularios por ellos mismos. Para cada elemento, el
  11472. desarrollador necesita crear la marcación para el elemento mismo,
  11473. comúnmente una etiqueta (label), y, si son amables con sus usuarios,
  11474. la marcación para mostrar mensajes de errores de validación. Cuanto
  11475. más elementos en una página, menos trivial se convierte esta tarea.
  11476. </para>
  11477. <para>
  11478. <code>Zend_Form_Element</code> intenta resolver este problema mediante
  11479. el uso de "decoradores". Los decoradores son clases simples que tienen
  11480. métodos de acceso al elemento y métodos para generar el contenido. Para
  11481. obtener mayor información sobre cómo trabajan los decoradores, consulte
  11482. por favor la sección sobre
  11483. <link linkend="zend.form.decorators">Zend_Form_Decorator</link>.
  11484. </para>
  11485. <para>
  11486. Los decoradores usados por defecto por
  11487. <code>Zend_Form_Element</code> son:
  11488. </para>
  11489. <itemizedlist>
  11490. <listitem><para>
  11491. <emphasis>ViewHelper</emphasis>: especifica un view helper que
  11492. usar para general el elemento. El atributo 'helper' del elemento
  11493. puede usarse para especificar qué auxiliar vista usar. Por
  11494. defecto, <code>Zend_Form_Element</code> especifica el auxiliar
  11495. vista 'formText', pero cada subclase especifica diferentes
  11496. auxiliares.
  11497. </para></listitem>
  11498. <listitem><para>
  11499. <emphasis>Errors</emphasis>: añade mensajes de error al elemento
  11500. usando <code>Zend_View_Helper_FormErrors</code>. Si no está
  11501. presente, no se añade nada.
  11502. </para></listitem>
  11503. <listitem><para>
  11504. <emphasis>Description</emphasis>: añade la descripción del
  11505. elemento. Si no está presente, no se añade nada. Por defecto, la
  11506. descripción es generada dentro de una etiqueta &lt;p&gt; con un
  11507. class 'description'.
  11508. </para></listitem>
  11509. <listitem><para>
  11510. <emphasis>HtmlTag</emphasis>: envuelve el elemento y los errores
  11511. en una etiqueta HTML &lt;dd&gt;.
  11512. </para></listitem>
  11513. <listitem><para>
  11514. <emphasis>Label</emphasis>: añade al comienzo una etiqueta al
  11515. elemento usando <code>Zend_View_Helper_FormLabel</code>, y
  11516. envolviéndola en una etiqueta &lt;dt&gt;. Si ninguna etiqueta es
  11517. provista, solo la etiqueta de la definición es generada.
  11518. </para></listitem>
  11519. </itemizedlist>
  11520. <note>
  11521. <title>Decoradores por defecto no necesitan ser cargados</title>
  11522. <para>
  11523. Por defecto, los decoradores por defecto son cargados durante la
  11524. inicialización del objeto. Puede deshabilitar esto pasando la
  11525. opción 'disableLoadDefaultDecorators' al constructor:
  11526. </para>
  11527. <programlisting role="php"><![CDATA[
  11528. $element = new Zend_Form_Element('foo',
  11529. array('disableLoadDefaultDecorators' =>
  11530. true)
  11531. );
  11532. ]]>
  11533. </programlisting>
  11534. <para>
  11535. Esta opción puede ser combinada junto con cualquier otra opción que
  11536. pase, ya sea como un array de opciones o en un objeto
  11537. <code>Zend_Config</code>.
  11538. </para>
  11539. </note>
  11540. <para>
  11541. Ya que el orden en el cual los decoradores son registrados importa
  11542. -- el primer decorador registrado es ejecutado primero -- necesitará
  11543. estar seguro de registrar sus decoradores en el orden apropiado, o
  11544. asegurarse de que estableció las opciones de colocación en el modo apropiado. Por
  11545. dar un ejemplo, aquí esta el código que registran los decoradores
  11546. por defecto:
  11547. </para>
  11548. <programlisting role="php"><![CDATA[
  11549. $this->addDecorators(array(
  11550. array('ViewHelper'),
  11551. array('Errors'),
  11552. array('Description', array('tag' => 'p', 'class' => 'description')),
  11553. array('HtmlTag', array('tag' => 'dd')),
  11554. array('Label', array('tag' => 'dt')),
  11555. ));
  11556. ]]>
  11557. </programlisting>
  11558. <para>
  11559. El contenido inicial es creado por el decorador 'ViewHelper', que
  11560. crea el propio elemento. En seguida, el decorador 'Errors' consulta
  11561. los mensajes de error del elemento, y, si hay alguno presente, los
  11562. pasa al auxiliar vista 'FormErrors' para mostrarlos. Si una
  11563. descripción está presente, el decorador 'Description' añadirá
  11564. un párrafo con class 'description' conteniendo el texto descriptivo
  11565. para el contenido agregado. El siguiente decorador, 'HtmlTag',
  11566. envuelve al elemento, los errores, y la descripción en una etiqueta
  11567. HTML &lt;dd&gt;. Finalmente, el último decorador, 'label', recupera
  11568. la etiqueta del elemento y la pasa al auxiliar vista 'FormLabel',
  11569. envolviéndolo en una etiqueta &lt;dt&gt;; por default el valor es
  11570. añadido al inicio del contenido. El resultado de la salida
  11571. básicamente se ve así:
  11572. </para>
  11573. <programlisting role="html"><![CDATA[
  11574. <dt><label for="foo" class="optional">Foo</label></dt>
  11575. <dd>
  11576. <input type="text" name="foo" id="foo" value="123" />
  11577. <ul class="errors">
  11578. <li>"123" is not an alphanumeric value</li>
  11579. </ul>
  11580. <p class="description">
  11581. This is some descriptive text regarding the element.
  11582. </p>
  11583. </dd>
  11584. ]]>
  11585. </programlisting>
  11586. <para>
  11587. Para más información sobre decoradores, lea la <link linkend="zend.form.decorators"> sección de Zend_Form_Decorator</link>.
  11588. </para>
  11589. <note>
  11590. <title>Usando múltiples decoradores al mismo tiempo</title>
  11591. <para>
  11592. Internamente, <code>Zend_Form_Element</code> utiliza una clase
  11593. decorador como mecanismo de búsqueda para la recuperación de
  11594. decoradores. Como resultado, no puede registrar múltiples
  11595. decoradores del mismo tipo; decoradores subsecuentes
  11596. simplemente sobreescribirán aquellos que ya existían.
  11597. </para>
  11598. <para>
  11599. Para evitar esto, puede usar <emphasis>alias</emphasis>. En
  11600. lugar de pasar un decorador o nombre de decorador como primer
  11601. argumento a <code>addDecorator()</code>, pase una matriz con un
  11602. solo elemento, con el alias apuntando al nombre o objeto
  11603. decorador:
  11604. </para>
  11605. <programlisting role="php"><![CDATA[
  11606. // Alias a 'FooBar':
  11607. $element->addDecorator(array('FooBar' => 'HtmlTag'),
  11608. array('tag' => 'div'));
  11609. // Y recuperandolo posteriormente:
  11610. $decorator = $element->getDecorator('FooBar');
  11611. ]]>
  11612. </programlisting>
  11613. <para>
  11614. En los métodos <code>addDecorators()</code> y
  11615. <code>setDecorators()</code>, necesitará pasar la opción
  11616. 'decorator' en la matriz representando el decorador:
  11617. </para>
  11618. <programlisting role="php"><![CDATA[
  11619. // Y dos decoradores 'HtmlTag', 'FooBar' como alias:
  11620. $element->addDecorators(
  11621. array('HtmlTag', array('tag' => 'div')),
  11622. array(
  11623. 'decorator' => array('FooBar' => 'HtmlTag'),
  11624. 'options' => array('tag' => 'dd')
  11625. ),
  11626. );
  11627. // Y recuperándolos posteriormente:
  11628. $htmlTag = $element->getDecorator('HtmlTag');
  11629. $fooBar = $element->getDecorator('FooBar');
  11630. ]]>
  11631. </programlisting>
  11632. </note>
  11633. <para>
  11634. Métodos asociados con decoradores incluyen:
  11635. </para>
  11636. <itemizedlist>
  11637. <listitem><para>
  11638. <code>addDecorator($nameOrDecorator, array $options = null)</code>
  11639. </para></listitem>
  11640. <listitem><para>
  11641. <code>addDecorators(array $decorators)</code>
  11642. </para></listitem>
  11643. <listitem><para>
  11644. <code>setDecorators(array $decorators)</code> (sobreescribe
  11645. todos los decoradores)
  11646. </para></listitem>
  11647. <listitem><para>
  11648. <code>getDecorator($name)</code> (recupera un objeto decorador
  11649. por su nombre)
  11650. </para></listitem>
  11651. <listitem><para>
  11652. <code>getDecorators()</code> (recupera todos los decoradores)
  11653. </para></listitem>
  11654. <listitem><para>
  11655. <code>removeDecorator($name)</code> (elimina un decorador por su
  11656. nombre)
  11657. </para></listitem>
  11658. <listitem><para>
  11659. <code>clearDecorators()</code> (elimina todos los decoradores)
  11660. </para></listitem>
  11661. </itemizedlist>
  11662. <para>
  11663. <code>Zend_Form_Element</code> también utiliza la sobrecarga para
  11664. permitir generar decoradores específicos. <code>__call()</code>
  11665. interceptará métodos que comiencen con el texto 'render' y utilizará
  11666. el resto del nombre del método para buscar un decorador; si se
  11667. encuentra, entonces será generado <emphasis>sólo ese</emphasis>
  11668. decorador. Cualquier argumento pasado al llamado del método será
  11669. usado como contenido para pasar al método <code>render()</code> del
  11670. decorador. Como ejemplo:
  11671. </para>
  11672. <programlisting role="php"><![CDATA[
  11673. // Genera solo el decorador ViewHelper:
  11674. echo $element->renderViewHelper();
  11675. // Genera solo el decorador HtmlTag, pasándole contenido:
  11676. echo $element->renderHtmlTag("This is the html tag content");
  11677. ]]></programlisting>
  11678. <para>
  11679. Si el decorador no existe, una excepción es lanzada.
  11680. </para>
  11681. </sect2>
  11682. <sect2 id="zend.form.elements.metadata">
  11683. <title>Metadatos y atributos</title>
  11684. <para>
  11685. <code>Zend_Form_Element</code> manipula una variedad de atributos y
  11686. medatados del elemento. Atributos básicos incluyen:
  11687. </para>
  11688. <itemizedlist>
  11689. <listitem><para>
  11690. <emphasis>name</emphasis>: el nombre del elemento. Emplea los
  11691. métodos de acceso <code>setName()</code> y <code>getName()</code>.
  11692. </para></listitem>
  11693. <listitem><para>
  11694. <emphasis>label</emphasis>: la etiqueta del elemento. Emplea los
  11695. métodos de acceso <code>setLabel()</code> y <code>getLabel()</code>.
  11696. </para></listitem>
  11697. <listitem><para>
  11698. <emphasis>order</emphasis>: el índice en el cual los elementos
  11699. deben ir mostrándose en el formulario. Emplea los métodos de
  11700. acceso <code>setOrder()</code> y <code>getOrder()</code>.
  11701. </para></listitem>
  11702. <listitem><para>
  11703. <emphasis>value</emphasis>: El valor del elemento actual. Emplea
  11704. los métodos de acceso <code>setValue()</code> y
  11705. <code>getValue()</code>.
  11706. </para></listitem>
  11707. <listitem><para>
  11708. <emphasis>description</emphasis>: una descripción del elemento;
  11709. a menudo utilizada para proveer un tooltip o ayuda contextual
  11710. con javascript describiendo el propósito del elemento. Emplea
  11711. los métodos de acceso <code>setDescription()</code> y
  11712. <code>getDescription()</code>.
  11713. </para></listitem>
  11714. <listitem><para>
  11715. <emphasis>required</emphasis>: bandera que indica si un elemento
  11716. es requerido o no cuando se efectúa la validación del
  11717. formulario. Emplea los métodos de acceso
  11718. <code>setRequired()</code> y <code>getRequired()</code>. Esta
  11719. bandera es false por defecto.
  11720. </para></listitem>
  11721. <listitem><para>
  11722. <emphasis>allowEmpty</emphasis>: bandera indicando si un
  11723. elemento no-requerido (opcional) debe intentar validar o no
  11724. valores vacíos. Cuando es true, y la bandera required es false,
  11725. valores vacíos no pasarán la cadena de validación, y se supone
  11726. verdadero. Emplea los métodos de acceso
  11727. <code>setAllowEmpty()</code> y <code>getAllowEmpty()</code>.
  11728. Esta bandera es true por defecto.
  11729. </para></listitem>
  11730. <listitem><para>
  11731. <emphasis>autoInsertNotEmptyValidator</emphasis>: bandera
  11732. indicando insertar o no un validador 'NotEmpty' cuando un
  11733. elemento es requerido. Por defecto, esta bandera es true.
  11734. Establezca la bandera con
  11735. <code>setAutoInsertNotEmptyValidator($flag)</code> y determine
  11736. el valor con <code>autoInsertNotEmptyValidator()</code>.
  11737. </para></listitem>
  11738. </itemizedlist>
  11739. <para>
  11740. Los elementos del formulario pueden requerir metainformación
  11741. adicional. Para elementos XHTML del formuladio, por ejemplo, puede
  11742. querer especificar atributos como el class o id. Para facilitar esto
  11743. hay un conjunto de métodos de acceso:
  11744. </para>
  11745. <itemizedlist>
  11746. <listitem><para>
  11747. <emphasis>setAttrib($name, $value)</emphasis>: añade un atributo
  11748. </para></listitem>
  11749. <listitem><para>
  11750. <emphasis>setAttribs(array $attribs)</emphasis>: como
  11751. addAttribs(), pero sobreescribiendo
  11752. </para></listitem>
  11753. <listitem><para>
  11754. <emphasis>getAttrib($name)</emphasis>: recupera el valor de solo
  11755. un atributo
  11756. </para></listitem>
  11757. <listitem><para>
  11758. <emphasis>getAttribs()</emphasis>: recupera todos los atributos
  11759. como pares clave/valor
  11760. </para></listitem>
  11761. </itemizedlist>
  11762. <para>
  11763. La mayoría de las veces, como sea, puede simplemente acceder a ellos
  11764. como propiedades de objeto, ya que <code>Zend_Form_Element</code>
  11765. utiliza la sobrecarga para facilitar el acceso a ellos:
  11766. </para>
  11767. <programlisting role="php"><![CDATA[
  11768. // Equivalente a $element->setAttrib('class', 'text'):
  11769. $element->class = 'text;
  11770. ]]>
  11771. </programlisting>
  11772. <para>
  11773. Por defecto, todos los atributos son pasados al auxiliar vista usado
  11774. por el elemento durante la generación, y generados como atributos de
  11775. la etiqueta del elemento.
  11776. </para>
  11777. </sect2>
  11778. <sect2 id="zend.form.elements.standard">
  11779. <title>Elementos Estándar</title>
  11780. <para>
  11781. <code>Zend_Form</code> contiene un buen número de elementos
  11782. estándar; por favor lea el capítulo <link linkend="zend.form.standarElements">Elementos Estándar</link> para
  11783. todos los detalles.
  11784. </para>
  11785. </sect2>
  11786. <sect2 id="zend.form.elements.methods">
  11787. <title>Métodos de Zend_Form_Element</title>
  11788. <para>
  11789. <code>Zend_Form_Element</code> tiene muchos, muchos métodos. Lo que
  11790. sigue es un sumario de sus funciones, agrupados por tipo:
  11791. </para>
  11792. <itemizedlist>
  11793. <listitem><para>Configuración:</para>
  11794. <itemizedlist>
  11795. <listitem><para><code>setOptions(array $options)</code></para></listitem>
  11796. <listitem><para><code>setConfig(Zend_Config $config)</code></para></listitem>
  11797. </itemizedlist>
  11798. </listitem>
  11799. <listitem><para>I18n:</para>
  11800. <itemizedlist>
  11801. <listitem><para><code>setTranslator(Zend_Translate_Adapter $translator = null)</code></para></listitem>
  11802. <listitem><para><code>getTranslator()</code></para></listitem>
  11803. <listitem><para><code>setDisableTranslator($flag)</code></para></listitem>
  11804. <listitem><para><code>translatorIsDisabled()</code></para></listitem>
  11805. </itemizedlist>
  11806. </listitem>
  11807. <listitem><para>Propiedades:</para>
  11808. <itemizedlist>
  11809. <listitem><para><code>setName($name)</code></para></listitem>
  11810. <listitem><para><code>getName()</code></para></listitem>
  11811. <listitem><para><code>setValue($value)</code></para></listitem>
  11812. <listitem><para><code>getValue()</code></para></listitem>
  11813. <listitem><para><code>getUnfilteredValue()</code></para></listitem>
  11814. <listitem><para><code>setLabel($label)</code></para></listitem>
  11815. <listitem><para><code>getLabel()</code></para></listitem>
  11816. <listitem><para><code>setDescription($description)</code></para></listitem>
  11817. <listitem><para><code>getDescription()</code></para></listitem>
  11818. <listitem><para><code>setOrder($order)</code></para></listitem>
  11819. <listitem><para><code>getOrder()</code></para></listitem>
  11820. <listitem><para><code>setRequired($flag)</code></para></listitem>
  11821. <listitem><para><code>getRequired()</code></para></listitem>
  11822. <listitem><para><code>setAllowEmpty($flag)</code></para></listitem>
  11823. <listitem><para><code>getAllowEmpty()</code></para></listitem>
  11824. <listitem><para><code>setAutoInsertNotEmptyValidator($flag)</code></para></listitem>
  11825. <listitem><para><code>autoInsertNotEmptyValidator()</code></para></listitem>
  11826. <listitem><para><code>setIgnore($flag)</code></para></listitem>
  11827. <listitem><para><code>getIgnore()</code></para></listitem>
  11828. <listitem><para><code>getType()</code></para></listitem>
  11829. <listitem><para><code>setAttrib($name, $value)</code></para></listitem>
  11830. <listitem><para><code>setAttribs(array $attribs)</code></para></listitem>
  11831. <listitem><para><code>getAttrib($name)</code></para></listitem>
  11832. <listitem><para><code>getAttribs()</code></para></listitem>
  11833. </itemizedlist>
  11834. </listitem>
  11835. <listitem><para>Cargadores y rutas de plugin:</para>
  11836. <itemizedlist>
  11837. <listitem><para><code>setPluginLoader(Zend_Loader_PluginLoader_Interface $loader, $type)</code></para></listitem>
  11838. <listitem><para><code>getPluginLoader($type)</code></para></listitem>
  11839. <listitem><para><code>addPrefixPath($prefix, $path, $type = null)</code></para></listitem>
  11840. <listitem><para><code>addPrefixPaths(array $spec)</code></para></listitem>
  11841. </itemizedlist>
  11842. </listitem>
  11843. <listitem><para>Validación:</para>
  11844. <itemizedlist>
  11845. <listitem><para><code>addValidator($validator, $breakChainOnFailure = false, $options = array())</code></para></listitem>
  11846. <listitem><para><code>addValidators(array $validators)</code></para></listitem>
  11847. <listitem><para><code>setValidators(array $validators)</code></para></listitem>
  11848. <listitem><para><code>getValidator($name)</code></para></listitem>
  11849. <listitem><para><code>getValidators()</code></para></listitem>
  11850. <listitem><para><code>removeValidator($name)</code></para></listitem>
  11851. <listitem><para><code>clearValidators()</code></para></listitem>
  11852. <listitem><para><code>isValid($value, $context = null)</code></para></listitem>
  11853. <listitem><para><code>getErrors()</code></para></listitem>
  11854. <listitem><para><code>getMessages()</code></para></listitem>
  11855. </itemizedlist>
  11856. </listitem>
  11857. <listitem><para>Filtros:</para>
  11858. <itemizedlist>
  11859. <listitem><para><code>addFilter($filter, $options = array())</code></para></listitem>
  11860. <listitem><para><code>addFilters(array $filters)</code></para></listitem>
  11861. <listitem><para><code>setFilters(array $filters)</code></para></listitem>
  11862. <listitem><para><code>getFilter($name)</code></para></listitem>
  11863. <listitem><para><code>getFilters()</code></para></listitem>
  11864. <listitem><para><code>removeFilter($name)</code></para></listitem>
  11865. <listitem><para><code>clearFilters()</code></para></listitem>
  11866. </itemizedlist>
  11867. </listitem>
  11868. <listitem><para>Generación:</para>
  11869. <itemizedlist>
  11870. <listitem><para><code>setView(Zend_View_Interface $view = null)</code></para></listitem>
  11871. <listitem><para><code>getView()</code></para></listitem>
  11872. <listitem><para><code>addDecorator($decorator, $options = null)</code></para></listitem>
  11873. <listitem><para><code>addDecorators(array $decorators)</code></para></listitem>
  11874. <listitem><para><code>setDecorators(array $decorators)</code></para></listitem>
  11875. <listitem><para><code>getDecorator($name)</code></para></listitem>
  11876. <listitem><para><code>getDecorators()</code></para></listitem>
  11877. <listitem><para><code>removeDecorator($name)</code></para></listitem>
  11878. <listitem><para><code>clearDecorators()</code></para></listitem>
  11879. <listitem><para><code>render(Zend_View_Interface $view = null)</code></para></listitem>
  11880. </itemizedlist>
  11881. </listitem>
  11882. </itemizedlist>
  11883. </sect2>
  11884. <sect2 id="zend.form.elements.config">
  11885. <title>Configuración</title>
  11886. <para>
  11887. El constructor de <code>Zend_Form_Element</code> acepta tanto una
  11888. matriz de opciones como un objeto <code>Zend_Config</code>
  11889. conteniendo opciones, y esto puede configurarse usando
  11890. <code>setOptions()</code> o <code>setConfig()</code>. Hablando de
  11891. manera general, las claves son nombradas de la siguiente manera:
  11892. </para>
  11893. <itemizedlist>
  11894. <listitem><para>
  11895. Si 'set' + clave se refiere a un método de
  11896. <code>Zend_Form_Element</code>, entonces el valor provisto será
  11897. pasado a el método.
  11898. </para></listitem>
  11899. <listitem><para>
  11900. De otra manera, el valor será usado para establecer un atributo.
  11901. </para></listitem>
  11902. </itemizedlist>
  11903. <para>
  11904. Excepciones a la regla incluyen las siguientes:
  11905. </para>
  11906. <itemizedlist>
  11907. <listitem><para>
  11908. <code>prefixPath</code> será pasado a
  11909. <code>addPrefixPaths()</code>
  11910. </para></listitem>
  11911. <listitem>
  11912. <para>
  11913. Los siguientes setters no pueden establecerse de esta manera:
  11914. </para>
  11915. <itemizedlist>
  11916. <listitem><para>
  11917. <code>setAttrib</code> (aunque
  11918. <code>setAttribs</code> <emphasis>funcionará</emphasis>
  11919. </para></listitem>
  11920. <listitem><para><code>setConfig</code></para></listitem>
  11921. <listitem><para><code>setOptions</code></para></listitem>
  11922. <listitem><para><code>setPluginLoader</code></para></listitem>
  11923. <listitem><para><code>setTranslator</code></para></listitem>
  11924. <listitem><para><code>setView</code></para></listitem>
  11925. </itemizedlist>
  11926. </listitem>
  11927. </itemizedlist>
  11928. <para>
  11929. Como ejemplo, aquí esta un archivo de configuración pasado para
  11930. cada tipo de dato configurable:
  11931. </para>
  11932. <programlisting role="ini"><![CDATA[
  11933. [element]
  11934. name = "foo"
  11935. value = "foobar"
  11936. label = "Foo:"
  11937. order = 10
  11938. required = true
  11939. allowEmpty = false
  11940. autoInsertNotEmptyValidator = true
  11941. description = "Foo elements are for examples"
  11942. ignore = false
  11943. attribs.id = "foo"
  11944. attribs.class = "element"
  11945. ; sets 'onclick' attribute
  11946. onclick = "autoComplete(this, '/form/autocomplete/element')"
  11947. prefixPaths.decorator.prefix = "My_Decorator"
  11948. prefixPaths.decorator.path = "My/Decorator/"
  11949. disableTranslator = 0
  11950. validators.required.validator = "NotEmpty"
  11951. validators.required.breakChainOnFailure = true
  11952. validators.alpha.validator = "alpha"
  11953. validators.regex.validator = "regex"
  11954. validators.regex.options.pattern = "/^[A-F].*/$"
  11955. filters.ucase.filter = "StringToUpper"
  11956. decorators.element.decorator = "ViewHelper"
  11957. decorators.element.options.helper = "FormText"
  11958. decorators.label.decorator = "Label"
  11959. ]]>
  11960. </programlisting>
  11961. </sect2>
  11962. <sect2 id="zend.form.elements.custom">
  11963. <title>Elementos personalizados</title>
  11964. <para>
  11965. Usted puede crear sus propios elementos personalizados simplemente
  11966. extendiendo la clase <code>Zend_Form_Element</code>. Las razones
  11967. comunes para hacer esto incluyen:
  11968. </para>
  11969. <itemizedlist>
  11970. <listitem><para>
  11971. Elementos que comparten validadores y/o filtros comunes
  11972. </para></listitem>
  11973. <listitem><para>
  11974. Elementos que tienen decoradores con funcionalidad personalizada
  11975. </para></listitem>
  11976. </itemizedlist>
  11977. <para>
  11978. Hay dos métodos típicamente usados para extender un elemento:
  11979. <code>init()</code>, el cual puede usarse para añadir una lógica de
  11980. inicialización personalizada a su elemento, y
  11981. <code>loadDefaultDecorators()</code>, el cual puede usarse para
  11982. establecer una lista de decoradores usados por su elemento de manera
  11983. predeterminada.
  11984. </para>
  11985. <para>
  11986. Como un ejemplo, digamos que todos los elementos de tipo texto en un
  11987. formulario que está creando, necesitan ser filtrados con
  11988. <code>StringTrim</code>, validados con una expresión regular, y que
  11989. quiere usar un decorador personalizado que ha creado para
  11990. mostrarlos, 'My_Decorator_TextItem'; adicionalmente, tiene un número
  11991. de atributos estándars, incluyendo 'size', 'maxLength', y 'class'
  11992. que quisiera especificar. Puede definir un elemento tal como sigue:
  11993. </para>
  11994. <programlisting role="php"><![CDATA[
  11995. class My_Element_Text extends Zend_Form_Element
  11996. {
  11997. public function init()
  11998. {
  11999. $this->addPrefixPath('My_Decorator', 'My/Decorator/', 'decorator')
  12000. ->addFilters('StringTrim')
  12001. ->addValidator('Regex', false, array('/^[a-z0-9]{6,}$/i'))
  12002. ->addDecorator('TextItem')
  12003. ->setAttrib('size', 30)
  12004. ->setAttrib('maxLength', 45)
  12005. ->setAttrib('class', 'text');
  12006. }
  12007. }
  12008. ]]>
  12009. </programlisting>
  12010. <para>
  12011. Entonces puede informar a su objeto formulario acerca del prefijo de
  12012. ruta para elementos de ese tipo, y comenzar creando elementos:
  12013. </para>
  12014. <programlisting role="php"><![CDATA[
  12015. $form->addPrefixPath('My_Element', 'My/Element/', 'element')
  12016. ->addElement('foo', 'text');
  12017. ]]>
  12018. </programlisting>
  12019. <para>
  12020. El elemento 'foo' será ahora del tipo <code>My_Element_Text</code>,
  12021. y mostrará el comportamiento que ha especificado.
  12022. </para>
  12023. <para>
  12024. Otro método que puede querer sobreescribir cuando extienda
  12025. <code>Zend_Form_Element</code> es el método
  12026. <code>loadDefaultDecorators()</code>. Este método carga
  12027. condicionalmente un grupo de decoradores predefinidos para su
  12028. elemento; puede querer sustituir su propio decorador en su clase
  12029. extendida:
  12030. </para>
  12031. <programlisting role="php"><![CDATA[
  12032. class My_Element_Text extends Zend_Form_Element
  12033. {
  12034. public function loadDefaultDecorators()
  12035. {
  12036. $this->addDecorator('ViewHelper')
  12037. ->addDecorator('DisplayError')
  12038. ->addDecorator('Label')
  12039. ->addDecorator('HtmlTag',
  12040. array('tag' => 'div', 'class' => 'element'));
  12041. }
  12042. }
  12043. ]]>
  12044. </programlisting>
  12045. <para>
  12046. Hay muchas maneras de personalizar elementos; asegúrese de leer la
  12047. documentación de la API de <code>Zend_Form_Element</code> para
  12048. conocer todos los métodos disponibles.
  12049. </para>
  12050. </sect2>
  12051. </sect1><!--
  12052. vim:se ts=4 sw=4 tw=80 ai et:
  12053. -->
  12054. <sect1 id="zend.form.forms" xml:base="module_specs/Zend_Form-Forms.xml">
  12055. <title>Creando formularios usando Zend_Form</title>
  12056. <para>
  12057. La clase <code>Zend_Form</code> es usada para agregar elementos de
  12058. formulario, desplegar grupos y subformularios. Éstos pueden ejecutar las
  12059. siguientes acciones en estos elementos:
  12060. </para>
  12061. <itemizedlist>
  12062. <listitem><para>
  12063. Validación, incluyendo la recuperación de código y mensajes de error
  12064. </para></listitem>
  12065. <listitem><para>
  12066. Agregación de valor, incluyendo el llenado de elementos y recuperación
  12067. de valores tanto filtrados como no filtrados para todos los elementos
  12068. </para></listitem>
  12069. <listitem><para>
  12070. Iteración sobre todos los elementos, en el orden en el cual han sido
  12071. introducidos o basados en el orden recuperado de cada elemento
  12072. </para></listitem>
  12073. <listitem><para>
  12074. Generando el formulario entero, ya sea por un simple decorador que
  12075. ejecuta un muestreo personalizado o por iteración sobre cada
  12076. elemento del formulario
  12077. </para></listitem>
  12078. </itemizedlist>
  12079. <para>
  12080. Mientras los formularios creados con <code>Zend_Form</code> pueden ser
  12081. complejos, probablemente su mejor uso es para formularios simples; es
  12082. mejor utilizarlo para desarrollar aplicaciones rápidas y de prototipado.
  12083. </para>
  12084. <para>
  12085. En lo más básico, simplemente instancie el objeto formulario:
  12086. </para>
  12087. <programlisting role="php"><![CDATA[
  12088. // Objeto form genérico:
  12089. $form = new Zend_Form();
  12090. // Objeto form personalizado:
  12091. $form = new My_Form()
  12092. ]]>
  12093. </programlisting>
  12094. <para>
  12095. Opcionalmente puede pasarlo en la configuración, la cual será usada para
  12096. establecer el estado del objeto, potencialmente así como también crear
  12097. nuevos elementos:
  12098. </para>
  12099. <programlisting role="php"><![CDATA[
  12100. // Pasando opciones en la configuración:
  12101. $form = new Zend_Form($config);
  12102. ]]>
  12103. </programlisting>
  12104. <para>
  12105. <code>Zend_Form</code> es iterable, e iterará sobre elementos, grupos que
  12106. mostrar y subformularios, usando el orden en el cual han sido registrados
  12107. y en cualquier índice de orden que cada uno pueda tener. Esto es útil
  12108. en casos donde desee generar los elementos manualmente en el orden apropiado.
  12109. </para>
  12110. <para>
  12111. La magia de <code>Zend_Form</code> radica en la habilidad para servir como
  12112. fábrica para elementos y grupos, así como también la habilidad de generarse
  12113. a sí mismo a través de decoradores.
  12114. </para>
  12115. <sect2 id="zend.form.forms.plugins">
  12116. <title>Cargadores de Plugin</title>
  12117. <para>
  12118. <code>Zend_Form</code> hace uso de
  12119. <code>Zend_Loader_PluginLoader</code> para permitir a los
  12120. desarroladores especificar la ubicación de elementos y decoradores
  12121. alternativos. Cada uno tiene su propio plugin loader asociado, y
  12122. métodos de acceso genéricos son usados para recuperar y modificar
  12123. cada uno.
  12124. </para>
  12125. <para>
  12126. Los siguientes tipos de cargadores son usados con los variados métodos
  12127. del plugin loader: 'element' y 'decorator'. Los nombres de los tipos
  12128. no distinguen mayúsculas de minúsculas.
  12129. </para>
  12130. <para>
  12131. Los métodos usados para interactuar con plugin loaders son los siguientes:
  12132. </para>
  12133. <itemizedlist>
  12134. <listitem><para>
  12135. <code>setPluginLoader($loader, $type)</code>: $loader es el propio
  12136. objeto plugin loader, mientras $type es uno de los tipos
  12137. especificados arriba. Esto establece el plugin loader para el
  12138. tipo dado al objeto loader recién especificado.
  12139. </para></listitem>
  12140. <listitem><para>
  12141. <code>getPluginLoader($type)</code>: recupera el plugin loader
  12142. asociado con $type.
  12143. </para></listitem>
  12144. <listitem><para>
  12145. <code>addPrefixPath($prefix, $path, $type = null)</code>: agrega
  12146. una asociación prefijo/ruta al loader especificado por $type. Si
  12147. $type es nulo, intentará añadir una ruta a todos los loaders,
  12148. añadiendo el prefijo "_Element" y "_Decorator"; y añadiendo la
  12149. ruta con "Element/" y "Decorator/". Si tiene todas sus clases
  12150. form element extras bajo una jerarquía común, éste es un método
  12151. coveniente para establecer el prefijo de base para ellas.
  12152. </para></listitem>
  12153. <listitem><para>
  12154. <code>addPrefixPaths(array $spec)</code>: le permite añadir varias
  12155. rutas en uno o mas plugin loaders. Se espera que cada elemento
  12156. del array sea un array con las claves 'path', 'prefix' y 'type'.
  12157. </para></listitem>
  12158. </itemizedlist>
  12159. <para>
  12160. Adicionalmente, puede especificar prefijos de rutas para todos los
  12161. elementos y mostrar grupos creados a través de una instancia de
  12162. <code>Zend_Form</code> usando los siguientes métodos:
  12163. </para>
  12164. <itemizedlist>
  12165. <listitem><para>
  12166. <code>addElementPrefixPath($prefix, $path, $type = null)</code>:
  12167. Igual que <code>addPrefixPath()</code>, debe especificar un
  12168. prefijo y ruta de clase. <code>$type</code>, cuando se especifica,
  12169. tiene que ser uno de los tipos plugin loader especificados por
  12170. <code>Zend_Form_Element</code>; vea la <link linkend="zend.form.elements.loaders">sección elemento plugins
  12171. </link> para más información de valores válidos para
  12172. <code>$type</code>. Si <code>$type</code> no es especificado, el
  12173. método asumirá que es un prefijo general para todos los tipos.
  12174. </para></listitem>
  12175. <listitem><para>
  12176. <code>addDisplayGroupPrefixPath($prefix, $path)</code>:
  12177. Igual que <code>addPrefixPath()</code>, debe especificar un
  12178. prefijo y ruta de clase; sin embargo, dado que los grupos de visualización (display groups)
  12179. sólo soportan decoradores como plugins, <code>$type</code> no es
  12180. necesario.
  12181. </para></listitem>
  12182. </itemizedlist>
  12183. <para>
  12184. Elementos y decoradores personalizados son una manera fácil de compartir
  12185. funcionalidad entre formularios y encapsular funcionalidad personalizada.
  12186. Vea el <link linkend="zend.form.elements.loaders.customLabel">ejemplo de Etiqueta
  12187. Personalizada</link> en la documentación de elementos para un
  12188. ejemplo de cómo elementos personalizados pueden ser usados como
  12189. reemplazos para clases estándar.
  12190. </para>
  12191. </sect2>
  12192. <sect2 id="zend.form.forms.elements">
  12193. <title>Elementos</title>
  12194. <para>
  12195. <code>Zend_Form</code> proporciona varios métodos de acceso para añadir
  12196. y eliminar elementos de el formulario. Éstos pueden tomar instancias
  12197. de objetos de elemento o servir como fábricas para instanciar el
  12198. objeto elemento a sí mismo.
  12199. </para>
  12200. <para>
  12201. El método más básico para añadir un elemento es
  12202. <code>addElement()</code>. Este método puede tomar también un objeto
  12203. de tipo <code>Zend_Form_Element</code> (o de una clase extendiendo
  12204. <code>Zend_Form_Element</code>), o argumentos para construir un nuevo
  12205. elemento -- incluyendo el elemento tipo, nombre y algunas opciones de
  12206. configuración.
  12207. </para>
  12208. <para>
  12209. Como algunos ejemplos:
  12210. </para>
  12211. <programlisting role="php"><![CDATA[
  12212. // Usando un elemento instanciado:
  12213. $element = new Zend_Form_Element_Text('foo');
  12214. $form->addElement($element);
  12215. // Usando una fábrica
  12216. //
  12217. // Crea un elemento de tipo Zend_Form_Element_Text con el
  12218. // nombre de 'foo':
  12219. $form->addElement('text', 'foo');
  12220. // Pasa una opción etiqueta al elemento:
  12221. $form->addElement('text', 'foo', array('label' => 'Foo:'));
  12222. ]]>
  12223. </programlisting>
  12224. <note>
  12225. <title>addElement() Implementa una Interfaz Fluida</title>
  12226. <para>
  12227. <code>addElement()</code> implementa una interfaz fluida; es
  12228. decir, retorna el objeto <code>Zend_Form</code> y no un
  12229. elemento. Esto se ha hecho para permitirle encadenar
  12230. multiples métodos addElement() u otros métodos formulario que
  12231. implementen una interfaz fluida (todos los establecedores en Zend_Form
  12232. implementan el patrón).
  12233. </para>
  12234. <para>
  12235. Si desea retornar el elemento, use
  12236. <code>createElement()</code>, el cual es esbozado abajo. Tenga en cuenta
  12237. de cualquier manera que <code>createElement()</code> no adjunta el
  12238. elemento al formulario.
  12239. </para>
  12240. <para>
  12241. Internamente, <code>addElement()</code> en realidad emplea
  12242. <code>createElement()</code> para crear el elemento antes de
  12243. adjuntarlo al formulario.
  12244. </para>
  12245. </note>
  12246. <para>
  12247. Una vez que el elemento ha sido añadido al formulario, puede recuperarlo por
  12248. el nombre. Puede también finalizar usando el método <code>getElement()</code>
  12249. o usando sobrecarga para acceder al elemento como una propiedad de
  12250. objeto:
  12251. </para>
  12252. <programlisting role="php"><![CDATA[
  12253. // getElement():
  12254. $foo = $form->getElement('foo');
  12255. // Como propiedad del objeto:
  12256. $foo = $form->foo;
  12257. ]]>
  12258. </programlisting>
  12259. <para>
  12260. Ocasionalmente, se quiere crear un elemento sin adjuntarlo
  12261. al formulario (para instanciar, si se desea hacer uso de las
  12262. rutas de plugin introducidas con el formulario, pero después se desea adjuntar el
  12263. objeto al subformulario). El método <code>createElement()</code>
  12264. permite hacer eso:
  12265. </para>
  12266. <programlisting role="php"><![CDATA[
  12267. // $username llega a ser un objeto Zend_Form_Element_Text:
  12268. $username = $form->createElement('text', 'username');
  12269. ]]>
  12270. </programlisting>
  12271. <sect3 id="zend.form.forms.elements.values">
  12272. <title>Llenar y recuperar valores</title>
  12273. <para>
  12274. Después de validar el formulario, originalmente se necesitará recuperar los
  12275. valores para poder ejecutar otras operaciones, tal como actualizar una
  12276. base de datos o notificar un servicio web. Se pueden recuperar todos los valores
  12277. para todos los elementos usando <code>getValues()</code>;
  12278. <code>getValue($name)</code> le permite recuperar un solo
  12279. valor del elemento por su nombre:
  12280. </para>
  12281. <programlisting role="php"><![CDATA[
  12282. // Obtener todos los valores:
  12283. $values = $form->getValues();
  12284. // Obtener sólo los valores del elemento 'foo':
  12285. $value = $form->getValue('foo');
  12286. ]]>
  12287. </programlisting>
  12288. <para>
  12289. A veces se quiere llenar el formulario con valores especificos
  12290. antes de generarlos. Éstos pueden ser llevados a cabo ya sea con los
  12291. métodos <code>setDefaults()</code> o <code>populate()</code>:
  12292. </para>
  12293. <programlisting role="php"><![CDATA[
  12294. $form->setDefaults($data);
  12295. $form->populate($data);
  12296. ]]>
  12297. </programlisting>
  12298. <para>
  12299. Por otro lado, si se quisera limpiar el formulario antes de llenarlo
  12300. o validarlo; se puede realizar usando el
  12301. método <code>reset()</code>:
  12302. </para>
  12303. <programlisting role="php"><![CDATA[
  12304. $form->reset();
  12305. ]]>
  12306. </programlisting>
  12307. </sect3>
  12308. <sect3 id="zend.form.forms.elements.global">
  12309. <title>Operaciones Globales</title>
  12310. <para>
  12311. Ocasionalemnte se necesitarán ciertas operaciones que afecten a todos
  12312. los elementos. Escenarios comunes incluyen la necesidad de determinar rutas de acceso
  12313. al prefijo complemento para todos los elementos, determinando decoradores para todos los elementos y
  12314. determinando filtros para todos los elementos. Como ejemplos:
  12315. </para>
  12316. <example id="zend.form.forms.elements.global.allpaths">
  12317. <title>Determinando rutas de acceso de prefijos para todos los elementos</title>
  12318. <para>
  12319. Se puede determinar rutas de acceso para prefijos para todos los elementos por tipo,
  12320. o usando un prefijo global. Como ejemplos:
  12321. </para>
  12322. <programlisting role="php"><![CDATA[
  12323. // Determinar la ruta de acceso de prefijos global
  12324. // Crear rutas de acceso para los prefijos My_Foo_Filter, My_Foo_Validate,
  12325. // y My_Foo_Decorator
  12326. $form->addElementPrefixPath('My_Foo', 'My/Foo/');
  12327. // Sólo rutas de acceso de filtros:
  12328. $form->addElementPrefixPath('My_Foo_Filter',
  12329. 'My/Foo/Filter',
  12330. 'filter');
  12331. // Sólo rutas de acceso de validadores:
  12332. $form->addElementPrefixPath('My_Foo_Validate',
  12333. 'My/Foo/Validate',
  12334. 'validate');
  12335. // Sólo rutas de acceso de decoradores:
  12336. $form->addElementPrefixPath('My_Foo_Decorator',
  12337. 'My/Foo/Decorator',
  12338. 'decorator');
  12339. ]]>
  12340. </programlisting>
  12341. </example>
  12342. <example id="zend.form.forms.elements.global.decorators">
  12343. <title>Determinando Decoradores para todos los elementos</title>
  12344. <para>
  12345. Se pueden determinar decoradores para todos los elementos.
  12346. <code>setElementDecorators()</code> acepta una matriz de
  12347. decoradores, solo como <code>setDecorators()</code>, y
  12348. reescribirá cualquier decorador previamente determinado en cada elemento. En
  12349. este ejemplo, determinamos los decoradores para simplificar una ViewHelper
  12350. y una Label:
  12351. </para>
  12352. <programlisting role="php"><![CDATA[
  12353. $form->setElementDecorators(array(
  12354. 'ViewHelper',
  12355. 'Label'
  12356. ));
  12357. ]]>
  12358. </programlisting>
  12359. </example>
  12360. <example id="zend.form.forms.elements.global.decoratorsFilter">
  12361. <title>Determinando decoradores para algunos elementos</title>
  12362. <para>
  12363. Pueden determinarse también decoradores para un subconjunto de elementos,
  12364. ya sea por inclusión o exclusión. El segundo argumento
  12365. <code>setElementDecorators()</code> puede ser un array de
  12366. nombres de elemento; por defecto, especificar un array de ese tipo
  12367. determinará los decoradores especificados en esos elementos solamente. Puede
  12368. tambien pasar un tercer elemento, una bandera indicando si
  12369. esta lista de elementos es para propósitos de inclusión o exclusión;
  12370. si es falso, decorará todos los elementos
  12371. <emphasis>excepto</emphasis> los pasados en la lista,
  12372. Como uso estándar del método, cualquier decorador pasado
  12373. reescribirá cualquier decorador previamente determinado en cada
  12374. elemento.
  12375. </para>
  12376. <para>
  12377. En el siguiente fragmento, indicamos que queremos los decoradores
  12378. ViewHelper y Label para los elementos
  12379. 'foo' y 'bar':
  12380. </para>
  12381. <programlisting role="php"><![CDATA[
  12382. $form->setElementDecorators(
  12383. array(
  12384. 'ViewHelper',
  12385. 'Label'
  12386. ),
  12387. array(
  12388. 'foo',
  12389. 'bar'
  12390. )
  12391. );
  12392. ]]>
  12393. </programlisting>
  12394. <para>
  12395. Por otro lado, con este fragmento, indicaremos
  12396. que queremos usar solamente los decoradores
  12397. ViewHelper y Label para cada elemento <emphasis>excepto</emphasis>
  12398. los elementos 'foo' y 'bar':
  12399. </para>
  12400. <programlisting role="php"><![CDATA[
  12401. $form->setElementDecorators(
  12402. array(
  12403. 'ViewHelper',
  12404. 'Label'
  12405. ),
  12406. array(
  12407. 'foo',
  12408. 'bar'
  12409. ),
  12410. false
  12411. );
  12412. ]]>
  12413. </programlisting>
  12414. </example>
  12415. <note>
  12416. <title>Algunos Decoradores son Inapropiados para algunos Elementos</title>
  12417. <para>
  12418. Mientras <code>setElementDecorators()</code> puede parecer
  12419. una buena solución, existen algunos casos donde puede
  12420. terminar con resultados inesperados, Por ejemplo,
  12421. los muchos elementos botones (Submit, Button, Reset),
  12422. actualmente usan la etiqueta como el valor del botón
  12423. y sólo usan los decoradores ViewHelper y DtDdWrapper --
  12424. previniendo una etiqueta adicional, errores, y sugerencias de
  12425. ser generadas; el ejemplo de arriba podría duplicar algún
  12426. contenido (la etiqueta).
  12427. </para>
  12428. <para>
  12429. Se puede usar el array de inclusión/exclusión para superar
  12430. este problema como se ha notado en el ejemplo anterior.
  12431. </para>
  12432. <para>
  12433. Entonces, use este método sabiamente y dése cuenta de que puede
  12434. necesitar excluir o cambiar manualmente algunos elementos decoradores
  12435. para prevenir una salida no deseada.
  12436. </para>
  12437. </note>
  12438. <example id="zend.form.forms.elements.global.filters">
  12439. <title>Determinando Filtros para todos los Elementos</title>
  12440. <para>
  12441. En muchos casos, puede quererse aplicar el mismo filtro a todos
  12442. los elementos; un caso común es <code>trim()</code> a todos los valores:
  12443. </para>
  12444. <programlisting role="php"><![CDATA[
  12445. $form->setElementFilters(array('StringTrim'));
  12446. ]]>
  12447. </programlisting>
  12448. </example>
  12449. </sect3>
  12450. <sect3 id="zend.form.forms.elements.methods">
  12451. <title>Métodos para Interactuar con los Elementos</title>
  12452. <para>
  12453. Los siguientes métodos pueden ser usados para interactuar con los elementos:
  12454. </para>
  12455. <itemizedlist>
  12456. <listitem><para>
  12457. <code>createElement($element, $name = null, $options = null)</code>
  12458. </para></listitem>
  12459. <listitem><para>
  12460. <code>addElement($element, $name = null, $options = null)</code>
  12461. </para></listitem>
  12462. <listitem><para>
  12463. <code>addElements(array $elements)</code>
  12464. </para></listitem>
  12465. <listitem><para>
  12466. <code>setElements(array $elements)</code>
  12467. </para></listitem>
  12468. <listitem><para>
  12469. <code>getElement($name)</code>
  12470. </para></listitem>
  12471. <listitem><para>
  12472. <code>getElements()</code>
  12473. </para></listitem>
  12474. <listitem><para>
  12475. <code>removeElement($name)</code>
  12476. </para></listitem>
  12477. <listitem><para>
  12478. <code>clearElements()</code>
  12479. </para></listitem>
  12480. <listitem><para>
  12481. <code>setDefaults(array $defaults)</code>
  12482. </para></listitem>
  12483. <listitem><para>
  12484. <code>setDefault($name, $value)</code>
  12485. </para></listitem>
  12486. <listitem><para>
  12487. <code>getValue($name)</code>
  12488. </para></listitem>
  12489. <listitem><para>
  12490. <code>getValues()</code>
  12491. </para></listitem>
  12492. <listitem><para>
  12493. <code>getUnfilteredValue($name)</code>
  12494. </para></listitem>
  12495. <listitem><para>
  12496. <code>getUnfilteredValues()</code>
  12497. </para></listitem>
  12498. <listitem><para>
  12499. <code>setElementFilters(array $filters)</code>
  12500. </para></listitem>
  12501. <listitem><para>
  12502. <code>setElementDecorators(array $decorators)</code>
  12503. </para></listitem>
  12504. <listitem><para>
  12505. <code>addElementPrefixPath($prefix, $path, $type = null)</code>
  12506. </para></listitem>
  12507. <listitem><para>
  12508. <code>addElementPrefixPaths(array $spec)</code>
  12509. </para></listitem>
  12510. </itemizedlist>
  12511. </sect3>
  12512. </sect2>
  12513. <sect2 id="zend.form.forms.displaygroups">
  12514. <title>Grupos de visualización (display groups)</title>
  12515. <para>
  12516. Los grupos de visualización (display groups) son una manera de crear grupos virtuales de elementos para
  12517. propósitos de visualización. Todos los elementos quedan accesibles por nombre en el
  12518. formulario, pero cuando interactúan o se ejecutan sobre el formulario, cualquiera de los elementos en
  12519. un grupos de visualización son generados juntos. El caso más común de uso es
  12520. agrupando los elementos en fieldsets. (TODO)
  12521. </para>
  12522. <para>
  12523. La clase base para los grupos de visualización es
  12524. <code>Zend_Form_DisplayGroup</code>. Mientras puede ser instanciado
  12525. directamente, es mejor usar el método <code>addDisplayGroup()</code>
  12526. de la clase<code>Zend_Form</code>. Este método toma un
  12527. array de elementos como primer argumento y el nombre para el grupo de
  12528. visualización como segundo argumento. Opcionalmente, se puede pasar en una array
  12529. de opciones o en un objeto <code>Zend_Config</code> como tercer argumento.
  12530. </para>
  12531. <para>
  12532. Asumiendo que los elementos 'username' y 'password' has sido determinados
  12533. en el formulario, el siguiente código podría agrupar estos elementos en un
  12534. grupo de visualización 'login':
  12535. </para>
  12536. <programlisting role="php"><![CDATA[
  12537. $form->addDisplayGroup(array('username', 'password'), 'login');
  12538. ]]>
  12539. </programlisting>
  12540. <para>
  12541. Puede acceder a los grupos de visualización usando el
  12542. método <code>getDisplayGroup()</code>, o mediante la sobrecarga usando el
  12543. nombre del grupo de visualización:
  12544. </para>
  12545. <programlisting role="php"><![CDATA[
  12546. // Usando getDisplayGroup():
  12547. $login = $form->getDisplayGroup('login');
  12548. // Usando sobrecarga:
  12549. $login = $form->login;
  12550. ]]>
  12551. </programlisting>
  12552. <note>
  12553. <title>Decoradores por defecto que no necesitan ser cargados</title>
  12554. <para>
  12555. Por defecto, los grupos de visualización son cargados durante la
  12556. inicialización del objeto. Se puede deshabilitar pasando la
  12557. opción 'disableLoadDefaultDecorators' cuando se crea un grupo de visualización:
  12558. </para>
  12559. <programlisting role="php"><![CDATA[
  12560. $form->addDisplayGroup(
  12561. array('foo', 'bar'),
  12562. 'foobar',
  12563. array('disableLoadDefaultDecorators' => true)
  12564. );
  12565. ]]>
  12566. </programlisting>
  12567. <para>
  12568. Esta opción puede ser una mezcla con otras opciones pasadas,
  12569. ambas como opciones de array o en el objeto <code>Zend_Config</code>
  12570. </para>
  12571. </note>
  12572. <sect3 id="zend.form.forms.displaygroups.global">
  12573. <title>Operaciones Globales</title>
  12574. <para>
  12575. Al igual que los elementos, existen algunas operaciones que
  12576. pueden afectar a todos los grupos de visualización; éstas incluyen determinar decoradores
  12577. y fijar la ruta de acceso donde buscar los decoradores.
  12578. </para>
  12579. <example id="zend.form.forms.displaygroups.global.paths">
  12580. <title>Fijando el Prefijo de Ruta del Decorador para todos los Grupos de Visualización</title>
  12581. <para>
  12582. Por defecto, los grupos de visualización heredan cualquier
  12583. ruta de decorador que use el formulario; sin embargo, si deberían buscar
  12584. en una ruta alternativa, puede usar el método
  12585. <code>addDisplayGroupPrefixPath()</code> method.
  12586. </para>
  12587. <programlisting role="php"><![CDATA[
  12588. $form->addDisplayGroupPrefixPath('My_Foo_Decorator', 'My/Foo/Decorator');
  12589. ]]>
  12590. </programlisting>
  12591. </example>
  12592. <example id="zend.form.forms.displaygroups.global.decorators">
  12593. <title>Fijando Decoradores para Todos los Grupos de Visualización</title>
  12594. <para>
  12595. Pueden determinarse decoradores para todos los grupos de visualización,
  12596. <code>setDisplayGroupDecorators()</code> admite un array de
  12597. decoradores, al igual que <code>setDecorators()</code>, y sobreescribirá
  12598. cualquier conjunto de decoradores previo en cada grupo de visualización.
  12599. En este ejemplo, fijamos los decoradores a un fieldset (el decorador FormElements
  12600. es necesario para asegurar que los elementos son iterador):
  12601. </para>
  12602. <programlisting role="php"><![CDATA[
  12603. $form->setDisplayGroupDecorators(array(
  12604. 'FormElements',
  12605. 'Fieldset'
  12606. ));
  12607. ]]>
  12608. </programlisting>
  12609. </example>
  12610. </sect3>
  12611. <sect3 id="zend.form.forms.displaygroups.customClasses">
  12612. <title>Usando Clases de Grupos de Visualización Personalizadas</title>
  12613. <para>
  12614. Por defecto, <code>Zend_Form</code> utiliza la clase
  12615. <code>Zend_Form_DisplayGroup</code> para grupos de visualización.
  12616. Puede ocurrir que necesite extender esta clase con el fin
  12617. de obtener una funcionalid personalizada. <code>addDisplayGroup()</code>
  12618. no permite pasar una instancia determinada, pero permite especificar
  12619. la clase que usar como una de sus opciones, usando la clave
  12620. 'displayGroupClass':
  12621. </para>
  12622. <programlisting role="php"><![CDATA[
  12623. // Use the 'My_DisplayGroup' class
  12624. $form->addDisplayGroup(
  12625. array('username', 'password'),
  12626. 'user',
  12627. array('displayGroupClass' => 'My_DisplayGroup')
  12628. );
  12629. ]]>
  12630. </programlisting>
  12631. <para>
  12632. Si la clase no ha sido todavía cargada, <code>Zend_Form</code>
  12633. intentará cargarla a través de <code>Zend_Loader</code>.
  12634. </para>
  12635. <para>
  12636. También puede especificar una clase de grupo de visualización por defecto
  12637. para usar con el formulario, de forma que todos los grupos de visualización
  12638. creados con el objeto formulario usen esa clase:
  12639. </para>
  12640. <programlisting role="php"><![CDATA[
  12641. // Use the 'My_DisplayGroup' class for all display groups:
  12642. $form->setDefaultDisplayGroupClass('My_DisplayGroup');
  12643. ]]>
  12644. </programlisting>
  12645. <para>
  12646. Esta funcionalidad puede especificarse en configuraciones como
  12647. 'defaultDisplayGroupClass', y será cargada con antelación para
  12648. asegurar que todos los grupos de visualización usen esa clase.
  12649. </para>
  12650. </sect3>
  12651. <sect3 id="zend.form.forms.displaygroups.interactionmethods">
  12652. <title>Métodos para Interactuar con Grupos de Visualización</title>
  12653. <para>
  12654. Los siguientes métodos pueden ser usados para interactuar con el grupo de visualización:
  12655. </para>
  12656. <itemizedlist>
  12657. <listitem><para>
  12658. <code>addDisplayGroup(array $elements, $name, $options = null)</code>
  12659. </para></listitem>
  12660. <listitem><para>
  12661. <code>addDisplayGroups(array $groups)</code>
  12662. </para></listitem>
  12663. <listitem><para>
  12664. <code>setDisplayGroups(array $groups)</code>
  12665. </para></listitem>
  12666. <listitem><para>
  12667. <code>getDisplayGroup($name)</code>
  12668. </para></listitem>
  12669. <listitem><para>
  12670. <code>getDisplayGroups()</code>
  12671. </para></listitem>
  12672. <listitem><para>
  12673. <code>removeDisplayGroup($name)</code>
  12674. </para></listitem>
  12675. <listitem><para>
  12676. <code>clearDisplayGroups()</code>
  12677. </para></listitem>
  12678. <listitem><para>
  12679. <code>setDisplayGroupDecorators(array $decorators)</code>
  12680. </para></listitem>
  12681. <listitem><para>
  12682. <code>addDisplayGroupPrefixPath($prefix, $path)</code>
  12683. </para></listitem>
  12684. <listitem><para>
  12685. <code>setDefaultDisplayGroupClass($class)</code>
  12686. </para></listitem>
  12687. <listitem><para>
  12688. <code>getDefaultDisplayGroupClass($class)</code>
  12689. </para></listitem>
  12690. </itemizedlist>
  12691. </sect3>
  12692. <sect3 id="zend.form.forms.displaygroups.methods">
  12693. <title>Métodos Zend_Form_DisplayGroup</title>
  12694. <para>
  12695. <code>Zend_Form_DisplayGroup</code> tiene los siguientes métodos,
  12696. agrupados por tipo:
  12697. </para>
  12698. <itemizedlist>
  12699. <listitem><para>Configuración:</para>
  12700. <itemizedlist>
  12701. <listitem><para><code>setOptions(array $options)</code></para></listitem>
  12702. <listitem><para><code>setConfig(Zend_Config $config)</code></para></listitem>
  12703. </itemizedlist>
  12704. </listitem>
  12705. <listitem><para>Metadatos:</para>
  12706. <itemizedlist>
  12707. <listitem><para><code>setAttrib($key, $value)</code></para></listitem>
  12708. <listitem><para><code>addAttribs(array $attribs)</code></para></listitem>
  12709. <listitem><para><code>setAttribs(array $attribs)</code></para></listitem>
  12710. <listitem><para><code>getAttrib($key)</code></para></listitem>
  12711. <listitem><para><code>getAttribs()</code></para></listitem>
  12712. <listitem><para><code>removeAttrib($key)</code></para></listitem>
  12713. <listitem><para><code>clearAttribs()</code></para></listitem>
  12714. <listitem><para><code>setName($name)</code></para></listitem>
  12715. <listitem><para><code>getName()</code></para></listitem>
  12716. <listitem><para><code>setDescription($value)</code></para></listitem>
  12717. <listitem><para><code>getDescription()</code></para></listitem>
  12718. <listitem><para><code>setLegend($legend)</code></para></listitem>
  12719. <listitem><para><code>getLegend()</code></para></listitem>
  12720. <listitem><para><code>setOrder($order)</code></para></listitem>
  12721. <listitem><para><code>getOrder()</code></para></listitem>
  12722. </itemizedlist>
  12723. </listitem>
  12724. <listitem><para>Elementos:</para>
  12725. <itemizedlist>
  12726. <listitem><para><code>createElement($type, $name, array $options = array())</code></para></listitem>
  12727. <listitem><para><code>addElement($typeOrElement, $name, array $options = array())</code></para></listitem>
  12728. <listitem><para><code>addElements(array $elements)</code></para></listitem>
  12729. <listitem><para><code>setElements(array $elements)</code></para></listitem>
  12730. <listitem><para><code>getElement($name)</code></para></listitem>
  12731. <listitem><para><code>getElements()</code></para></listitem>
  12732. <listitem><para><code>removeElement($name)</code></para></listitem>
  12733. <listitem><para><code>clearElements()</code></para></listitem>
  12734. </itemizedlist>
  12735. </listitem>
  12736. <listitem><para>Cargadores Complemento:</para>
  12737. <itemizedlist>
  12738. <listitem><para><code>setPluginLoader(Zend_Loader_PluginLoader $loader)</code></para></listitem>
  12739. <listitem><para><code>getPluginLoader()</code></para></listitem>
  12740. <listitem><para><code>addPrefixPath($prefix, $path)</code></para></listitem>
  12741. <listitem><para><code>addPrefixPaths(array $spec)</code></para></listitem>
  12742. </itemizedlist>
  12743. </listitem>
  12744. <listitem><para>Decoratores:</para>
  12745. <itemizedlist>
  12746. <listitem><para><code>addDecorator($decorator, $options = null)</code></para></listitem>
  12747. <listitem><para><code>addDecorators(array $decorators)</code></para></listitem>
  12748. <listitem><para><code>setDecorators(array $decorators)</code></para></listitem>
  12749. <listitem><para><code>getDecorator($name)</code></para></listitem>
  12750. <listitem><para><code>getDecorators()</code></para></listitem>
  12751. <listitem><para><code>removeDecorator($name)</code></para></listitem>
  12752. <listitem><para><code>clearDecorators()</code></para></listitem>
  12753. </itemizedlist>
  12754. </listitem>
  12755. <listitem><para>Generadores:</para>
  12756. <itemizedlist>
  12757. <listitem><para><code>setView(Zend_View_Interface $view = null)</code></para></listitem>
  12758. <listitem><para><code>getView()</code></para></listitem>
  12759. <listitem><para><code>render(Zend_View_Interface $view = null)</code></para></listitem>
  12760. </itemizedlist>
  12761. </listitem>
  12762. <listitem><para>I18n:</para>
  12763. <itemizedlist>
  12764. <listitem><para><code>setTranslator(Zend_Translate_Adapter $translator = null)</code></para></listitem>
  12765. <listitem><para><code>getTranslator()</code></para></listitem>
  12766. <listitem><para><code>setDisableTranslator($flag)</code></para></listitem>
  12767. <listitem><para><code>translatorIsDisabled()</code></para></listitem>
  12768. </itemizedlist>
  12769. </listitem>
  12770. </itemizedlist>
  12771. </sect3>
  12772. </sect2>
  12773. <sect2 id="zend.form.forms.subforms">
  12774. <title>Subformularios</title>
  12775. <para>
  12776. Los Sub formularios sirven para diferentes propósitos:
  12777. </para>
  12778. <itemizedlist>
  12779. <listitem><para>
  12780. Crear grupos de elementos lógicos. Dado que los sub formularios son
  12781. simplemente formularios, se pueden validar subformularios como entidades individuales.
  12782. </para></listitem>
  12783. <listitem><para>
  12784. Crear formularios multi-páginas. Dado que los sub formularios son simplemente formularios,
  12785. se puede deplegar un sub formulario por separado por página, incrementando formularios
  12786. multi-páginas donde cada formulario tiene su propia validación lógica. Solo una vez
  12787. que todos los sub formularios se validen, el formulario se consideraría completo.
  12788. </para></listitem>
  12789. <listitem><para>
  12790. Agrupaciones de visualización. Como grupos de visualización, los sub formularios, cuando son generados
  12791. como parte de un formulario más grande, pueden ser usados para agrupar elementos. Sea consciente,
  12792. de todas maneras, que el objeto formulario principal no tendrá
  12793. conocimiento de los elementos en un sub formulario.
  12794. </para></listitem>
  12795. </itemizedlist>
  12796. <para>
  12797. Un sub formulario puede ser un objeto <code>Zend_Form</code> o mas
  12798. originalmente, un objeto <code>Zend_Form_SubForm</code>. éste último
  12799. contiene decoradores apropiados para la inclusión en un formulario extenso (i.e.,
  12800. no se generan adicionales formulario etiquetas HTML, pero si grupos de
  12801. elementos). Para adjuntar un sub formulario, simplemente añádalo al formulario y déle
  12802. un nombre:
  12803. </para>
  12804. <programlisting role="php"><![CDATA[
  12805. $form->addSubForm($subForm, 'subform');
  12806. ]]>
  12807. </programlisting>
  12808. <para>
  12809. Se puede recuperar un sub formulario usando ya sea
  12810. <code>getSubForm($name)</code> o sobrecarga usando el nombre
  12811. del sub formulario:
  12812. </para>
  12813. <programlisting role="php"><![CDATA[
  12814. // Usando getSubForm():
  12815. $subForm = $form->getSubForm('subform');
  12816. // Usando sobrecarga:
  12817. $subForm = $form->subform;
  12818. ]]>
  12819. </programlisting>
  12820. <para>
  12821. Los Subformularios son incluidos en la interacción del formulario, sin embargo los elementos
  12822. que lo contienen no lo son
  12823. </para>
  12824. <sect3 id="zend.form.forms.subforms.global">
  12825. <title>Operaciones Globales</title>
  12826. <para>
  12827. Como los elementos y los grupos de visualización, existen algunas operaciones que
  12828. pueden afectar a todos los sub formularios. A diferencia de los grupos de visualización y los
  12829. elementos, sin embargo, los sub formularios heredan más funcionalidad del
  12830. objeto formulario principal, y la única operación real que puede
  12831. realizarse globalmente es determinar decoradores para sub formularios. Para
  12832. este propósito, existe el método <code>setSubFormDecorators()</code>.
  12833. En el siguiente ejemplo, determinaremos el decorador para todos los
  12834. subformularios que sera un simple campo (el decorador FormElements es
  12835. necesario para asegurar que los elementos son iterados):
  12836. </para>
  12837. <programlisting role="php"><![CDATA[
  12838. $form->setSubFormDecorators(array(
  12839. 'FormElements',
  12840. 'Fieldset'
  12841. ));
  12842. ]]>
  12843. </programlisting>
  12844. </sect3>
  12845. <sect3 id="zend.form.forms.subforms.methods">
  12846. <title>Métodos para interactuar con Sub Formularios</title>
  12847. <para>
  12848. Los siguientes métodos pueden ser usados para interactuar con sub formularios:
  12849. </para>
  12850. <itemizedlist>
  12851. <listitem><para>
  12852. <code>addSubForm(Zend_Form $form, $name, $order = null)</code>
  12853. </para></listitem>
  12854. <listitem><para>
  12855. <code>addSubForms(array $subForms)</code>
  12856. </para></listitem>
  12857. <listitem><para>
  12858. <code>setSubForms(array $subForms)</code>
  12859. </para></listitem>
  12860. <listitem><para>
  12861. <code>getSubForm($name)</code>
  12862. </para></listitem>
  12863. <listitem><para>
  12864. <code>getSubForms()</code>
  12865. </para></listitem>
  12866. <listitem><para>
  12867. <code>removeSubForm($name)</code>
  12868. </para></listitem>
  12869. <listitem><para>
  12870. <code>clearSubForms()</code>
  12871. </para></listitem>
  12872. <listitem><para>
  12873. <code>setSubFormDecorators(array $decorators)</code>
  12874. </para></listitem>
  12875. </itemizedlist>
  12876. </sect3>
  12877. </sect2>
  12878. <sect2 id="zend.form.forms.metadata">
  12879. <title>Metadatos y Atributos</title>
  12880. <para>
  12881. Mientras la utilidad de un formulario primariamente deriva de los elementos
  12882. que contiene, también pueden contener otros metadatos, como un nombre (usado
  12883. a menudo como ID único en el marcado HTML ); la accion y el método del formulario;
  12884. el número de elementos, grupos y sub formularios que lo contienen; y
  12885. arbitrariamente metadatos (usualmente usados para determinar atributos HTML para la
  12886. etiqueta del propio formulario).
  12887. </para>
  12888. <para>
  12889. Se puede determinar y recuperar el nombre del formulario usando el accesor nombre:
  12890. </para>
  12891. <programlisting role="php"><![CDATA[
  12892. // Determinar el nombre:
  12893. $form->setName('registration');
  12894. // Recuperar el nombre:
  12895. $name = $form->getName();
  12896. ]]>
  12897. </programlisting>
  12898. <para>
  12899. Para determinar la acción (url en el cual se envia el formulario) y método (método
  12900. por el cual debería enviar, ej. 'POST' or 'GET'), use los accesores acción
  12901. y método:
  12902. </para>
  12903. <programlisting role="php"><![CDATA[
  12904. // Determinar la acción y método:
  12905. $form->setAction('/user/login')
  12906. ->setMethod('post');
  12907. ]]>
  12908. </programlisting>
  12909. <para>
  12910. Se puede también especificar el tipo de codificación del fomulario usando el
  12911. enctype accessors. Zend_Form define dos constantes,
  12912. <code>Zend_Form::ENCTYPE_URLENCODED</code> y
  12913. <code>Zend_Form::ENCTYPE_MULTIPART</code>, correspondiente a los
  12914. valores 'application/x-www-form-urlencoded' y
  12915. 'multipart/form-data', respectivamente; sin embargo, puede configurarlo
  12916. con cualquier tipo de codificación.
  12917. </para>
  12918. <programlisting role="php"><![CDATA[
  12919. // Determinar la acción, método y enctype:
  12920. $form->setAction('/user/login')
  12921. ->setMethod('post')
  12922. ->setEnctype(Zend_Form::ENCTYPE_MULTIPART);
  12923. ]]>
  12924. </programlisting>
  12925. <note>
  12926. <para>
  12927. El método, acción y enctype son solo usados internamente para generar,
  12928. y no para algún tipo de validación.
  12929. </para>
  12930. </note>
  12931. <para>
  12932. <code>Zend_Form</code> implementa la interfaz <code>Countable</code>
  12933. permitiéndole pasarlo como un argumento para contar:
  12934. </para>
  12935. <programlisting role="php"><![CDATA[
  12936. $numItems = count($form);
  12937. ]]>
  12938. </programlisting>
  12939. <para>
  12940. Determinar metadatos arbitrariamente se realiza a través de los accesores 'atribs'.
  12941. Dado que la sobrecarga en <code>Zend_Form</code> es usada para acceder
  12942. elementos, grupos de visualización y subformularios, este es el único método para
  12943. acceder a los metadatos.
  12944. </para>
  12945. <programlisting role="php"><![CDATA[
  12946. // Determinando atributos:
  12947. $form->setAttrib('class', 'zend-form')
  12948. ->addAttribs(array(
  12949. 'id' => 'registration',
  12950. 'onSubmit' => 'validate(this)',
  12951. ));
  12952. // Recuperando atributos:
  12953. $class = $form->getAttrib('class');
  12954. $attribs = $form->getAttribs();
  12955. // Removiendo atributos:
  12956. $form->removeAttrib('onSubmit');
  12957. // Limpiando todos los atributos:
  12958. $form->clearAttribs();
  12959. ]]>
  12960. </programlisting>
  12961. </sect2>
  12962. <sect2 id="zend.form.forms.decorators">
  12963. <title>Decoradores</title>
  12964. <para>
  12965. Crear el marcado para un formulario es a menudo una tarea que consume mucho tiempo,
  12966. particularmente si se planea reusar el mismo marcado para mostrar acciones
  12967. tales como validación de errores, enviar valores, etc.
  12968. La respuesta de <code>Zend_Form</code> a este problema es los
  12969. <emphasis>decoradores</emphasis>.
  12970. </para>
  12971. <para>
  12972. Los decoradores para objetos <code>Zend_Form</code> pueden ser usados para generar
  12973. un formulario. El decorador FormElements iterará a través de todos los elementos en
  12974. un formulario -- elementos, grupos de visualización y subformularios -- y los generará,
  12975. devolviendo el resultado. Adicionalmente, los decoradores pueden ser usados
  12976. para envolver el contenido o anteponerlo o postponerlo.
  12977. </para>
  12978. <para>
  12979. Los decoradores por defecto de <code>Zend_Form</code> son FormElements,
  12980. HtmlTag (envuelve una lista de definición) y Form; el código equivalente
  12981. para crearlos es como sigue:
  12982. </para>
  12983. <programlisting role="php"><![CDATA[
  12984. $form->setDecorators(array(
  12985. 'FormElements',
  12986. array('HtmlTag', array('tag' => 'dl')),
  12987. 'Form'
  12988. ));
  12989. ]]>
  12990. </programlisting>
  12991. <para>
  12992. Que crea la salida como sigue:
  12993. </para>
  12994. <programlisting role="html"><![CDATA[
  12995. <form action="/form/action" method="post">
  12996. <dl>
  12997. ...
  12998. </dl>
  12999. </form>
  13000. ]]>
  13001. </programlisting>
  13002. <para>
  13003. Algunos de los atributos se determinan en el objeto formulario que será usado como
  13004. atributos HTML de la etiqueta <code>&lt;form&gt;</code>.
  13005. </para>
  13006. <note>
  13007. <title>Decoradores por defecto que no necesitan ser cargados</title>
  13008. <para>
  13009. Por defecto, el decorador por defecto son cargados durante la
  13010. inicialización del objeto. Puede deshabilitarlo pasando la
  13011. opción 'disableLoadDefaultDecorators' al constructor:
  13012. </para>
  13013. <programlisting role="php"><![CDATA[
  13014. $form = new Zend_Form(array('disableLoadDefaultDecorators' => true));
  13015. ]]>
  13016. </programlisting>
  13017. <para>
  13018. Esta opción puede ser combinada con alguna otra opción que usted pueda pasar,
  13019. tanto como opciones de array o en un objeto <code>Zend_Config</code>
  13020. </para>
  13021. </note>
  13022. <note>
  13023. <title>Usando multiples decoradores del mismo tipo</title>
  13024. <para>
  13025. Internamente, <code>Zend_Form</code> usa una clase decorador
  13026. como un mecanismo buscador cuando se recuperan decoradores. Como
  13027. resultado, no se pueden registrar multiples decoradores del mismo
  13028. tipo; subsecuentemente los decoradores simplemente sobrescribirán esos
  13029. decoradores que existían antes.
  13030. </para>
  13031. <para>
  13032. Para conseguir esto, se pueden usar alias. En vez de pasar un
  13033. decorador o un nombre de decorador como primer argumento a
  13034. <code>addDecorator()</code>, pase un array con un solo
  13035. elemento, con el alias apuntando al objeto decorador o
  13036. nombre:
  13037. </para>
  13038. <programlisting role="php"><![CDATA[
  13039. // Alias para 'FooBar':
  13040. $form->addDecorator(array('FooBar' => 'HtmlTag'), array('tag' => 'div'));
  13041. // y recuperarlo después:
  13042. $form = $element->getDecorator('FooBar');
  13043. ]]>
  13044. </programlisting>
  13045. <para>
  13046. En los métodos <code>addDecorators()</code> y
  13047. <code>setDecorators()</code>, se necesitará pasar
  13048. la opción 'decorator' en el array representando el decorador:
  13049. </para>
  13050. <programlisting role="php"><![CDATA[
  13051. // Añadir dos decoradores 'HtmlTag', poniendo un alias a 'FooBar':
  13052. $form->addDecorators(
  13053. array('HtmlTag', array('tag' => 'div')),
  13054. array(
  13055. 'decorator' => array('FooBar' => 'HtmlTag'),
  13056. 'options' => array('tag' => 'dd')
  13057. ),
  13058. );
  13059. // y recuperándolo después:
  13060. $htmlTag = $form->getDecorator('HtmlTag');
  13061. $fooBar = $form->getDecorator('FooBar');
  13062. ]]>
  13063. </programlisting>
  13064. </note>
  13065. <para>
  13066. Puede crear su propio decorador para generar el formulario. Un
  13067. caso de uso común es si sabe el HTML exacto que desea usar; su
  13068. decorador puede crear el mismo HTML y simplemente retornarlo,
  13069. potencialmente usando los decoradores de individuales elementos o
  13070. grupos de visualización.
  13071. </para>
  13072. <para>
  13073. Los siguientes métodos puden ser usados para interactuar con decoradores:
  13074. </para>
  13075. <itemizedlist>
  13076. <listitem><para>
  13077. <code>addDecorator($decorator, $options = null)</code>
  13078. </para></listitem>
  13079. <listitem><para>
  13080. <code>addDecorators(array $decorators)</code>
  13081. </para></listitem>
  13082. <listitem><para>
  13083. <code>setDecorators(array $decorators)</code>
  13084. </para></listitem>
  13085. <listitem><para>
  13086. <code>getDecorator($name)</code>
  13087. </para></listitem>
  13088. <listitem><para>
  13089. <code>getDecorators()</code>
  13090. </para></listitem>
  13091. <listitem><para>
  13092. <code>removeDecorator($name)</code>
  13093. </para></listitem>
  13094. <listitem><para>
  13095. <code>clearDecorators()</code>
  13096. </para></listitem>
  13097. </itemizedlist>
  13098. <para>
  13099. <code>Zend_Form</code> también usa sobrecarga que permite generar
  13100. decoradores específicos. <code>__call()</code> interceptará métodos
  13101. que lleve con el texto 'render' y use el resto del nombre del método
  13102. para buscar un decorador; si se encuentran, serán generados por un
  13103. <emphasis>solo</emphasis> decorador. Cualquier argumento pasado a la
  13104. llamada del método será usado como contenido que pasar al método
  13105. <code>render()</code> del decorador. Como ejemplo:
  13106. </para>
  13107. <programlisting role="php"><![CDATA[
  13108. // Generar solo los decoradores FormElements:
  13109. echo $form->renderFormElements();
  13110. // Generar solo el campo decorador, pasando el contenido:
  13111. echo $form->renderFieldset("<p>This is fieldset content</p>");
  13112. ]]></programlisting>
  13113. <para>
  13114. Si el decorador no existe, una excepción se creará.
  13115. </para>
  13116. </sect2>
  13117. <sect2 id="zend.form.forms.validation">
  13118. <title>Validación</title>
  13119. <para>
  13120. Un caso de uso primario para formularios es validar datos enviados.
  13121. <code>Zend_Form</code> le permite validar un formulario entero de una vez,
  13122. o una parte de él, asi como también automatizar las respuestas de validación para
  13123. XmlHttpRequests (AJAX). Si los datos enviados no son válidos, contiene
  13124. métodos para recuperar los distintos códigos errores y los mensajes de
  13125. elementos y subformularios de validaciones fallidas.
  13126. </para>
  13127. <para>
  13128. Para validar un formulario entero, use el método <code>isValid()</code>:
  13129. </para>
  13130. <programlisting role="php"><![CDATA[
  13131. if (!$form->isValid($_POST)) {
  13132. // validación fallida
  13133. }
  13134. ]]>
  13135. </programlisting>
  13136. <para>
  13137. <code>isValid()</code> validará cada elemento requerido, y algún
  13138. elemento no requerido contenido en la data sometida.
  13139. </para>
  13140. <para>
  13141. Algunas veces se necesitará validar sólo un subset del dato; para
  13142. esto use <code>isValidPartial($data)</code>:
  13143. </para>
  13144. <programlisting role="php"><![CDATA[
  13145. if (!$form->isValidPartial($data)) {
  13146. // validación fallida
  13147. }
  13148. ]]>
  13149. </programlisting>
  13150. <para>
  13151. <code>isValidPartial()</code> sólo intenta validar aquellos elementos
  13152. en la información para los cuales existen similares elementos; si un elemento es
  13153. no representado en la información, es pasado por alto.
  13154. </para>
  13155. <para>
  13156. Cuando se validan elementos o grupos de elementos para un requeirimiento AJAX,
  13157. típicamente se validará un subset del formulario, y quiere la respuesta
  13158. en JSON. <code>processAjax()</code> precisamente realiza eso:
  13159. </para>
  13160. <programlisting role="php"><![CDATA[
  13161. $json = $form->processAjax($data);
  13162. ]]>
  13163. </programlisting>
  13164. <para>
  13165. Entonces, puede simplemente enviar la respuesta JSON al cliente. Si el
  13166. formulario es válido, ésta será una respuesta booleana. Si no, será
  13167. un objeto javascript conteniendo pares de clave/mensaje, donde cada
  13168. 'message' es un array de validación de mensajes de error.
  13169. </para>
  13170. <para>
  13171. Para los formularios que fallan la validación, se pueden recuperar ambos códigos
  13172. de error y mensajes de error, usando <code>getErrors()</code> y
  13173. <code>getMessages()</code>, respectivamente:
  13174. </para>
  13175. <programlisting role="php"><![CDATA[
  13176. $codes = $form->getErrors();
  13177. $messages = $form->getMessage();
  13178. ]]>
  13179. </programlisting>
  13180. <note>
  13181. <para>
  13182. Dado que los mensajes devueltos por <code>getMessages()</code> son un
  13183. array de pares de errores código/mensaje, <code>getErrors()</code> no
  13184. es necesario.
  13185. </para>
  13186. </note>
  13187. <para>
  13188. Puede recuperar códigos y mensajes de error para elementos individuales
  13189. simplemente pasando el nombre del elemento a cada uno:
  13190. </para>
  13191. <programlisting role="php"><![CDATA[
  13192. $codes = $form->getErrors('username');
  13193. $messages = $form->getMessages('username');
  13194. ]]>
  13195. </programlisting>
  13196. <note>
  13197. <para>
  13198. Nota: Cuando validamos elementos, <code>Zend_Form</code> envía un
  13199. segundo argumento a cada método <code>isValid()</code> del elemento:
  13200. el array de los datos que se están validando. Esto puede ser usado por
  13201. validadores individuales para permitirles utilizar otros valores
  13202. enviados al determinar la validez de los datos. Un ejemplo
  13203. sería un formulario de registro que requiere tanto una contraseña
  13204. como una confirmación de la contraseña; el elemento contraseña puede usar la
  13205. confirmación de la contraseña como parte de su validación.
  13206. </para>
  13207. </note>
  13208. <sect3 id="zend.form.forms.validation.errors">
  13209. <title>Mensajes de error personalizados</title>
  13210. <para>
  13211. A veces, puede querer especificar uno o más mensajes
  13212. de error en vez de los mensajes de error generados por los
  13213. validadores adjuntos a los elementos. Adicionalmente, a veces
  13214. puede querer marcar el formulario inválido usted mismo. Como 1.6.0,
  13215. esta funcionalidad es posible siguiendo los métodos.
  13216. At times, you may want to specify one or more specific error
  13217. messages to use instead of the error messages generated by the
  13218. validators attached to your elements. Additionally, at times you
  13219. may want to mark the form invalid yourself. As of 1.6.0, this
  13220. functionality is possible via the following methods.
  13221. </para>
  13222. <itemizedlist>
  13223. <listitem><para>
  13224. <code>addErrorMessage($message)</code>: añade un mensaje de error
  13225. para desplegar en el formulario los errores de validación. Se debe llamar más
  13226. de una vez, y los nuevos mensajes son adicionados a la pila.
  13227. </para></listitem>
  13228. <listitem><para>
  13229. <code>addErrorMessages(array $messages)</code>: añade múltiples
  13230. mensajes de error para desplegar en el formulario los errores de validación
  13231. </para></listitem>
  13232. <listitem><para>
  13233. <code>setErrorMessages(array $messages)</code>: añade multiples
  13234. mensajes de error para desplegar en el formulario los errores de validación,
  13235. sobrescribiendo todos los mensajes de error previamente determinados.
  13236. </para></listitem>
  13237. <listitem><para>
  13238. <code>getErrorMessages()</code>: recupera la lista de
  13239. mensajes de error personalizados que han sido definidos.
  13240. </para></listitem>
  13241. <listitem><para>
  13242. <code>clearErrorMessages()</code>: remueve todos los mensajes
  13243. de error personalizados que han sido definidos.
  13244. </para></listitem>
  13245. <listitem><para>
  13246. <code>markAsError()</code>: marca el formulario como que la
  13247. validación ha fallado.
  13248. </para></listitem>
  13249. <listitem><para>
  13250. <code>addError($message)</code>: añade un mensaje a la pila de
  13251. mensajes de error personalizados y señala al formulario como inválido.
  13252. </para></listitem>
  13253. <listitem><para>
  13254. <code>addErrors(array $messages)</code>: añade muchos
  13255. mensajes a la pila de mensajes de error personalizados y señala al
  13256. formulario como inválido.
  13257. </para></listitem>
  13258. <listitem><para>
  13259. <code>setErrors(array $messages)</code>: sobrescribe la
  13260. pila de mensajes de error personalizada con los mensajes proporcionados
  13261. y señala el formulario como inválido.
  13262. </para></listitem>
  13263. </itemizedlist>
  13264. <para>
  13265. Todos los errores determinados de esta manera pueden ser traducidos.
  13266. </para>
  13267. </sect3>
  13268. </sect2>
  13269. <sect2 id="zend.form.forms.methods">
  13270. <title>Métodos</title>
  13271. <para>
  13272. La siguiente lista es la lista completa de métodos disponibles para
  13273. <code>Zend_Form</code>, agrupados por tipo:
  13274. </para>
  13275. <itemizedlist>
  13276. <listitem><para>Configuración y opciones:</para>
  13277. <itemizedlist>
  13278. <listitem><para><code>setOptions(array $options)</code></para></listitem>
  13279. <listitem><para><code>setConfig(Zend_Config $config)</code></para></listitem>
  13280. </itemizedlist>
  13281. </listitem>
  13282. <listitem><para>Cargadores de plugins y rutas:</para>
  13283. <itemizedlist>
  13284. <listitem><para><code>setPluginLoader(Zend_Loader_PluginLoader_Interface $loader, $type = null)</code></para></listitem>
  13285. <listitem><para><code>getPluginLoader($type = null)</code></para></listitem>
  13286. <listitem><para><code>addPrefixPath($prefix, $path, $type = null) </code></para></listitem>
  13287. <listitem><para><code>addPrefixPaths(array $spec)</code></para></listitem>
  13288. <listitem><para><code>addElementPrefixPath($prefix, $path, $type = null)</code></para></listitem>
  13289. <listitem><para><code>addElementPrefixPaths(array $spec)</code></para></listitem>
  13290. <listitem><para><code>addDisplayGroupPrefixPath($prefix, $path)</code></para></listitem>
  13291. </itemizedlist>
  13292. </listitem>
  13293. <listitem><para>Metadato:</para>
  13294. <itemizedlist>
  13295. <listitem><para><code>setAttrib($key, $value)</code></para></listitem>
  13296. <listitem><para><code>addAttribs(array $attribs)</code></para></listitem>
  13297. <listitem><para><code>setAttribs(array $attribs)</code></para></listitem>
  13298. <listitem><para><code>getAttrib($key)</code></para></listitem>
  13299. <listitem><para><code>getAttribs()</code></para></listitem>
  13300. <listitem><para><code>removeAttrib($key)</code></para></listitem>
  13301. <listitem><para><code>clearAttribs()</code></para></listitem>
  13302. <listitem><para><code>setAction($action)</code></para></listitem>
  13303. <listitem><para><code>getAction()</code></para></listitem>
  13304. <listitem><para><code>setMethod($method)</code></para></listitem>
  13305. <listitem><para><code>getMethod()</code></para></listitem>
  13306. <listitem><para><code>setName($name)</code></para></listitem>
  13307. <listitem><para><code>getName()</code></para></listitem>
  13308. </itemizedlist>
  13309. </listitem>
  13310. <listitem><para>Elementos:</para>
  13311. <itemizedlist>
  13312. <listitem><para><code>addElement($element, $name = null, $options = null)</code></para></listitem>
  13313. <listitem><para><code>addElements(array $elements)</code></para></listitem>
  13314. <listitem><para><code>setElements(array $elements)</code></para></listitem>
  13315. <listitem><para><code>getElement($name)</code></para></listitem>
  13316. <listitem><para><code>getElements()</code></para></listitem>
  13317. <listitem><para><code>removeElement($name)</code></para></listitem>
  13318. <listitem><para><code>clearElements()</code></para></listitem>
  13319. <listitem><para><code>setDefaults(array $defaults)</code></para></listitem>
  13320. <listitem><para><code>setDefault($name, $value)</code></para></listitem>
  13321. <listitem><para><code>getValue($name)</code></para></listitem>
  13322. <listitem><para><code>getValues()</code></para></listitem>
  13323. <listitem><para><code>getUnfilteredValue($name)</code></para></listitem>
  13324. <listitem><para><code>getUnfilteredValues()</code></para></listitem>
  13325. <listitem><para><code>setElementFilters(array $filters)</code></para></listitem>
  13326. <listitem><para><code>setElementDecorators(array $decorators)</code></para></listitem>
  13327. </itemizedlist>
  13328. </listitem>
  13329. <listitem><para>Subformularios:</para>
  13330. <itemizedlist>
  13331. <listitem><para><code>addSubForm(Zend_Form $form, $name, $order = null)</code></para></listitem>
  13332. <listitem><para><code>addSubForms(array $subForms)</code></para></listitem>
  13333. <listitem><para><code>setSubForms(array $subForms)</code></para></listitem>
  13334. <listitem><para><code>getSubForm($name)</code></para></listitem>
  13335. <listitem><para><code>getSubForms()</code></para></listitem>
  13336. <listitem><para><code>removeSubForm($name)</code></para></listitem>
  13337. <listitem><para><code>clearSubForms()</code></para></listitem>
  13338. <listitem><para><code>setSubFormDecorators(array $decorators)</code></para></listitem>
  13339. </itemizedlist>
  13340. </listitem>
  13341. <listitem><para>Grupos de Visualización</para>
  13342. <itemizedlist>
  13343. <listitem><para><code>addDisplayGroup(array $elements, $name, $options = null)</code></para></listitem>
  13344. <listitem><para><code>addDisplayGroups(array $groups)</code></para></listitem>
  13345. <listitem><para><code>setDisplayGroups(array $groups)</code></para></listitem>
  13346. <listitem><para><code>getDisplayGroup($name)</code></para></listitem>
  13347. <listitem><para><code>getDisplayGroups()</code></para></listitem>
  13348. <listitem><para><code>removeDisplayGroup($name)</code></para></listitem>
  13349. <listitem><para><code>clearDisplayGroups()</code></para></listitem>
  13350. <listitem><para><code>setDisplayGroupDecorators(array $decorators)</code></para></listitem>
  13351. </itemizedlist>
  13352. </listitem>
  13353. <listitem><para>Validación</para>
  13354. <itemizedlist>
  13355. <listitem><para><code>populate(array $values)</code></para></listitem>
  13356. <listitem><para><code>isValid(array $data)</code></para></listitem>
  13357. <listitem><para><code>isValidPartial(array $data)</code></para></listitem>
  13358. <listitem><para><code>processAjax(array $data)</code></para></listitem>
  13359. <listitem><para><code>persistData()</code></para></listitem>
  13360. <listitem><para><code>getErrors($name = null)</code></para></listitem>
  13361. <listitem><para><code>getMessages($name = null)</code></para></listitem>
  13362. </itemizedlist>
  13363. </listitem>
  13364. <listitem><para>Generadores:</para>
  13365. <itemizedlist>
  13366. <listitem><para><code>setView(Zend_View_Interface $view = null)</code></para></listitem>
  13367. <listitem><para><code>getView()</code></para></listitem>
  13368. <listitem><para><code>addDecorator($decorator, $options = null)</code></para></listitem>
  13369. <listitem><para><code>addDecorators(array $decorators)</code></para></listitem>
  13370. <listitem><para><code>setDecorators(array $decorators)</code></para></listitem>
  13371. <listitem><para><code>getDecorator($name)</code></para></listitem>
  13372. <listitem><para><code>getDecorators()</code></para></listitem>
  13373. <listitem><para><code>removeDecorator($name)</code></para></listitem>
  13374. <listitem><para><code>clearDecorators()</code></para></listitem>
  13375. <listitem><para><code>render(Zend_View_Interface $view = null)</code></para></listitem>
  13376. </itemizedlist>
  13377. </listitem>
  13378. <listitem><para>I18n:</para>
  13379. <itemizedlist>
  13380. <listitem><para><code>setTranslator(Zend_Translate_Adapter $translator = null)</code></para></listitem>
  13381. <listitem><para><code>getTranslator()</code></para></listitem>
  13382. <listitem><para><code>setDisableTranslator($flag)</code></para></listitem>
  13383. <listitem><para><code>translatorIsDisabled()</code></para></listitem>
  13384. </itemizedlist>
  13385. </listitem>
  13386. </itemizedlist>
  13387. </sect2>
  13388. <sect2 id="zend.form.forms.config">
  13389. <title>Configuración</title>
  13390. <para>
  13391. <code>Zend_Form</code> es totalmente configurable mediante
  13392. <code>setOptions()</code> y <code>setConfig()</code> (o
  13393. pasando opciones o un objeto <code>Zend_Config</code> al
  13394. constructor). Usando estos métodos, se pueden especificar elementos formulario,
  13395. grupos de visualización, decoradores, y metadatos.
  13396. </para>
  13397. <para>
  13398. Como regla general, si 'set' + la clave de opción (option key) hacen referencia a
  13399. métodos <code>Zend_Form</code>, entonces el valor proporcionado será
  13400. pasado al método. Si el accessor no existe, se asume que la clave
  13401. referencia a un atributo, y será pasado a
  13402. <code>setAttrib()</code>.
  13403. </para>
  13404. <para>
  13405. Excepciones a las reglas incluyen lo siguiente:
  13406. </para>
  13407. <itemizedlist>
  13408. <listitem><para>
  13409. <code>prefixPaths</code> será pasado a
  13410. <code>addPrefixPaths()</code>
  13411. </para></listitem>
  13412. <listitem><para>
  13413. <code>elementPrefixPaths</code> será pasado a
  13414. <code>addElementPrefixPaths()</code>
  13415. </para></listitem>
  13416. <listitem><para>
  13417. <code>displayGroupPrefixPaths</code> será pasado a
  13418. <code>addDisplayGroupPrefixPaths()</code>
  13419. </para></listitem>
  13420. <listitem>
  13421. <para>los siguientes establecedores no pueden ser determinado de ésta manera:</para>
  13422. <itemizedlist>
  13423. <listitem><para><code>setAttrib (aunque setAttribs *funcionará*)</code></para></listitem>
  13424. <listitem><para><code>setConfig</code></para></listitem>
  13425. <listitem><para><code>setDefault</code></para></listitem>
  13426. <listitem><para><code>setOptions</code></para></listitem>
  13427. <listitem><para><code>setPluginLoader</code></para></listitem>
  13428. <listitem><para><code>setSubForms</code></para></listitem>
  13429. <listitem><para><code>setTranslator</code></para></listitem>
  13430. <listitem><para><code>setView</code></para></listitem>
  13431. </itemizedlist>
  13432. </listitem>
  13433. </itemizedlist>
  13434. <para>
  13435. Como un ejemplo, aquí esta un archivo de configuración que pasa la configuración
  13436. por cada tipo de datos configurables:
  13437. </para>
  13438. <programlisting role="ini"><![CDATA[
  13439. [element]
  13440. name = "registration"
  13441. action = "/user/register"
  13442. method = "post"
  13443. attribs.class = "zend_form"
  13444. attribs.onclick = "validate(this)"
  13445. disableTranslator = 0
  13446. prefixPath.element.prefix = "My_Element"
  13447. prefixPath.element.path = "My/Element/"
  13448. elementPrefixPath.validate.prefix = "My_Validate"
  13449. elementPrefixPath.validate.path = "My/Validate/"
  13450. displayGroupPrefixPath.prefix = "My_Group"
  13451. displayGroupPrefixPath.path = "My/Group/"
  13452. elements.username.type = "text"
  13453. elements.username.options.label = "Username"
  13454. elements.username.options.validators.alpha.validator = "Alpha"
  13455. elements.username.options.filters.lcase = "StringToLower"
  13456. ; more elements, of course...
  13457. elementFilters.trim = "StringTrim"
  13458. ;elementDecorators.trim = "StringTrim"
  13459. displayGroups.login.elements.username = "username"
  13460. displayGroups.login.elements.password = "password"
  13461. displayGroupDecorators.elements.decorator = "FormElements"
  13462. displayGroupDecorators.fieldset.decorator = "Fieldset"
  13463. decorators.elements.decorator = "FormElements"
  13464. decorators.fieldset.decorator = "FieldSet"
  13465. decorators.fieldset.decorator.options.class = "zend_form"
  13466. decorators.form.decorator = "Form"
  13467. ]]>
  13468. </programlisting>
  13469. <para>
  13470. El código de arriba fácilmente puede ser abstraído a un XML o un archivo de configuración basado en arrays PHP.
  13471. </para>
  13472. </sect2>
  13473. <sect2 id="zend.form.forms.custom">
  13474. <title>Formularios personalizados</title>
  13475. <para>
  13476. Una alternativa a usar los formularios basados en configuraciones es realizar una subclase de
  13477. <code>Zend_Form</code>. Esto tiene muchos beneficios:
  13478. </para>
  13479. <itemizedlist>
  13480. <listitem><para>
  13481. Se puede centrar la prueba de su formulario facilmente para asegurar las validaciones y
  13482. generar la ejecución esperada.
  13483. </para></listitem>
  13484. <listitem><para>
  13485. Control preciso sobre los individuales elementos.
  13486. </para></listitem>
  13487. <listitem><para>
  13488. Reutilización del objeto formulario, y mejor portabilidad (no se necesita
  13489. seguir los archivos de configuración).
  13490. </para></listitem>
  13491. <listitem><para>
  13492. Implementar funcionalidad personalizada.
  13493. </para></listitem>
  13494. </itemizedlist>
  13495. <para>
  13496. El caso mas típico de uso sería el método
  13497. <code>init()</code> para determinar elementos de formulario específicos y
  13498. de configuración:
  13499. </para>
  13500. <programlisting role="php"><![CDATA[
  13501. class My_Form_Login extends Zend_Form
  13502. {
  13503. public function init()
  13504. {
  13505. $username = new Zend_Form_Element_Text('username');
  13506. $username->class = 'formtext';
  13507. $username->setLabel('Username:')
  13508. ->setDecorators(array(
  13509. array('ViewHelper',
  13510. array('helper' => 'formText')),
  13511. array('Label',
  13512. array('class' => 'label'))
  13513. ));
  13514. $password = new Zend_Form_Element_Password('password');
  13515. $password->class = 'formtext';
  13516. $password->setLabel('Username:')
  13517. ->setDecorators(array(
  13518. array('ViewHelper',
  13519. array('helper' => 'formPassword')),
  13520. array('Label',
  13521. array('class' => 'label'))
  13522. ));
  13523. $submit = new Zend_Form_Element_Submit('login');
  13524. $submit->class = 'formsubmit';
  13525. $submit->setValue('Login')
  13526. ->setDecorators(array(
  13527. array('ViewHelper',
  13528. array('helper' => 'formSubmit'))
  13529. ));
  13530. $this->addElements(array(
  13531. $username,
  13532. $password,
  13533. $submit
  13534. ));
  13535. $this->setDecorators(array(
  13536. 'FormElements',
  13537. 'Fieldset',
  13538. 'Form'
  13539. ));
  13540. }
  13541. }
  13542. ]]>
  13543. </programlisting>
  13544. <para>
  13545. Este formulario puede ser instanciado simplemente así:
  13546. </para>
  13547. <programlisting role="php"><![CDATA[
  13548. $form = new My_Form_Login();
  13549. ]]>
  13550. </programlisting>
  13551. <para>
  13552. y toda la funcionalidad está instalada y lista; no se necesitan archivos
  13553. de configuración. (Note que este ejemplo esta simplificado, no contiene
  13554. validadores o filtros para los elementos.)
  13555. </para>
  13556. <para>
  13557. Otra razón común para la extension es definir un conjunto de
  13558. decoradores por defecto. Puede hacerlo sobreescribiendo el
  13559. método <code>loadDefaultDecorators()</code>:
  13560. </para>
  13561. <programlisting role="php"><![CDATA[
  13562. class My_Form_Login extends Zend_Form
  13563. {
  13564. public function loadDefaultDecorators()
  13565. {
  13566. $this->setDecorators(array(
  13567. 'FormElements',
  13568. 'Fieldset',
  13569. 'Form'
  13570. ));
  13571. }
  13572. }
  13573. ]]>
  13574. </programlisting>
  13575. </sect2>
  13576. </sect1><!--
  13577. vim:se ts=4 sw=4 et:
  13578. -->
  13579. <sect1 id="zend.form.decorators" xml:base="module_specs/Zend_Form-Decorators.xml">
  13580. <title>Creando un personalizado marcado de formulario usando Zend_Form_Decorator</title>
  13581. <para>
  13582. Representar un objeto form es completamente opcional -- no está obligado a usar
  13583. los métodos <code>Zend_Form</code> render() en absoluto. Sin embargo, si lo hace,
  13584. los decoradores se usan para representar distintos objetos form.
  13585. </para>
  13586. <para>
  13587. Un número arbitrario de decoradores pueden estar junto a cada elemento
  13588. (elements, display groups, sub forms o el objeto form por si mismo);
  13589. Sin embargo, solo un decorador de un tipo dado puede estar al lado de cada
  13590. elemento. Los decoradores son llamados en el orden en que han sido introducidos. Dependiendo
  13591. del decorador, puede reemplazar el contenido que se ha pasado, postponerlo o
  13592. anteponerlo.
  13593. </para>
  13594. <para>
  13595. El estado del objeto es determinado a través de las opciones de configuración pasadas al constructor
  13596. o el método decorador <code>setOptions()</code>. Cuando se crean
  13597. decoradores mediante funciones <code>addDecorator()</code> o métodos relacionados,
  13598. las opciones pueden ser pasadas como argumentos al método. Esto puese ser usado para
  13599. una ubicación especifica, un separador se usa entre el contenido pasado y el
  13600. nuevo contenido generado y cualquier opción que el decorador soporte.
  13601. </para>
  13602. <para>
  13603. Antes de que el <code>render()</code> de cada decorador sea llamado, el
  13604. item actual es determinado en el decorador usando <code>setElement()</code>,
  13605. dando al decorador conocimiento del item representado. Esto permite
  13606. crear decoradores que sólo representan porciones especificas del item
  13607. -- tal como etiquetas, el valor, mensajes de error, etc. Encadenando
  13608. muchos decoradores que representan especificos segmentos, puede construir
  13609. marcados complejos representando al item entero.
  13610. </para>
  13611. <sect2 id="zend.form.decorators.operation">
  13612. <title>Operación</title>
  13613. <para>
  13614. Para configurar un decorador, pase un array de opciones o un
  13615. objeto <code>Zend_Config</code> a este constructor, a un array
  13616. <code>setOptions()</code>, o a un objeto <code>Zend_Config</code>
  13617. <code>setConfig()</code>.
  13618. </para>
  13619. <para>
  13620. Opciones estándar incluyen:
  13621. </para>
  13622. <itemizedlist>
  13623. <listitem><para>
  13624. <code>placement</code>: La ubicación puede ser cualquiera de los dos 'append' o
  13625. 'prepend' (caso insensitivo) e indica cualquier contenido
  13626. pasado a <code>render()</code> será postpuesto o
  13627. antepuesto respectivamente. En el caso de que el decorador
  13628. reemplace el contenido, esta configuración es ignorada. La configuración
  13629. por defecto es adjuntada.
  13630. </para></listitem>
  13631. <listitem><para>
  13632. <code>separator</code>: El separator es usado entre el
  13633. contenido pasado a <code>render()</code> y el nuevo contenido
  13634. generado por el decorador, o entre items generados por el
  13635. decorador (ejemplo FormElements usa el separador entre cada
  13636. item generado). En el caso que un decorador reemplace el
  13637. contenido, esta configuración puede ser ignorada. El valor por defecto
  13638. es <code>PHP_EOL</code>.
  13639. </para></listitem>
  13640. </itemizedlist>
  13641. <para>
  13642. La interface del decorador especifica los métodos para interactuar con las
  13643. opciones. Esto incluye:
  13644. </para>
  13645. <itemizedlist>
  13646. <listitem><para>
  13647. <code>setOption($key, $value)</code>: determina una sola opción.
  13648. </para></listitem>
  13649. <listitem><para>
  13650. <code>getOption($key)</code>: recuperar un solo valor de opción.
  13651. </para></listitem>
  13652. <listitem><para>
  13653. <code>getOptions()</code>: recuperar todas las opciones.
  13654. </para></listitem>
  13655. <listitem><para>
  13656. <code>removeOption($key)</code>: eliminar una sola opción.
  13657. </para></listitem>
  13658. <listitem><para>
  13659. <code>clearOptions()</code>: eliminar todas las opciones.
  13660. </para></listitem>
  13661. </itemizedlist>
  13662. <para>
  13663. Decoradores son diseñados para interactuar con varios
  13664. tipos de clases <code>Zend_Form</code>: <code>Zend_Form</code>,
  13665. <code>Zend_Form_Element</code>, <code>Zend_Form_DisplayGroup</code>,
  13666. y todas las clases derivan de ellas. El método
  13667. <code>setElement()</code> permite determinar el objeto del
  13668. decorador que esta actualmente trabajando con, y <code>getElement()</code>
  13669. es usado para recuperarlo.
  13670. </para>
  13671. <para>
  13672. Cada método decorador <code>render()</code> acepta una cadena
  13673. <code>$content</code>. Cuando el primer decorador es llamado, esta
  13674. cadena esta tipicamente vacía, mientras las subsecuentes llamadas serán
  13675. puestas. Basados en el tipo de decorador y en las opciones pasadas,
  13676. el decorador ya sea reemplazará la cadena, antenpodrá la cadena
  13677. o adjuntará la cadena; una separador opcional será usado en las
  13678. dos últimas situaciones.
  13679. </para>
  13680. </sect2>
  13681. <sect2 id="zend.form.decorators.standard">
  13682. <title>Decoradores estándar</title>
  13683. <para>
  13684. <code>Zend_Form</code> entrega muchos decoradores estándar; ver
  13685. <link linkend="zend.form.standardDecorators">el capítulo Decoradores
  13686. estándar</link> para detalles.
  13687. </para>
  13688. </sect2>
  13689. <sect2 id="zend.form.decorators.custom">
  13690. <title>Decoradores personalizados</title>
  13691. <para>
  13692. Si encuentra que sus necesidades son complejas o necesita una enorme
  13693. personalización, debería considerar crear un decorador personalizado.
  13694. </para>
  13695. <para>
  13696. Los decoradores necesitan implementar sólo
  13697. <code>Zend_Decorator_Interface</code>. La interface especifica lo
  13698. siguiente:
  13699. </para>
  13700. <programlisting role="php"><![CDATA[
  13701. interface Zend_Decorator_Interface
  13702. {
  13703. public function __construct($options = null);
  13704. public function setElement($element);
  13705. public function getElement();
  13706. public function setOptions(array $options);
  13707. public function setConfig(Zend_Config $config);
  13708. public function setOption($key, $value);
  13709. public function getOption($key);
  13710. public function getOptions();
  13711. public function removeOption($key);
  13712. public function clearOptions();
  13713. public function render($content);
  13714. }
  13715. ]]>
  13716. </programlisting>
  13717. <para>
  13718. Para hacerlo mas simple, simplemente puede extender
  13719. <code>Zend_Decorator_Abstract</code>, el cual implementa todos los métodos
  13720. excepto <code>render()</code>.
  13721. </para>
  13722. <para>
  13723. Como ejemplo, digamos que quiere reducir el número de
  13724. decoradores que utiliza, y construir un decorador compuesto que se
  13725. encargó de renderizar la etiqueta generadora, el elemento, cualquier
  13726. mensaje de error, y descripción en un <code>div</code> HTML.
  13727. Puede construir como un decorador compuesto como sigue:
  13728. </para>
  13729. <programlisting role="php"><![CDATA[
  13730. class My_Decorator_Composite extends Zend_Form_Decorator_Abstract
  13731. {
  13732. public function buildLabel()
  13733. {
  13734. $element = $this->getElement();
  13735. $label = $element->getLabel();
  13736. if ($translator = $element->getTranslator()) {
  13737. $label = $translator->translate($label);
  13738. }
  13739. if ($element->isRequired()) {
  13740. $label .= '*';
  13741. }
  13742. $label .= ':';
  13743. return $element->getView()
  13744. ->formLabel($element->getName(), $label);
  13745. }
  13746. public function buildInput()
  13747. {
  13748. $element = $this->getElement();
  13749. $helper = $element->helper;
  13750. return $element->getView()->$helper(
  13751. $element->getName(),
  13752. $element->getValue(),
  13753. $element->getAttribs(),
  13754. $element->options
  13755. );
  13756. }
  13757. public function buildErrors()
  13758. {
  13759. $element = $this->getElement();
  13760. $messages = $element->getMessages();
  13761. if (empty($messages)) {
  13762. return '';
  13763. }
  13764. return '<div class="errors">' .
  13765. $element->getView()->formErrors($messages) . '</div>';
  13766. }
  13767. public function buildDescription()
  13768. {
  13769. $element = $this->getElement();
  13770. $desc = $element->getDescription();
  13771. if (empty($desc)) {
  13772. return '';
  13773. }
  13774. return '<div class="description">' . $desc . '</div>';
  13775. }
  13776. public function render($content)
  13777. {
  13778. $element = $this->getElement();
  13779. if (!$element instanceof Zend_Form_Element) {
  13780. return $content;
  13781. }
  13782. if (null === $element->getView()) {
  13783. return $content;
  13784. }
  13785. $separator = $this->getSeparator();
  13786. $placement = $this->getPlacement();
  13787. $label = $this->buildLabel();
  13788. $input = $this->buildInput();
  13789. $errors = $this->buildErrors();
  13790. $desc = $this->buildDescription();
  13791. $output = '<div class="form element">'
  13792. . $label
  13793. . $input
  13794. . $errors
  13795. . $desc
  13796. . '</div>'
  13797. switch ($placement) {
  13798. case (self::PREPEND):
  13799. return $output . $separator . $content;
  13800. case (self::APPEND):
  13801. default:
  13802. return $content . $separator . $output;
  13803. }
  13804. }
  13805. }
  13806. ]]>
  13807. </programlisting>
  13808. <para>
  13809. Puede entonces ubicarlo en el directorio del decorador:
  13810. </para>
  13811. <programlisting role="php"><![CDATA[
  13812. // para un elemento:
  13813. $element->addPrefixPath('My_Decorator',
  13814. 'My/Decorator/',
  13815. 'decorator');
  13816. // para todos los elementos:
  13817. $form->addElementPrefixPath('My_Decorator',
  13818. 'My/Decorator/',
  13819. 'decorator');
  13820. ]]>
  13821. </programlisting>
  13822. <para>
  13823. Puede especificar este decorador como compuesto (composite) y adjuntarlo a
  13824. un elemento:
  13825. </para>
  13826. <programlisting role="php"><![CDATA[
  13827. // Sobreescribe los decoradores existentes con este otro:
  13828. $element->setDecorators(array('Composite'));
  13829. ]]>
  13830. </programlisting>
  13831. <para>
  13832. Mientras este ejemplo mostró cómo crear un decorador que genera
  13833. salidas complejas de muchas propiedades de elementos, puede también crear
  13834. decoradores que manejen un solo aspecto de un elemento; los decoradores
  13835. 'Decorator' y 'Label' son excelentes ejemplos para
  13836. esta práctica. Hacerlo le permite mezclar y combinar decoradores para llegar
  13837. a complejas salidas -- y también anular aspectos de decoración para
  13838. personalizar sus necesidades.
  13839. </para>
  13840. <para>
  13841. Por ejemplo, si quiere simplemente desplegar que un error ha ocurrido
  13842. cuando validábamos un elemento, pero no desplegar individualmente
  13843. cada uno de los mensajes de error, usted podría crear su propio
  13844. decorador 'Errores':
  13845. </para>
  13846. <programlisting role="php"><![CDATA[
  13847. class My_Decorator_Errors
  13848. {
  13849. public function render($content = '')
  13850. {
  13851. $output = '<div class="errors">El valor que proporcionó no es válido;
  13852. please try again</div>';
  13853. $placement = $this->getPlacement();
  13854. $separator = $this->getSeparator();
  13855. switch ($placement) {
  13856. case 'PREPEND':
  13857. return $output . $separator . $content;
  13858. case 'APPEND':
  13859. default:
  13860. return $content . $separator . $output;
  13861. }
  13862. }
  13863. }
  13864. ]]>
  13865. </programlisting>
  13866. <para>
  13867. En este ejemplo particular, debido al segmento del decorador final,
  13868. 'Errors', se combina como <code>Zend_Form_Decorator_Errors</code>,
  13869. será generado <emphasis>en lugar de</emphasis> el decorador
  13870. -- significa que no necesitará cambiar ningún decorador para modificar la
  13871. salida. Nombrando sus decoradores después de los decoradores existentes
  13872. estándar, usted puede modificar decoradores sin necesitad de modificar sus
  13873. elementos decoradores.
  13874. </para>
  13875. </sect2>
  13876. <sect2 id="zend.form.decorators.individual">
  13877. <title>Generando decoradores individuales</title>
  13878. <para>
  13879. Desde que los decoradores pueden capturar distintos metadatos del elemento o formulario
  13880. que ellos decoran, es a menudo útil generar un decorador individual.
  13881. Afortunadamente, esta caracteristica es posible inicializando el método
  13882. en cada tipo de clase form (forms, sub form, display group,
  13883. element).
  13884. </para>
  13885. <para>
  13886. Para hacer eso, simplemente <code>render[DecoratorName]()</code>, cuando
  13887. "[DecoratorName]" es el "nombre corto" de su decorador; opcionalmente,
  13888. puede pasar en el contenido lo que usted quiera. Por ejemplo:
  13889. </para>
  13890. <programlisting role="php"><![CDATA[
  13891. // genera el elemento decorador label:
  13892. echo $element->renderLabel();
  13893. // genera sólo el campo display group, con algún contenido:
  13894. echo $group->renderFieldset('fieldset content');
  13895. // genera sólo el formulario HTML, con algún contenido:
  13896. echo $form->renderHtmlTag('wrap this content');
  13897. ]]></programlisting>
  13898. <para>
  13899. Si el decorador no existe, una excepción es inicializada.
  13900. </para>
  13901. <para>
  13902. Esto puede ser útil particularmente cuando se genera un formulario con el
  13903. decorador ViewScript; cada elemento puede usar sus decoradores adjuntos
  13904. para generar contenido, pero con un control minucioso.
  13905. </para>
  13906. </sect2>
  13907. </sect1><!--
  13908. vim:se ts=4 sw=4 et:
  13909. -->
  13910. <sect1 id="zend.form.standardElements" xml:base="module_specs/Zend_Form-StandardElements.xml">
  13911. <title>Elementos Enviados en el Formulario Estandard de Zend Framework</title>
  13912. <para>
  13913. Zend Framework viene con clases de elementos concretos cubriendo la
  13914. mayoría de los elementos de los formularios HTML. La mayoría simplemente
  13915. especifica una vista de ayuda para usar cuando se decora el elemento,
  13916. pero varios ofrecen funcionalidad adicional. La siguiente es una lista
  13917. de todas las clases, así como también una descripción de la
  13918. funcionalidad que ofrecen.
  13919. </para>
  13920. <sect2 id="zend.form.standardElements.button">
  13921. <title>Zend_Form_Element_Button</title>
  13922. <para>
  13923. Usada para crear elementos HTML de tipo button,
  13924. <code>Zend_Form_Element_Button</code> extiende <link linkend="zend.form.standardElements.submit">Zend_Form_Element_Submit</link>,
  13925. derivandi sy funcionalidad personalizada. It specifies the 'formButton'
  13926. view helper for decoration.
  13927. </para>
  13928. <para>
  13929. Like the submit element, it uses the element's label as the element
  13930. value for display purposes; in other words, to set the text of the
  13931. button, set the value of the element. The label will be translated
  13932. if a translation adapter is present.
  13933. </para>
  13934. <para>
  13935. Because the label is used as part of the element, the button element
  13936. uses only the <link linkend="zend.form.standardDecorators.viewHelper">ViewHelper</link>
  13937. and <link linkend="zend.form.standardDecorators.dtDdWrapper">DtDdWrapper</link>
  13938. decorators.
  13939. </para>
  13940. <para>
  13941. Después de llenar o validar un formulario, se puede verificar si el
  13942. botón dado fue clickeado usando el método <code>isChecked()</code>.
  13943. </para>
  13944. </sect2>
  13945. <sect2 id="zend.form.standardElements.captcha">
  13946. <title>Zend_Form_Element_Captcha</title>
  13947. <para>
  13948. Los CAPTCHAs son usados para prevenir el envio automático de
  13949. formularios por los robots y otros procesos automatizados.
  13950. </para>
  13951. <para>
  13952. The Captcha form element allows you to specify which
  13953. <link linkend="zend.captcha.adapters">Zend_Captcha adapter</link> you
  13954. wish to utilize as a form captcha. It then sets this adapter as a
  13955. validator to the object, and uses a Captcha decorator for rendering
  13956. (which proxies to the captcha adapter).
  13957. </para>
  13958. <para>
  13959. Adapters may be any adapters in <code>Zend_Captcha</code>, as well
  13960. as any custom adapters you may have defined elsewhere. To allow
  13961. this, you may pass an additional plugin loader type key, 'CAPTCHA'
  13962. or 'captcha', when specifying a plugin loader prefix path:
  13963. </para>
  13964. <programlisting role="php"><![CDATA[
  13965. $element->addPrefixPath('My_Captcha', 'My/Captcha/', 'captcha');
  13966. ]]>
  13967. </programlisting>
  13968. <para>
  13969. Los Captcha entonces pueden ser cargados usando el método
  13970. <code>setCaptcha()</code>, el cual puede tomar una instancia
  13971. cualquiera de captcha instance, o el nombre corto del adaptador
  13972. captcha:
  13973. </para>
  13974. <programlisting role="php"><![CDATA[
  13975. // instancia concreta:
  13976. $element->setCaptcha(new Zend_Captcha_Figlet());
  13977. // Usando nombre corto:
  13978. $element->setCaptcha('Dumb');
  13979. ]]>
  13980. </programlisting>
  13981. <para>
  13982. Si desea cargar sus elementos configuración, especifique la clave
  13983. 'captcha' con un array conteniendo la clave 'captcha', o
  13984. ambas claves 'captcha' y 'captchaOptions':
  13985. </para>
  13986. <programlisting role="php"><![CDATA[
  13987. // Usindo la clave captcha simple:
  13988. $element = new Zend_Form_Element_Captcha('foo', array(
  13989. 'label' => "Please verify you're a human",
  13990. 'captcha' => array(
  13991. 'captcha' => 'Figlet',
  13992. 'wordLen' => 6,
  13993. 'timeout' => 300,
  13994. ),
  13995. ));
  13996. // Usindo captcha y captchaOptions:
  13997. $element = new Zend_Form_Element_Captcha('foo', array(
  13998. 'label' => "Please verify you're a human"
  13999. 'captcha' => 'Figlet',
  14000. 'captchaOptions' => array(
  14001. 'captcha' => 'Figlet',
  14002. 'wordLen' => 6,
  14003. 'timeout' => 300,
  14004. ),
  14005. ));
  14006. ]]>
  14007. </programlisting>
  14008. <para>
  14009. El decorador usado es determinado consultando el adaptador captcha.
  14010. Por defecto, es usado el
  14011. <link linkend="zend.form.standardDecorators.captcha">Captcha
  14012. decorator</link>, pero un adaptadpr puede especificar uno
  14013. diferente vía su método<code>getDecorator()</code>.
  14014. </para>
  14015. <para>
  14016. Como ha notado, el adaptador captcha actúa él mismo como un validador
  14017. para el elemento. Adicionalmente, el validador NotEmpty validator
  14018. no es usado y el elemento es marcado como requerido. Enla mayoría de
  14019. los casos, usted no necesitará hacer nada más para tener un captcha
  14020. presente en su formulario.
  14021. </para>
  14022. </sect2>
  14023. <sect2 id="zend.form.standardElements.checkbox">
  14024. <title>Zend_Form_Element_Checkbox</title>
  14025. <para>
  14026. Las casillas de verigicación (checkboxes) HTML le permiten devolver
  14027. un valor específico, pero básicamente operata como los booleanos:
  14028. cuando está marcada, el valor es enviado; cuando no está marcada, no se envía nada. Internamente, Zend_Form_Element_Checkbox forza este
  14029. estado.
  14030. </para>
  14031. <para>
  14032. Por defecto, si la casilla (checkbox) está marcada su valor es '1',
  14033. y si no está marcada su valor es '0'.
  14034. You can specify the values to use using the
  14035. <code>setCheckedValue()</code> and <code>setUncheckedValue()</code>
  14036. accessors, respectively. Internally, any time you set the value, if
  14037. the provided value matches the checked value, then it is set, but
  14038. any other value causes the unchecked value to be set.
  14039. </para>
  14040. <para>
  14041. Additionally, setting the value sets the <code>checked</code>
  14042. property of the checkbox. You can query this using
  14043. <code>isChecked()</code> or simply accessing the property. Using the
  14044. <code>setChecked($flag)</code> method will both set the state of the
  14045. flag as well as set the appropriate checked or unchecked value in the
  14046. element. Please use this method when setting the checked state of a
  14047. checkbox element to ensure the value is set properly.
  14048. </para>
  14049. <para>
  14050. <code>Zend_Form_Element_Checkbox</code> uses the 'formCheckbox' view
  14051. helper. The checked value is always used to populate it.
  14052. </para>
  14053. </sect2>
  14054. <sect2 id="zend.form.standardElements.file">
  14055. <title>Zend_Form_Element_File</title>
  14056. <para>
  14057. The File form element provides a mechanism for supplying file upload
  14058. fields to your form. It utilizes <link linkend="zend.file.transfer.introduction">Zend_File_Transfer</link>
  14059. internally to provide this functionality, and the
  14060. <code>FormFile</code> view helper as also the <code>File</code>
  14061. decorator to display the form element.
  14062. </para>
  14063. <para>
  14064. By default, it uses the <code>Http</code> transfer adapter, which
  14065. introspects the <code>$_FILES</code> array and allows you to attach
  14066. validators and filters. Validators and filters attached to the form
  14067. element will be attached to the transfer adapter.
  14068. </para>
  14069. <example id="zend.form.standardElements.file.usage">
  14070. <title>File form element usage</title>
  14071. <para>
  14072. The above explanation of using the File form element may seem
  14073. arcane, but actual usage is relatively trivial:
  14074. </para>
  14075. <programlisting role="php"><![CDATA[
  14076. $element = new Zend_Form_Element_File('foo');
  14077. $element->setLabel('Upload an image:')
  14078. ->setDestination('/var/www/upload');
  14079. // ensure only 1 file
  14080. $element->addValidator('Count', false, 1);
  14081. // limit to 100K
  14082. $element->addValidator('Size', false, 102400);
  14083. // only JPEG, PNG, and GIFs
  14084. $element->addValidator('Extension', false, 'jpg,png,gif');
  14085. $form->addElement($element, 'foo');
  14086. ]]>
  14087. </programlisting>
  14088. <para>
  14089. También debe asegurarse de que se ha provisto un tipo de
  14090. codificación corecto al formulario; se debe utilizar
  14091. 'multipart/form-data'. Se puede hacer esto estableciendo el
  14092. atributo 'enctype' en el formulario:
  14093. </para>
  14094. <programlisting role="php"><![CDATA[
  14095. $form->setAttrib('enctype', 'multipart/form-data');
  14096. ]]>
  14097. </programlisting>
  14098. <para>
  14099. Cuando el atributo ha sido validado exitosamente, usted debe
  14100. recibir el archivo para alamacenarlo en el destino final
  14101. usando receive(). Adicionalmente puede determinar la
  14102. ubicación final usando getFileName():
  14103. </para>
  14104. <programlisting role="php"><![CDATA[
  14105. if (!$form->isValid) {
  14106. print "Ohoh... validation error";
  14107. }
  14108. if (!$form->foo->receive()) {
  14109. print "Error receiving the file";
  14110. }
  14111. $location = $form->foo->getFileName();
  14112. ]]>
  14113. </programlisting>
  14114. </example>
  14115. <note>
  14116. <title>Ubicaciones Predeterminadas para la Carga de Archivos</title>
  14117. <para>
  14118. Por defecto, los archivos son cargados al directorio temp del
  14119. sistema.
  14120. </para>
  14121. </note>
  14122. <note>
  14123. <title>Valores de archivo</title>
  14124. <para>
  14125. Dentro de HTTP un elemento file no tiene valor. Por tanto y a
  14126. causa de razones de seguridad usted solo obtendrá el nombre del
  14127. archivo cargado llamando a getValue() y no el destino completo.
  14128. si usted necesita la información completa llame getFileName() y
  14129. le retormará el destino y nombre de archivo completo.
  14130. </para>
  14131. </note>
  14132. <para>
  14133. <code>Zend_Form_Element_File</code> soporta también archivos
  14134. múltiples. Para llamar el método <code>setMultiFile($count)</code>
  14135. usted puede establecer la cantidad de elementos file que usted desea
  14136. crear. Esto le previene de establecer la misma configuración varias
  14137. veces.
  14138. </para>
  14139. <example id="zend.form.standardElements.file.multiusage">
  14140. <title>Configuración de múltiples archivos</title>
  14141. <para>
  14142. Crear un elemento multi archivo es lo mismo que querer configurar
  14143. un elemento único. Sólo tiene que llamar a
  14144. <code>setMultiFile()</code> adicionalmente después de la creación:
  14145. </para>
  14146. <programlisting role="php"><![CDATA[
  14147. $element = new Zend_Form_Element_File('foo');
  14148. $element->setLabel('Upload an image:')
  14149. ->setDestination('/var/www/upload');
  14150. // asegura mínimo 1, maximo 3 archivos
  14151. $element->addValidator('Count', false, array('min' => 1, 'max' => 3));
  14152. // limita a 100K
  14153. $element->addValidator('Size', false, 102400);
  14154. // solo JPEG, PNG, y GIFs
  14155. $element->addValidator('Extension', false, 'jpg,png,gif');
  14156. // define 3 elementos file idénticos
  14157. $element->setMultiFile(3);
  14158. $form->addElement($element, 'foo');
  14159. ]]>
  14160. </programlisting>
  14161. <para>
  14162. En su vista usted ahora obtendrá 3 elementos para carga de
  14163. archivos idénticos los cuales comparten la misma configuración.
  14164. para obtener el conjunto de el número de archivos múltiples
  14165. simplemente llame <code>getMultiFile()</code>.
  14166. </para>
  14167. </example>
  14168. <note>
  14169. <title>Elementos File en Subformularioss</title>
  14170. <para>
  14171. Cuando usted use elementos file in subformularios debería
  14172. establecer nombres únicos.
  14173. Así, cuando usted nombre su elemento file en el subformulario1,
  14174. debe darle un nombre diferente el el subformulario2.
  14175. </para>
  14176. <para>
  14177. Tan pronto como haya dos elementos file nombrados de forma
  14178. idéntica, el segundo elemento no se mostrará o enviará.
  14179. </para>
  14180. </note>
  14181. <para>
  14182. Para limitar el tamaño del archivo, el cual es cargado por el
  14183. cliente, debe establecer el tamaño máximo de archivo que el
  14184. formulario acepta . Esto limitará eñ tamaño del archivo en el lado
  14185. del cliente configurando la opción <code>MAX_FILE_SIZE</code>
  14186. en el formulario. Tan pronto como establesca este valor usando
  14187. el método <code>setMaxFileSize($size)</code>, estó será generado
  14188. con el elemento file.
  14189. </para>
  14190. <programlisting role="php"><![CDATA[
  14191. $element = new Zend_Form_Element_File('foo');
  14192. $element->setLabel('Upload an image:')
  14193. ->setDestination('/var/www/upload')
  14194. ->addValidator('Size', false, 102400) // límite en 100K
  14195. ->setMaxFileSize(102400); // limita el tamaño del archivo en el lado del cliente
  14196. $form->addElement($element, 'foo');
  14197. ]]>
  14198. </programlisting>
  14199. <note>
  14200. <title>MaxFileSize con elementos file múltiples</title>
  14201. <para>
  14202. Cuando usted usa elementos file múltiples en los formularios tiene
  14203. que establecer el <code>MAX_FILE_SIZE</code> una sola vez.
  14204. Establecerlo otra vez sobreescribirá el valor previamente
  14205. establecido.
  14206. </para>
  14207. <para>
  14208. Note, que usted puede establecer <code>MAX_FILE_SIZE</code>
  14209. una sola ves, incluso si usas múltiples formularios.
  14210. </para>
  14211. </note>
  14212. </sect2>
  14213. <sect2 id="zend.form.standardElements.hidden">
  14214. <title>Zend_Form_Element_Hidden</title>
  14215. <para>
  14216. Los elementos Hidden simplemente injectan datos que deben ser
  14217. enviados, pero que el usuario no debe manipular.
  14218. <code>Zend_Form_Element_Hidden</code> logra esto através del uso de
  14219. el helper de vista 'formHidden'.
  14220. </para>
  14221. </sect2>
  14222. <sect2 id="zend.form.standardElements.hash">
  14223. <title>Zend_Form_Element_Hash</title>
  14224. <para>
  14225. Este elemento provee protección de ataques desde CSRF sobre
  14226. formularios, asegurando que el dato es enviado por la sesión del
  14227. usuario que generó el formulario y no por un script pillero.
  14228. La protección se logra mediante la adición de un elemento hash a
  14229. un formulario y verificandolo cuando el formulario es enviado.
  14230. </para>
  14231. <para>
  14232. El nombre del elemnto hash debe ser único. Se recomienda usar la
  14233. opción <literal>salt</literal> para el elemento, dos hashes con
  14234. el mismo nombre y diferentes salts no chocan:
  14235. </para>
  14236. <programlisting role="php"><![CDATA[
  14237. $form->addElement('hash', 'no_csrf_foo', array('salt' => 'unique'));
  14238. ]]>
  14239. </programlisting>
  14240. <para>
  14241. Puede establecer el salt más tarde usando el método
  14242. <code>setSalt($salt)</code>.
  14243. </para>
  14244. <para>
  14245. Internamente, el elemento alamacena un identificador único usando
  14246. <code>Zend_Session_Namespace</code>, y lo comprueba en el momento
  14247. que se envía (comprueba que el TTL has no espiró). El validador
  14248. 'Identical' entonces es usado para asegurarse que el hash enviado
  14249. marcha con el hash alamacenado.
  14250. </para>
  14251. <para>
  14252. El helper de vista 'formHidden' es usado par generar el elemento
  14253. en el formulario.
  14254. form.
  14255. </para>
  14256. </sect2>
  14257. <sect2 id="zend.form.standardElements.Image">
  14258. <title>Zend_Form_Element_Image</title>
  14259. <para>
  14260. Las imáagenes pueden ser usadas como elmentos de formulario, y le
  14261. permite especificar elementos gráficos como botones de formulario.
  14262. </para>
  14263. <para>
  14264. Los elementos Image necesitan una imagen fuente.
  14265. <code>Zend_Form_Element_Image</code> le permite especificar esto
  14266. usando el método de acceso <code>setImage()</code>
  14267. (o clave de configuración 'image'). Opcionalmente, también puede
  14268. especificar un valor para utilizar al momento de enviar la imagen
  14269. utilizando el método de acceso <code>setImageValue()</code>
  14270. (o clave de configuración 'imageValue'). Cuando el valor establecido
  14271. para el elemento son similares al <code>imageValue</code>, entonces
  14272. el método de acceso <code>isChecked()</code> devolverá true.
  14273. </para>
  14274. <para>
  14275. El elemento Image usa el
  14276. <link linkend="zend.form.standardDecorators.image">Decorador de
  14277. Imagen </link> para generar (así como el estandard Errors,
  14278. HtmlTag, y decorador Label). Opcionalmente, puede especificar una
  14279. etiqueta para el decorador <code>Image</code> que luego
  14280. envuelva al elemento imagen.
  14281. </para>
  14282. </sect2>
  14283. <sect2 id="zend.form.standardElements.multiCheckbox">
  14284. <title>Zend_Form_Element_MultiCheckbox</title>
  14285. <para>
  14286. A menudo tiene un conjunto de checkboxes, y desea agrupar los
  14287. resultados. Esto es como un
  14288. <link linkend="zend.form.standardElements.multiselect">Multiselect</link>,
  14289. pero en lugar de estar en una lista desplegable, necesita mostrarlos en pares checkbox/value (casilla de verificación/valor).
  14290. </para>
  14291. <para>
  14292. <code>Zend_Form_Element_MultiCheckbox</code> hace esto sencillo. Like
  14293. all other elements extending the base Multi element, you can specify
  14294. a list of options, and easily validate against that same list. The
  14295. 'formMultiCheckbox' view helper ensures that these are returned as
  14296. an array in the form submission.
  14297. </para>
  14298. <para>
  14299. By default, this element registers an <code>InArray</code> validator
  14300. which validates against the array keys of registered options. You
  14301. can disable this behavior by either calling
  14302. <code>setRegisterInArrayValidator(false)</code>, or by passing a
  14303. false value to the <code>registerInArrayValidator</code>
  14304. configuration key.
  14305. </para>
  14306. <para>
  14307. You may manipulate the various checkbox options using the following
  14308. methods:
  14309. </para>
  14310. <itemizedlist>
  14311. <listitem><para><code>addMultiOption($option, $value)</code></para></listitem>
  14312. <listitem><para><code>addMultiOptions(array $options)</code></para></listitem>
  14313. <listitem><para><code>setMultiOptions(array $options)</code>
  14314. (overwrites existing options)</para></listitem>
  14315. <listitem><para>getMultiOption($option)</para></listitem>
  14316. <listitem><para>getMultiOptions()</para></listitem>
  14317. <listitem><para><code>removeMultiOption($option)</code></para></listitem>
  14318. <listitem><para><code>clearMultiOptions()</code></para></listitem>
  14319. </itemizedlist>
  14320. <para>
  14321. To mark checked items, you need to pass an array of values to
  14322. <code>setValue()</code>. The following will check the values "bar"
  14323. and "bat":
  14324. </para>
  14325. <programlisting role="php"><![CDATA[
  14326. $element = new Zend_Form_Element_MultiCheckbox('foo', array(
  14327. 'multiOptions' => array(
  14328. 'foo' => 'Foo Option',
  14329. 'bar' => 'Bar Option',
  14330. 'baz' => 'Baz Option',
  14331. 'bat' => 'Bat Option',
  14332. );
  14333. ));
  14334. $element->setValue(array('bar', 'bat'));
  14335. ]]>
  14336. </programlisting>
  14337. <para>
  14338. Note that even when setting a single value, you must pass an array.
  14339. </para>
  14340. </sect2>
  14341. <sect2 id="zend.form.standardElements.multiselect">
  14342. <title>Zend_Form_Element_Multiselect</title>
  14343. <para>
  14344. XHTML <code>select</code> elements allow a 'multiple' attribute,
  14345. indicating multiple options may be selected for submission, instead
  14346. of the usual one. <code>Zend_Form_Element_Multiselect</code> extends
  14347. <link linkend="zend.form.standardElements.select">Zend_Form_Element_Select</link>,
  14348. and sets the <code>multiple</code> attribute to 'multiple'. Like
  14349. other classes that inherit from the base
  14350. <code>Zend_Form_Element_Multi</code> class, you can manipulate the
  14351. options for the select using:
  14352. </para>
  14353. <itemizedlist>
  14354. <listitem><para><code>addMultiOption($option, $value)</code></para></listitem>
  14355. <listitem><para><code>addMultiOptions(array $options)</code></para></listitem>
  14356. <listitem><para><code>setMultiOptions(array $options)</code>
  14357. (overwrites existing options)</para></listitem>
  14358. <listitem><para>getMultiOption($option)</para></listitem>
  14359. <listitem><para>getMultiOptions()</para></listitem>
  14360. <listitem><para><code>removeMultiOption($option)</code></para></listitem>
  14361. <listitem><para><code>clearMultiOptions()</code></para></listitem>
  14362. </itemizedlist>
  14363. <para>
  14364. If a translation adapter is registered with the form and/or element,
  14365. option values will be translated for display purposes.
  14366. </para>
  14367. <para>
  14368. By default, this element registers an <code>InArray</code> validator
  14369. which validates against the array keys of registered options. You
  14370. can disable this behavior by either calling
  14371. <code>setRegisterInArrayValidator(false)</code>, or by passing a
  14372. false value to the <code>registerInArrayValidator</code>
  14373. configuration key.
  14374. </para>
  14375. </sect2>
  14376. <sect2 id="zend.form.standardElements.password">
  14377. <title>Zend_Form_Element_Password</title>
  14378. <para>
  14379. Password elements are basically normal text elements -- except that
  14380. you typically do not want the submitted password displayed in error
  14381. messages or the element itself when the form is re-displayed.
  14382. </para>
  14383. <para>
  14384. <code>Zend_Form_Element_Password</code> achieves this by calling
  14385. <code>setObscureValue(true)</code> on each validator (ensuring that
  14386. the password is obscured in validation error messages), and using
  14387. the 'formPassword' view helper (which does not display the value
  14388. passed to it).
  14389. </para>
  14390. </sect2>
  14391. <sect2 id="zend.form.standardElements.radio">
  14392. <title>Zend_Form_Element_Radio</title>
  14393. <para>
  14394. Radio elements allow you to specify several options, of which you
  14395. need a single value returned. <code>Zend_Form_Element_Radio</code>
  14396. extends the base <code>Zend_Form_Element_Multi</code> class,
  14397. allowing you to specify a number of options, and then uses the
  14398. <code>formRadio</code> view helper to display these.
  14399. </para>
  14400. <para>
  14401. By default, this element registers an <code>InArray</code> validator
  14402. which validates against the array keys of registered options. You
  14403. can disable this behavior by either calling
  14404. <code>setRegisterInArrayValidator(false)</code>, or by passing a
  14405. false value to the <code>registerInArrayValidator</code>
  14406. configuration key.
  14407. </para>
  14408. <para>
  14409. Like all elements extending the Multi element base class, the
  14410. following methods may be used to manipulate the radio options
  14411. displayed:
  14412. </para>
  14413. <itemizedlist>
  14414. <listitem><para><code>addMultiOption($option, $value)</code></para></listitem>
  14415. <listitem><para><code>addMultiOptions(array $options)</code></para></listitem>
  14416. <listitem><para><code>setMultiOptions(array $options)</code>
  14417. (overwrites existing options)</para></listitem>
  14418. <listitem><para>getMultiOption($option)</para></listitem>
  14419. <listitem><para>getMultiOptions()</para></listitem>
  14420. <listitem><para><code>removeMultiOption($option)</code></para></listitem>
  14421. <listitem><para><code>clearMultiOptions()</code></para></listitem>
  14422. </itemizedlist>
  14423. </sect2>
  14424. <sect2 id="zend.form.standardElements.reset">
  14425. <title>Zend_Form_Element_Reset</title>
  14426. <para>
  14427. Reset buttons are typically used to clear a form, and are not part
  14428. of submitted data. However, as they serve a purpose in the display,
  14429. they are included in the standard elements.
  14430. </para>
  14431. <para>
  14432. <code>Zend_Form_Element_Reset</code> extends <link linkend="zend.form.standardElements.submit">Zend_Form_Element_Submit</link>.
  14433. As such, the label is used for the button display, and will be
  14434. translated if a translation adapter is present. It utilizes only the
  14435. 'ViewHelper' and 'DtDdWrapper' decorators, as there should never be
  14436. error messages for such elements, nor will a label be necessary.
  14437. </para>
  14438. </sect2>
  14439. <sect2 id="zend.form.standardElements.select">
  14440. <title>Zend_Form_Element_Select</title>
  14441. <para>
  14442. Select boxes are a common way of limiting to specific choices for a
  14443. given form datum. <code>Zend_Form_Element_Select</code> allows you
  14444. to generate these quickly and easily.
  14445. </para>
  14446. <para>
  14447. By default, this element registers an <code>InArray</code> validator
  14448. which validates against the array keys of registered options. You
  14449. can disable this behavior by either calling
  14450. <code>setRegisterInArrayValidator(false)</code>, or by passing a
  14451. false value to the <code>registerInArrayValidator</code>
  14452. configuration key.
  14453. </para>
  14454. <para>
  14455. As it extends the base Multi element, the following methods may be
  14456. used to manipulate the select options:
  14457. </para>
  14458. <itemizedlist>
  14459. <listitem><para><code>addMultiOption($option, $value)</code></para></listitem>
  14460. <listitem><para><code>addMultiOptions(array $options)</code></para></listitem>
  14461. <listitem><para><code>setMultiOptions(array $options)</code>
  14462. (overwrites existing options)</para></listitem>
  14463. <listitem><para>getMultiOption($option)</para></listitem>
  14464. <listitem><para>getMultiOptions()</para></listitem>
  14465. <listitem><para><code>removeMultiOption($option)</code></para></listitem>
  14466. <listitem><para><code>clearMultiOptions()</code></para></listitem>
  14467. </itemizedlist>
  14468. <para>
  14469. <code>Zend_Form_Element_Select</code> uses the 'formSelect' view
  14470. helper for decoration.
  14471. </para>
  14472. </sect2>
  14473. <sect2 id="zend.form.standardElements.submit">
  14474. <title>Zend_Form_Element_Submit</title>
  14475. <para>
  14476. Submit buttons are used to submit a form. You may use multiple
  14477. submit buttons; you can use the button used to submit the form to
  14478. decide what action to take with the data submitted.
  14479. <code>Zend_Form_Element_Submit</code> makes this decisioning easy,
  14480. by adding a <code>isChecked()</code> method; as only one button
  14481. element will be submitted by the form, after populating or
  14482. validating the form, you can call this method on each submit button
  14483. to determine which one was used.
  14484. </para>
  14485. <para>
  14486. <code>Zend_Form_Element_Submit</code> uses the label as the "value"
  14487. of the submit button, translating it if a translation adapter is
  14488. present. <code>isChecked()</code> checks the submitted value against
  14489. the label in order to determine if the button was used.
  14490. </para>
  14491. <para>
  14492. The <link linkend="zend.form.standardDecorators.viewHelper">ViewHelper</link>
  14493. and <link linkend="zend.form.standardDecorators.dtDdWrapper">DtDdWrapper</link>
  14494. decorators to render the element. No label decorator is used, as the
  14495. button label is used when rendering the element; also, typically,
  14496. you will not associate errors with a submit element.
  14497. </para>
  14498. </sect2>
  14499. <sect2 id="zend.form.standardElements.text">
  14500. <title>Zend_Form_Element_Text</title>
  14501. <para>
  14502. By far the most prevalent type of form element is the text element,
  14503. allowing for limited text entry; it's an ideal element for most data
  14504. entry. <code>Zend_Form_Element_Text</code> simply uses the
  14505. 'formText' view helper to display the element.
  14506. </para>
  14507. </sect2>
  14508. <sect2 id="zend.form.standardElements.textarea">
  14509. <title>Zend_Form_Element_Textarea</title>
  14510. <para>
  14511. Textareas are used when large quantities of text are expected, and
  14512. place no limits on the amount of text submitted (other than maximum
  14513. size limits as dictated by your server or PHP).
  14514. <code>Zend_Form_Element_Textarea</code> uses the 'textArea' view
  14515. helper to display such elements, placing the value as the content of
  14516. the element.
  14517. </para>
  14518. </sect2>
  14519. </sect1><!--
  14520. vim:se ts=4 sw=4 tw=80 et:
  14521. -->
  14522. <sect1 id="zend.form.standardDecorators" xml:base="module_specs/Zend_Form-StandardDecorators.xml">
  14523. <title>Decoradores de Formulario (Form Decorartors) estándar contenidos en Zend Framework</title>
  14524. <para>
  14525. <code>Zend_Form</code> se distribuye con distintos decoradores estándar. Para más
  14526. información sobre el uso de decoradores en general, vea <link linkend="zend.form.decorators">la sección sobre decoradores</link>.
  14527. </para>
  14528. <sect2 id="zend.form.standardDecorators.callback">
  14529. <title>Zend_Form_Decorator_Callback</title>
  14530. <para>
  14531. El decorador Callback (llamada de retorno) permite ejecutar una llamada de retorno para
  14532. mostrar el contenido. Las llamadas de retorno deben especificarse a través
  14533. de la opción 'callback' pasada en la configuración del decorador, y pueden
  14534. ser de cualquier valor de llamada de retorno PHP. Los Callbacks deben
  14535. aceptar tres argumentos: <code>$content</code> (el contenido original
  14536. enviado al decorador), <code>$element</code> (el objeto que se está decorando),
  14537. y un array de <code>$options</code>. Un callback de ejemplo sería:
  14538. </para>
  14539. <programlisting role="php"><![CDATA[
  14540. class Util
  14541. {
  14542. public static function label($content, $element, array $options)
  14543. {
  14544. return '<span class="label">' . $element->getLabel() . "</span>";
  14545. }
  14546. }
  14547. ]]>
  14548. </programlisting>
  14549. <para>
  14550. Esta llamada de retorno se especificaría como <code>array('Util',
  14551. 'label')</code>, y generaría un (mal) código HTML para
  14552. la etiqueta. El decorador Callback reemplazará, antepondrá o postpondrá
  14553. el contenido original con el que devuelva.
  14554. </para>
  14555. <para>
  14556. El decorador Callback permite especificar un valor null para la opción
  14557. placement (colocación), que reemplazará el contenido original
  14558. con el valor devuelto de la llamada de retorno; 'prepend' (anteponer) y 'append' (postponer)
  14559. siguen siendo válidas.
  14560. </para>
  14561. </sect2>
  14562. <sect2 id="zend.form.standardDecorators.captcha">
  14563. <title>Zend_Form_Decorator_Captcha</title>
  14564. <para>
  14565. El decorador Captcha se usa junto con el <link linkend="zend.form.standardElements.captcha">elemento de formulario Captcha</link>. Utiliza el método
  14566. <code>render()</code> del adaptador del captcha para generar la salida.
  14567. </para>
  14568. <para>
  14569. Una variante del decorador Captcha, 'Captcha_Word', es usada frecuentemente,
  14570. y crea dos elementos, un id y una entrada (input). El id indica
  14571. el identificador de sesión que hay que comparar, y la entrada es para
  14572. la verificación de usuario del captcha. Éstos elementos son validados
  14573. como un sólo elemento.
  14574. </para>
  14575. </sect2>
  14576. <sect2 id="zend.form.standardDecorators.description">
  14577. <title>Zend_Form_Decorator_Description</title>
  14578. <para>
  14579. El decorador Description puede ser usado para mostrar un conjunto de descripciones
  14580. de un elemento <code>Zend_Form</code>, <code>Zend_Form_Element</code>, o
  14581. <code>Zend_Form_DisplayGroup</code>; toma la descripción usando el método
  14582. <code>getDescription()</code> del objeto.
  14583. </para>
  14584. <para>
  14585. Por defecto, si no se encuentra la descripción, no se genera ninguna salida.
  14586. Si la descripción está presente, entonces se envolverá en una etiqueta
  14587. <code>p</code> HTML por defecto, aunque tiene la posibilidad de especificar
  14588. una etiqueta pasando una opción <code>tag</code> al crear el decorador, o
  14589. llamando a <code>setTag()</code>. También puede especificar una clase
  14590. para el tag usando la opción <code>class</code> o llamando a
  14591. <code>setClass()</code>; por defecto, se usa la clase 'hint'.
  14592. </para>
  14593. <para>
  14594. La descripción es escapada utilizando los mecanismos de escapado por defecto
  14595. del objeto de vista. Puede desactivar esto pasando un valor
  14596. <code>false</code> a la opción 'escape' del decorador o el método
  14597. <code>setEscape()</code>.
  14598. </para>
  14599. </sect2>
  14600. <sect2 id="zend.form.standardDecorators.dtDdWrapper">
  14601. <title>Zend_Form_Decorator_DtDdWrapper</title>
  14602. <para>
  14603. Los decoradores por defecto utilizan listas de definición
  14604. (<code>&lt;dl&gt;</code>) para generar elementos de formulario (form).
  14605. Dato que los elementos de formulario pueden aparecer en cualquier orden,
  14606. grupos de visualización y subformularios pueden ser encapsulados dentro de
  14607. otros elementos de formulario. Para mantener estos tipos de elemento particulares
  14608. dentro de la lista de definición, DtDdWrapper crea una nuevo término de definición
  14609. vacío (definition term)(<code>&lt;dt&gt;</code>) y encapsula su contenido
  14610. en un nuevo dato de definición (<code>&lt;dd&gt;</code>).
  14611. La salida queda como sigue:
  14612. </para>
  14613. <programlisting role="html"><![CDATA[
  14614. <dt></dt>
  14615. <dd><fieldset id="subform">
  14616. <legend>Información de Usuario</legend>
  14617. ...
  14618. </fieldset></dd>
  14619. ]]>
  14620. </programlisting>
  14621. <para>
  14622. Este decorador reemplaza el contenido que se le provee
  14623. envolviéndolo dentro del elemento <code>&lt;dd&gt;</code>.
  14624. </para>
  14625. </sect2>
  14626. <sect2 id="zend.form.standardDecorators.errors">
  14627. <title>Zend_Form_Decorator_Errors</title>
  14628. <para>
  14629. Los errores de elemento obtienen su propio decorador con el decorador
  14630. de errores. Este decorador sustituye al view helper FormErrors,
  14631. que genera mensajes de error en una lista no ordenada
  14632. (<code>&lt;ul&gt;</code>) como elementos de lista (li). El elemento
  14633. <code>&lt;ul&gt;</code> recibe una clase de "errores".
  14634. </para>
  14635. <para>
  14636. El decorador de Errores puede anteponerse o postponerse al contenido
  14637. que se le provee.
  14638. </para>
  14639. </sect2>
  14640. <sect2 id="zend.form.standardDecorators.fieldset">
  14641. <title>Zend_Form_Decorator_Fieldset</title>
  14642. <para>
  14643. Por defecto, los grupos de visualización y subformularios generan sus contenidos dentro
  14644. de fieldsets, EL decorador Fieldset busca la opción
  14645. 'legend' o bien el método <code>getLegend()</code> en el elemento
  14646. registrado, y lo usa como campo "legend" si no es vacío. Cualquier
  14647. contenido pasado es envuelto en el fieldset HTML, reemplazando
  14648. al contenido original. Cualquier atributo pasado al elemento decorado
  14649. será generado como atributo del fieldset HTML.
  14650. </para>
  14651. </sect2>
  14652. <sect2 id="zend.form.standardDecorators.file">
  14653. <title>Zend_Form_Decorator_File</title>
  14654. <para>
  14655. Los elementos de tipo "File" (upload de ficheros) tienen una notación especial
  14656. cuando se usan múltiples elementos file o subformularios. El decorador
  14657. File es usado por <code>Zend_Form_Element_File</code> y permite fijar
  14658. múltiples elementos file con una única llamada al método. Se usa automáticamente
  14659. y fija el nombre de cada elemento.
  14660. </para>
  14661. </sect2>
  14662. <sect2 id="zend.form.standardDecorators.form">
  14663. <title>Zend_Form_Decorator_Form</title>
  14664. <para>
  14665. Los objetos <code>Zend_Form</code> normalmente necesitan generar una etiqueta
  14666. HTML "form". El decorador Form utiliza la ayuda del view helper Form. Encapsula
  14667. cualquier contenido provista en un elemento HTML form, usando la acción y el
  14668. método del objeto Zend Form, y cualquier atributo como atributo HTML.
  14669. </para>
  14670. </sect2>
  14671. <sect2 id="zend.form.standardDecorators.formElements">
  14672. <title>Zend_Form_Decorator_FormElements</title>
  14673. <para>
  14674. Los formularios(forms), grupos de visualización y subformularios
  14675. son colecciones de elementos. Para poder generar estos elementos,
  14676. utilizan el decorador FormElements, el cual itera sobre todos los elementos,
  14677. llamando a <code>render()</code> en cada uno de ellos y uniéndolos
  14678. con el separador indicado. Puede anteponer o postponer al contenido que
  14679. se le envía.
  14680. </para>
  14681. </sect2>
  14682. <sect2 id="zend.form.standardDecorators.formErrors">
  14683. <title>Zend_Form_Decorator_FormErrors</title>
  14684. <para>
  14685. Algunos desarrolladores y diseñadores prefieren agrupar todos los
  14686. mensajes de error en la parte superior del formulario. El decorador
  14687. FormErrors le permite hacer esto.
  14688. </para>
  14689. <para>
  14690. Por defecto, la lista de errores generada tiene el siguiente marcado:
  14691. </para>
  14692. <programlisting role="html"><![CDATA[
  14693. <ul class="form-errors">
  14694. <li><b>[etiqueta de elemento o nombre]</b><ul>
  14695. <li>[mensaje de error]</li>
  14696. <li>[mensaje de error]</li>
  14697. </ul>
  14698. </li>
  14699. <li><ul>
  14700. <li><b>[etiqueta o nombre de elemento subformulario</b><ul>
  14701. <li>[mensaje de error]</li>
  14702. <li>[mensaje de error]</li>
  14703. </ul>
  14704. </li>
  14705. </ul></li>
  14706. </ul>
  14707. ]]></programlisting>
  14708. <para>
  14709. Puede pasar como parámetro varias opciones para configurar la salida generada:
  14710. </para>
  14711. <itemizedlist>
  14712. <listitem><para>
  14713. <code>ignoreSubForms</code>: se desactiva o no la recursividad
  14714. en los subformularios. Por defecto: false (i.e., permitir recursividad).
  14715. </para></listitem>
  14716. <listitem><para>
  14717. <code>markupElementLabelEnd</code>: Marcado para postponer las etiquetas de elementos. Por defecto: '&lt;/b&gt;'
  14718. </para></listitem>
  14719. <listitem><para>
  14720. <code>markupElementLabelStart</code>: Marcado para anteponer las etiquetas de elementos. Por defecto'&lt;b&gt;'
  14721. </para></listitem>
  14722. <listitem><para>
  14723. <code>markupListEnd</code>: Marcado para postponer listas de mensajes de error. Por defecto: '&lt;/ul&gt;'.
  14724. </para></listitem>
  14725. <listitem><para>
  14726. <code>markupListItemEnd</code>: Marcado para postponer mensajes de error individuales. Por defecto: '&lt;/li&gt;'
  14727. </para></listitem>
  14728. <listitem><para>
  14729. <code>markupListItemStart</code>: Marcado para anteponer mensajes de error individuales. Por defecto: '&lt;li&gt;'
  14730. </para></listitem>
  14731. <listitem><para>
  14732. <code>markupListStart</code>: Marcado para anteponer listas de mensajes de error. Por defecto: '&lt;ul class="form-errors"&gt;'
  14733. </para></listitem>
  14734. </itemizedlist>
  14735. <para>
  14736. El decorador FormErrors puede anteponerse o postponerse al contenido
  14737. que se le provee.
  14738. </para>
  14739. </sect2>
  14740. <sect2 id="zend.form.standardDecorators.htmlTag">
  14741. <title>Zend_Form_Decorator_HtmlTag</title>
  14742. <para>
  14743. El decorador HtmlTag le permite utilizar etiquetas HTML para
  14744. decorador el contenido; la etiqueta utiliza es pasada en la opción 'tag'
  14745. , y cualquier otra opción es usada como atributo HTML de esa etiqueta.
  14746. Por defecto, el contenido generado reemplaza al contenido envolviéndolo en
  14747. la etiqueta dada. De cualquier forma, se permite especificar una
  14748. localización de tipo 'append' (postponer) o 'prepend' (anteponer).
  14749. </para>
  14750. </sect2>
  14751. <sect2 id="zend.form.standardDecorators.image">
  14752. <title>Zend_Form_Decorator_Image</title>
  14753. <para>
  14754. El decorador Image le permite crear un input HTML de tipo image
  14755. (<code>&lt;input type="image" ... /&gt;</code>), y opcionalmente
  14756. mostrarlo dentro de otro tag HTML.
  14757. </para>
  14758. <para>
  14759. Por defecto, el decorador usa la propiedad src del elemento,
  14760. que puede fijarse con el método <code>setImage()</code>, como la ruta
  14761. de la imagen ('src'). Adicionalmente, la etiqueta del elemento será usada
  14762. como la etiqueta 'alt', y <code>imageValue</code> (manipulado con los
  14763. métodos <code>setImageValue()</code> y
  14764. <code>getImageValue()</code>) será usada como el campo 'value'.
  14765. </para>
  14766. <para>
  14767. Para especificar una etiqueta HTML que utilizar con el elemento, pase la opción
  14768. 'tag' al decorador, o llame explícitamente a
  14769. <code>setTag()</code>.
  14770. </para>
  14771. </sect2>
  14772. <sect2 id="zend.form.standardDecorators.label">
  14773. <title>Zend_Form_Decorator_Label</title>
  14774. <para>
  14775. Comúnmente, los elementos de formulario tienen etiquetas (labels) y se
  14776. usa el decorador Label para generar esas etiquetas.
  14777. Utiliza la ayuda del view helper FormLabel,
  14778. y toma la etiqueta del elemento mediante el método
  14779. <code>getLabel()</code> de ese elemento. Si no se encuentra
  14780. la etiqueta, no se genera. Por defecto, las etiquetas se
  14781. traducen cuando existe un adaptador de traducciones y existe una
  14782. traducción para la etiqueta.
  14783. </para>
  14784. <para>
  14785. Opcionalmente, se puede especificar la opción 'tag'; si se suministra, encapsula
  14786. la etiqueta en la etiqueta HTML en cuestión. Si la opción está presenta
  14787. pero no hay etiqueta, la etiqueta será generada sin contenido.
  14788. Puede especificar la clase que usar con la etiqueta mediante la opción
  14789. 'class' o llamando a <code>setClass()</code>.
  14790. </para>
  14791. <para>
  14792. Adicionalmente, se pueden especificar prefijos o sufijos que usar
  14793. al mostrar en pantalla los elementos, basados en si la etiqueta es para
  14794. un elemento opcional o requerido. Por ejemplo, podríamos querer
  14795. añadir ':' a la etiqueta o un '*', indicando que el elemento es requerido.
  14796. Se puede realizar con las siguientes opciones y métodos:
  14797. </para>
  14798. <itemizedlist>
  14799. <listitem><para>
  14800. <code>optionalPrefix</code>: fija el texto antepuesto a la etiqueta
  14801. cuando el elemento es opcional. Utilice los accesores
  14802. <code>setOptionalPrefix()</code> y
  14803. <code>getOptionalPrefix()</code> para manipularlo.
  14804. </para></listitem>
  14805. <listitem><para>
  14806. <code>optionalSuffix</code>: fija el texto pospuesto a la etiqueta
  14807. cuando el elemento es opcional. Utilice los accesores
  14808. <code>setOptionalSuffix()</code> y
  14809. <code>getOptionalSuffix()</code> para manipularlo.
  14810. </para></listitem>
  14811. <listitem><para>
  14812. <code>requiredPrefix</code>: fija el texto antepuesto a la etiqueta
  14813. cuando el elemento es requerido. Utilice los accesores
  14814. <code>setRequiredPrefix()</code> y
  14815. <code>getRequiredPrefix()</code> para manipularlo.
  14816. </para></listitem>
  14817. <listitem><para>
  14818. <code>requiredSuffix</code>: fija el texto antepuesto a la etiqueta
  14819. cuando el elemento es requerido. Utilice los accesores
  14820. <code>setRequiredSuffix()</code> y
  14821. <code>getRequiredSuffix()</code> para manipularlo.
  14822. </para></listitem>
  14823. </itemizedlist>
  14824. <para>
  14825. Por defecto, el decorador Label antecede al contenido provisto;
  14826. especifique la opción 'placement' (colocación) como 'append' para
  14827. colocarlo después del contenido.
  14828. </para>
  14829. </sect2>
  14830. <sect2 id="zend.form.standardDecorators.prepareElements">
  14831. <title>Zend_Form_Decorator_PrepareElements</title>
  14832. <para>
  14833. Formularios, grupos de visualización, y subformularios son colecciones
  14834. de elementos. Al usar el decorador <link linkend="zend.form.standardDecorators.viewScript">ViewScript</link>
  14835. con un formulario o subformulario, resulta útil el poder fijar
  14836. recursívamente el objeto de vista, el traductor (translator)y todos los
  14837. nombres relacionados (determinados por la notiación de tabla del subformulario).
  14838. Esta tarea puede realizarse gracias al decorador
  14839. 'PrepareElements'. Normalmente, se indicará como el primer
  14840. decorador en al lista.
  14841. </para>
  14842. <programlisting role="php"><![CDATA[
  14843. $form->setDecorators(array(
  14844. 'PrepareElements',
  14845. array('ViewScript', array('viewScript' => 'form.phtml')),
  14846. ));
  14847. ]]></programlisting>
  14848. </sect2>
  14849. <sect2 id="zend.form.standardDecorators.viewHelper">
  14850. <title>Zend_Form_Decorator_ViewHelper</title>
  14851. <para>
  14852. La mayoría de los elementos utiliza helpers <code>Zend_View</code>
  14853. para generar el contenido, y esto se realiza con el decorador ViewHelper.
  14854. Con él, se puede especificar una etiqueta 'helper' para fijar
  14855. explicitamente el view helper que utilizar; si no se suministra ninguno,
  14856. utiliza el último segmento del nombre de clase del elemento para determinar
  14857. el helper, anteponiéndole la cadena 'form': e.g., 'Zend_Form_Element_Text'
  14858. buscaría un view helper del tipo 'formText'.
  14859. </para>
  14860. <para>
  14861. Cualquier atributo del elemento suministrado es pasado al view helper
  14862. como atributo del elemento.
  14863. </para>
  14864. <para>
  14865. Por defecto, este decorador postpone el contenido; utilice la opción 'placement'
  14866. para especificar una localización distinta.
  14867. </para>
  14868. </sect2>
  14869. <sect2 id="zend.form.standardDecorators.viewScript">
  14870. <title>Zend_Form_Decorator_ViewScript</title>
  14871. <para>
  14872. A veces es necesario usar un view script para crear elementos;
  14873. De esta forma, se puede tener un control preciso sobre los elementos;
  14874. entregar el view script a un diseñador, o simplemente crear
  14875. una forma fácil de sobreescribir basado en el módulo que se esté usando.
  14876. El decorador ViewScript soluciona este problema.
  14877. </para>
  14878. <para>
  14879. El decorador ViewScript requiere una opción 'viewScript', o bien suministrada
  14880. al decorador, o bien como atributo del elemento. Entonces genera ese script de vista como un
  14881. script parcial, lo que significa que cada llamada a él tiene su propio espacio de variables;
  14882. Ninguna variable de la vista será rellenada, aparte del elemento en sí. Distintas variables son
  14883. entonces rellenadas:
  14884. </para>
  14885. <itemizedlist>
  14886. <listitem><para>
  14887. <code>element</code>: el elemento decorado
  14888. </para></listitem>
  14889. <listitem><para>
  14890. <code>content</code>: el contenido pasado al decorador
  14891. </para></listitem>
  14892. <listitem><para>
  14893. <code>decorator</code>: el propio objeto decorador
  14894. </para></listitem>
  14895. <listitem><para>
  14896. Del mismo modo, todas las opciones pasadas al decorador a través de
  14897. <code>setOptions()</code> que no son usadas internamente (tales
  14898. como placement, separator, etc.) son pasadas como
  14899. variables de vista.
  14900. </para></listitem>
  14901. </itemizedlist>
  14902. <para>
  14903. Como ejemplo, se pueden tener el siguiente elemento:
  14904. </para>
  14905. <programlisting role="php"><![CDATA[
  14906. // Fija un decorador ViewScript a un único elemento ,
  14907. // especificando como opción el script de vista (obligatorio) y algunas opciones extra
  14908. $element->setDecorators(array(array('ViewScript', array(
  14909. 'viewScript' => '_element.phtml',
  14910. 'class' => 'form element'
  14911. ))));
  14912. // o especificando el viewScript como un atributo del elemento:
  14913. $element->viewScript = '_element.phtml';
  14914. $element->setDecorators(array(array('ViewScript',
  14915. array('class' => 'form element'))));
  14916. ]]>
  14917. </programlisting>
  14918. <para>
  14919. Un view script puede tener el siguiente aspecto:
  14920. </para>
  14921. <programlisting role="php"><![CDATA[
  14922. <div class="<?= $this->class ?>">
  14923. <?= $this->formLabel($this->element->getName(),
  14924. $this->element->getLabel()) ?>
  14925. <?= $this->{$this->element->helper}(
  14926. $this->element->getName(),
  14927. $this->element->getValue(),
  14928. $this->element->getAttribs()
  14929. ) ?>
  14930. <?= $this->formErrors($this->element->getMessages()) ?>
  14931. <div class="hint"><?= $this->element->getDescription() ?></div>
  14932. </div>
  14933. ]]>
  14934. </programlisting>
  14935. <note>
  14936. <title>Reemplazar contenido con un script de vista (view script)</title>
  14937. <para>
  14938. Resulta interesante que el script de vista reemplace el
  14939. contenido provisto por el decorador -- por ejemplo, si desea encapsularlo.
  14940. Puede hacer esto especificando un valor booleano false en la
  14941. opción 'placement' del decorador:
  14942. </para>
  14943. <programlisting role="php"><![CDATA[
  14944. // En la creación del decorador:
  14945. $element->addDecorator('ViewScript', array('placement' => false));
  14946. // Aplicado a una instancia de un decorador ya existente:
  14947. $decorator->setOption('placement', false);
  14948. // Aplicado a un decorador ya asociado a un elemento:
  14949. $element->getDecorator('ViewScript')->setOption('placement', false);
  14950. // Dentro de un view script usado por un decorador:
  14951. $this->decorator->setOption('placement', false);
  14952. ]]>
  14953. </programlisting>
  14954. </note>
  14955. <para>
  14956. Se recomienda usar el decorador ViewScript cuando necesite un control
  14957. muy preciso sobre cómo generados sus elementos.
  14958. </para>
  14959. </sect2>
  14960. </sect1><!--
  14961. vim:se ts=4 sw=4 tw=80 et:
  14962. -->
  14963. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Form-I18n.xml"/>
  14964. <sect1 id="zend.form.advanced" xml:base="module_specs/Zend_Form-Advanced.xml">
  14965. <title>Uso avanzado de Zend_Form</title>
  14966. <para>
  14967. <code>Zend_Form</code> tiene una riqueza de funcionalidad, has a wealth of functionality, muchas de ellas diregidas
  14968. a expertos desarroladores. Este capítulo tiene por objeto al documento algunas de estas
  14969. funcionalidades con ejemplos y casos de uso.
  14970. </para>
  14971. <sect2 id="zend.form.advanced.arrayNotation">
  14972. <title>Notación de array</title>
  14973. <para>
  14974. Muchos desarroladores experimentados les gusta agrupar elementos de formulario
  14975. usando notación de array en los nombres de elementos. Por ejemplo, si se tiene
  14976. dos direcciones que se desea capturar, un envio y una dirección de facturación,
  14977. se puede tener elementos identicos; agrupandolos en un array se puede
  14978. asegurar que son capturados por separado. Toma el siguiente fomrulario
  14979. por ejemplo:
  14980. </para>
  14981. <programlisting role="html"><![CDATA[
  14982. <form>
  14983. <fieldset>
  14984. <legend>Shipping Address</legend>
  14985. <dl>
  14986. <dt><label for="recipient">Ship to:</label></dt>
  14987. <dd><input name="recipient" type="text" value="" /></dd>
  14988. <dt><label for="address">Address:</label></dt>
  14989. <dd><input name="address" type="text" value="" /></dd>
  14990. <dt><label for="municipality">City:</label></dt>
  14991. <dd><input name="municipality" type="text" value="" /></dd>
  14992. <dt><label for="province">State:</label></dt>
  14993. <dd><input name="province" type="text" value="" /></dd>
  14994. <dt><label for="postal">Postal Code:</label></dt>
  14995. <dd><input name="postal" type="text" value="" /></dd>
  14996. </dl>
  14997. </fieldset>
  14998. <fieldset>
  14999. <legend>Billing Address</legend>
  15000. <dl>
  15001. <dt><label for="payer">Bill To:</label></dt>
  15002. <dd><input name="payer" type="text" value="" /></dd>
  15003. <dt><label for="address">Address:</label></dt>
  15004. <dd><input name="address" type="text" value="" /></dd>
  15005. <dt><label for="municipality">City:</label></dt>
  15006. <dd><input name="municipality" type="text" value="" /></dd>
  15007. <dt><label for="province">State:</label></dt>
  15008. <dd><input name="province" type="text" value="" /></dd>
  15009. <dt><label for="postal">Postal Code:</label></dt>
  15010. <dd><input name="postal" type="text" value="" /></dd>
  15011. </dl>
  15012. </fieldset>
  15013. <dl>
  15014. <dt><label for="terms">I agree to the Terms of Service</label></dt>
  15015. <dd><input name="terms" type="checkbox" value="" /></dd>
  15016. <dt></dt>
  15017. <dd><input name="save" type="submit" value="Save" /></dd>
  15018. </dl>
  15019. </form>
  15020. ]]>
  15021. </programlisting>
  15022. <para>
  15023. En este ejemplo, la facturación y la dirección de envío contienen algunos
  15024. campos identicos, eso significa uno puede sobre escribir al otro. Nosotros podemos
  15025. resolver esta solución usando una notación de array:
  15026. </para>
  15027. <programlisting role="html"><![CDATA[
  15028. <form>
  15029. <fieldset>
  15030. <legend>Shipping Address</legend>
  15031. <dl>
  15032. <dt><label for="shipping-recipient">Ship to:</label></dt>
  15033. <dd><input name="shipping[recipient]" id="shipping-recipient"
  15034. type="text" value="" /></dd>
  15035. <dt><label for="shipping-address">Address:</label></dt>
  15036. <dd><input name="shipping[address]" id="shipping-address"
  15037. type="text" value="" /></dd>
  15038. <dt><label for="shipping-municipality">City:</label></dt>
  15039. <dd><input name="shipping[municipality]" id="shipping-municipality"
  15040. type="text" value="" /></dd>
  15041. <dt><label for="shipping-province">State:</label></dt>
  15042. <dd><input name="shipping[province]" id="shipping-province"
  15043. type="text" value="" /></dd>
  15044. <dt><label for="shipping-postal">Postal Code:</label></dt>
  15045. <dd><input name="shipping[postal]" id="shipping-postal"
  15046. type="text" value="" /></dd>
  15047. </dl>
  15048. </fieldset>
  15049. <fieldset>
  15050. <legend>Billing Address</legend>
  15051. <dl>
  15052. <dt><label for="billing-payer">Bill To:</label></dt>
  15053. <dd><input name="billing[payer]" id="billing-payer"
  15054. type="text" value="" /></dd>
  15055. <dt><label for="billing-address">Address:</label></dt>
  15056. <dd><input name="billing[address]" id="billing-address"
  15057. type="text" value="" /></dd>
  15058. <dt><label for="billing-municipality">City:</label></dt>
  15059. <dd><input name="billing[municipality]" id="billing-municipality"
  15060. type="text" value="" /></dd>
  15061. <dt><label for="billing-province">State:</label></dt>
  15062. <dd><input name="billing[province]" id="billing-province"
  15063. type="text" value="" /></dd>
  15064. <dt><label for="billing-postal">Postal Code:</label></dt>
  15065. <dd><input name="billing[postal]" id="billing-postal"
  15066. type="text" value="" /></dd>
  15067. </dl>
  15068. </fieldset>
  15069. <dl>
  15070. <dt><label for="terms">I agree to the Terms of Service</label></dt>
  15071. <dd><input name="terms" type="checkbox" value="" /></dd>
  15072. <dt></dt>
  15073. <dd><input name="save" type="submit" value="Save" /></dd>
  15074. </dl>
  15075. </form>
  15076. ]]>
  15077. </programlisting>
  15078. <para>
  15079. In the above sample, we now get separate addresses. In the submitted
  15080. form, we'll now have three elements, the 'save' element for the
  15081. submit, and then two arrays, 'shipping' and 'billing', each with
  15082. keys for their various elements.
  15083. </para>
  15084. <para>
  15085. <code>Zend_Form</code> attempts to automate this process with its
  15086. <link linkend="zend.form.forms.subforms">sub forms</link>. By
  15087. default, sub forms render using the array notation as shown in the
  15088. previous HTML form listing, complete with ids. The array name is
  15089. based on the sub form name, with the keys based on the elements
  15090. contained in the sub form. Sub forms may be nested arbitrarily deep,
  15091. and this will create nested arrays to reflect the structure.
  15092. Additionally, the various validation routines in
  15093. <code>Zend_Form</code> honor the array structure, ensuring that your
  15094. form validates correctly, no matter how arbitrarily deep you nest
  15095. your sub forms. You need do nothing to benefit from this; this
  15096. behaviour is enabled by default.
  15097. </para>
  15098. <para>
  15099. Additionally, there are facilities that allow you to turn on array
  15100. notation conditionally, as well as specify the specific array to
  15101. which an element or collection belongs:
  15102. </para>
  15103. <itemizedlist>
  15104. <listitem>
  15105. <para>
  15106. <code>Zend_Form::setIsArray($flag)</code>: By setting the
  15107. flag true, you can indicate that an entire form should be
  15108. treated as an array. By default, the form's name will be
  15109. used as the name of the array, unless
  15110. <code>setElementsBelongTo()</code> has been called. If the
  15111. form has no specified name, or if
  15112. <code>setElementsBelongTo()</code> has not been set, this
  15113. flag will be ignored (as there is no array name to which
  15114. the elements may belong).
  15115. </para>
  15116. <para>
  15117. You may determine if a form is being treated as an array
  15118. using the <code>isArray()</code> accessor.
  15119. </para>
  15120. </listitem>
  15121. <listitem><para>
  15122. <code>Zend_Form::setElementsBelongTo($array)</code>:
  15123. Using this method, you can specify the name of an array to
  15124. which all elements of the form belong. You can determine the
  15125. name using the <code>getElementsBelongTo()</code> accessor.
  15126. </para></listitem>
  15127. </itemizedlist>
  15128. <para>
  15129. Additionally, on the element level, you can specify individual
  15130. elements may belong to particular arrays using
  15131. <code>Zend_Form_Element::setBelongsTo()</code> method.
  15132. To discover what this value is -- whether set explicitly or
  15133. implicitly via the form -- you may use the
  15134. <code>getBelongsTo()</code> accessor.
  15135. </para>
  15136. </sect2>
  15137. <sect2 id="zend.form.advanced.multiPage">
  15138. <title>Multi-Page Forms</title>
  15139. <para>
  15140. Currently, Multi-Page forms are not officially supported in
  15141. <code>Zend_Form</code>; however, most support for implementing them
  15142. is available and can be utilized with a little extra tooling.
  15143. </para>
  15144. <para>
  15145. The key to creating a multi-page form is to utilize sub forms, but
  15146. to display only one such sub form per page. This allows you to
  15147. submit a single sub form at a time and validate it, but not process
  15148. the form until all sub forms are complete.
  15149. </para>
  15150. <example id="zend.form.advanced.multiPage.registration">
  15151. <title>Registration Form Example</title>
  15152. <para>
  15153. Let's use a registration form as an example. For our purposes,
  15154. we want to capture the desired username and password on the
  15155. first page, then the user's metadata -- given name, family name,
  15156. and location -- and finally allow them to decide what mailing
  15157. lists, if any, they wish to subscribe to.
  15158. </para>
  15159. <para>
  15160. First, let's create our own form, and define several sub forms
  15161. within it:
  15162. </para>
  15163. <programlisting role="php"><![CDATA[
  15164. class My_Form_Registration extends Zend_Form
  15165. {
  15166. public function init()
  15167. {
  15168. // Create user sub form: username and password
  15169. $user = new Zend_Form_SubForm();
  15170. $user->addElements(array(
  15171. new Zend_Form_Element_Text('username', array(
  15172. 'required' => true,
  15173. 'label' => 'Username:',
  15174. 'filters' => array('StringTrim', 'StringToLower'),
  15175. 'validators' => array(
  15176. 'Alnum',
  15177. array('Regex',
  15178. false,
  15179. array('/^[a-z][a-z0-9]{2,}$/'))
  15180. )
  15181. )),
  15182. new Zend_Form_Element_Password('password', array(
  15183. 'required' => true,
  15184. 'label' => 'Password:',
  15185. 'filters' => array('StringTrim'),
  15186. 'validators' => array(
  15187. 'NotEmpty',
  15188. array('StringLength', false, array(6))
  15189. )
  15190. )),
  15191. ));
  15192. // Create demographics sub form: given name, family name, and
  15193. // location
  15194. $demog = new Zend_Form_SubForm();
  15195. $demog->addElements(array(
  15196. new Zend_Form_Element_Text('givenName', array(
  15197. 'required' => true,
  15198. 'label' => 'Given (First) Name:',
  15199. 'filters' => array('StringTrim'),
  15200. 'validators' => array(
  15201. array('Regex',
  15202. false,
  15203. array('/^[a-z][a-z0-9., \'-]{2,}$/i'))
  15204. )
  15205. )),
  15206. new Zend_Form_Element_Text('familyName', array(
  15207. 'required' => true,
  15208. 'label' => 'Family (Last) Name:',
  15209. 'filters' => array('StringTrim'),
  15210. 'validators' => array(
  15211. array('Regex',
  15212. false,
  15213. array('/^[a-z][a-z0-9., \'-]{2,}$/i'))
  15214. )
  15215. )),
  15216. new Zend_Form_Element_Text('location', array(
  15217. 'required' => true,
  15218. 'label' => 'Your Location:',
  15219. 'filters' => array('StringTrim'),
  15220. 'validators' => array(
  15221. array('StringLength', false, array(2))
  15222. )
  15223. )),
  15224. ));
  15225. // Create mailing lists sub form
  15226. $listOptions = array(
  15227. 'none' => 'No lists, please',
  15228. 'fw-general' => 'Zend Framework General List',
  15229. 'fw-mvc' => 'Zend Framework MVC List',
  15230. 'fw-auth' => 'Zend Framwork Authentication and ACL List',
  15231. 'fw-services' => 'Zend Framework Web Services List',
  15232. );
  15233. $lists = new Zend_Form_SubForm();
  15234. $lists->addElements(array(
  15235. new Zend_Form_Element_MultiCheckbox('subscriptions', array(
  15236. 'label' =>
  15237. 'Which lists would you like to subscribe to?',
  15238. 'multiOptions' => $listOptions,
  15239. 'required' => true,
  15240. 'filters' => array('StringTrim'),
  15241. 'validators' => array(
  15242. array('InArray',
  15243. false,
  15244. array(array_keys($listOptions)))
  15245. )
  15246. )),
  15247. ));
  15248. // Attach sub forms to main form
  15249. $this->addSubForms(array(
  15250. 'user' => $user,
  15251. 'demog' => $demog,
  15252. 'lists' => $lists
  15253. ));
  15254. }
  15255. }
  15256. ]]>
  15257. </programlisting>
  15258. <para>
  15259. Note that there are no submit buttons, and that we have done
  15260. nothing with the sub form decorators -- which means that by
  15261. default they will be displayed as fieldsets. We will need to be
  15262. able to override these as we display each individual sub form,
  15263. and add in submit buttons so we can actually process them --
  15264. which will also require action and method properties. Let's add
  15265. some scaffolding to our class to provide that information:
  15266. </para>
  15267. <programlisting role="php"><![CDATA[
  15268. class My_Form_Registration extends Zend_Form
  15269. {
  15270. // ...
  15271. /**
  15272. * Prepare a sub form for display
  15273. *
  15274. * @param string|Zend_Form_SubForm $spec
  15275. * @return Zend_Form_SubForm
  15276. */
  15277. public function prepareSubForm($spec)
  15278. {
  15279. if (is_string($spec)) {
  15280. $subForm = $this->{$spec};
  15281. } elseif ($spec instanceof Zend_Form_SubForm) {
  15282. $subForm = $spec;
  15283. } else {
  15284. throw new Exception('Invalid argument passed to ' .
  15285. __FUNCTION__ . '()');
  15286. }
  15287. $this->setSubFormDecorators($subForm)
  15288. ->addSubmitButton($subForm)
  15289. ->addSubFormActions($subForm);
  15290. return $subForm;
  15291. }
  15292. /**
  15293. * Add form decorators to an individual sub form
  15294. *
  15295. * @param Zend_Form_SubForm $subForm
  15296. * @return My_Form_Registration
  15297. */
  15298. public function setSubFormDecorators(Zend_Form_SubForm $subForm)
  15299. {
  15300. $subForm->setDecorators(array(
  15301. 'FormElements',
  15302. array('HtmlTag', array('tag' => 'dl',
  15303. 'class' => 'zend_form')),
  15304. 'Form',
  15305. ));
  15306. return $this;
  15307. }
  15308. /**
  15309. * Add a submit button to an individual sub form
  15310. *
  15311. * @param Zend_Form_SubForm $subForm
  15312. * @return My_Form_Registration
  15313. */
  15314. public function addSubmitButton(Zend_Form_SubForm $subForm)
  15315. {
  15316. $subForm->addElement(new Zend_Form_Element_Submit(
  15317. 'save',
  15318. array(
  15319. 'label' => 'Save and continue',
  15320. 'required' => false,
  15321. 'ignore' => true,
  15322. )
  15323. ));
  15324. return $this;
  15325. }
  15326. /**
  15327. * Add action and method to sub form
  15328. *
  15329. * @param Zend_Form_SubForm $subForm
  15330. * @return My_Form_Registration
  15331. */
  15332. public function addSubFormActions(Zend_Form_SubForm $subForm)
  15333. {
  15334. $subForm->setAction('/registration/process')
  15335. ->setMethod('post');
  15336. return $this;
  15337. }
  15338. }
  15339. ]]>
  15340. </programlisting>
  15341. <para>
  15342. Next, we need to add some scaffolding in our action controller,
  15343. and have several considerations. First, we need to make sure we
  15344. persist form data between requests, so that we can determine
  15345. when to quit. Second, we need some logic to determine what form
  15346. segments have already been submitted, and what sub form to
  15347. display based on that information. We'll use
  15348. <code>Zend_Session_Namespace</code> to persist data, which will
  15349. also help us answer the question of which form to submit.
  15350. </para>
  15351. <para>
  15352. Let's create our controller, and add a method for retrieving a
  15353. form instance:
  15354. </para>
  15355. <programlisting role="php"><![CDATA[
  15356. class RegistrationController extends Zend_Controller_Action
  15357. {
  15358. protected $_form;
  15359. public function getForm()
  15360. {
  15361. if (null === $this->_form) {
  15362. $this->_form = new My_Form_Registration();
  15363. }
  15364. return $this->_form;
  15365. }
  15366. }
  15367. ]]>
  15368. </programlisting>
  15369. <para>
  15370. Now, let's add some functionality for determining which form to
  15371. display. Basically, until the entire form is considered valid,
  15372. we need to continue displaying form segments. Additionally, we
  15373. likely want to make sure they're in a particular order: user,
  15374. demog, and then lists. We can determine what data has been
  15375. submitted by checking our session namespace for particular keys
  15376. representing each subform.
  15377. </para>
  15378. <programlisting role="php"><![CDATA[
  15379. class RegistrationController extends Zend_Controller_Action
  15380. {
  15381. // ...
  15382. protected $_namespace = 'RegistrationController';
  15383. protected $_session;
  15384. /**
  15385. * Get the session namespace we're using
  15386. *
  15387. * @return Zend_Session_Namespace
  15388. */
  15389. public function getSessionNamespace()
  15390. {
  15391. if (null === $this->_session) {
  15392. $this->_session =
  15393. new Zend_Session_Namespace($this->_namespace);
  15394. }
  15395. return $this->_session;
  15396. }
  15397. /**
  15398. * Get a list of forms already stored in the session
  15399. *
  15400. * @return array
  15401. */
  15402. public function getStoredForms()
  15403. {
  15404. $stored = array();
  15405. foreach ($this->getSessionNamespace() as $key => $value) {
  15406. $stored[] = $key;
  15407. }
  15408. return $stored;
  15409. }
  15410. /**
  15411. * Get list of all subforms available
  15412. *
  15413. * @return array
  15414. */
  15415. public function getPotentialForms()
  15416. {
  15417. return array_keys($this->getForm()->getSubForms());
  15418. }
  15419. /**
  15420. * What sub form was submitted?
  15421. *
  15422. * @return false|Zend_Form_SubForm
  15423. */
  15424. public function getCurrentSubForm()
  15425. {
  15426. $request = $this->getRequest();
  15427. if (!$request->isPost()) {
  15428. return false;
  15429. }
  15430. foreach ($this->getPotentialForms() as $name) {
  15431. if ($data = $request->getPost($name, false)) {
  15432. if (is_array($data)) {
  15433. return $this->getForm()->getSubForm($name);
  15434. break;
  15435. }
  15436. }
  15437. }
  15438. return false;
  15439. }
  15440. /**
  15441. * Get the next sub form to display
  15442. *
  15443. * @return Zend_Form_SubForm|false
  15444. */
  15445. public function getNextSubForm()
  15446. {
  15447. $storedForms = $this->getStoredForms();
  15448. $potentialForms = $this->getPotentialForms();
  15449. foreach ($potentialForms as $name) {
  15450. if (!in_array($name, $storedForms)) {
  15451. return $this->getForm()->getSubForm($name);
  15452. }
  15453. }
  15454. return false;
  15455. }
  15456. }
  15457. ]]>
  15458. </programlisting>
  15459. <para>
  15460. The above methods allow us to use notations such as "<code>$subForm =
  15461. $this-&gt;getCurrentSubForm();</code>" to retrieve the current
  15462. sub form for validation, or "<code>$next =
  15463. $this-&gt;getNextSubForm();</code>" to get the next one to
  15464. display.
  15465. </para>
  15466. <para>
  15467. Now, let's figure out how to process and display the various sub
  15468. forms. We can use <code>getCurrentSubForm()</code> to determine
  15469. if any sub forms have been submitted (false return values
  15470. indicate none have been displayed or submitted), and
  15471. <code>getNextSubForm()</code> to retrieve a form to display. We
  15472. can then use the form's <code>prepareSubForm()</code> method to
  15473. ensure the form is ready for display.
  15474. </para>
  15475. <para>
  15476. When we have a form submission, we can validate the sub form,
  15477. and then check to see if the entire form is now valid. To do
  15478. these tasks, we'll need additional methods that ensure that
  15479. submitted data is added to the session, and that when validating
  15480. the form entire, we validate against all segments from the
  15481. session:
  15482. </para>
  15483. <programlisting role="php"><![CDATA[
  15484. class RegistrationController extends Zend_Controller_Action
  15485. {
  15486. // ...
  15487. /**
  15488. * Is the sub form valid?
  15489. *
  15490. * @param Zend_Form_SubForm $subForm
  15491. * @param array $data
  15492. * @return bool
  15493. */
  15494. public function subFormIsValid(Zend_Form_SubForm $subForm,
  15495. array $data)
  15496. {
  15497. $name = $subForm->getName();
  15498. if ($subForm->isValid($data)) {
  15499. $this->getSessionNamespace()->$name = $subForm->getValues();
  15500. return true;
  15501. }
  15502. return false;
  15503. }
  15504. /**
  15505. * Is the full form valid?
  15506. *
  15507. * @return bool
  15508. */
  15509. public function formIsValid()
  15510. {
  15511. $data = array();
  15512. foreach ($this->getSessionNamespace() as $key => $info) {
  15513. $data[$key] = $info;
  15514. }
  15515. return $this->getForm()->isValid($data);
  15516. }
  15517. }
  15518. ]]>
  15519. </programlisting>
  15520. <para>
  15521. Now that we have the legwork out of the way, let's build the
  15522. actions for this controller. We'll need a landing page for the
  15523. form, and then a 'process' action for processing the form.
  15524. </para>
  15525. <programlisting role="php"><![CDATA[
  15526. class RegistrationController extends Zend_Controller_Action
  15527. {
  15528. // ...
  15529. public function indexAction()
  15530. {
  15531. // Either re-display the current page, or grab the "next"
  15532. // (first) sub form
  15533. if (!$form = $this->getCurrentSubForm()) {
  15534. $form = $this->getNextSubForm();
  15535. }
  15536. $this->view->form = $this->getForm()->prepareSubForm($form);
  15537. }
  15538. public function processAction()
  15539. {
  15540. if (!$form = $this->getCurrentSubForm()) {
  15541. return $this->_forward('index');
  15542. }
  15543. if (!$this->subFormIsValid($form,
  15544. $this->getRequest()->getPost())) {
  15545. $this->view->form = $this->getForm()->prepareSubForm($form);
  15546. return $this->render('index');
  15547. }
  15548. if (!$this->formIsValid()) {
  15549. $form = $this->getNextSubForm();
  15550. $this->view->form = $this->getForm()->prepareSubForm($form);
  15551. return $this->render('index');
  15552. }
  15553. // Valid form!
  15554. // Render information in a verification page
  15555. $this->view->info = $this->getSessionNamespace();
  15556. $this->render('verification');
  15557. }
  15558. }
  15559. ]]>
  15560. </programlisting>
  15561. <para>
  15562. As you'll notice, the actual code for processing the form is
  15563. relatively simple. We check to see if we have a current sub form
  15564. submission, and if not, we go back to the landing page. If we do
  15565. have a sub form, we attempt to validate it, redisplaying it if
  15566. it fails. If the sub form is valid, we then check to see if the
  15567. form is valid, which would indicate we're done; if not, we
  15568. display the next form segment. Finally, we display a
  15569. verification page with the contents of the session.
  15570. </para>
  15571. <para>
  15572. The view scripts are very simple:
  15573. </para>
  15574. <programlisting role="php"><![CDATA[
  15575. <? // registration/index.phtml ?>
  15576. <h2>Registration</h2>
  15577. <?= $this->form ?>
  15578. <? // registration/verification.phtml ?>
  15579. <h2>Thank you for registering!</h2>
  15580. <p>
  15581. Here is the information you provided:
  15582. </p>
  15583. <?
  15584. // Have to do this construct due to how items are stored in session
  15585. // namespaces
  15586. foreach ($this->info as $info):
  15587. foreach ($info as $form => $data): ?>
  15588. <h4><?= ucfirst($form) ?>:</h4>
  15589. <dl>
  15590. <? foreach ($data as $key => $value): ?>
  15591. <dt><?= ucfirst($key) ?></dt>
  15592. <? if (is_array($value)):
  15593. foreach ($value as $label => $val): ?>
  15594. <dd><?= $val ?></dd>
  15595. <? endforeach;
  15596. else: ?>
  15597. <dd><?= $this->escape($value) ?></dd>
  15598. <? endif;
  15599. endforeach; ?>
  15600. </dl>
  15601. <? endforeach;
  15602. endforeach ?>
  15603. ]]>
  15604. </programlisting>
  15605. <para>
  15606. Upcoming releases of Zend Framework will include components to
  15607. make multi page forms simpler by abstracting the session and
  15608. ordering logic. In the meantime, the above example should serve
  15609. as a reasonable guideline on how to accomplish this task for
  15610. your site.
  15611. </para>
  15612. </example>
  15613. </sect2>
  15614. </sect1><!--
  15615. vim:se ts=4 sw=4 et:
  15616. -->
  15617. </chapter>
  15618. <chapter id="zend.gdata">
  15619. <title>Zend_Gdata</title>
  15620. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Gdata-Introduction.xml"/>
  15621. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Gdata_AuthSub.xml"/>
  15622. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Gdata_Books.xml"/>
  15623. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Gdata_ClientLogin.xml"/>
  15624. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Gdata_Calendar.xml"/>
  15625. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Gdata_Docs.xml"/>
  15626. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Gdata_Spreadsheets.xml"/>
  15627. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Gdata_Gapps.xml"/>
  15628. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Gdata_Gbase.xml"/>
  15629. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Gdata_Photos.xml"/>
  15630. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Gdata_YouTube.xml"/>
  15631. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Gdata_Exception.xml"/>
  15632. </chapter>
  15633. <chapter id="zend.http">
  15634. <title>Zend_Http</title>
  15635. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Http_Client.xml"/>
  15636. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Http_Client-Advanced.xml"/>
  15637. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Http_Client-Adapters.xml"/>
  15638. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Http_Cookie-Handling.xml"/>
  15639. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Http_Response.xml"/>
  15640. </chapter>
  15641. <chapter id="zend.infocard">
  15642. <title>Zend_InfoCard</title>
  15643. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_InfoCard-Basics.xml"/>
  15644. </chapter>
  15645. <chapter id="zend.json">
  15646. <title>Zend_Json</title>
  15647. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Json-Introduction.xml"/>
  15648. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Json-Basics.xml"/>
  15649. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Json-Objects.xml"/>
  15650. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Json-xml2json.xml"/>
  15651. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Json-Server.xml"/>
  15652. </chapter>
  15653. <chapter id="zend.layout">
  15654. <title>Zend_Layout</title>
  15655. <sect1 id="zend.layout.introduction" xml:base="module_specs/Zend_Layout-Introduction.xml">
  15656. <title>Introducción</title>
  15657. <para>
  15658. <code>Zend_Layout</code> implementa un patrón clásico "Vista en dos
  15659. etapas" (Two Step View) permitiendo a los desarrolladores colocar el
  15660. contenido de la aplicación dentro de otra vista, usualmente
  15661. representando la plantilla del sitio. Tales plantillas son a menudo
  15662. denominadas <emphasis>layouts</emphasis> por otros proyectos, y Zend
  15663. Framework ha adoptado este término por consistencia.
  15664. </para>
  15665. <para>
  15666. Los objetivos principales de <code>Zend_Layout</code> son los
  15667. siguientes:
  15668. </para>
  15669. <itemizedlist>
  15670. <listitem><para>
  15671. Automatizar la selección y renderizado de layouts cuando se usan
  15672. con los componentes MVC de Zend Framework.
  15673. </para></listitem>
  15674. <listitem><para>
  15675. Proveer ámbitos separados para variables relacionadas al diseño
  15676. y contenido.
  15677. </para></listitem>
  15678. <listitem><para>
  15679. Permitir configuraciones, incluyendo el nombre del layout,
  15680. resolución (inflexión) del script layout, y ruta del script
  15681. layout.
  15682. </para></listitem>
  15683. <listitem><para>
  15684. Permitir deshabilitar layouts, cambiar el script de diseño y
  15685. otras condiciones; permitir estas acciones dentro de los
  15686. controladores y scripts de vista.
  15687. </para></listitem>
  15688. <listitem><para>
  15689. Seguir normas de resolución similares (inflexión) como el <link linkend="zend.controller.actionhelpers.viewrenderer">ViewRenderer</link>,
  15690. pero permitiendo también el uso de normas distintas
  15691. </para></listitem>
  15692. <listitem><para>
  15693. Permitir el uso de los componentes MVC de Zend Framework.
  15694. </para></listitem>
  15695. </itemizedlist>
  15696. </sect1><!--
  15697. vim:se ts=4 sw=4 et:
  15698. -->
  15699. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Layout-QuickStart.xml"/>
  15700. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Layout-Options.xml"/>
  15701. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Layout-Advanced.xml"/>
  15702. </chapter>
  15703. <chapter id="zend.ldap">
  15704. <title>Zend_Ldap</title>
  15705. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Ldap.xml"/>
  15706. </chapter>
  15707. <chapter id="zend.loader">
  15708. <title>Zend_Loader</title>
  15709. <!-- versión 12819 --><sect1 id="zend.loader.load" xml:base="module_specs/Zend_Loader.xml">
  15710. <title>Cargando archivos y clases dinámicamente</title>
  15711. <para>
  15712. La clase Zend_Loader incluye métodos para ayudar a cargar archivos
  15713. dinámicamente.
  15714. </para>
  15715. <tip>
  15716. <title>Zend_Loader vs. require_once()</title>
  15717. <para>
  15718. Los métodos de <code>Zend_Loader</code> tienen más utilidad si el
  15719. nombre de archivo que necesita cargar es variable. Por ejemplo,
  15720. si éste se basa en un parametro de entrada del usuario o argumento
  15721. de un método. Si carga un archivo o clase cuyo nombre es constante, no
  15722. hay ningún beneficio al usar <code>Zend_Loader</code> sobre el uso
  15723. de funciones tradicionales de PHP como
  15724. <ulink url="http://php.net/require_once"><code>require_once()</code></ulink>.
  15725. </para>
  15726. </tip>
  15727. <sect2 id="zend.loader.load.file">
  15728. <title>Cargando Archivos</title>
  15729. <para>
  15730. El método estático <code>Zend_Loader::loadFile()</code> carga un archivo
  15731. PHP. El archivo cargado puede contener cualquier código PHP.
  15732. El método se comporta como un envoltorio para la función PHP
  15733. <ulink url="http://php.net/include"><code>include()</code></ulink>.
  15734. Este método devuelve un booleano false en caso de fallo, por ejemplo,
  15735. si el archivo especificado no existe.
  15736. </para>
  15737. <example id="zend.loader.load.file.example">
  15738. <title>Ejemplo del Método loadFile()</title>
  15739. <programlisting role="php"><![CDATA[
  15740. Zend_Loader::loadFile($filename, $dirs=null, $once=false);
  15741. ]]>
  15742. </programlisting>
  15743. </example>
  15744. <para>
  15745. El argumento <code>$filename</code> especifica el archivo que se va a cargar,
  15746. el cual no debe contener ninguna información de rutas.
  15747. Una verificación de seguridad es efectuada sobre <code>$filename</code>.
  15748. El archivo <code>$filename</code> sólo puede contener caracteres alfanuméricos,
  15749. guiones ("-"), barras bajas ("_"), o puntos (".").
  15750. No hay ninguna restricción en el argumento <code>$dirs</code>.
  15751. </para>
  15752. <para>
  15753. El parámetro <code>$dirs</code> especifica en qué carpetas buscar el archivo.
  15754. Si el valor es <code>NULL</code>, sólo se buscará en el <code>include_path</code>
  15755. ; si el valor es un string o un array, se buscará en la carpeta o carpetas especificadas
  15756. , seguidas del <code>include_path</code>.
  15757. </para>
  15758. <para>
  15759. El argumento <code>$once</code> es un booleano. Si es <code>TRUE</code>,
  15760. <code>Zend_Loader::loadFile()</code> esa la función PHP
  15761. <ulink url="http://php.net/include"><code>include_once()</code></ulink>
  15762. para cargar el archivo, de lo contrario se utiliza la función PHP
  15763. <ulink url="http://php.net/include_once"><code>include()</code></ulink>.
  15764. </para>
  15765. </sect2>
  15766. <sect2 id="zend.loader.load.class">
  15767. <title>Cargando Clases</title>
  15768. <para>
  15769. El método estático <code>Zend_Loader::loadClass($class, $dirs)</code>
  15770. carga un archivo PHP y comprueba la existencia de la clase.
  15771. </para>
  15772. <example id="zend.loader.load.class.example">
  15773. <title>Ejemplo del método loadClass()</title>
  15774. <programlisting role="php"><![CDATA[
  15775. Zend_Loader::loadClass('Container_Tree',
  15776. array(
  15777. '/home/production/mylib',
  15778. '/home/production/myapp'
  15779. )
  15780. );
  15781. ]]>
  15782. </programlisting>
  15783. </example>
  15784. <para>
  15785. La cadena que especifica la clase es convertida a una ruta relativa sustituyendo las barras
  15786. bajas (_) por el separador de carpeta de su Sistema Operativo, y añadiendo
  15787. '.php'. En el ejemplo de arriba, 'Container_Tree' se convierte en 'Container/Tree.php' en Windows.
  15788. </para>
  15789. <para>
  15790. Si <code>$dirs</code> es una cadena o un array,
  15791. <code>Zend_Loader::loadClass()</code> busca las carpetas en el
  15792. orden suministrado. El primer archivo encontrado es cargado. Si el archivo
  15793. no existe en el <code>$dirs</code> especificado, entonces se busca en el
  15794. <code>include_path</code> del entorno PHP.
  15795. </para>
  15796. <para>
  15797. Si el archivo no es encontrado o la clase no existe después de la carga,
  15798. <code>Zend_Loader::loadClass()</code> lanza una <code>Zend_Exception</code>.
  15799. </para>
  15800. <para>
  15801. <code>Zend_Loader::loadFile()</code> se usa para cargar, así que
  15802. el nombre de la clase puede contener únicamente caracteres alfanuméricos,
  15803. guiones ('-'), barras bajas ('_'), y puntos ('.').
  15804. </para>
  15805. </sect2>
  15806. <sect2 id="zend.loader.load.isreadable">
  15807. <title>Comprobando si un Archivo Puede Ser Leído</title>
  15808. <para>
  15809. El método estático <code>Zend_Loader::isReadable($pathname)</code>
  15810. devuelve <code>TRUE</code> si el archivo en la ruta $pathname existe
  15811. y tiene permisos de lectura, <code>FALSE</code> en caso contrario.
  15812. </para>
  15813. <example id="zend.loader.load.isreadable.example">
  15814. <title>Ejemplo del método isReadable()</title>
  15815. <programlisting role="php"><![CDATA[
  15816. if (Zend_Loader::isReadable($filename)) {
  15817. // hace algo con $filename
  15818. }
  15819. ]]>
  15820. </programlisting>
  15821. </example>
  15822. <para>
  15823. El argumento <code>$filename</code> especifica el nombre de archivo que
  15824. comprobar. Puede contener información de la ruta.
  15825. Este método envuelve la función PHP
  15826. <ulink url="http://php.net/is_readable"><code>is_readable()</code></ulink>.
  15827. La función PHP no busca en <code>include_path</code>,
  15828. mientras que <code>Zend_Loader::isReadable()</code> sí.
  15829. </para>
  15830. </sect2>
  15831. <sect2 id="zend.loader.load.autoload">
  15832. <title>Usando el Autoloader</title>
  15833. <para>
  15834. La clase <code>Zend_Loader</code> contiene un método que se puede registrar
  15835. con PHP SPL autoloader. <code>Zend_Loader::autoload()</code> es el método
  15836. callback. Por comodidad, <code>Zend_Loader</code> permite a la función
  15837. <code>registerAutoload()</code> registrar su método
  15838. <code>autoload()</code>. Si la extensión <code>spl_autoload</code>
  15839. no está presente en el entorno PHP, entonces el método
  15840. <code>registerAutoload()</code> lanza una <code>Zend_Exception</code>.
  15841. </para>
  15842. <example id="zend.loader.load.autoload.example">
  15843. <title>Ejemplo de registro del método callback del autoloader</title>
  15844. <programlisting role="php"><![CDATA[
  15845. Zend_Loader::registerAutoload();
  15846. ]]>
  15847. </programlisting>
  15848. </example>
  15849. <para>
  15850. Después de registrar el callback de autoload de Zend Framework, se pueden
  15851. referenciar clases de Zend Framework sin tener que cargarlas
  15852. explícitamente. El método <code>autoload()</code> usa automáticamente
  15853. <code>Zend_Loader::loadClass()</code> cuando referencie una clase.
  15854. </para>
  15855. <para>
  15856. Si ha extendido la clase <code>Zend_Loader</code>, se puede pasar un
  15857. argumento opcional a <code>registerAutoload()</code>, para especificar
  15858. la clase a partir de la cual registrar un método <code>autoload()</code>.
  15859. </para>
  15860. <example id="zend.loader.load.autoload.example-extended">
  15861. <title>Ejemplo de registro del método de callback autoload desde una clase
  15862. extendida</title>
  15863. <para>
  15864. Debido a la semántica de referencia de funciones estáticas en PHP,
  15865. se debe implementar código tanto para la clase <code>loadClass()</code>
  15866. como <code>autoload()</code>, y <code>autoload()</code>
  15867. debe llamar a <code>self::loadClass()</code>. Si su método
  15868. <code>autoload()</code> delega en su padre la llamada a
  15869. <code>self::loadClass()</code>, entonces llamará
  15870. al método con ese nombre en la clase padre, no la subclase.
  15871. </para>
  15872. <programlisting role="php"><![CDATA[
  15873. class My_Loader extends Zend_Loader
  15874. {
  15875. public static function loadClass($class, $dirs = null)
  15876. {
  15877. parent::loadClass($class, $dirs);
  15878. }
  15879. public static function autoload($class)
  15880. {
  15881. try {
  15882. self::loadClass($class);
  15883. return $class;
  15884. } catch (Exception $e) {
  15885. return false;
  15886. }
  15887. }
  15888. }
  15889. Zend_Loader::registerAutoload('My_Loader');
  15890. ]]>
  15891. </programlisting>
  15892. </example>
  15893. <para>
  15894. Se puede eliminar un callback de autoload.
  15895. <code>registerAutoload()</code> tiene un segundo parámetro opcional,
  15896. que es <code>true</code> por defecto. Si este parámetro es
  15897. <code>false</code>, el callback de autoload será borrado de la pila
  15898. de autoload SPL.
  15899. </para>
  15900. </sect2>
  15901. </sect1><!--
  15902. vim:se ts=4 sw=4 et:
  15903. -->
  15904. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Loader-PluginLoader.xml"/>
  15905. </chapter>
  15906. <chapter id="zend.locale">
  15907. <title>Zend_Locale</title>
  15908. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Locale-Introduction.xml"/>
  15909. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Locale-Functions.xml"/>
  15910. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Locale-Parsing.xml"/>
  15911. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Locale-DatesTimes.xml"/>
  15912. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Locale-AppendixLanguages.xml"/>
  15913. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Locale-Migration.xml"/>
  15914. </chapter>
  15915. <chapter id="zend.log">
  15916. <title>Zend_Log</title>
  15917. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Log-Overview.xml"/>
  15918. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Log-Writers.xml" parse="xml"/>
  15919. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Log-Formatters.xml"/>
  15920. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Log-Filters.xml"/>
  15921. </chapter>
  15922. <chapter id="zend.mail">
  15923. <title>Zend_Mail</title>
  15924. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Mail-Introduction.xml"/>
  15925. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Mail-Sending.xml"/>
  15926. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Mail-MultipleEmails.xml"/>
  15927. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Mail-DifferentTransports.xml"/>
  15928. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Mail-HtmlMails.xml"/>
  15929. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Mail-Attachments.xml"/>
  15930. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Mail-AddingRecipients.xml"/>
  15931. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Mail-Boundary.xml"/>
  15932. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Mail-AdditionalHeaders.xml"/>
  15933. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Mail-CharacterSets.xml"/>
  15934. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Mail-Encoding.xml"/>
  15935. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Mail-SmtpAuthentication.xml"/>
  15936. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Mail-SmtpSecure.xml"/>
  15937. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Mail_Read.xml"/>
  15938. </chapter>
  15939. <chapter id="zend.measure">
  15940. <title>Zend_Measure</title>
  15941. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Measure-Introduction.xml"/>
  15942. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Measure-Creation.xml"/>
  15943. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Measure-Output.xml"/>
  15944. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Measure-Edit.xml"/>
  15945. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Measure-Types.xml"/>
  15946. </chapter>
  15947. <chapter id="zend.memory">
  15948. <title>Zend_Memory</title>
  15949. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Memory-Overview.xml"/>
  15950. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Memory-MemoryManager.xml"/>
  15951. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Memory-MemoryObjects.xml"/>
  15952. </chapter>
  15953. <chapter id="zend.mime">
  15954. <title>Zend_Mime</title>
  15955. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Mime.xml"/>
  15956. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Mime_Message.xml"/>
  15957. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Mime_Part.xml"/>
  15958. </chapter>
  15959. <chapter id="zend.openid">
  15960. <title>Zend_OpenId</title>
  15961. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_OpenId-Introduction.xml"/>
  15962. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_OpenId-Consumer.xml"/>
  15963. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_OpenId-Provider.xml"/>
  15964. </chapter>
  15965. <chapter id="zend.paginator">
  15966. <title>Zend_Paginator</title>
  15967. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Paginator-Introduction.xml"/>
  15968. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Paginator-Usage.xml"/>
  15969. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Paginator-Configuration.xml"/>
  15970. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Paginator-Advanced.xml"/>
  15971. </chapter>
  15972. <chapter id="zend.pdf">
  15973. <title>Zend_Pdf</title>
  15974. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Pdf-Introduction.xml"/>
  15975. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Pdf-Create.xml"/>
  15976. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Pdf-Save.xml"/>
  15977. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Pdf-Pages.xml"/>
  15978. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Pdf-Drawing.xml"/>
  15979. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Pdf-Properties.xml"/>
  15980. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Pdf-Usage.xml"/>
  15981. </chapter>
  15982. <chapter id="zend.progressbar">
  15983. <title>Zend_ProgressBar</title>
  15984. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_ProgressBar.xml"/>
  15985. </chapter>
  15986. <chapter id="zend.registry">
  15987. <title>Zend_Registry</title>
  15988. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Registry.xml"/>
  15989. </chapter>
  15990. <chapter id="zend.rest">
  15991. <title>Zend_Rest</title>
  15992. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Rest.xml"/>
  15993. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Rest_Client.xml"/>
  15994. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Rest_Server.xml"/>
  15995. </chapter>
  15996. <chapter id="zend.search.lucene">
  15997. <title>Zend_Search_Lucene</title>
  15998. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Search_Lucene-Overview.xml"/>
  15999. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Search_Lucene-IndexCreation.xml"/>
  16000. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Search_Lucene-Searching.xml"/>
  16001. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Search_Lucene-QueryLanguage.xml"/>
  16002. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Search_Lucene-Queries.xml"/>
  16003. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Search_Lucene-Charset.xml"/>
  16004. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Search_Lucene-Extending.xml"/>
  16005. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Search_Lucene-JavaLucene.xml"/>
  16006. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Search_Lucene-Advanced.xml"/>
  16007. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Search_Lucene-BestPractice.xml"/>
  16008. </chapter>
  16009. <chapter id="zend.server">
  16010. <title>Zend_Server</title>
  16011. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Server.xml"/>
  16012. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Server_Reflection.xml"/>
  16013. </chapter>
  16014. <chapter id="zend.service">
  16015. <title>Zend_Service</title>
  16016. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Service.xml"/>
  16017. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Service_Akismet.xml"/>
  16018. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Service_Amazon.xml"/>
  16019. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Service_Audioscrobbler.xml"/>
  16020. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Service_Delicious.xml"/>
  16021. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Service_Flickr.xml"/>
  16022. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Service_Nirvanix.xml"/>
  16023. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Service-ReCaptcha.xml"/>
  16024. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Service_Simpy.xml"/>
  16025. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Service_SlideShare.xml"/>
  16026. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Service_StrikeIron-Overview.xml"/>
  16027. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Service_StrikeIron-BundledServices.xml"/>
  16028. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Service_StrikeIron-AdvancedUses.xml"/>
  16029. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Service_Technorati.xml"/>
  16030. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Service_Twitter.xml" parse="xml"/>
  16031. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Service_Yahoo.xml"/>
  16032. </chapter>
  16033. <chapter id="zend.session">
  16034. <title>Zend_Session</title>
  16035. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Session-Introduction.xml"/>
  16036. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Session-BasicUsage.xml"/>
  16037. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Session-AdvancedUsage.xml"/>
  16038. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Session-GlobalSessionManagement.xml"/>
  16039. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Session-SaveHandler-DbTable.xml"/>
  16040. </chapter>
  16041. <chapter id="zend.soap">
  16042. <title>Zend_Soap</title>
  16043. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Soap_Server.xml"/>
  16044. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Soap_Client.xml"/>
  16045. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Soap_Wsdl.xml"/>
  16046. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Soap_AutoDiscovery.xml"/>
  16047. </chapter>
  16048. <chapter id="zend.test">
  16049. <title>Zend_Test</title>
  16050. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Test.xml"/>
  16051. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Test-PHPUnit.xml" parse="xml"/>
  16052. </chapter>
  16053. <chapter id="zend.text">
  16054. <title>Zend_Text</title>
  16055. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Text_Figlet.xml"/>
  16056. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Text_Table.xml"/>
  16057. </chapter>
  16058. <chapter id="zend.timesync">
  16059. <title>Zend_TimeSync</title>
  16060. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_TimeSync.xml"/>
  16061. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_TimeSync-Working.xml"/>
  16062. </chapter>
  16063. <chapter id="zend.translate">
  16064. <title>Zend_Translate</title>
  16065. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Translate-Introduction.xml"/>
  16066. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Translate-Adapters.xml"/>
  16067. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Translate-Using.xml"/>
  16068. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Translate-Migration.xml"/>
  16069. </chapter>
  16070. <chapter id="zend.uri">
  16071. <title>Zend_Uri</title>
  16072. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Uri.xml"/>
  16073. </chapter>
  16074. <chapter id="zend.validate">
  16075. <title>Zend_Validate</title>
  16076. <sect1 id="zend.validate.introduction" xml:base="module_specs/Zend_Validate.xml">
  16077. <title>Introducción</title>
  16078. <para>
  16079. Cuando se necesita validar algún tipo de dato, el componente Zend_Validate ofrece un conjunto de validadores,
  16080. como así también un sencillo mecanismo de encadenado de validaciones por el cual
  16081. múltiples validadores pueden aplicarse a un dato en un orden definido por el usuario.
  16082. </para>
  16083. <sect2 id="zend.validate.introduction.definition">
  16084. <title>¿Qué es un validador?</title>
  16085. <para>
  16086. Un validador examina su entrada con respecto a algunos requerimientos
  16087. y produce un resultado booleano si la entrada valida satisfactoriamente
  16088. con los requisitos. Si la entrada no cumple los requisitos,
  16089. un validador también podrá proporcionar información adicional
  16090. sobre que requisito(s) no son satisfechos.
  16091. </para>
  16092. <para>
  16093. Por ejemplo, una aplicación web podría requerir que un usuario ingrese
  16094. su nombre, de entre seis y doce caracteres de longitud y
  16095. que sólo puede contener caracteres alfanuméricos.
  16096. Se puede usar un validador para asegurar que los usuarios cumplan
  16097. estos requisitos.
  16098. Si el nombre de usuario elegido no cumple con uno o ambos de los requisitos,
  16099. sería útil saber cuál de estos requisitos no se cumple.
  16100. </para>
  16101. </sect2>
  16102. <sect2 id="zend.validate.introduction.using">
  16103. <title>Uso básico de validadores</title>
  16104. <para>
  16105. Habiendo definido la validación de esta manera, Zend Framework nos proporciona el fundamento
  16106. para <code>Zend_Validate_Interface</code> que define dos métodos,
  16107. <code>isValid()</code> y <code>getMessages()</code>.
  16108. El método <code>isValid()</code> realiza la validación del valor,
  16109. devolviendo <code>true</code> si y sólo si el valor pasa contra el criterio de
  16110. validación.
  16111. </para>
  16112. <para>
  16113. Si <code>isValid()</code> devuelve <code>false</code>, la función
  16114. <code>getMessages()</code> devuelve un array de mensajes explicando
  16115. el motivo(s) del fracaso de la validación. Las claves del array son
  16116. strings cortos que identifican las razones por las cuales fracasó
  16117. la validación, y los valores del array son los correspondientes mensajes
  16118. para ser leídos por un ser humano.
  16119. Las claves y los valores son dependientes de la clase; cada clase de validación
  16120. define su propio conjunto de mensajes de validación fallidas y las
  16121. claves únicas que las identifican.
  16122. Cada clase tiene también una definición <code>const</code>
  16123. que hace corresponder a cada identificador con una causa del fallo
  16124. de validación.
  16125. </para>
  16126. <note>
  16127. <para>
  16128. El método <code>getMessages()</code> devuelve información del fracaso
  16129. de la validación sólo para la llamada más reciente a <code>isValid()</code>.
  16130. Cada llamada a <code>isValid()</code> borra los mensajes y errores
  16131. causados por una llamada anterior <code>isValid()</code>, porque es
  16132. probable que cada llamada a <code>isValid()</code> se refiera al valor de una entrada diferente.
  16133. </para>
  16134. </note>
  16135. <para>
  16136. El siguiente ejemplo ilustra la validación de una dirección de e-mail:
  16137. <programlisting role="php"><![CDATA[
  16138. $validator = new Zend_Validate_EmailAddress();
  16139. if ($validator->isValid($email)) {
  16140. // email parece ser válido
  16141. } else {
  16142. // email es inválido; muestre la razones
  16143. foreach ($validator->getMessages() as $messageId => $message) {
  16144. echo "Falla de validación '$messageId': $message\n";
  16145. }
  16146. }
  16147. ]]>
  16148. </programlisting>
  16149. </para>
  16150. </sect2>
  16151. <sect2 id="zend.validate.introduction.messages">
  16152. <title>Personalizar los mensajes</title>
  16153. <para>
  16154. Para validar las clases se proporciona un método <code>setMessage()</code>
  16155. con el que se puede especificar el formato de un mensaje devuelto por
  16156. <code>getMessages()</code> en caso de fallo de validación.
  16157. El primer argumento de este método es un string que contiene el mensaje
  16158. de error. Usted puede incluir tokens en este array que serán sustituidos
  16159. con datos relevantes al validador. El token <code>%value%</code> es aceptado
  16160. por todos los validadores, que es sustituido por el valor que pasó a
  16161. <code>isValid()</code>. Cada clase de validación, puede dar apoyo a otros
  16162. tokens en base a cada caso. Por ejemplo, <code>%max%</code> es un token
  16163. apoyado por <code>Zend_Validate_LessThan</code>.
  16164. El método <code>getMessageVariables()</code> devuelve un array de tokens
  16165. variables aceptados por el validador.
  16166. </para>
  16167. <para>
  16168. El segundo argumento opcional es un string que identifica la plantilla
  16169. de mensajes que se establecerá en caso del fracaso de la validación,
  16170. lo que es útil cuando una clase de validación define más de una causa para
  16171. el fallo.
  16172. Si omite el segundo argumento, <code>setMessage()</code> asume que el
  16173. mensaje que especifique debe ser utilizado por la plantilla del
  16174. primer mensaje que declaró en la clase de validación.
  16175. Muchas clases de validación sólo definen una plantilla de mensaje de
  16176. error, así que no hay necesidad de especificar el cambio de plantilla
  16177. de mensaje.
  16178. </para>
  16179. <para>
  16180. <programlisting role="php"><![CDATA[
  16181. $validator = new Zend_Validate_StringLength(8);
  16182. $validator->setMessage(
  16183. 'El string \'%value%\' es muy corto; debe tener al menos %min% ' .
  16184. 'caracteres',
  16185. Zend_Validate_StringLength::TOO_SHORT);
  16186. if (!$validator->isValid('word')) {
  16187. $messages = $validator->getMessages();
  16188. echo current($messages);
  16189. // "El string 'word' es muy corto; debe tener al menos 8 caracteres"
  16190. }
  16191. ]]>
  16192. </programlisting>
  16193. </para>
  16194. <para>
  16195. Puede establecer varios mensajes usando el método <code>setMessages()</code>.
  16196. Su argumento es un array que contiene pares de clave/mensaje.
  16197. <programlisting role="php"><![CDATA[
  16198. $validator = new Zend_Validate_StringLength(8, 12);
  16199. $validator->setMessages( array(
  16200. Zend_Validate_StringLength::TOO_SHORT =>
  16201. 'El string \'%value%\' es muy corto',
  16202. Zend_Validate_StringLength::TOO_LONG =>
  16203. 'El string \'%value%\' es muy largo'
  16204. ));
  16205. ]]>
  16206. </programlisting>
  16207. </para>
  16208. <para>
  16209. Incluso, si su aplicación requiere una mayor flexibilidad para informar
  16210. los fallos de validación, puede acceder a las propiedades por el
  16211. mismo nombre, tal como los tokens de mensajes apoyados por una determinada
  16212. clase de validación.
  16213. La propiedad <code>value</code> siempre está disponible en un validador;
  16214. es el valor que especificó en el argumento de <code>isValid()</code>.
  16215. En cada clase de validación se puede dar apoyo a otras propiedades
  16216. basándose en el esquema de caso por caso.
  16217. <programlisting role="php"><![CDATA[
  16218. $validator = new Zend_Validate_StringLength(8, 12);
  16219. if (!validator->isValid('word')) {
  16220. echo 'Palabra fallada: '
  16221. . $validator->value
  16222. . '; su longitud no está entre '
  16223. . $validator->min
  16224. . ' y '
  16225. . $validator->max
  16226. . "\n";
  16227. }
  16228. ]]>
  16229. </programlisting>
  16230. </para>
  16231. </sect2>
  16232. <sect2 id="zend.validate.introduction.static">
  16233. <title>Utilizando el método estático <code>is()</code> </title>
  16234. <para>
  16235. Si es inconveniente cargar una clase de validación y crear una
  16236. instancia del validador, puede usar el método estático
  16237. <code>Zend_Validate::is()</code> como un estilo alternativo de invocación.
  16238. El primer argumento de este método es el valor de una entrada de datos
  16239. que usted pasaría al método <code>isValid()</code>.
  16240. El segundo argumento es un string, que corresponde al nombre base
  16241. de la clase de validación, relativo al nombre de espacio <code>Zend_Validate</code>.
  16242. El método <code>is()</code> carga automáticamente la clase, crea una
  16243. instancia y aplica el método <code>isValid()</code> a la entrada de datos.
  16244. <programlisting role="php"><![CDATA[
  16245. if (Zend_Validate::is($email, 'EmailAddress')) {
  16246. // Si, el email parece ser válido
  16247. }
  16248. ]]>
  16249. </programlisting>
  16250. </para>
  16251. <para>
  16252. Si el validador lo necesita, también puede pasar un array de constructores de argumentos.
  16253. <programlisting role="php"><![CDATA[
  16254. if (Zend_Validate::is($value, 'Between', array(1, 12))) {
  16255. // Si, $value está entre 1 y 12
  16256. }
  16257. ]]>
  16258. </programlisting>
  16259. </para>
  16260. <para>
  16261. El método <code>is()</code> devuelve un valor booleano, lo mismo que
  16262. el método <code>isValid()</code>. Cuando se utiliza el método estático
  16263. <code>is()</code>, no están disponibles los mensajes de fracaso de
  16264. validación.
  16265. </para>
  16266. <para>
  16267. El uso estático puede ser conveniente para invocar un validador ad-hoc
  16268. (hecho especialmente), pero si tiene la necesidad de ejecutar el validador para múltiples
  16269. entradas, es más eficiente usar métodos no estáticos, creando una
  16270. instancia del objeto validador y llamando a su método <code>isValid()</code>.
  16271. </para>
  16272. <para>
  16273. También la clase <code>Zend_Filter_Input</code> le permite crear
  16274. ejemplos y ejecutar múltiples filtros y clases de validadores por
  16275. demanda, para procesar juegos de datos de entrada. Ver
  16276. <xref linkend="zend.filter.input"/>.
  16277. </para>
  16278. </sect2>
  16279. </sect1><!--
  16280. vim:se ts=4 sw=4 et:
  16281. -->
  16282. <sect1 xmlns:xi="http://www.w3.org/2001/XInclude" id="zend.validate.set" xml:base="module_specs/Zend_Validate-Set.xml">
  16283. <title>Clases de Validación Estándar</title>
  16284. <para>
  16285. Zend Framework viene con un conjunto estándar de clases de validación
  16286. listas para usar.
  16287. </para>
  16288. <sect2 id="zend.validate.set.alnum">
  16289. <title>Alnum</title>
  16290. <para>
  16291. Devuelve <code>true</code> si y sólo si <code>$valor</code> contiene
  16292. caracteres alfanuméricos únicamente.
  16293. Este validador incluye una opción para considerar también al espacio
  16294. en blanco como caracter válido.
  16295. </para>
  16296. </sect2>
  16297. <sect2 id="zend.validate.set.alpha">
  16298. <title>Alpha</title>
  16299. <para>
  16300. Devuelve <code>true</code> si y sólo si <code>$valor</code> sólo
  16301. contiene caracteres alfabéticos.
  16302. Este validador incluye una opción para considerar también al espacio
  16303. en blanco como caracter válido.
  16304. </para>
  16305. </sect2>
  16306. <sect2 id="zend.validate.set.barcode">
  16307. <title>Barcode</title>
  16308. <para>
  16309. Este validador es instanciado con un tipo de código de barras contra
  16310. el valor del código de barras que quiere validar.
  16311. En la actualidad acepta los tipos de código de barras "<code>UPC-A</code>"
  16312. (Universal Product Code) y "<code>EAN-13</code>" (European Article Number),
  16313. además el método <code>isValid()</code> devuelve verdadero si y solo si
  16314. la entrada valida satisfactoriamente contra el algoritmo de validación
  16315. del código de barras.
  16316. Antes de enviar los datos de entrada al validador, debe asegurarse
  16317. de eliminar todos los caracteres distintos a los dígitos cero a nueve (0-9).
  16318. </para>
  16319. </sect2>
  16320. <sect2 id="zend.validate.set.between">
  16321. <title>Between</title>
  16322. <para>
  16323. Devuelve <code>true</code> si y sólo si <code>$valor</code> está entre
  16324. los valores límites mínimo y máximo.
  16325. La comparación es inclusiva por defecto (<code>$valor</code> puede ser
  16326. igual a una valor límite), aunque esto puede ser anulado a fin de
  16327. hacer una comparación estricta, donde <code>$valor</code> debe ser
  16328. estrictamente mayor al mínimo y estrictamente menor al máximo.
  16329. </para>
  16330. </sect2>
  16331. <sect2 id="zend.validate.set.ccnum">
  16332. <title>Ccnum</title>
  16333. <para>
  16334. Devuelve <code>true</code> si y sólo si <code>$valor</code> sigue el
  16335. algoritmo Luhn (mod-10 checksum) para tarjetas de crédito.
  16336. </para>
  16337. </sect2>
  16338. <sect2 id="zend.validate.set.date">
  16339. <title>Date</title>
  16340. <para>
  16341. Devuelve <code>true</code> si y sólo si <code>$valor</code> es una
  16342. fecha válida en el formato <code>YYYY-MM-DD</code> (AAAA-MM-DD).
  16343. Si se usa la opción <code>locale</code> entonces la fecha
  16344. será validada de acuerdo a lo establecido para ese lugar.
  16345. El formato <code>format</code> es una opción que establece este
  16346. formato a ser utilizado para la validación.
  16347. Para los detalles acerca de los parámetros opcionales ver en:
  16348. <link linkend="zend.date.others.comparison.table">Zend_Date::isDate()</link>.
  16349. </para>
  16350. </sect2>
  16351. <sect2 id="zend.validate.set.digits">
  16352. <title>Digits</title>
  16353. <para>
  16354. Devuelve <code>true</code> si y sólo si <code>$valor</code> contiene
  16355. solamente dígitos.
  16356. </para>
  16357. </sect2>
  16358. <!--
  16359. <xi:include href="Zend_Validate-EmailAddress.xml" />
  16360. -->
  16361. <sect2 id="zend.validate.set.float">
  16362. <title>Float</title>
  16363. <para>
  16364. Devuelve <code>true</code> si y sólo si <code>$valor</code> es un
  16365. valor de punto flotante.
  16366. </para>
  16367. </sect2>
  16368. <sect2 id="zend.validate.set.greater_than">
  16369. <title>GreaterThan</title>
  16370. <para>
  16371. Devuelve <code>true</code> si y sólo si <code>$valor</code> es mayor
  16372. al límite mínimo.
  16373. </para>
  16374. </sect2>
  16375. <sect2 id="zend.validate.set.hex">
  16376. <title>Hex</title>
  16377. <para>
  16378. Devuelve <code>true</code> si y sólo si <code>$valor</code> contiene
  16379. caracteres hexadecimales (0-9 y A-F).
  16380. </para>
  16381. </sect2>
  16382. <sect2 id="zend.validate.set.hostname">
  16383. <title>Hostname (Nombre de Host)</title>
  16384. <para>
  16385. <code>Zend_Validate_Hostname</code> le permite validar un nombre de host
  16386. contra una serie de especificaciones conocidas.
  16387. Es posible comprobar por tres diferentes tipos de nombres:
  16388. el DNS Hostname (domain.com por ejemplo), dirección IP (es decir 1.2.3.4),
  16389. y nombres de host locales (localhost, por ejemplo).
  16390. Por defecto sólo se comprobarán nombres de host DNS.
  16391. </para>
  16392. <para>
  16393. <emphasis role="strong">Uso básico</emphasis>
  16394. </para>
  16395. <para>
  16396. El siguiente es un ejemplo de uso basico:
  16397. <programlisting role="php"><![CDATA[
  16398. $validator = new Zend_Validate_Hostname();
  16399. if ($validator->isValid($hostname)) {
  16400. // hostname parece ser válido
  16401. } else {
  16402. // hostname es inválido; muestre las razones
  16403. foreach ($validator->getMessages() as $message) {
  16404. echo "$message\n";
  16405. }
  16406. }
  16407. ]]>
  16408. </programlisting>
  16409. Comprobará el nombre de host <code>$hostname</code> y si fracasa
  16410. alimentará a <code>$validator-&gt;getMessages()</code> con mensajes de error.
  16411. </para>
  16412. <para>
  16413. <emphasis role="strong">Validar diferentes tipos de nombres de host</emphasis>
  16414. </para>
  16415. <para>
  16416. También se puede encontrar coincidencias de direcciones IP,
  16417. nombres de host locales, o una combinación de todos los tipos permitidos.
  16418. Esto puede hacerse pasando un parámetro a <code>Zend_Validate_Hostname</code>
  16419. cuando lo instancia.
  16420. El parámetro debe ser un entero que determina qué tipos de nombres de
  16421. host están permitidos.
  16422. Se recomienda el uso de las constantes de <code>Zend_Validate_Hostname</code>
  16423. para hacerlo.
  16424. </para>
  16425. <para>
  16426. Las constantes de <code>Zend_Validate_Hostname</code> son:
  16427. <code>ALLOW_DNS</code> para permitir sólo nombres de host DNS,
  16428. <code>ALLOW_IP</code> para permitir direcciones IP,
  16429. <code>ALLOW_LOCAL</code> para permitir nombres de host de la red local, y
  16430. <code>ALLOW_ALL</code> para permitir todos estos tres tipos.
  16431. Para comprobar que direcciones IP puede utilizar, vea el siguiente ejemplo:
  16432. <programlisting role="php"><![CDATA[
  16433. $validator = new Zend_Validate_Hostname(Zend_Validate_Hostname::ALLOW_IP);
  16434. if ($validator->isValid($hostname)) {
  16435. // hostname parece ser válido
  16436. } else {
  16437. // hostname es inválido; muestre las razones
  16438. foreach ($validator->getMessages() as $message) {
  16439. echo "$message\n";
  16440. }
  16441. }
  16442. ]]>
  16443. </programlisting>
  16444. </para>
  16445. <para>
  16446. Usando <code>ALLOW_ALL</code> para aceptar todos los tipos de nombres de
  16447. host, también puede combinar estos tipos para realizar combinaciones.
  16448. Por ejemplo, para aceptar nombres de host DNS y locales, instancie el
  16449. objeto <code>Zend_Validate_Hostname</code> como:
  16450. <programlisting role="php"><![CDATA[
  16451. $validator = new Zend_Validate_Hostname(Zend_Validate_Hostname::ALLOW_DNS |
  16452. Zend_Validate_Hostname::ALLOW_IP);
  16453. ]]>
  16454. </programlisting>
  16455. </para>
  16456. <para>
  16457. <emphasis role="strong">Validación de Nombres de Dominio Internacionales</emphasis>
  16458. </para>
  16459. <para>
  16460. Algunos (ccTLD), es decir países "Country Code Top Level Domains" , como 'de' (Alemania),
  16461. aceptan caracteres internacionales como nombres de dominio.
  16462. Estos son conocidos como Nombres de Dominio Internacionales
  16463. (IDN, por sus siglas en inglés).
  16464. Se puede buscar una coincidencia de estos dominios con Zend_Validate_Hostname,
  16465. a través de caracteres extendidos que se utilizan en el proceso de validación.
  16466. </para>
  16467. <para>
  16468. En la actualidad la lista de las ccTLDs incluyen a:
  16469. <itemizedlist>
  16470. <listitem>
  16471. <para>at (Austria)</para>
  16472. </listitem>
  16473. <listitem>
  16474. <para>ch (Suiza)</para>
  16475. </listitem>
  16476. <listitem>
  16477. <para>li (Liechtenstein)</para>
  16478. </listitem>
  16479. <listitem>
  16480. <para>de (Alemania)</para>
  16481. </listitem>
  16482. <listitem>
  16483. <para>fi (Finlandia)</para>
  16484. </listitem>
  16485. <listitem>
  16486. <para>hu (Hungría)</para>
  16487. </listitem>
  16488. <listitem>
  16489. <para>no (Noruega)</para>
  16490. </listitem>
  16491. <listitem>
  16492. <para>se (Suecia)</para>
  16493. </listitem>
  16494. </itemizedlist>
  16495. </para>
  16496. <para>
  16497. Cotejar dominios IDN es tan simple como usar el validador estándar
  16498. Hostname, ya que este viene habilitado por defecto.
  16499. Si desea desactivar la validación IDN, se puede hacer ya sea pasando un
  16500. parámetro al constructor Zend_Validate_Hostname o a través del método
  16501. <code>$validator-&gt;setValidateIdn()</code>.
  16502. </para>
  16503. <para>
  16504. Puede deshabilitar la validación IDN, pasando un segundo parámetro al
  16505. constructor Zend_Validate_Hostname de la siguiente manera.
  16506. <programlisting role="php"><![CDATA[
  16507. $validator =
  16508. new Zend_Validate_Hostname(Zend_Validate_Hostname::ALLOW_DNS, false);
  16509. ]]>
  16510. </programlisting>
  16511. Alternativamente puede pasar TRUE o FALSE a <code>$validator-&gt;setValidateIdn()</code>
  16512. para activar o desactivar la validación IDN.
  16513. Si está tratando de cotejar un nombre de host IDN que actualmente no
  16514. está soportado, es probable que falle la validación si tiene caracteres
  16515. internacionales en el nombre de host.
  16516. Cuando un archivo ccTLD no existe en Zend/Validate/Hostname, especificando
  16517. los caracteres adicionales se puede realizar una validación normal.
  16518. </para>
  16519. <para>
  16520. Tenga en cuenta que una validación IDN solo se realizará si tiene habilidada
  16521. la validación para nombres de host DNS.
  16522. </para>
  16523. <para>
  16524. <emphasis role="strong">Validar dominios de nivel superior</emphasis>
  16525. </para>
  16526. <para>
  16527. Por defecto un nombre de host se cotejará con una lista de TLDs conocidos.
  16528. Si esta funcionalidad no es necesaria, puede ser desactivada en la misma
  16529. forma que deshabilita el soporte IDN.
  16530. Puede deshabilitar la validación TLD pasando un tercer parámetro al
  16531. constructor Zend_Validate_Hostname.
  16532. En el siguiente ejemplo estamos dando respaldo a la validación IDN a través
  16533. del segundo parámetro.
  16534. <programlisting role="php"><![CDATA[
  16535. $validator =
  16536. new Zend_Validate_Hostname(Zend_Validate_Hostname::ALLOW_DNS,
  16537. true,
  16538. false);
  16539. ]]>
  16540. </programlisting>
  16541. Alternativamente puede pasar TRUE o FALSE a <code>$validator-&gt;setValidateTld()</code>
  16542. para activar o desactivar la validación TLD.
  16543. </para>
  16544. <para>
  16545. Tenga en cuenta que una validación de TLDs solo se realizará si tiene habilidada
  16546. la validación para nombres de host DNS.
  16547. </para>
  16548. </sect2><!--
  16549. vim:se ts=4 sw=4 et:
  16550. -->
  16551. <sect2 id="zend.validate.set.in_array">
  16552. <title>InArray</title>
  16553. <para>
  16554. Devuelve <code>true</code> si y sólo si <code>$valor</code> se encuentra
  16555. en un array, y si la opción es estricta entonces también verificará
  16556. el tipo de dato de <code>$valor</code>.
  16557. </para>
  16558. </sect2>
  16559. <sect2 id="zend.validate.set.int">
  16560. <title>Int</title>
  16561. <para>
  16562. Devuelve <code>true</code> si y sólo si <code>$valor</code> es un valor entero válido.
  16563. </para>
  16564. </sect2>
  16565. <sect2 id="zend.validate.set.ip">
  16566. <title>Ip</title>
  16567. <para>
  16568. Devuelve <code>true</code> si y sólo si <code>$valor</code> es una dirección IP válida.
  16569. </para>
  16570. </sect2>
  16571. <sect2 id="zend.validate.set.less_than">
  16572. <title>LessThan</title>
  16573. <para>
  16574. Devuelve <code>true</code> si y sólo si <code>$valor</code> es menor
  16575. al límite máximo.
  16576. </para>
  16577. </sect2>
  16578. <sect2 id="zend.validate.set.not_empty">
  16579. <title>NotEmpty</title>
  16580. <para>
  16581. Devuelve <code>true</code> si y sólo si <code>$valor</code> no es vacío.
  16582. </para>
  16583. </sect2>
  16584. <sect2 id="zend.validate.set.regex">
  16585. <title>Regex</title>
  16586. <para>
  16587. Devuelve <code>true</code> si y sólo si <code>$valor</code> coincide
  16588. con el patrón de una expresión regular.
  16589. </para>
  16590. </sect2>
  16591. <sect2 id="zend.validate.set.string_length">
  16592. <title>StringLength</title>
  16593. <para>
  16594. Devuelve <code>true</code> si y sólo si la longitud del string <code>$valor</code>
  16595. es por lo menos un mínimo y no mayor a un máximo
  16596. (cuando la opción max no es <code>null</code>).
  16597. Desde la versión 1.5.0, el método <code>setMin()</code> lanza una
  16598. excepción si la longitud mínima tiene un valor mayor que la longitud
  16599. máxima establecida, y el método <code>setMax()</code> lanza una excepción si la
  16600. longitud máxima se fija a un valor inferior que la longitud
  16601. mínima establecida. Desde la versión 1.0.2, esta clase soporta UTF-8 y a otras
  16602. codificaciones, basado en el valor actual de:
  16603. <ulink url="http://www.php.net/manual/en/ref.iconv.php#iconv.configuration"><code>iconv.internal_encoding</code></ulink>.
  16604. </para>
  16605. </sect2>
  16606. </sect1><!--
  16607. vim:se ts=4 sw=4 et:
  16608. -->
  16609. <sect1 id="zend.validate.validator_chains" xml:base="module_specs/Zend_Validate-ValidatorChains.xml">
  16610. <title>Cadenas de Validadores</title>
  16611. <para>
  16612. Frecuentemente deben aplicarse múltiples validaciones a algún valor en
  16613. un orden particular.
  16614. El siguiente código demuestra una forma de resolver el ejemplo de la
  16615. <link linkend="zend.validate.introduction">introducción</link>, donde el
  16616. nombre de usuario debe tener entre 6 y 12 caracteres alfanuméricos.
  16617. <programlisting role="php"><![CDATA[
  16618. // Crea una cadena de validadores y le agrega validadores
  16619. $validatorChain = new Zend_Validate();
  16620. $validatorChain->addValidator(new Zend_Validate_StringLength(6, 12))
  16621. ->addValidator(new Zend_Validate_Alnum());
  16622. // Valida el username
  16623. if ($validatorChain->isValid($username)) {
  16624. // username pasó la validación
  16625. } else {
  16626. // username falló en la validación; muestre las razones
  16627. foreach ($validatorChain->getMessages() as $message) {
  16628. echo "$message\n";
  16629. }
  16630. }
  16631. ]]>
  16632. </programlisting>
  16633. Los validadores se ejecutan en el orden en que se agregaron a <code>Zend_Validate</code>.
  16634. En el ejemplo anterior, el nombre de usuario, primero se comprueba que
  16635. su longitud esté entre 6 y 12 caracteres y luego se controla para garantizar
  16636. que sólo contiene caracteres alfanuméricos.
  16637. La segunda validación; de caracteres alfanuméricos; se realiza independientemente
  16638. de que la primera validación; de longitud entre 6 y 12 caracteres; tenga éxito.
  16639. Esto significa que si ambas validaciones fallan, <code>getMessages()</code>
  16640. devolverá mensajes de fracaso desde ambos validadores.
  16641. </para>
  16642. <para>
  16643. En algunos casos tiene sentido detener la cadena de validación si falla
  16644. alguno de los procesos de validación.
  16645. <code>Zend_Validate</code> acepta tales casos pasando como segundo
  16646. parámetro el método <code>addValidator()</code>.
  16647. Poniendo <code>$breakChainOnFailure</code> a <code>true</code>,
  16648. el validador agregado quebrará la cadena de ejecución por el fracaso,
  16649. que evita correr cualquier otra validación que se decida que es
  16650. innecesaria o inapropiada para la situación.
  16651. Si el ejemplo anterior fue escrito como sigue, entonces el sistema
  16652. de validación alfanumérica no se ejecutará si falla la longitud del
  16653. string de validación:
  16654. <programlisting role="php"><![CDATA[
  16655. $validatorChain->addValidator(new Zend_Validate_StringLength(6, 12), true)
  16656. ->addValidator(new Zend_Validate_Alnum());
  16657. ]]>
  16658. </programlisting>
  16659. </para>
  16660. <para>
  16661. Cualquier objeto que implemente <code>Zend_Validate_Interface</code>
  16662. puede ser utilizado en una cadena de validación.
  16663. </para>
  16664. </sect1><!--
  16665. vim:se ts=4 sw=4 et:
  16666. -->
  16667. <sect1 id="zend.validate.writing_validators" xml:base="module_specs/Zend_Validate-WritingValidators.xml">
  16668. <title>Escribiendo Validadores</title>
  16669. <para>
  16670. Zend_Validate provee un conjunto de validadores que suelen necesitarse,
  16671. pero inevitablemente, los desarrolladores quiere escribir sus propios
  16672. validadores personalizados para sus necesidades particulares.
  16673. La tarea de escribir un validador personalizado se describe en esta sección.
  16674. </para>
  16675. <para>
  16676. <code>Zend_Validate_Interface</code> define tres métodos, isValid(),
  16677. getMessages(), y getErrors(), que pueden ser implementadas por clases de usuario
  16678. a fin de crear objetos de validación personalizados.
  16679. Un objeto que implementa una interfaz <code>Zend_Validate_Interface</code>
  16680. puede añadirse a una cadena de validación con <code>Zend_Validate::addValidator()</code>.
  16681. Tales objetos también pueden ser usados con
  16682. <link linkend="zend.filter.input"><code>Zend_Filter_Input</code></link>.
  16683. </para>
  16684. <para>
  16685. De la descripción anterior de <code>Zend_Validate_Interface</code>, podrá inferir
  16686. que las clases de validación que proporciona Zend Framework devuelven un
  16687. valor booleano para cuando un valor se valida satisfactoriamente o no.
  16688. También proporcionan información sobre <emphasis role="bold">por qué</emphasis>
  16689. un valor falló en la validación.
  16690. La disponibilidad de las razones para los fracasos de validación puede ser
  16691. valiosa para una aplicación por diversos motivos, tales como proporcionar
  16692. estadísticas para análisis de usabilidad.
  16693. </para>
  16694. <para>
  16695. La funcionalidad de los mensajes de validación básica de fallos están
  16696. implementados en <code>Zend_Validate_Abstract</code>.
  16697. A fin de incluir esta funcionalidad al crear una clase de validación,
  16698. simplemente extienda <code>Zend_Validate_Abstract</code>.
  16699. En la extensión de la clase deberá aplicar la lógica del método
  16700. <code>isValid()</code> y definir las variables y plantillas de mensajes
  16701. que correspondan a los tipos de fallos de validación que puedan suceder.
  16702. Si falla un valor en su test de validación, entonces <code>isValid()</code>
  16703. deberá devolver <code>false</code>.
  16704. Si el valor pasa su test de validación, entonces <code>isValid()</code>
  16705. deberá devolver <code>true</code>.
  16706. </para>
  16707. <para>
  16708. En general, el método <code>isValid()</code> no debería arrojar
  16709. excepciones, salvo que sea imposible determinar si el valor de entrada
  16710. es válido o no.
  16711. Algunos ejemplos de casos razonables para lanzar una excepción podría ser
  16712. si un archivo no puede abrirse, que un servidor LDAP no pudiera ser
  16713. contactado, o una conexión a una base de datos no estuviera disponible.
  16714. Estos son casos en los que puede ser necesario determinar el éxito o
  16715. fracaso de la validación.
  16716. </para>
  16717. <example id="zend.validate.writing_validators.example.simple">
  16718. <title>Crear una Clase de Validación sencilla</title>
  16719. <para>
  16720. El siguiente ejemplo demuestra cómo podría escribirse un sencillo
  16721. validador personalizado.
  16722. En este caso las reglas de validación son simplemente que el valor
  16723. de entrada debe ser de punto flotante.
  16724. <programlisting role="php"><![CDATA[
  16725. class MyValid_Float extends Zend_Validate_Abstract
  16726. {
  16727. const FLOAT = 'float';
  16728. protected $_messageTemplates = array(
  16729. self::FLOAT => "'%value%' no es un valor de punto flotante"
  16730. );
  16731. public function isValid($value)
  16732. {
  16733. $this->_setValue($value);
  16734. if (!is_float($value)) {
  16735. $this->_error();
  16736. return false;
  16737. }
  16738. return true;
  16739. }
  16740. }
  16741. ]]>
  16742. </programlisting>
  16743. La clase define una plantilla para su único mensaje de fallo de
  16744. validación, que incluye el mágico parámetro <code>%value%</code>.
  16745. La llamada a <code>_setValue()</code> prepara al objeto para insertar
  16746. automáticamente en el mensaje de fallo al valor probado, si éste
  16747. falla en la validación.
  16748. La llamada a <code>_error()</code> sigue las pistas para establecer
  16749. una razón por el fracaso de la validación.
  16750. Dado que esta clase sólo define un mensaje de fallo, no es necesario
  16751. darle a <code>_error()</code> el nombre de la plantilla del mensaje
  16752. de fallo.
  16753. </para>
  16754. </example>
  16755. <example id="zend.validate.writing_validators.example.conditions.dependent">
  16756. <title>Escribiendo una Clase de Validación habiendo Condiciones Dependientes </title>
  16757. <para>
  16758. El siguiente ejemplo muestra un conjunto de reglas de validación
  16759. más complejo, donde es necesario que el valor de entrada ser numérico
  16760. y dentro del límite de un rango de valores mínimos y máximos.
  16761. Un valor de entrada podría fallar en la validación exactamente por una
  16762. de las siguientes razones:
  16763. <itemizedlist>
  16764. <listitem>
  16765. <para>El valor de entrada no es numérico.</para>
  16766. </listitem>
  16767. <listitem>
  16768. <para>El valor de entrada es menor que el valor mínimo permitido.</para>
  16769. </listitem>
  16770. <listitem>
  16771. <para>El valor de entrada es mayor que el valor máximo permitido.</para>
  16772. </listitem>
  16773. </itemizedlist>
  16774. </para>
  16775. <para>
  16776. Estas razones en el fallo de validación, son traducidas a las definiciones en la clase:
  16777. <programlisting role="php"><![CDATA[
  16778. class MyValid_NumericBetween extends Zend_Validate_Abstract
  16779. {
  16780. const MSG_NUMERIC = 'msgNumeric';
  16781. const MSG_MINIMUM = 'msgMinimum';
  16782. const MSG_MAXIMUM = 'msgMaximum';
  16783. public $minimum = 0;
  16784. public $maximum = 100;
  16785. protected $_messageVariables = array(
  16786. 'min' => 'minimum',
  16787. 'max' => 'maximum'
  16788. );
  16789. protected $_messageTemplates = array(
  16790. self::MSG_NUMERIC => "'%value%' no es numérico",
  16791. self::MSG_MINIMUM => "'%value%' debe ser al menos '%min%'",
  16792. self::MSG_MAXIMUM => "'%value%' debe ser no mayor a '%max%'"
  16793. );
  16794. public function isValid($value)
  16795. {
  16796. $this->_setValue($value);
  16797. if (!is_numeric($value)) {
  16798. $this->_error(self::MSG_NUMERIC);
  16799. return false;
  16800. }
  16801. if ($value < $this->minimum) {
  16802. $this->_error(self::MSG_MINIMUM);
  16803. return false;
  16804. }
  16805. if ($value > $this->maximum) {
  16806. $this->_error(self::MSG_MAXIMUM);
  16807. return false;
  16808. }
  16809. return true;
  16810. }
  16811. }
  16812. ]]>
  16813. </programlisting>
  16814. Las propiedades públicas <code>$minimum</code> y <code>$maximum</code>
  16815. se han establecido para proporcionar los límites mínimo y máximo,
  16816. respectivamente, de un valor a validar.
  16817. La clase también define dos variables de mensajes que corresponden a
  16818. las propiedades públicas y permiten usar <code>min</code> y <code>max</code>
  16819. en plantillas de mensajes como parámetros mágicos, al igual que con
  16820. <code>value</code>.
  16821. </para>
  16822. <para>
  16823. Tenga en cuenta que si cualquiera de las comprobaciones de validación
  16824. falla en <code>isValid()</code>, ya está preparado un mensaje apropiado,
  16825. y el método inmediatamente devuelve <code>false</code>.
  16826. Estas reglas de validación son por lo tanto secuencialmente dependientes.
  16827. Es decir, si uno de los tests falla, no hay necesidad de poner a
  16828. prueba las posteriores reglas de validación.
  16829. Sin embargo, esta necesidad no será el caso.
  16830. El siguiente ejemplo ilustra cómo escribir una clase con reglas de
  16831. validación independientes, donde el objeto validación puede devolver
  16832. múltiples razones por las cuales fracasó un intento de validación en
  16833. particular.
  16834. </para>
  16835. </example>
  16836. <example id="zend.validate.writing_validators.example.conditions.independent">
  16837. <title>Validación con Condiciones Independientes, Múltiples Razones del Fracaso</title>
  16838. <para>
  16839. Considere escribir una clase de validación y control de
  16840. contraseñas - cuando es necesario que un usuario elija una
  16841. contraseña que cumple determinados criterios para ayudar a tener
  16842. cuentas de usuario seguras. Supongamos que la seguridad de la contraseña
  16843. aplica criterios que fuerzan a lo siguiente:
  16844. <itemizedlist>
  16845. <listitem>
  16846. <para>debe tener al menos una longitud de 8 caracteres,</para>
  16847. </listitem>
  16848. <listitem>
  16849. <para>contener al menos una letra en mayúscula,</para>
  16850. </listitem>
  16851. <listitem>
  16852. <para>contener al menos una letra en minúscula,</para>
  16853. </listitem>
  16854. <listitem>
  16855. <para>contener al menos un dígito.</para>
  16856. </listitem>
  16857. </itemizedlist>
  16858. </para>
  16859. <para>
  16860. La siguiente clase implementa estos criterios de validación:
  16861. <programlisting role="php"><![CDATA[
  16862. class MyValid_PasswordStrength extends Zend_Validate_Abstract
  16863. {
  16864. const LENGTH = 'length';
  16865. const UPPER = 'upper';
  16866. const LOWER = 'lower';
  16867. const DIGIT = 'digit';
  16868. protected $_messageTemplates = array(
  16869. self::LENGTH => "'%value%' debe tener al menos una longitud de 8 caracteres",
  16870. self::UPPER => "'%value%' debe contener al menos una letra en mayúscula",
  16871. self::LOWER => "'%value%' debe contener al menos una letra en minúscula",
  16872. self::DIGIT => "'%value%' debe contener al menos un dígito"
  16873. );
  16874. public function isValid($value)
  16875. {
  16876. $this->_setValue($value);
  16877. $isValid = true;
  16878. if (strlen($value) < 8) {
  16879. $this->_error(self::LENGTH);
  16880. $isValid = false;
  16881. }
  16882. if (!preg_match('/[A-Z]/', $value)) {
  16883. $this->_error(self::UPPER);
  16884. $isValid = false;
  16885. }
  16886. if (!preg_match('/[a-z]/', $value)) {
  16887. $this->_error(self::LOWER);
  16888. $isValid = false;
  16889. }
  16890. if (!preg_match('/\d/', $value)) {
  16891. $this->_error(self::DIGIT);
  16892. $isValid = false;
  16893. }
  16894. return $isValid;
  16895. }
  16896. }
  16897. ]]>
  16898. </programlisting>
  16899. Las cuatro pruebas de criterio en <code>isValid()</code> no devuelven
  16900. inmediatamente <code>false</code>.
  16901. Esto permite a la clase de validación a proporcionar <emphasis role="bold">todas</emphasis>
  16902. las razones por las que la contraseña de entrada no cumplió los requisitos
  16903. de validación.
  16904. Si, por ejemplo, un usuario ingresara el string "<code>#$%</code>"
  16905. como contraseña, <code>isValid()</code> causaría que los cuatro
  16906. mensajes de fracaso de validación sean devueltos por un llamado posterior
  16907. a <code>getMessages()</code>.
  16908. </para>
  16909. </example>
  16910. </sect1><!--
  16911. vim:se ts=4 sw=4 et:
  16912. -->
  16913. </chapter>
  16914. <chapter id="zend.version">
  16915. <title>Zend_Version</title>
  16916. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Version.xml"/>
  16917. </chapter>
  16918. <chapter id="zend.view">
  16919. <title>Zend_View</title>
  16920. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_View-Introduction.xml"/>
  16921. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_View-Controllers.xml"/>
  16922. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_View-Scripts.xml"/>
  16923. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_View-Helpers.xml" parse="xml"/>
  16924. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_View-Abstract.xml"/>
  16925. </chapter>
  16926. <chapter id="zend.wildfire">
  16927. <title>Zend_Wildfire</title>
  16928. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_Wildfire.xml"/>
  16929. </chapter>
  16930. <chapter id="zend.xmlrpc">
  16931. <title>Zend_XmlRpc</title>
  16932. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_XmlRpc.xml"/>
  16933. <sect1 id="zend.xmlrpc.client" xml:base="module_specs/Zend_XmlRpc_Client.xml">
  16934. <title>Zend_XmlRpc_Client</title>
  16935. <sect2 id="zend.xmlrpc.client.introduction">
  16936. <title>Introdución</title>
  16937. <para>
  16938. Zend Framework provee soporte para consumo remoto para servicios XML-RPC
  16939. como un cliente en el paquete <code>Zend_XmlRpc_Client</code>
  16940. . Su mejor característica es la conversión atuomática de tipos
  16941. entre PHP y XML-RPC, un servidor de objeto proxy, y acceso a
  16942. capacidades de instrospección del servidor.
  16943. </para>
  16944. </sect2>
  16945. <sect2 id="zend.xmlrpc.client.method-calls">
  16946. <title>Method Calls</title>
  16947. <para>
  16948. El constructor de <code>Zend_XmlRpc_Client</code> recibe la
  16949. URL del servidor XML-RPC como su primer parámetro.
  16950. La nueva instacia devuelta pu7ede ser usada para llamar cualquier número de métodos remotos en el punto final.
  16951. </para>
  16952. <para>
  16953. Para llamar un método remoto con el cliente XML-RPC, instáncealo
  16954. y usa el método de instancia <code>call()</code> . El código de ejemplo a continuación utiliza una demostración en el servidor XML-RPC en el sitio wed del Zend Framework
  16955. . Puede utilizarlo para probar o explorar los componentes
  16956. <code>Zend_XmlRpc</code>.
  16957. </para>
  16958. <example id="zend.xmlrpc.client.method-calls.example-1">
  16959. <title>XML-RPC Method Call</title>
  16960. <programlisting role="php"><![CDATA[
  16961. $client = new Zend_XmlRpc_Client('http://framework.zend.com/xmlrpc');
  16962. echo $client->call('test.sayHello');
  16963. // hello
  16964. ]]>
  16965. </programlisting>
  16966. </example>
  16967. <para>
  16968. El valor XML-RPC devuelto desde la llamada al método remoto automáticamente será convertida al tipo nativo PHP equivalente
  16969. . En el ejemplo anterior, es devuelto un <code>string</code> PHP
  16970. y está listo para ser usada inmediatamente.
  16971. </para>
  16972. <para>
  16973. El primer parámetro del método <code>call()</code> recibe el nombre del método remoto a llamar. Si el método remoto requiere algún parámetro, este puede ser enviado por el suministro de un segundo, parámetro opcional a <code>call()</code> con un <code>array</code> de
  16974. valores para pasar el método remoto:
  16975. </para>
  16976. <example id="zend.xmlrpc.client.method-calls.example-2">
  16977. <title>XML-RPC Method Call with Parameters</title>
  16978. <programlisting role="php"><![CDATA[
  16979. $client = new Zend_XmlRpc_Client('http://framework.zend.com/xmlrpc');
  16980. $arg1 = 1.1;
  16981. $arg2 = 'foo';
  16982. $result = $client->call('test.sayHello', array($arg1, $arg2));
  16983. // $result es un tipo nativo PHP
  16984. ]]>
  16985. </programlisting>
  16986. </example>
  16987. <para>
  16988. si el método remoto no requiere parámetros, este parámetro opcional
  16989. podrá ser excluido o se puede pasar un <code>array()</code>
  16990. vacío. El array de parámeters para el método repoto puede contener tipos nativos PHPs, objetos <code>Zend_XmlRpc_Value</code>
  16991. , o una combinación de estos.
  16992. </para>
  16993. <para>
  16994. El método <code>call()</code> convertirá automáticamente la respuesta
  16995. XML-RPC y devolverá su tipo nativo PHP equivalente. Un objeto
  16996. <code>Zend_XmlRpc_Response</code> para el valor devuelto también estará
  16997. disponible para llamar el método <code>getLastResponse()</code>
  16998. después de la llamada.
  16999. </para>
  17000. </sect2>
  17001. <sect2 id="zend.xmlrpc.value.parameters">
  17002. <title>Tipos y Conversiones</title>
  17003. <para>
  17004. Algunas llamadas a métodos remoto requieren parámetros. Estos son
  17005. dados al método <code>call()</code> de <code>Zend_XmlRpc_Client</code>
  17006. como un array en el segundo parámetro. Cada parámetro puede ser dado
  17007. como cualquier tipo nativo PHP ya que este será convertido automáticamente,
  17008. o como un objeto que representa un tipo específico de XML-RPC
  17009. (uno de los objetos <code>Zend_XmlRpc_Value</code>).
  17010. </para>
  17011. <sect3 id="zend.xmlrpc.value.parameters.php-native">
  17012. <title>Tipos Nativos PHP como Parámetro</title>
  17013. <para>
  17014. Los parámetros pueden ser pasados a <code>call()</code> como variables
  17015. PHP nativas, ya sea un <code>string</code>,
  17016. <code>integer</code>, <code>float</code>,
  17017. <code>boolean</code>, <code>array</code>, o un
  17018. <code>object</code>. En este caso, cada tipo PHP nativo será
  17019. autodetectada y convertida en uno de los tipos XML-RPC
  17020. de acuerdo con esta tabla:
  17021. </para>
  17022. <table id="zend.xmlrpc.value.parameters.php-native.table-1">
  17023. <title>Tipos de Conversión entre PHP y XML-RPC</title>
  17024. <tgroup cols="2">
  17025. <thead>
  17026. <row>
  17027. <entry>Tipo Nativo PHP</entry>
  17028. <entry>Tipo XML-RPC</entry>
  17029. </row>
  17030. </thead>
  17031. <tbody>
  17032. <row>
  17033. <entry>integer</entry>
  17034. <entry>int</entry>
  17035. </row>
  17036. <row>
  17037. <entry>double</entry>
  17038. <entry>double</entry>
  17039. </row>
  17040. <row>
  17041. <entry>boolean</entry>
  17042. <entry>boolean</entry>
  17043. </row>
  17044. <row>
  17045. <entry>string</entry>
  17046. <entry>string</entry>
  17047. </row>
  17048. <row>
  17049. <entry>array</entry>
  17050. <entry>array</entry>
  17051. </row>
  17052. <row>
  17053. <entry>array asociativo</entry>
  17054. <entry>struct</entry>
  17055. </row>
  17056. <row>
  17057. <entry>object</entry>
  17058. <entry>array</entry>
  17059. </row>
  17060. </tbody>
  17061. </tgroup>
  17062. </table>
  17063. <note>
  17064. <title>¿A qué tipo se convierten los arrays Vacios?</title>
  17065. <para>
  17066. Pasar un array vacío a un método XML-RPC es problemático,
  17067. as it could represent either an array or a struct.
  17068. <code>Zend_XmlRpc_Client</code> detects such conditions and
  17069. makes a request to the server's
  17070. <code>system.methodSignature</code> method to determine the
  17071. appropriate XML-RPC type to cast to.
  17072. </para>
  17073. <para>
  17074. However, this in itself can lead to issues. First off,
  17075. servers that do not support
  17076. <code>system.methodSignature</code> will log failed
  17077. requests, and <code>Zend_XmlRpc_Client</code> will resort to
  17078. casting the value to an XML-RPC array type. Additionally,
  17079. this means that any call with array arguments will result in
  17080. an additional call to the remote server.
  17081. </para>
  17082. <para>
  17083. To disable the lookup entirely, you can call the
  17084. <code>setSkipSystemLookup()</code> method prior to making
  17085. your XML-RPC call:
  17086. </para>
  17087. <programlisting role="php"><![CDATA[
  17088. $client->setSkipSystemLookup(true);
  17089. $result = $client->call('foo.bar', array(array()));
  17090. ]]>
  17091. </programlisting>
  17092. </note>
  17093. </sect3>
  17094. <sect3 id="zend.xmlrpc.value.parameters.xmlrpc-value">
  17095. <title><code>Zend_XmlRpc_Value</code> Objects as Parameters</title>
  17096. <para>
  17097. Parameters may also be created as <code>Zend_XmlRpc_Value</code>
  17098. instances to specify an exact XML-RPC type. The primary reasons
  17099. for doing this are:
  17100. <itemizedlist>
  17101. <listitem>
  17102. <para>
  17103. When you want to make sure the correct parameter
  17104. type is passed to the procedure (i.e. the
  17105. procedure requires an integer and you may get it
  17106. from a database as a string)
  17107. </para>
  17108. </listitem>
  17109. <listitem>
  17110. <para>
  17111. When the procedure requires <code>base64</code> or
  17112. <code>dateTime.iso8601</code> type (which doesn't exists as a
  17113. PHP native type)
  17114. </para>
  17115. </listitem>
  17116. <listitem>
  17117. <para>
  17118. When auto-conversion may fail (i.e. you want to
  17119. pass an empty XML-RPC struct as a parameter. Empty
  17120. structs are represented as empty arrays in PHP
  17121. but, if you give an empty array as a parameter it
  17122. will be auto-converted to an XML-RPC array since
  17123. it's not an associative array)
  17124. </para>
  17125. </listitem>
  17126. </itemizedlist>
  17127. </para>
  17128. <para>
  17129. There are two ways to create a <code>Zend_XmlRpc_Value</code>
  17130. object: instantiate one of the <code>Zend_XmlRpc_Value</code>
  17131. subclasses directly, or use the static factory method
  17132. <code>Zend_XmlRpc_Value::getXmlRpcValue()</code>.
  17133. </para>
  17134. <table id="zend.xmlrpc.value.parameters.xmlrpc-value.table-1">
  17135. <title><code>Zend_XmlRpc_Value</code> Objects for XML-RPC Types</title>
  17136. <tgroup cols="3">
  17137. <thead>
  17138. <row>
  17139. <entry>XML-RPC Type</entry>
  17140. <entry><code>Zend_XmlRpc_Value</code> Constant</entry>
  17141. <entry><code>Zend_XmlRpc_Value</code> Object</entry>
  17142. </row>
  17143. </thead>
  17144. <tbody>
  17145. <row>
  17146. <entry>int</entry>
  17147. <entry><code>Zend_XmlRpc_Value::XMLRPC_TYPE_INTEGER</code></entry>
  17148. <entry><code>Zend_XmlRpc_Value_Integer</code></entry>
  17149. </row>
  17150. <row>
  17151. <entry>double</entry>
  17152. <entry><code>Zend_XmlRpc_Value::XMLRPC_TYPE_DOUBLE</code></entry>
  17153. <entry><code>Zend_XmlRpc_Value_Double</code></entry>
  17154. </row>
  17155. <row>
  17156. <entry>boolean</entry>
  17157. <entry><code>Zend_XmlRpc_Value::XMLRPC_TYPE_BOOLEAN</code></entry>
  17158. <entry><code>Zend_XmlRpc_Value_Boolean</code></entry>
  17159. </row>
  17160. <row>
  17161. <entry>string</entry>
  17162. <entry><code>Zend_XmlRpc_Value::XMLRPC_TYPE_STRING</code></entry>
  17163. <entry><code>Zend_XmlRpc_Value_String</code></entry>
  17164. </row>
  17165. <row>
  17166. <entry>base64</entry>
  17167. <entry><code>Zend_XmlRpc_Value::XMLRPC_TYPE_BASE64</code></entry>
  17168. <entry><code>Zend_XmlRpc_Value_Base64</code></entry>
  17169. </row>
  17170. <row>
  17171. <entry>dateTime.iso8601</entry>
  17172. <entry><code>Zend_XmlRpc_Value::XMLRPC_TYPE_DATETIME</code></entry>
  17173. <entry><code>Zend_XmlRpc_Value_DateTime</code></entry>
  17174. </row>
  17175. <row>
  17176. <entry>array</entry>
  17177. <entry><code>Zend_XmlRpc_Value::XMLRPC_TYPE_ARRAY</code></entry>
  17178. <entry><code>Zend_XmlRpc_Value_Array</code></entry>
  17179. </row>
  17180. <row>
  17181. <entry>struct</entry>
  17182. <entry><code>Zend_XmlRpc_Value::XMLRPC_TYPE_STRUCT</code></entry>
  17183. <entry><code>Zend_XmlRpc_Value_Struct</code></entry>
  17184. </row>
  17185. </tbody>
  17186. </tgroup>
  17187. </table>
  17188. <para>
  17189. <note>
  17190. <title>Automatic Conversion</title>
  17191. <para>
  17192. When building a new <code>Zend_XmlRpc_Value</code>
  17193. object, its value is set by a PHP type. The PHP type
  17194. will be converted to the specified type using
  17195. PHP casting. For example, if a string is given as a
  17196. value to the <code>Zend_XmlRpc_Value_Integer</code>
  17197. object, it will be converted using
  17198. <code>(int)$value</code>.
  17199. </para>
  17200. </note>
  17201. </para>
  17202. </sect3>
  17203. </sect2>
  17204. <sect2 id="zend.xmlrpc.client.requests-and-responses">
  17205. <title>Server Proxy Object</title>
  17206. <para>
  17207. Another way to call remote methods with the XML-RPC client is to
  17208. use the server proxy. This is a PHP object that proxies a remote
  17209. XML-RPC namespace, making it work as close to a native PHP object
  17210. as possible.
  17211. </para>
  17212. <para>
  17213. To instantiate a server proxy, call the <code>getProxy()</code>
  17214. instance method of <code>Zend_XmlRpc_Client</code>. This will
  17215. return an instance of <code>Zend_XmlRpc_Client_ServerProxy</code>.
  17216. Any method call on the server proxy object will be forwarded to
  17217. the remote, and parameters may be passed like any other PHP
  17218. method.
  17219. </para>
  17220. <example id="zend.xmlrpc.client.requests-and-responses.example-1">
  17221. <title>Proxy the Default Namespace</title>
  17222. <programlisting role="php"><![CDATA[
  17223. $client = new Zend_XmlRpc_Client('http://framework.zend.com/xmlrpc');
  17224. $server = $client->getProxy(); // Proxy the default namespace
  17225. $hello = $server->test->sayHello(1, 2); // test.Hello(1, 2) returns "hello"
  17226. ]]>
  17227. </programlisting>
  17228. </example>
  17229. <para>
  17230. The <code>getProxy()</code> method receives an optional argument
  17231. specifying which namespace of the remote server to proxy. If it
  17232. does not receive a namespace, the default namespace will be
  17233. proxied. In the next example, the <code>test</code> namespace
  17234. will be proxied:
  17235. </para>
  17236. <example id="zend.xmlrpc.client.requests-and-responses.example-2">
  17237. <title>Proxy Any Namespace</title>
  17238. <programlisting role="php"><![CDATA[
  17239. $client = new Zend_XmlRpc_Client('http://framework.zend.com/xmlrpc');
  17240. $test = $client->getProxy('test'); // Proxy the "test" namespace
  17241. $hello = $test->sayHello(1, 2); // test.Hello(1,2) returns "hello"
  17242. ]]>
  17243. </programlisting>
  17244. </example>
  17245. <para>
  17246. If the remote server supports nested namespaces of any depth,
  17247. these can also be used through the server proxy. For example, if
  17248. the server in the example above had a method
  17249. <code>test.foo.bar()</code>, it could be called as
  17250. <code>$test-&gt;foo-&gt;bar()</code>.
  17251. </para>
  17252. </sect2>
  17253. <sect2 id="zend.xmlrpc.client.error-handling">
  17254. <title>Error Handling</title>
  17255. <para>
  17256. Two kinds of errors can occur during an XML-RPC method call: HTTP
  17257. errors and XML-RPC faults. The <code>Zend_XmlRpc_Client</code>
  17258. recognizes each and provides the ability to detect and trap them
  17259. independently.
  17260. </para>
  17261. <sect3 id="zend.xmlrpc.client.error-handling.http">
  17262. <title>HTTP Errors</title>
  17263. <para>
  17264. If any HTTP error occurs, such as the remote HTTP server
  17265. returns a <code>404 Not Found</code>, a
  17266. <code>Zend_XmlRpc_Client_HttpException</code> will be thrown.
  17267. </para>
  17268. <example id="zend.xmlrpc.client.error-handling.http.example-1">
  17269. <title>Handling HTTP Errors</title>
  17270. <programlisting role="php"><![CDATA[
  17271. $client = new Zend_XmlRpc_Client('http://foo/404');
  17272. try {
  17273. $client->call('bar', array($arg1, $arg2));
  17274. } catch (Zend_XmlRpc_Client_HttpException $e) {
  17275. // $e->getCode() returns 404
  17276. // $e->getMessage() returns "Not Found"
  17277. }
  17278. ]]>
  17279. </programlisting>
  17280. </example>
  17281. <para>
  17282. Regardless of how the XML-RPC client is used, the
  17283. <code>Zend_XmlRpc_Client_HttpException</code> will be thrown
  17284. whenever an HTTP error occurs.
  17285. </para>
  17286. </sect3>
  17287. <sect3 id="zend.xmlrpc.client.error-handling.faults">
  17288. <title>XML-RPC Faults</title>
  17289. <para>
  17290. An XML-RPC fault is analogous to a PHP exception. It is a
  17291. special type returned from an XML-RPC method call that has
  17292. both an error code and an error message. XML-RPC faults are
  17293. handled differently depending on the context of how the
  17294. <code>Zend_XmlRpc_Client</code> is used.
  17295. </para>
  17296. <para>
  17297. When the <code>call()</code> method or the server
  17298. proxy object is used, an XML-RPC fault will result in a
  17299. <code>Zend_XmlRpc_Client_FaultException</code> being thrown.
  17300. The code and message of the exception will map directly to
  17301. their respective values in the original XML-RPC fault
  17302. response.
  17303. </para>
  17304. <example id="zend.xmlrpc.client.error-handling.faults.example-1">
  17305. <title>Handling XML-RPC Faults</title>
  17306. <programlisting role="php"><![CDATA[
  17307. $client = new Zend_XmlRpc_Client('http://framework.zend.com/xmlrpc');
  17308. try {
  17309. $client->call('badMethod');
  17310. } catch (Zend_XmlRpc_Client_FaultException $e) {
  17311. // $e->getCode() returns 1
  17312. // $e->getMessage() returns "Unknown method"
  17313. }
  17314. ]]>
  17315. </programlisting>
  17316. </example>
  17317. <para>
  17318. When the <code>call()</code> method is used to make the
  17319. request, the <code>Zend_XmlRpc_Client_FaultException</code> will be
  17320. thrown on fault. A <code>Zend_XmlRpc_Response</code> object
  17321. containing the fault will also be available by calling
  17322. <code>getLastResponse()</code>.
  17323. </para>
  17324. <para>
  17325. When the <code>doRequest()</code> method is used to make the
  17326. request, it will not throw the exception. Instead, it will
  17327. return a <code>Zend_XmlRpc_Response</code> object returned
  17328. will containing the fault. This can be checked with
  17329. <code>isFault()</code> instance method of
  17330. <code>Zend_XmlRpc_Response</code>.
  17331. </para>
  17332. </sect3>
  17333. </sect2>
  17334. <sect2 id="zend.xmlrpc.client.introspection">
  17335. <title>Server Introspection</title>
  17336. <para>
  17337. Some XML-RPC servers support the de facto introspection methods under the XML-RPC
  17338. <code>system.</code> namespace. <code>Zend_XmlRpc_Client</code> provides special
  17339. support for servers with these capabilities.
  17340. </para>
  17341. <para>
  17342. A <code>Zend_XmlRpc_Client_ServerIntrospection</code> instance may be retrieved by calling
  17343. the <code>getIntrospector()</code> method of <code>Zend_XmlRpcClient</code>. It can
  17344. then be used to perform introspection operations on the server.
  17345. </para>
  17346. </sect2>
  17347. <sect2 id="zend.xmlrpc.client.request-to-response">
  17348. <title>From Request to Response</title>
  17349. <para>
  17350. Under the hood, the <code>call()</code> instance method of <code>Zend_XmlRpc_Client</code>
  17351. builds a request object (<code>Zend_XmlRpc_Request</code>) and sends it to another method,
  17352. <code>doRequest()</code>, that returns a response object (<code>Zend_XmlRpc_Response</code>).
  17353. </para>
  17354. <para>
  17355. The <code>doRequest()</code> method is also available for use directly:
  17356. </para>
  17357. <example id="zend.xmlrpc.client.request-to-response.example-1">
  17358. <title>Processing Request to Response</title>
  17359. <programlisting role="php"><![CDATA[
  17360. $client = new Zend_XmlRpc_Client('http://framework.zend.com/xmlrpc');
  17361. $request = new Zend_XmlRpc_Request();
  17362. $request->setMethod('test.sayHello');
  17363. $request->setParams(array('foo', 'bar'));
  17364. $client->doRequest($request);
  17365. // $server->getLastRequest() returns instanceof Zend_XmlRpc_Request
  17366. // $server->getLastResponse() returns instanceof Zend_XmlRpc_Response
  17367. ]]>
  17368. </programlisting>
  17369. </example>
  17370. <para>
  17371. Whenever an XML-RPC method call is made by the client through any
  17372. means, either the <code>call()</code> method,
  17373. <code>doRequest()</code> method, or server proxy, the last request
  17374. object and its resultant response object will always be available
  17375. through the methods <code>getLastRequest()</code> and
  17376. <code>getLastResponse()</code> respectively.
  17377. </para>
  17378. </sect2>
  17379. <sect2 id="zend.xmlrpc.client.http-client">
  17380. <title>HTTP Client and Testing</title>
  17381. <para>
  17382. In all of the prior examples, an HTTP client was never specified.
  17383. When this is the case, a new instance of
  17384. <code>Zend_Http_Client</code> will be created with its default
  17385. options and used by <code>Zend_XmlRpc_Client</code> automatically.
  17386. </para>
  17387. <para>
  17388. The HTTP client can be retrieved at any time with the
  17389. <code>getHttpClient()</code> method. For most cases, the default
  17390. HTTP client will be sufficient. However, the
  17391. <code>setHttpClient()</code> method allows for a different HTTP
  17392. client instance to be injected.
  17393. </para>
  17394. <para>
  17395. The <code>setHttpClient()</code> is particularly useful for unit testing. When combined
  17396. with the <code>Zend_Http_Client_Adapter_Test</code>, remote services can be mocked
  17397. out for testing. See the unit tests for <code>Zend_XmlRpc_Client</code> for examples
  17398. of how to do this.
  17399. </para>
  17400. </sect2>
  17401. </sect1><!--
  17402. vim:se ts=4 sw=4 et:
  17403. -->
  17404. <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="module_specs/Zend_XmlRpc_Server.xml"/>
  17405. </chapter>
  17406. <appendix id="requirements" xml:base="ref/requirements.xml">
  17407. <title>Zend Framework Requirements</title>
  17408. <para>
  17409. Zend Framework requires a PHP 5 interpreter with a web server configured
  17410. to handle PHP scripts correctly. Some features require additional extensions or
  17411. web server features; in most cases the framework can be used without them, although
  17412. performance may suffer or ancillary features may not be fully functional. An example
  17413. of such a dependency is mod_rewrite in an Apache environment, which can be used to
  17414. implement "pretty URL's" like "http://www.example.com/user/edit". If mod_rewrite is
  17415. not enabled, ZF can be configured to support URL's such as "http://www.example.com?controller=user&amp;action=edit".
  17416. Pretty URL's may be used to shorten URL's for textual representation or search engine optimization (SEO),
  17417. but they do not directly affect the functionality of the application.
  17418. </para>
  17419. <sect1 id="requirements.version">
  17420. <title>PHP Version</title>
  17421. <para>
  17422. Zend recommends PHP 5.2.3 or higher for critical security and performance enhancements, although
  17423. Zend Framework requires only PHP 5.1.4 or later.
  17424. </para>
  17425. <para>
  17426. Zend Framework has an extensive collection of unit tests, which you can run using PHPUnit 3.0 or later.
  17427. </para>
  17428. </sect1>
  17429. <sect1 id="requirements.extensions">
  17430. <title>PHP Extensions</title>
  17431. <para>
  17432. You will find a table listing all extensions typically found in PHP
  17433. and how they are used in Zend Framework below. You should verify that the extensions on
  17434. which ZF components you'll be using in your application are available in your PHP environments.
  17435. Many applications will not require every extension listed below.
  17436. </para>
  17437. <para>
  17438. A dependency of type "hard" indicates that the components or classes
  17439. cannot function properly if the respective extension is not available,
  17440. while a dependency of type "soft" indicates that the component may use
  17441. the extension if it is available but will function properly if it is not.
  17442. Many components will automatically use certain extensions if they are available
  17443. to optimize performance but will execute code with similar functionality in the
  17444. component itself if the extensions are unavailable.
  17445. </para>
  17446. <table frame="all" id="requirements.extensions.table-1">
  17447. <title>PHP Extensions Used in Zend Framework by Component</title>
  17448. <tgroup cols="3">
  17449. <!-- <colspec colwidth='1in'/>
  17450. <colspec colwidth='1in'/>
  17451. <colspec colwidth='3in'/> -->
  17452. <thead>
  17453. <row>
  17454. <entry>Extension</entry>
  17455. <entry>Dependency Type</entry>
  17456. <entry>Used by Zend Framework Components</entry>
  17457. </row>
  17458. </thead>
  17459. <tbody>
  17460. <row>
  17461. <entry><emphasis role="strong"><ulink url="http://www.php.net/manual/en/ref.apc.php"><code>apc</code></ulink></emphasis></entry>
  17462. <entry>Hard</entry>
  17463. <entry><ulink url="http://framework.zend.com/manual/en/zend.cache.backends.html"><code>Zend_Cache_Backend_Apc</code></ulink></entry>
  17464. </row>
  17465. <row>
  17466. <entry><emphasis role="strong"><ulink url="http://www.php.net/manual/en/ref.bc.php"><code>bcmath</code></ulink></emphasis></entry>
  17467. <entry>Soft</entry>
  17468. <entry><ulink url="http://framework.zend.com/manual/en/zend.locale.html"><code>Zend_Locale</code></ulink></entry>
  17469. </row>
  17470. <row>
  17471. <entry><emphasis role="strong"><ulink url="http://pecl.php.net/package/Bitset"><code>bitset</code></ulink></emphasis></entry>
  17472. <entry>Soft</entry>
  17473. <entry><ulink url="http://framework.zend.com/manual/en/zend.search.lucene.html"><code>Zend_Search_Lucene</code></ulink></entry>
  17474. </row>
  17475. <row>
  17476. <entry><emphasis role="strong"><ulink url="http://www.php.net/manual/en/ref.bzip2.php"><code>bz2</code></ulink></emphasis></entry>
  17477. <entry>---</entry>
  17478. <entry>---</entry>
  17479. </row>
  17480. <row>
  17481. <entry><emphasis role="strong"><ulink url="http://www.php.net/manual/en/ref.calendar.php"><code>calendar</code></ulink></emphasis></entry>
  17482. <entry>---</entry>
  17483. <entry>---</entry>
  17484. </row>
  17485. <row>
  17486. <entry><emphasis role="strong"><ulink url="http://www.php.net/manual/en/ref.com.php"><code>com_dotnet</code></ulink></emphasis></entry>
  17487. <entry>---</entry>
  17488. <entry>---</entry>
  17489. </row>
  17490. <row>
  17491. <entry morerows="8" valign="middle"><emphasis role="strong"><ulink url="http://www.php.net/manual/en/ref.ctype.php"><code>ctype</code></ulink></emphasis></entry>
  17492. <entry morerows="8" valign="middle">Hard</entry>
  17493. <entry><ulink url="http://framework.zend.com/manual/en/zend.auth.adapter.http.html"><code>Zend_Auth_Adapter_Http</code></ulink></entry>
  17494. </row>
  17495. <row>
  17496. <entry><ulink url="http://framework.zend.com/manual/en/zend.gdata.html"><code>Zend_Gdata</code></ulink></entry>
  17497. </row>
  17498. <row>
  17499. <entry><ulink url="http://framework.zend.com/manual/en/zend.http.html"><code>Zend_Http_Client</code></ulink></entry>
  17500. </row>
  17501. <row>
  17502. <entry><ulink url="http://framework.zend.com/manual/en/zend.pdf.html"><code>Zend_Pdf</code></ulink></entry>
  17503. </row>
  17504. <row>
  17505. <entry><ulink url="http://framework.zend.com/manual/en/zend.rest.client.html"><code>Zend_Rest_Client</code></ulink></entry>
  17506. </row>
  17507. <row>
  17508. <entry><ulink url="http://framework.zend.com/manual/en/zend.rest.server.html"><code>Zend_Rest_Server</code></ulink></entry>
  17509. </row>
  17510. <row>
  17511. <entry><ulink url="http://framework.zend.com/manual/en/zend.search.lucene.html"><code>Zend_Search_Lucene</code></ulink></entry>
  17512. </row>
  17513. <row>
  17514. <entry><ulink url="http://framework.zend.com/manual/en/zend.uri.html"><code>Zend_Uri</code></ulink></entry>
  17515. </row>
  17516. <row>
  17517. <entry><ulink url="http://framework.zend.com/manual/en/zend.validate.html"><code>Zend_Validate</code></ulink></entry>
  17518. </row>
  17519. <row>
  17520. <entry><emphasis role="strong"><ulink url="http://www.php.net/manual/en/ref.curl.php"><code>curl</code></ulink></emphasis></entry>
  17521. <entry>Hard</entry>
  17522. <entry><ulink url="http://framework.zend.com/manual/en/zend.http.client.adapters.html"><code>Zend_Http_Client_Adapter_Curl</code></ulink></entry>
  17523. </row>
  17524. <row>
  17525. <entry><emphasis role="strong"><ulink url="http://www.php.net/manual/en/ref.datetime.php"><code>date</code></ulink></emphasis></entry>
  17526. <entry>---</entry>
  17527. <entry>---</entry>
  17528. </row>
  17529. <row>
  17530. <entry><emphasis role="strong"><ulink url="http://www.php.net/manual/en/ref.dba.php"><code>dba</code></ulink></emphasis></entry>
  17531. <entry>---</entry>
  17532. <entry>---</entry>
  17533. </row>
  17534. <row>
  17535. <entry><emphasis role="strong"><ulink url="http://www.php.net/manual/en/ref.dbase.php"><code>dbase</code></ulink></emphasis></entry>
  17536. <entry>---</entry>
  17537. <entry>---</entry>
  17538. </row>
  17539. <row>
  17540. <entry morerows="10" valign="middle"><emphasis role="strong"><ulink url="http://www.php.net/manual/en/ref.dom.php"><code>dom</code></ulink></emphasis></entry>
  17541. <entry morerows="10" valign="middle">Hard</entry>
  17542. <entry><ulink url="http://framework.zend.com/manual/en/zend.feed.html"><code>Zend_Feed</code></ulink></entry>
  17543. </row>
  17544. <row>
  17545. <entry><ulink url="http://framework.zend.com/manual/en/zend.gdata.html"><code>Zend_Gdata</code></ulink></entry>
  17546. </row>
  17547. <row>
  17548. <entry><ulink url="http://framework.zend.com/manual/en/zend.log.formatters.html"><code>Zend_Log_Formatter_Xml</code></ulink></entry>
  17549. </row>
  17550. <row>
  17551. <entry><ulink url="http://framework.zend.com/manual/en/zend.rest.server.html"><code>Zend_Rest_Server</code></ulink></entry>
  17552. </row>
  17553. <row>
  17554. <entry><ulink url="http://framework.zend.com/manual/en/zend.search.lucene.html"><code>Zend_Search_Lucene</code></ulink></entry>
  17555. </row>
  17556. <row>
  17557. <entry><ulink url="http://framework.zend.com/manual/en/zend.service.amazon.html"><code>Zend_Service_Amazon</code></ulink></entry>
  17558. </row>
  17559. <row>
  17560. <entry><ulink url="http://framework.zend.com/manual/en/zend.service.delicious.html"><code>Zend_Service_Delicious</code></ulink></entry>
  17561. </row>
  17562. <row>
  17563. <entry><ulink url="http://framework.zend.com/manual/en/zend.service.flickr.html"><code>Zend_Service_Flickr</code></ulink></entry>
  17564. </row>
  17565. <row>
  17566. <entry><ulink url="http://framework.zend.com/manual/en/zend.service.simpy.html"><code>Zend_Service_Simpy</code></ulink></entry>
  17567. </row>
  17568. <row>
  17569. <entry><ulink url="http://framework.zend.com/manual/en/zend.service.yahoo.html"><code>Zend_Service_Yahoo</code></ulink></entry>
  17570. </row>
  17571. <row>
  17572. <entry><ulink url="http://framework.zend.com/manual/en/zend.xmlrpc.html"><code>Zend_XmlRpc</code></ulink></entry>
  17573. </row>
  17574. <row>
  17575. <entry><emphasis role="strong"><ulink url="http://www.php.net/manual/en/ref.exif.php"><code>exif</code></ulink></emphasis></entry>
  17576. <entry>---</entry>
  17577. <entry>---</entry>
  17578. </row>
  17579. <row>
  17580. <entry><emphasis role="strong"><ulink url="http://www.php.net/manual/en/ref.fbsql.php"><code>fbsql</code></ulink></emphasis></entry>
  17581. <entry>---</entry>
  17582. <entry>---</entry>
  17583. </row>
  17584. <row>
  17585. <entry><emphasis role="strong"><ulink url="http://www.php.net/manual/en/ref.fdf.php"><code>fdf</code></ulink></emphasis></entry>
  17586. <entry>---</entry>
  17587. <entry>---</entry>
  17588. </row>
  17589. <row>
  17590. <entry><emphasis role="strong"><ulink url="http://www.php.net/manual/en/ref.filter.php"><code>filter</code></ulink></emphasis></entry>
  17591. <entry>---</entry>
  17592. <entry>---</entry>
  17593. </row>
  17594. <row>
  17595. <entry><emphasis role="strong"><ulink url="http://www.php.net/manual/en/ref.ftp.php"><code>ftp</code></ulink></emphasis></entry>
  17596. <entry>---</entry>
  17597. <entry>---</entry>
  17598. </row>
  17599. <row>
  17600. <entry><emphasis role="strong"><ulink url="http://www.php.net/manual/en/ref.image.php"><code>gd</code></ulink></emphasis></entry>
  17601. <entry>Hard</entry>
  17602. <entry><ulink url="http://framework.zend.com/manual/en/zend.pdf.html"><code>Zend_Pdf</code></ulink></entry>
  17603. </row>
  17604. <row>
  17605. <entry><emphasis role="strong"><ulink url="http://www.php.net/manual/en/ref.gettext.php"><code>gettext</code></ulink></emphasis></entry>
  17606. <entry>---</entry>
  17607. <entry>---</entry>
  17608. </row>
  17609. <row>
  17610. <entry><emphasis role="strong"><ulink url="http://www.php.net/manual/en/ref.gmp.php"><code>gmp</code></ulink></emphasis></entry>
  17611. <entry>---</entry>
  17612. <entry>---</entry>
  17613. </row>
  17614. <row>
  17615. <entry><emphasis role="strong"><ulink url="http://www.php.net/manual/en/ref.hash.php"><code>hash</code></ulink></emphasis></entry>
  17616. <entry>Hard</entry>
  17617. <entry><ulink url="http://framework.zend.com/manual/en/zend.auth.adapter.http.html"><code>Zend_Auth_Adapter_Http</code></ulink></entry>
  17618. </row>
  17619. <row>
  17620. <entry><emphasis role="strong"><ulink url="http://www.php.net/manual/en/ref.ibm-db2.php"><code>ibm_db2</code></ulink></emphasis></entry>
  17621. <entry>Hard</entry>
  17622. <entry><ulink url="http://framework.zend.com/manual/en/zend.db.html"><code>Zend_Db_Adapter_Db2</code></ulink></entry>
  17623. </row>
  17624. <row>
  17625. <entry morerows="7" valign="middle"><emphasis role="strong"><ulink url="http://www.php.net/manual/en/ref.iconv.php"><code>iconv</code></ulink></emphasis></entry>
  17626. <entry morerows="7" valign="middle">Hard</entry>
  17627. <entry><ulink url="http://framework.zend.com/manual/en/zend.currency.html"><code>Zend_Currency</code></ulink></entry>
  17628. </row>
  17629. <row>
  17630. <entry><ulink url="http://framework.zend.com/manual/en/zend.locale.parsing.html"><code>Zend_Locale_Format</code></ulink></entry>
  17631. </row>
  17632. <row>
  17633. <entry><ulink url="http://framework.zend.com/manual/en/zend.mime.html"><code>Zend_Mime</code></ulink></entry>
  17634. </row>
  17635. <row>
  17636. <entry><ulink url="http://framework.zend.com/manual/en/zend.pdf.html"><code>Zend_Pdf</code></ulink></entry>
  17637. </row>
  17638. <row>
  17639. <entry><ulink url="http://framework.zend.com/manual/en/zend.search.lucene.html"><code>Zend_Search_Lucene</code></ulink></entry>
  17640. </row>
  17641. <row>
  17642. <entry><ulink url="http://framework.zend.com/manual/en/zend.service.audioscrobbler.html"><code>Zend_Service_Audioscrobbler</code></ulink></entry>
  17643. </row>
  17644. <row>
  17645. <entry><ulink url="http://framework.zend.com/manual/en/zend.service.flickr.html"><code>Zend_Service_Flickr</code></ulink></entry>
  17646. </row>
  17647. <row>
  17648. <entry><ulink url="http://framework.zend.com/manual/en/zend.xmlrpc.client.html"><code>Zend_XmlRpc_Client</code></ulink></entry>
  17649. </row>
  17650. <row>
  17651. <entry><emphasis role="strong"><ulink url="http://www.php.net/manual/en/ref.imap.php"><code>imap</code></ulink></emphasis></entry>
  17652. <entry>---</entry>
  17653. <entry>---</entry>
  17654. </row>
  17655. <row>
  17656. <entry><emphasis role="strong"><ulink url="http://www.php.net/manual/en/ref.ifx.php"><code>informix</code></ulink></emphasis></entry>
  17657. <entry>---</entry>
  17658. <entry>---</entry>
  17659. </row>
  17660. <row>
  17661. <entry><emphasis role="strong"><ulink url="http://www.php.net/manual/en/ref.ibase.php"><code>interbase</code></ulink></emphasis></entry>
  17662. <entry>Hard</entry>
  17663. <entry>Zend_Db_Adapter_Firebird</entry>
  17664. </row>
  17665. <row>
  17666. <entry><emphasis role="strong"><ulink url="http://www.php.net/manual/en/ref.json.php"><code>json</code></ulink></emphasis></entry>
  17667. <entry>Soft</entry>
  17668. <entry><ulink url="http://framework.zend.com/manual/en/zend.json.html"><code>Zend_Json</code></ulink></entry>
  17669. </row>
  17670. <row>
  17671. <entry><emphasis role="strong"><ulink url="http://www.php.net/manual/en/ref.ldap.php"><code>ldap</code></ulink></emphasis></entry>
  17672. <entry>---</entry>
  17673. <entry>---</entry>
  17674. </row>
  17675. <row>
  17676. <entry morerows="2" valign="middle"><emphasis role="strong"><ulink url="http://www.php.net/manual/en/ref.libxml.php"><code>libxml</code></ulink></emphasis></entry>
  17677. <entry morerows="2" valign="middle">Hard</entry>
  17678. <entry><ulink url="http://www.php.net/manual/en/ref.dom.php"><code>DOM</code></ulink></entry>
  17679. </row>
  17680. <row>
  17681. <entry><ulink url="http://www.php.net/manual/en/ref.simplexml.php"><code>SimpleXML</code></ulink></entry>
  17682. </row>
  17683. <row>
  17684. <entry><ulink url="http://www.php.net/manual/en/ref.xslt.php"><code>XSLT</code></ulink></entry>
  17685. </row>
  17686. <row>
  17687. <entry><emphasis role="strong"><ulink url="http://www.php.net/manual/en/ref.mbstring.php"><code>mbstring</code></ulink></emphasis></entry>
  17688. <entry>Hard</entry>
  17689. <entry><ulink url="http://framework.zend.com/manual/en/zend.feed.html"><code>Zend_Feed</code></ulink></entry>
  17690. </row>
  17691. <row>
  17692. <entry><emphasis role="strong"><ulink url="http://www.php.net/manual/en/ref.mcrypt.php"><code>mcrypt</code></ulink></emphasis></entry>
  17693. <entry>---</entry>
  17694. <entry>---</entry>
  17695. </row>
  17696. <row>
  17697. <entry><emphasis role="strong"><ulink url="http://www.php.net/manual/en/ref.memcache.php"><code>memcache</code></ulink></emphasis></entry>
  17698. <entry>Hard</entry>
  17699. <entry><ulink url="http://framework.zend.com/manual/en/zend.cache.backends.html"><code>Zend_Cache_Backend_Memcached</code></ulink></entry>
  17700. </row>
  17701. <row>
  17702. <entry><emphasis role="strong"><ulink url="http://www.php.net/manual/en/ref.mhash.php"><code>mhash</code></ulink></emphasis></entry>
  17703. <entry>---</entry>
  17704. <entry>---</entry>
  17705. </row>
  17706. <row>
  17707. <entry><emphasis role="strong"><ulink url="http://www.php.net/manual/en/ref.mime-magic.php"><code>mime_magic</code></ulink></emphasis></entry>
  17708. <entry>Hard</entry>
  17709. <entry><ulink url="http://framework.zend.com/manual/en/zend.http.html"><code>Zend_Http_Client</code></ulink></entry>
  17710. </row>
  17711. <row>
  17712. <entry><emphasis role="strong"><ulink url="http://www.php.net/manual/en/ref.ming.php"><code>ming</code></ulink></emphasis></entry>
  17713. <entry>---</entry>
  17714. <entry>---</entry>
  17715. </row>
  17716. <row>
  17717. <entry><emphasis role="strong"><ulink url="http://www.php.net/manual/en/ref.msql.php"><code>msql</code></ulink></emphasis></entry>
  17718. <entry>---</entry>
  17719. <entry>---</entry>
  17720. </row>
  17721. <row>
  17722. <entry><emphasis role="strong"><ulink url="http://www.php.net/manual/en/ref.mssql.php"><code>mssql</code></ulink></emphasis></entry>
  17723. <entry>---</entry>
  17724. <entry>---</entry>
  17725. </row>
  17726. <row>
  17727. <entry><emphasis role="strong"><ulink url="http://www.php.net/manual/en/ref.mysql.php"><code>mysql</code></ulink></emphasis></entry>
  17728. <entry>---</entry>
  17729. <entry>---</entry>
  17730. </row>
  17731. <row>
  17732. <entry><emphasis role="strong"><ulink url="http://www.php.net/manual/en/ref.mysqli.php"><code>mysqli</code></ulink></emphasis></entry>
  17733. <entry>Hard</entry>
  17734. <entry><ulink url="http://framework.zend.com/manual/en/zend.db.html"><code>Zend_Db_Adapter_Mysqli</code></ulink></entry>
  17735. </row>
  17736. <row>
  17737. <entry><emphasis role="strong"><ulink url="http://www.php.net/manual/en/ref.ncurses.php"><code>ncurses</code></ulink></emphasis></entry>
  17738. <entry>---</entry>
  17739. <entry>---</entry>
  17740. </row>
  17741. <row>
  17742. <entry><emphasis role="strong"><ulink url="http://www.php.net/manual/en/ref.oci8.php"><code>oci8</code></ulink></emphasis></entry>
  17743. <entry>Hard</entry>
  17744. <entry><ulink url="http://framework.zend.com/manual/en/zend.db.html"><code>Zend_Db_Adapter_Oracle</code></ulink></entry>
  17745. </row>
  17746. <row>
  17747. <entry><emphasis role="strong"><ulink url="http://www.php.net/manual/en/ref.uodbc.php"><code>odbc</code></ulink></emphasis></entry>
  17748. <entry>---</entry>
  17749. <entry>---</entry>
  17750. </row>
  17751. <row>
  17752. <entry><emphasis role="strong"><ulink url="http://www.php.net/manual/en/ref.openssl.php"><code>openssl</code></ulink></emphasis></entry>
  17753. <entry>---</entry>
  17754. <entry>---</entry>
  17755. </row>
  17756. <row>
  17757. <entry><emphasis role="strong"><ulink url="http://www.php.net/manual/en/ref.pcntl.php"><code>pcntl</code></ulink></emphasis></entry>
  17758. <entry>---</entry>
  17759. <entry>---</entry>
  17760. </row>
  17761. <row>
  17762. <entry><emphasis role="strong"><ulink url="http://www.php.net/manual/en/ref.pcre.php"><code>pcre</code></ulink></emphasis></entry>
  17763. <entry>Hard</entry>
  17764. <entry>Virtually all components</entry>
  17765. </row>
  17766. <row>
  17767. <entry><emphasis role="strong"><ulink url="http://www.php.net/manual/en/ref.pdo.php"><code>pdo</code></ulink></emphasis></entry>
  17768. <entry>Hard</entry>
  17769. <entry>All PDO database adapters</entry>
  17770. </row>
  17771. <row>
  17772. <entry><emphasis role="strong"><ulink url="http://www.php.net/manual/en/ref.pdo-dblib.php"><code>pdo_dblib</code></ulink></emphasis></entry>
  17773. <entry>---</entry>
  17774. <entry>---</entry>
  17775. </row>
  17776. <row>
  17777. <entry><emphasis role="strong"><ulink url="http://www.php.net/manual/en/ref.pdo-firebird.php"><code>pdo_firebird</code></ulink></emphasis></entry>
  17778. <entry>---</entry>
  17779. <entry>---</entry>
  17780. </row>
  17781. <row>
  17782. <entry><emphasis role="strong"><code>pdo_mssql</code></emphasis></entry>
  17783. <entry>Hard</entry>
  17784. <entry><ulink url="http://framework.zend.com/manual/en/zend.db.html"><code>Zend_Db_Adapter_Pdo_Mssql</code></ulink></entry>
  17785. </row>
  17786. <row>
  17787. <entry><emphasis role="strong"><ulink url="http://www.php.net/manual/en/ref.pdo-mysql.php"><code>pdo_mysql</code></ulink></emphasis></entry>
  17788. <entry>Hard</entry>
  17789. <entry><ulink url="http://framework.zend.com/manual/en/zend.db.html"><code>Zend_Db_Adapter_Pdo_Mysql</code></ulink></entry>
  17790. </row>
  17791. <row>
  17792. <entry><emphasis role="strong"><ulink url="http://www.php.net/manual/en/ref.pdo-oci.php"><code>pdo_oci</code></ulink></emphasis></entry>
  17793. <entry>Hard</entry>
  17794. <entry><ulink url="http://framework.zend.com/manual/en/zend.db.html"><code>Zend_Db_Adapter_Pdo_Oci</code></ulink></entry>
  17795. </row>
  17796. <row>
  17797. <entry><emphasis role="strong"><ulink url="http://www.php.net/manual/en/ref.pdo-pgsql.php"><code>pdo_pgsql</code></ulink></emphasis></entry>
  17798. <entry>Hard</entry>
  17799. <entry><ulink url="http://framework.zend.com/manual/en/zend.db.html"><code>Zend_Db_Adapter_Pdo_Pgsql</code></ulink></entry>
  17800. </row>
  17801. <row>
  17802. <entry><emphasis role="strong"><ulink url="http://www.php.net/manual/en/ref.pdo-sqlite.php"><code>pdo_sqlite</code></ulink></emphasis></entry>
  17803. <entry>Hard</entry>
  17804. <entry><ulink url="http://framework.zend.com/manual/en/zend.db.html"><code>Zend_Db_Adapter_Pdo_Sqlite</code></ulink></entry>
  17805. </row>
  17806. <row>
  17807. <entry><emphasis role="strong"><ulink url="http://www.php.net/manual/en/ref.pgsql.php"><code>pgsql</code></ulink></emphasis></entry>
  17808. <entry>---</entry>
  17809. <entry>---</entry>
  17810. </row>
  17811. <row>
  17812. <entry><emphasis role="strong"><ulink url="http://www.php.net/manual/en/ref.posix.php"><code>posix</code></ulink></emphasis></entry>
  17813. <entry>Soft</entry>
  17814. <entry><ulink url="http://framework.zend.com/manual/en/zend.mail.html"><code>Zend_Mail</code></ulink></entry>
  17815. </row>
  17816. <row>
  17817. <entry><emphasis role="strong"><ulink url="http://www.php.net/manual/en/ref.pspell.php"><code>pspell</code></ulink></emphasis></entry>
  17818. <entry>---</entry>
  17819. <entry>---</entry>
  17820. </row>
  17821. <row>
  17822. <entry><emphasis role="strong"><ulink url="http://www.php.net/manual/en/ref.readline.php"><code>readline</code></ulink></emphasis></entry>
  17823. <entry>---</entry>
  17824. <entry>---</entry>
  17825. </row>
  17826. <row>
  17827. <entry><emphasis role="strong"><ulink url="http://www.php.net/manual/en/ref.recode.php"><code>recode</code></ulink></emphasis></entry>
  17828. <entry>---</entry>
  17829. <entry>---</entry>
  17830. </row>
  17831. <row>
  17832. <entry morerows="9" valign="middle"><emphasis role="strong"><ulink url="http://www.php.net/manual/en/language.oop5.reflection.php"><code>Reflection</code></ulink></emphasis></entry>
  17833. <entry morerows="9" valign="middle">Hard</entry>
  17834. <entry><ulink url="http://framework.zend.com/manual/en/zend.controller.html"><code>Zend_Controller</code></ulink></entry>
  17835. </row>
  17836. <row>
  17837. <entry><ulink url="http://framework.zend.com/manual/en/zend.filter.html"><code>Zend_Filter</code></ulink></entry>
  17838. </row>
  17839. <row>
  17840. <entry><ulink url="http://framework.zend.com/manual/en/zend.filter.input.html"><code>Zend_Filter_Input</code></ulink></entry>
  17841. </row>
  17842. <row>
  17843. <entry><ulink url="http://framework.zend.com/manual/en/zend.json.html"><code>Zend_Json</code></ulink></entry>
  17844. </row>
  17845. <row>
  17846. <entry><ulink url="http://framework.zend.com/manual/en/zend.log.html"><code>Zend_Log</code></ulink></entry>
  17847. </row>
  17848. <row>
  17849. <entry><ulink url="http://framework.zend.com/manual/en/zend.rest.server.html"><code>Zend_Rest_Server</code></ulink></entry>
  17850. </row>
  17851. <row>
  17852. <entry><ulink url="http://framework.zend.com/manual/en/zend.server.reflection.html"><code>Zend_Server_Reflection</code></ulink></entry>
  17853. </row>
  17854. <row>
  17855. <entry><ulink url="http://framework.zend.com/manual/en/zend.validate.html"><code>Zend_Validate</code></ulink></entry>
  17856. </row>
  17857. <row>
  17858. <entry><ulink url="http://framework.zend.com/manual/en/zend.view.html"><code>Zend_View</code></ulink></entry>
  17859. </row>
  17860. <row>
  17861. <entry><ulink url="http://framework.zend.com/manual/en/zend.xmlrpc.server.html"><code>Zend_XmlRpc_Server</code></ulink></entry>
  17862. </row>
  17863. <row>
  17864. <entry morerows="1" valign="middle"><emphasis role="strong"><ulink url="http://www.php.net/manual/en/ref.session.php"><code>session</code></ulink></emphasis></entry>
  17865. <entry morerows="1" valign="middle">Hard</entry>
  17866. <entry><ulink url="http://framework.zend.com/manual/en/zend.controller.actionhelpers.html"><code>Zend_Controller_Action_Helper_Redirector</code></ulink></entry>
  17867. </row>
  17868. <row>
  17869. <entry><ulink url="http://framework.zend.com/manual/en/zend.session.html"><code>Zend_Session</code></ulink></entry>
  17870. </row>
  17871. <row>
  17872. <entry><emphasis role="strong"><ulink url="http://www.php.net/manual/en/ref.shmop.php"><code>shmop</code></ulink></emphasis></entry>
  17873. <entry>---</entry>
  17874. <entry/>
  17875. </row>
  17876. <row>
  17877. <entry morerows="4" valign="middle"><emphasis role="strong"><ulink url="http://www.php.net/manual/en/ref.simplexml.php"><code>SimpleXML</code></ulink></emphasis></entry>
  17878. <entry morerows="4" valign="middle">Hard</entry>
  17879. <entry><ulink url="http://framework.zend.com/manual/en/zend.config.adapters.xml.html"><code>Zend_Config_Xml</code></ulink></entry>
  17880. </row>
  17881. <row>
  17882. <entry><ulink url="http://framework.zend.com/manual/en/zend.feed.html"><code>Zend_Feed</code></ulink></entry>
  17883. </row>
  17884. <row>
  17885. <entry><ulink url="http://framework.zend.com/manual/en/zend.rest.client.html"><code>Zend_Rest_Client</code></ulink></entry>
  17886. </row>
  17887. <row>
  17888. <entry><ulink url="http://framework.zend.com/manual/en/zend.service.audioscrobbler.html"><code>Zend_Service_Audioscrobbler</code></ulink></entry>
  17889. </row>
  17890. <row>
  17891. <entry><ulink url="http://framework.zend.com/manual/en/zend.xmlrpc.html"><code>Zend_XmlRpc</code></ulink></entry>
  17892. </row>
  17893. <row>
  17894. <entry><emphasis role="strong"><ulink url="http://www.php.net/manual/en/ref.soap.php"><code>soap</code></ulink></emphasis></entry>
  17895. <entry>Hard</entry>
  17896. <entry><ulink url="http://framework.zend.com/manual/en/zend.service.strikeiron.html"><code>Zend_Service_StrikeIron</code></ulink></entry>
  17897. </row>
  17898. <row>
  17899. <entry><emphasis role="strong"><ulink url="http://www.php.net/manual/en/ref.sockets.php"><code>sockets</code></ulink></emphasis></entry>
  17900. <entry>---</entry>
  17901. <entry>---</entry>
  17902. </row>
  17903. <row>
  17904. <entry><emphasis role="strong"><ulink url="http://www.php.net/manual/en/ref.spl.php"><code>SPL</code></ulink></emphasis></entry>
  17905. <entry>Hard</entry>
  17906. <entry>Virtually all components</entry>
  17907. </row>
  17908. <row>
  17909. <entry><emphasis role="strong"><ulink url="http://www.php.net/manual/en/ref.sqlite.php"><code>SQLite</code></ulink></emphasis></entry>
  17910. <entry>Hard</entry>
  17911. <entry><ulink url="http://framework.zend.com/manual/en/zend.cache.backends.html">Zend_Cache_Backend_Sqlite</ulink></entry>
  17912. </row>
  17913. <row>
  17914. <entry><emphasis role="strong"><code>standard</code></emphasis></entry>
  17915. <entry>Hard</entry>
  17916. <entry>Virtually all components</entry>
  17917. </row>
  17918. <row>
  17919. <entry><emphasis role="strong"><ulink url="http://www.php.net/manual/en/ref.sybase.php"><code>sybase</code></ulink></emphasis></entry>
  17920. <entry>---</entry>
  17921. <entry>---</entry>
  17922. </row>
  17923. <row>
  17924. <entry><emphasis role="strong">sysvmsg</emphasis></entry>
  17925. <entry>---</entry>
  17926. <entry>---</entry>
  17927. </row>
  17928. <row>
  17929. <entry><emphasis role="strong">sysvsem</emphasis></entry>
  17930. <entry>---</entry>
  17931. <entry>--</entry>
  17932. </row>
  17933. <row>
  17934. <entry><emphasis role="strong">sysvshm</emphasis></entry>
  17935. <entry>---</entry>
  17936. <entry>---</entry>
  17937. </row>
  17938. <row>
  17939. <entry><emphasis role="strong"><ulink url="http://www.php.net/manual/en/ref.tidy.php"><code>tidy</code></ulink></emphasis></entry>
  17940. <entry>---</entry>
  17941. <entry>---</entry>
  17942. </row>
  17943. <row>
  17944. <entry><emphasis role="strong"><ulink url="http://www.php.net/manual/en/ref.tokenizer.php"><code>tokenizer</code></ulink></emphasis></entry>
  17945. <entry>---</entry>
  17946. <entry>---</entry>
  17947. </row>
  17948. <row>
  17949. <entry><emphasis role="strong"><ulink url="http://www.php.net/manual/en/ref.wddx.php"><code>wddx</code></ulink></emphasis></entry>
  17950. <entry>---</entry>
  17951. <entry>---</entry>
  17952. </row>
  17953. <row>
  17954. <entry morerows="2" valign="middle"><emphasis role="strong"><ulink url="http://www.php.net/manual/en/ref.xml.php"><code>xml</code></ulink></emphasis></entry>
  17955. <entry morerows="2" valign="middle">Hard</entry>
  17956. <entry><ulink url="http://framework.zend.com/manual/en/zend.translate.adapter.html"><code>Zend_Translate_Adapter_Qt</code></ulink></entry>
  17957. </row>
  17958. <row>
  17959. <entry><ulink url="http://framework.zend.com/manual/en/zend.translate.adapter.html"><code>Zend_Translate_Adapter_Tmx</code></ulink></entry>
  17960. </row>
  17961. <row>
  17962. <entry><ulink url="http://framework.zend.com/manual/en/zend.translate.adapter.html"><code>Zend_Translate_Adapter_Xliff</code></ulink></entry>
  17963. </row>
  17964. <row>
  17965. <entry><emphasis role="strong"><ulink url="http://www.php.net/manual/en/ref.xmlreader.php"><code>XMLReader</code></ulink></emphasis></entry>
  17966. <entry>---</entry>
  17967. <entry>---</entry>
  17968. </row>
  17969. <row>
  17970. <entry><emphasis role="strong"><ulink url="http://www.php.net/manual/en/ref.xmlrpc.php"><code>xmlrpc</code></ulink></emphasis></entry>
  17971. <entry>---</entry>
  17972. <entry>---</entry>
  17973. </row>
  17974. <row>
  17975. <entry><emphasis role="strong"><ulink url="http://www.php.net/manual/en/ref.xmlwriter.php"><code>XMLWriter</code></ulink></emphasis></entry>
  17976. <entry>---</entry>
  17977. <entry>---</entry>
  17978. </row>
  17979. <row>
  17980. <entry><emphasis role="strong"><ulink url="http://www.php.net/manual/en/ref.xsl.php"><code>xsl</code></ulink></emphasis></entry>
  17981. <entry>---</entry>
  17982. <entry>---</entry>
  17983. </row>
  17984. <row>
  17985. <entry><emphasis role="strong"><ulink url="http://www.php.net/manual/en/ref.zip.php"><code>zip</code></ulink></emphasis></entry>
  17986. <entry>---</entry>
  17987. <entry>---</entry>
  17988. </row>
  17989. <row>
  17990. <entry morerows="1" valign="middle"><emphasis role="strong"><ulink url="http://www.php.net/manual/en/ref.zlib.php"><code>zlib</code></ulink></emphasis></entry>
  17991. <entry morerows="1" valign="middle">Hard</entry>
  17992. <entry><ulink url="http://framework.zend.com/manual/en/zend.pdf.html"><code>Zend_Pdf</code></ulink></entry>
  17993. </row>
  17994. <row>
  17995. <entry><ulink url="http://www.php.net/manual/en/ref.memcache.php"><code>Memcache</code></ulink></entry>
  17996. </row>
  17997. </tbody>
  17998. </tgroup>
  17999. </table>
  18000. </sect1>
  18001. <sect1 id="requirements.zendcomponents">
  18002. <title>Zend Framework Components</title>
  18003. <para>
  18004. Below is a table that lists all available Zend Framework Components
  18005. and which PHP extension they need. This can help guide you
  18006. to know which extensions are required for your application.
  18007. Not all extensions used by Zend Framework are required for every
  18008. application.
  18009. </para>
  18010. <para>
  18011. A dependency of type "hard" indicates that the components or classes
  18012. cannot function properly if the respective extension is not available,
  18013. while a dependency of type "soft" indicates that the component may use
  18014. the extension if it is available but will function properly if it is not.
  18015. Many components will automatically use certain extensions if they are available
  18016. to optimize performance but will execute code with similar functionality in the
  18017. component itself if the extensions are unavailable.
  18018. </para>
  18019. <table frame="all" id="requirements.zendcomponents.table-1">
  18020. <title>Zend Framework Components and the PHP Extensions they use</title>
  18021. <tgroup cols="4">
  18022. <!-- <colspec colwidth='3in'/>
  18023. <colspec colwidth='1in'/>
  18024. <colspec colwidth='3in'/>
  18025. <colspec colwidth='3in'/> -->
  18026. <thead>
  18027. <row>
  18028. <entry>Zend Framework Components</entry>
  18029. <entry>Dependency Type</entry>
  18030. <entry>Subclass</entry>
  18031. <entry>PHP Extension</entry>
  18032. </row>
  18033. </thead>
  18034. <tbody>
  18035. <row>
  18036. <entry morerows="2" valign="middle"><emphasis role="strong">All Components</emphasis></entry>
  18037. <entry morerows="2" valign="middle">Hard</entry>
  18038. <entry morerows="2" valign="middle">---</entry>
  18039. <entry><ulink url="http://www.php.net/manual/en/ref.pcre.php"><code>pcre</code></ulink></entry>
  18040. </row>
  18041. <row>
  18042. <entry><ulink url="http://www.php.net/manual/en/ref.spl.php"><code>SPL</code></ulink></entry>
  18043. </row>
  18044. <row>
  18045. <entry><code>standard</code></entry>
  18046. </row>
  18047. <row>
  18048. <entry><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.acl.html"><code>Zend_Acl</code></ulink></emphasis></entry>
  18049. <entry>---</entry>
  18050. <entry>---</entry>
  18051. <entry>---</entry>
  18052. </row>
  18053. <row>
  18054. <entry morerows="1" valign="middle"><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.auth.html"><code>Zend_Auth</code></ulink></emphasis></entry>
  18055. <entry morerows="1" valign="middle">Hard</entry>
  18056. <entry morerows="1" valign="middle"><ulink url="http://framework.zend.com/manual/en/zend.auth.adapter.http.html"><code>Zend_Auth_Adapter_Http</code></ulink></entry>
  18057. <entry><ulink url="http://www.php.net/manual/en/ref.ctype.php"><code>ctype</code></ulink></entry>
  18058. </row>
  18059. <row>
  18060. <entry><ulink url="http://www.php.net/manual/en/ref.hash.php"><code>hash</code></ulink></entry>
  18061. </row>
  18062. <row>
  18063. <entry morerows="3" valign="middle"><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.cache.html"><code>Zend_Cache</code></ulink></emphasis></entry>
  18064. <entry morerows="3" valign="middle">Hard</entry>
  18065. <entry><ulink url="http://framework.zend.com/manual/en/zend.cache.backends.html"><code>Zend_Cache_Backend_Apc</code></ulink></entry>
  18066. <entry><ulink url="http://www.php.net/manual/en/ref.apc.php"><code>apc</code></ulink></entry>
  18067. </row>
  18068. <row>
  18069. <entry><ulink url="http://framework.zend.com/manual/en/zend.cache.backends.html"><code>Zend_Cache_Backend_Memcached</code></ulink></entry>
  18070. <entry><ulink url="http://www.php.net/manual/en/ref.memcache.php"><code>memcache</code></ulink></entry>
  18071. </row>
  18072. <row>
  18073. <entry><ulink url="http://framework.zend.com/manual/en/zend.cache.backends.html"><code>Zend_Cache_Backend_Sqlite</code></ulink></entry>
  18074. <entry><ulink url="http://www.php.net/manual/en/ref.sqlite.php"><code>sqlite</code></ulink></entry>
  18075. </row>
  18076. <row>
  18077. <entry><ulink url="http://framework.zend.com/manual/en/zend.cache.backends.html"><code>Zend_Cache_Backend_Zlib</code></ulink></entry>
  18078. <entry><ulink url="http://www.php.net/manual/en/ref.zlib.php"><code>zlib</code></ulink></entry>
  18079. </row>
  18080. <row>
  18081. <entry morerows="1" valign="middle"><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.config.html"><code>Zend_Config</code></ulink></emphasis></entry>
  18082. <entry morerows="1" valign="middle">Hard</entry>
  18083. <entry morerows="1" valign="middle"><ulink url="http://framework.zend.com/manual/en/zend.config.adapters.xml.html"><code>Zend_Config_Xml</code></ulink></entry>
  18084. <entry><ulink url="http://www.php.net/manual/en/ref.libxml.php"><code>libxml</code></ulink></entry>
  18085. </row>
  18086. <row>
  18087. <entry><ulink url="http://www.php.net/manual/en/ref.simplexml.php"><code>SimpleXML</code></ulink></entry>
  18088. </row>
  18089. <row>
  18090. <entry><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.console.getopt.html"><code>Zend_Console_Getopt</code></ulink></emphasis></entry>
  18091. <entry>---</entry>
  18092. <entry>---</entry>
  18093. <entry>---</entry>
  18094. </row>
  18095. <row>
  18096. <entry morerows="1" valign="middle"><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.controller.html"><code>Zend_Controller</code></ulink></emphasis></entry>
  18097. <entry morerows="1" valign="middle">Hard</entry>
  18098. <entry>---</entry>
  18099. <entry><ulink url="http://www.php.net/manual/en/language.oop5.reflection.php"><code>Reflection</code></ulink></entry>
  18100. </row>
  18101. <row>
  18102. <entry><ulink url="http://framework.zend.com/manual/en/zend.controller.actionhelpers.html"><code>Zend_Controller_Action_Helper_Redirector</code></ulink></entry>
  18103. <entry><ulink url="http://www.php.net/manual/en/ref.session.php"><code>session</code></ulink></entry>
  18104. </row>
  18105. <row>
  18106. <entry><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.currency.html"><code>Zend_Currency</code></ulink></emphasis></entry>
  18107. <entry>Hard</entry>
  18108. <entry>---</entry>
  18109. <entry><ulink url="http://www.php.net/manual/en/ref.iconv.php"><code>iconv</code></ulink></entry>
  18110. </row>
  18111. <row>
  18112. <entry><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.date.html"><code>Zend_Date</code></ulink></emphasis></entry>
  18113. <entry>---</entry>
  18114. <entry>---</entry>
  18115. <entry>---</entry>
  18116. </row>
  18117. <row>
  18118. <entry morerows="8" valign="middle"><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.db.html"><code>Zend_Db</code></ulink></emphasis></entry>
  18119. <entry morerows="8" valign="middle">Hard</entry>
  18120. <entry>All PDO Adapters</entry>
  18121. <entry><ulink url="http://www.php.net/manual/en/ref.pdo.php"><code>pdo</code></ulink></entry>
  18122. </row>
  18123. <row>
  18124. <entry><ulink url="http://framework.zend.com/manual/en/zend.db.html"><code>Zend_Db_Adapter_Db2</code></ulink></entry>
  18125. <entry><ulink url="http://www.php.net/manual/en/ref.ibm-db2.php"><code>ibm_db2</code></ulink></entry>
  18126. </row>
  18127. <row>
  18128. <entry><ulink url="http://framework.zend.com/manual/en/zend.db.html"><code>Zend_Db_Adapter_Mysqli</code></ulink></entry>
  18129. <entry><ulink url="http://www.php.net/manual/en/ref.mysqli.php"><code>mysqli</code></ulink></entry>
  18130. </row>
  18131. <row>
  18132. <entry><ulink url="http://framework.zend.com/manual/en/zend.db.html"><code>Zend_Db_Adapter_Oracle</code></ulink></entry>
  18133. <entry><ulink url="http://www.php.net/manual/en/ref.oci8.php"><code>oci8</code></ulink></entry>
  18134. </row>
  18135. <row>
  18136. <entry><ulink url="http://framework.zend.com/manual/en/zend.db.html"><code>Zend_Db_Adapter_Pdo_Mssql</code></ulink></entry>
  18137. <entry>pdo_mssql</entry>
  18138. </row>
  18139. <row>
  18140. <entry><ulink url="http://framework.zend.com/manual/en/zend.db.html"><code>Zend_Db_Adapter_Pdo_Mysql</code></ulink></entry>
  18141. <entry><ulink url="http://www.php.net/manual/en/ref.pdo-mysql.php"><code>pdo_mysql</code></ulink></entry>
  18142. </row>
  18143. <row>
  18144. <entry><ulink url="http://framework.zend.com/manual/en/zend.db.html"><code>Zend_Db_Adapter_Pdo_Oci</code></ulink></entry>
  18145. <entry><ulink url="http://www.php.net/manual/en/ref.pdo-oci.php"><code>pdo_oci</code></ulink></entry>
  18146. </row>
  18147. <row>
  18148. <entry><ulink url="http://framework.zend.com/manual/en/zend.db.html"><code>Zend_Db_Adapter_Pdo_Pgsql</code></ulink></entry>
  18149. <entry><ulink url="http://www.php.net/manual/en/ref.pdo-pgsql.php"><code>pdo_pgsql</code></ulink></entry>
  18150. </row>
  18151. <row>
  18152. <entry><ulink url="http://framework.zend.com/manual/en/zend.db.html"><code>Zend_Db_Adapter_Pdo_Sqlite</code></ulink></entry>
  18153. <entry><ulink url="http://www.php.net/manual/en/ref.pdo-sqlite.php"><code>pdo_sqlite</code></ulink></entry>
  18154. </row>
  18155. <row>
  18156. <entry><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.debug.html"><code>Zend_Debug</code></ulink></emphasis></entry>
  18157. <entry>---</entry>
  18158. <entry>---</entry>
  18159. <entry>---</entry>
  18160. </row>
  18161. <row>
  18162. <entry><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.exception.html"><code>Zend_Exception</code></ulink></emphasis></entry>
  18163. <entry>---</entry>
  18164. <entry>---</entry>
  18165. <entry>---</entry>
  18166. </row>
  18167. <row>
  18168. <entry morerows="3" valign="middle"><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.feed.html"><code>Zend_Feed</code></ulink></emphasis></entry>
  18169. <entry morerows="3" valign="middle">Hard</entry>
  18170. <entry morerows="3" valign="middle">---</entry>
  18171. <entry><ulink url="http://www.php.net/manual/en/ref.dom.php"><code>dom</code></ulink></entry>
  18172. </row>
  18173. <row>
  18174. <entry><ulink url="http://www.php.net/manual/en/ref.libxml.php"><code>libxml</code></ulink></entry>
  18175. </row>
  18176. <row>
  18177. <entry><ulink url="http://www.php.net/manual/en/ref.mbstring.php"><code>mbstring</code></ulink></entry>
  18178. </row>
  18179. <row>
  18180. <entry><ulink url="http://www.php.net/manual/en/ref.simplexml.php"><code>SimpleXML</code></ulink></entry>
  18181. </row>
  18182. <row>
  18183. <entry><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.filter.html"><code>Zend_Filter</code></ulink></emphasis></entry>
  18184. <entry>Hard</entry>
  18185. <entry>---</entry>
  18186. <entry><ulink url="http://www.php.net/manual/en/language.oop5.reflection.php"><code>Reflection</code></ulink></entry>
  18187. </row>
  18188. <row>
  18189. <entry><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.form.html"><code>Zend_Form</code></ulink></emphasis></entry>
  18190. <entry>---</entry>
  18191. <entry>---</entry>
  18192. <entry>---</entry>
  18193. </row>
  18194. <row>
  18195. <entry morerows="2" valign="middle"><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.gdata.html"><code>Zend_Gdata</code></ulink></emphasis></entry>
  18196. <entry morerows="2" valign="middle">Hard</entry>
  18197. <entry><ulink url="http://framework.zend.com/manual/en/zend.gdata.html"><code>Zend_Gdata_App</code></ulink></entry>
  18198. <entry><ulink url="http://www.php.net/manual/en/ref.ctype.php"><code>ctype</code></ulink></entry>
  18199. </row>
  18200. <row>
  18201. <entry morerows="1" valign="middle">---</entry>
  18202. <entry><ulink url="http://www.php.net/manual/en/ref.dom.php"><code>dom</code></ulink></entry>
  18203. </row>
  18204. <row>
  18205. <entry><ulink url="http://www.php.net/manual/en/ref.libxml.php"><code>libxml</code></ulink></entry>
  18206. </row>
  18207. <row>
  18208. <entry morerows="2" valign="middle"><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.http.html"><code>Zend_Http</code></ulink></emphasis></entry>
  18209. <entry morerows="2" valign="middle">Hard</entry>
  18210. <entry><ulink url="http://framework.zend.com/manual/en/zend.http.client.adapters.html"><code>Zend_Http_Client_Adapter_Curl</code></ulink></entry>
  18211. <entry><ulink url="http://www.php.net/manual/en/ref.curl.php"><code>curl</code></ulink></entry>
  18212. </row>
  18213. <row>
  18214. <entry morerows="1" valign="middle"><ulink url="http://framework.zend.com/manual/en/zend.http.html"><code>Zend_Http_Client</code></ulink></entry>
  18215. <entry><ulink url="http://www.php.net/manual/en/ref.ctype.php"><code>ctype</code></ulink></entry>
  18216. </row>
  18217. <row>
  18218. <entry><ulink url="http://www.php.net/manual/en/ref.mime-magic.php"><code>mime_magic</code></ulink></entry>
  18219. </row>
  18220. <row>
  18221. <entry><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.infocard.html"><code>Zend_InfoCard</code></ulink></emphasis></entry>
  18222. <entry>---</entry>
  18223. <entry>---</entry>
  18224. <entry>---</entry>
  18225. </row>
  18226. <row>
  18227. <entry morerows="1" valign="middle"><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.json.html"><code>Zend_Json</code></ulink></emphasis></entry>
  18228. <entry>Soft</entry>
  18229. <entry>---</entry>
  18230. <entry><ulink url="http://www.php.net/manual/en/ref.json.php"><code>json</code></ulink></entry>
  18231. </row>
  18232. <row>
  18233. <entry>Hard</entry>
  18234. <entry>---</entry>
  18235. <entry><ulink url="http://www.php.net/manual/en/language.oop5.reflection.php"><code>Reflection</code></ulink></entry>
  18236. </row>
  18237. <row>
  18238. <entry><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.layout.html"><code>Zend_Layout</code></ulink></emphasis></entry>
  18239. <entry>---</entry>
  18240. <entry>---</entry>
  18241. <entry>---</entry>
  18242. </row>
  18243. <row>
  18244. <entry><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.ldap.html"><code>Zend_Ldap</code></ulink></emphasis></entry>
  18245. <entry>---</entry>
  18246. <entry>---</entry>
  18247. <entry>---</entry>
  18248. </row>
  18249. <row>
  18250. <entry><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.loader.html"><code>Zend_Loader</code></ulink></emphasis></entry>
  18251. <entry>---</entry>
  18252. <entry>---</entry>
  18253. <entry>---</entry>
  18254. </row>
  18255. <row>
  18256. <entry morerows="1" valign="middle"><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.locale.html"><code>Zend_Locale</code></ulink></emphasis></entry>
  18257. <entry>Soft</entry>
  18258. <entry><ulink url="http://framework.zend.com/manual/en/zend.locale.html"><code>Zend_Locale_Math</code></ulink></entry>
  18259. <entry><ulink url="http://www.php.net/manual/en/ref.bc.php"><code>bcmath</code></ulink></entry>
  18260. </row>
  18261. <row>
  18262. <entry>Hard</entry>
  18263. <entry><ulink url="http://framework.zend.com/manual/en/zend.locale.parsing.html"><code>Zend_Locale_Format</code></ulink></entry>
  18264. <entry><ulink url="http://www.php.net/manual/en/ref.iconv.php"><code>iconv</code></ulink></entry>
  18265. </row>
  18266. <row>
  18267. <entry morerows="2" valign="middle"><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.log.html"><code>Zend_Log</code></ulink></emphasis></entry>
  18268. <entry morerows="2" valign="middle">Hard</entry>
  18269. <entry morerows="1" valign="middle"><ulink url="http://framework.zend.com/manual/en/zend.log.formatters.html"><code>Zend_Log_Formatter_Xml</code></ulink></entry>
  18270. <entry><ulink url="http://www.php.net/manual/en/ref.dom.php"><code>dom</code></ulink></entry>
  18271. </row>
  18272. <row>
  18273. <entry><ulink url="http://www.php.net/manual/en/ref.libxml.php"><code>libxml</code></ulink></entry>
  18274. </row>
  18275. <row>
  18276. <entry>---</entry>
  18277. <entry><ulink url="http://www.php.net/manual/en/language.oop5.reflection.php"><code>Reflection</code></ulink></entry>
  18278. </row>
  18279. <row>
  18280. <entry><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.mail.html"><code>Zend_Mail</code></ulink></emphasis></entry>
  18281. <entry>Soft</entry>
  18282. <entry>---</entry>
  18283. <entry><ulink url="http://www.php.net/manual/en/ref.posix.php"><code>posix</code></ulink></entry>
  18284. </row>
  18285. <row>
  18286. <entry><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.measure.html"><code>Zend_Measure</code></ulink></emphasis></entry>
  18287. <entry>---</entry>
  18288. <entry>---</entry>
  18289. <entry>---</entry>
  18290. </row>
  18291. <row>
  18292. <entry><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.memory.html"><code>Zend_Memory</code></ulink></emphasis></entry>
  18293. <entry>---</entry>
  18294. <entry>---</entry>
  18295. <entry>---</entry>
  18296. </row>
  18297. <row>
  18298. <entry><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.mime.html"><code>Zend_Mime</code></ulink></emphasis></entry>
  18299. <entry>Hard</entry>
  18300. <entry><ulink url="http://framework.zend.com/manual/en/zend.mime.html"><code>Zend_Mime_Decode</code></ulink></entry>
  18301. <entry><ulink url="http://www.php.net/manual/en/ref.iconv.php"><code>iconv</code></ulink></entry>
  18302. </row>
  18303. <row>
  18304. <entry><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.openid.html"><code>Zend_OpenId</code></ulink></emphasis></entry>
  18305. <entry>---</entry>
  18306. <entry>---</entry>
  18307. <entry>---</entry>
  18308. </row>
  18309. <row>
  18310. <entry morerows="3" valign="middle"><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.pdf.html"><code>Zend_Pdf</code></ulink></emphasis></entry>
  18311. <entry morerows="3" valign="middle">Hard</entry>
  18312. <entry morerows="3" valign="middle">---</entry>
  18313. <entry><ulink url="http://www.php.net/manual/en/ref.ctype.php"><code>ctype</code></ulink></entry>
  18314. </row>
  18315. <row>
  18316. <entry><ulink url="http://www.php.net/manual/en/ref.image.php"><code>gd</code></ulink></entry>
  18317. </row>
  18318. <row>
  18319. <entry><ulink url="http://www.php.net/manual/en/ref.iconv.php"><code>iconv</code></ulink></entry>
  18320. </row>
  18321. <row>
  18322. <entry><ulink url="http://www.php.net/manual/en/ref.zlib.php"><code>zlib</code></ulink></entry>
  18323. </row>
  18324. <row>
  18325. <entry><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.registry.html"><code>Zend_Registry</code></ulink></emphasis></entry>
  18326. <entry>---</entry>
  18327. <entry>---</entry>
  18328. <entry>---</entry>
  18329. </row>
  18330. <row>
  18331. <entry><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.request.html"><code>Zend_Request</code></ulink></emphasis></entry>
  18332. <entry>---</entry>
  18333. <entry>---</entry>
  18334. <entry>---</entry>
  18335. </row>
  18336. <row>
  18337. <entry morerows="6" valign="middle"><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.rest.html"><code>Zend_Rest</code></ulink></emphasis></entry>
  18338. <entry morerows="6" valign="middle">Hard</entry>
  18339. <entry morerows="2" valign="middle"><ulink url="http://framework.zend.com/manual/en/zend.rest.client.html"><code>Zend_Rest_Client</code></ulink></entry>
  18340. <entry><ulink url="http://www.php.net/manual/en/ref.ctype.php"><code>ctype</code></ulink></entry>
  18341. </row>
  18342. <row>
  18343. <entry><ulink url="http://www.php.net/manual/en/ref.libxml.php"><code>libxml</code></ulink></entry>
  18344. </row>
  18345. <row>
  18346. <entry><ulink url="http://www.php.net/manual/en/ref.simplexml.php"><code>SimpleXML</code></ulink></entry>
  18347. </row>
  18348. <row>
  18349. <entry morerows="3" valign="middle"><ulink url="http://framework.zend.com/manual/en/zend.rest.server.html"><code>Zend_Rest_Server</code></ulink></entry>
  18350. <entry><ulink url="http://www.php.net/manual/en/ref.ctype.php"><code>ctype</code></ulink></entry>
  18351. </row>
  18352. <row>
  18353. <entry><ulink url="http://www.php.net/manual/en/ref.dom.php"><code>dom</code></ulink></entry>
  18354. </row>
  18355. <row>
  18356. <entry><ulink url="http://www.php.net/manual/en/ref.libxml.php"><code>libxml</code></ulink></entry>
  18357. </row>
  18358. <row>
  18359. <entry><ulink url="http://www.php.net/manual/en/language.oop5.reflection.php"><code>Reflection</code></ulink></entry>
  18360. </row>
  18361. <row>
  18362. <entry morerows="4" valign="middle"><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.search.lucene.html"><code>Zend_Search_Lucene</code></ulink></emphasis></entry>
  18363. <entry>Soft</entry>
  18364. <entry morerows="4" valign="middle">---</entry>
  18365. <entry><ulink url="http://pecl.php.net/package/Bitset"><code>bitset</code></ulink></entry>
  18366. </row>
  18367. <row>
  18368. <entry morerows="3" valign="middle">Hard</entry>
  18369. <entry><ulink url="http://www.php.net/manual/en/ref.ctype.php"><code>ctype</code></ulink></entry>
  18370. </row>
  18371. <row>
  18372. <entry><ulink url="http://www.php.net/manual/en/ref.dom.php"><code>dom</code></ulink></entry>
  18373. </row>
  18374. <row>
  18375. <entry><ulink url="http://www.php.net/manual/en/ref.iconv.php"><code>iconv</code></ulink></entry>
  18376. </row>
  18377. <row>
  18378. <entry><ulink url="http://www.php.net/manual/en/ref.libxml.php"><code>libxml</code></ulink></entry>
  18379. </row>
  18380. <row>
  18381. <entry><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.server.reflection.html"><code>Zend_Server_Reflection</code></ulink></emphasis></entry>
  18382. <entry>Hard</entry>
  18383. <entry>---</entry>
  18384. <entry><ulink url="http://www.php.net/manual/en/language.oop5.reflection.php"><code>Reflection</code></ulink></entry>
  18385. </row>
  18386. <row>
  18387. <entry><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.service.akismet.html"><code>Zend_Service_Akismet</code></ulink></emphasis></entry>
  18388. <entry>---</entry>
  18389. <entry>---</entry>
  18390. <entry>---</entry>
  18391. </row>
  18392. <row>
  18393. <entry morerows="1" valign="middle"><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.service.amazon.html"><code>Zend_Service_Amazon</code></ulink></emphasis></entry>
  18394. <entry morerows="1" valign="middle">Hard</entry>
  18395. <entry morerows="1" valign="middle">---</entry>
  18396. <entry><ulink url="http://www.php.net/manual/en/ref.dom.php"><code>dom</code></ulink></entry>
  18397. </row>
  18398. <row>
  18399. <entry><ulink url="http://www.php.net/manual/en/ref.libxml.php"><code>libxml</code></ulink></entry>
  18400. </row>
  18401. <row>
  18402. <entry morerows="2" valign="middle"><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.service.audioscrobbler.html"><code>Zend_Service_Audioscrobbler</code></ulink></emphasis></entry>
  18403. <entry morerows="2" valign="middle">Hard</entry>
  18404. <entry morerows="2" valign="middle">---</entry>
  18405. <entry><ulink url="http://www.php.net/manual/en/ref.iconv.php"><code>iconv</code></ulink></entry>
  18406. </row>
  18407. <row>
  18408. <entry><ulink url="http://www.php.net/manual/en/ref.libxml.php"><code>libxml</code></ulink></entry>
  18409. </row>
  18410. <row>
  18411. <entry><ulink url="http://www.php.net/manual/en/ref.simplexml.php"><code>SimpleXML</code></ulink></entry>
  18412. </row>
  18413. <row>
  18414. <entry morerows="1" valign="middle"><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.service.delicious.html"><code>Zend_Service_Delicious</code></ulink></emphasis></entry>
  18415. <entry morerows="1" valign="middle">Hard</entry>
  18416. <entry morerows="1" valign="middle">---</entry>
  18417. <entry><ulink url="http://www.php.net/manual/en/ref.dom.php"><code>dom</code></ulink></entry>
  18418. </row>
  18419. <row>
  18420. <entry><ulink url="http://www.php.net/manual/en/ref.libxml.php"><code>libxml</code></ulink></entry>
  18421. </row>
  18422. <row>
  18423. <entry morerows="2" valign="middle"><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.service.flickr.html"><code>Zend_Service_Flickr</code></ulink></emphasis></entry>
  18424. <entry morerows="2" valign="middle">Hard</entry>
  18425. <entry morerows="2" valign="middle">---</entry>
  18426. <entry><ulink url="http://www.php.net/manual/en/ref.dom.php"><code>dom</code></ulink></entry>
  18427. </row>
  18428. <row>
  18429. <entry><ulink url="http://www.php.net/manual/en/ref.iconv.php"><code>iconv</code></ulink></entry>
  18430. </row>
  18431. <row>
  18432. <entry><ulink url="http://www.php.net/manual/en/ref.libxml.php"><code>libxml</code></ulink></entry>
  18433. </row>
  18434. <row>
  18435. <entry><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.service.nirvanix.html"><code>Zend_Service_Nirvanix</code></ulink></emphasis></entry>
  18436. <entry>---</entry>
  18437. <entry>---</entry>
  18438. <entry>---</entry>
  18439. </row>
  18440. <row>
  18441. <entry morerows="1" valign="middle"><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.service.simpy.html"><code>Zend_Service_Simpy</code></ulink></emphasis></entry>
  18442. <entry morerows="1" valign="middle">Hard</entry>
  18443. <entry morerows="1" valign="middle">---</entry>
  18444. <entry><ulink url="http://www.php.net/manual/en/ref.dom.php"><code>dom</code></ulink></entry>
  18445. </row>
  18446. <row>
  18447. <entry><ulink url="http://www.php.net/manual/en/ref.libxml.php"><code>libxml</code></ulink></entry>
  18448. </row>
  18449. <row>
  18450. <entry><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.service.slideshare.html"><code>Zend_Service_SlideShare</code></ulink></emphasis></entry>
  18451. <entry>---</entry>
  18452. <entry>---</entry>
  18453. <entry>---</entry>
  18454. </row>
  18455. <row>
  18456. <entry><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.service.strikeiron.html"><code>Zend_Service_StrikeIron</code></ulink></emphasis></entry>
  18457. <entry>Hard</entry>
  18458. <entry>---</entry>
  18459. <entry><ulink url="http://www.php.net/manual/en/ref.soap.php"><code>soap</code></ulink></entry>
  18460. </row>
  18461. <row>
  18462. <entry><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.service.technorati.html"><code>Zend_Service_Technorati</code></ulink></emphasis></entry>
  18463. <entry>---</entry>
  18464. <entry>---</entry>
  18465. <entry>---</entry>
  18466. </row>
  18467. <row>
  18468. <entry morerows="1" valign="middle"><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.service.yahoo.html"><code>Zend_Service_Yahoo</code></ulink></emphasis></entry>
  18469. <entry morerows="1" valign="middle">Hard</entry>
  18470. <entry morerows="1" valign="middle">---</entry>
  18471. <entry><ulink url="http://www.php.net/manual/en/ref.dom.php"><code>dom</code></ulink></entry>
  18472. </row>
  18473. <row>
  18474. <entry><ulink url="http://www.php.net/manual/en/ref.libxml.php"><code>libxml</code></ulink></entry>
  18475. </row>
  18476. <row>
  18477. <entry><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.session.html"><code>Zend_Session</code></ulink></emphasis></entry>
  18478. <entry>Hard</entry>
  18479. <entry>---</entry>
  18480. <entry><ulink url="http://www.php.net/manual/en/ref.session.php"><code>session</code></ulink></entry>
  18481. </row>
  18482. <row>
  18483. <entry><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.timesync.html"><code>Zend_TimeSync</code></ulink></emphasis></entry>
  18484. <entry>---</entry>
  18485. <entry>---</entry>
  18486. <entry>---</entry>
  18487. </row>
  18488. <row>
  18489. <entry morerows="2" valign="middle"><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.translate.html"><code>Zend_Translate</code></ulink></emphasis></entry>
  18490. <entry morerows="2" valign="middle">Hard</entry>
  18491. <entry><ulink url="http://framework.zend.com/manual/en/zend.translate.adapter.html"><code>Zend_Translate_Adapter_Qt</code></ulink></entry>
  18492. <entry><ulink url="http://www.php.net/manual/en/ref.xml.php"><code>xml</code></ulink></entry>
  18493. </row>
  18494. <row>
  18495. <entry><ulink url="http://framework.zend.com/manual/en/zend.translate.adapter.html"><code>Zend_Translate_Adapter_Tmx</code></ulink></entry>
  18496. <entry><ulink url="http://www.php.net/manual/en/ref.xml.php"><code>xml</code></ulink></entry>
  18497. </row>
  18498. <row>
  18499. <entry><ulink url="http://framework.zend.com/manual/en/zend.translate.adapter.html"><code>Zend_Translate_Adapter_Xliff</code></ulink></entry>
  18500. <entry><ulink url="http://www.php.net/manual/en/ref.xml.php"><code>xml</code></ulink></entry>
  18501. </row>
  18502. <row>
  18503. <entry><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.uri.html"><code>Zend_Uri</code></ulink></emphasis></entry>
  18504. <entry>Hard</entry>
  18505. <entry>---</entry>
  18506. <entry><ulink url="http://www.php.net/manual/en/ref.ctype.php"><code>ctype</code></ulink></entry>
  18507. </row>
  18508. <row>
  18509. <entry morerows="1" valign="middle"><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.validate.html"><code>Zend_Validate</code></ulink></emphasis></entry>
  18510. <entry morerows="1" valign="middle">Hard</entry>
  18511. <entry morerows="1" valign="middle">---</entry>
  18512. <entry><ulink url="http://www.php.net/manual/en/ref.ctype.php"><code>ctype</code></ulink></entry>
  18513. </row>
  18514. <row>
  18515. <entry><ulink url="http://www.php.net/manual/en/language.oop5.reflection.php"><code>Reflection</code></ulink></entry>
  18516. </row>
  18517. <row>
  18518. <entry><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.version.html"><code>Zend_Version</code></ulink></emphasis></entry>
  18519. <entry>---</entry>
  18520. <entry>---</entry>
  18521. <entry>---</entry>
  18522. </row>
  18523. <row>
  18524. <entry><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.validate.html"><code>Zend_Validate</code></ulink></emphasis></entry>
  18525. <entry>Hard</entry>
  18526. <entry>---</entry>
  18527. <entry><ulink url="http://www.php.net/manual/en/language.oop5.reflection.php"><code>Reflection</code></ulink></entry>
  18528. </row>
  18529. <row>
  18530. <entry morerows="4" valign="middle"><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.xmlrpc.html"><code>Zend_XmlRpc</code></ulink></emphasis></entry>
  18531. <entry morerows="4" valign="middle">Hard</entry>
  18532. <entry morerows="2" valign="middle">---</entry>
  18533. <entry><ulink url="http://www.php.net/manual/en/ref.dom.php"><code>dom</code></ulink></entry>
  18534. </row>
  18535. <row>
  18536. <entry><ulink url="http://www.php.net/manual/en/ref.libxml.php"><code>libxml</code></ulink></entry>
  18537. </row>
  18538. <row>
  18539. <entry><ulink url="http://www.php.net/manual/en/ref.simplexml.php"><code>SimpleXML</code></ulink></entry>
  18540. </row>
  18541. <row>
  18542. <entry><ulink url="http://framework.zend.com/manual/en/zend.xmlrpc.client.html"><code>Zend_XmlRpc_Client</code></ulink></entry>
  18543. <entry><ulink url="http://www.php.net/manual/en/ref.iconv.php"><code>iconv</code></ulink></entry>
  18544. </row>
  18545. <row>
  18546. <entry><ulink url="http://framework.zend.com/manual/en/zend.xmlrpc.server.html"><code>Zend_XmlRpc_Server</code></ulink></entry>
  18547. <entry><ulink url="http://www.php.net/manual/en/language.oop5.reflection.php"><code>Reflection</code></ulink></entry>
  18548. </row>
  18549. </tbody>
  18550. </tgroup>
  18551. </table>
  18552. </sect1>
  18553. <sect1 id="requirements.dependencies">
  18554. <title>Zend Framework Dependencies</title>
  18555. <para>
  18556. Below you can find a table listing Zend Framework Components
  18557. and their dependencies to other Zend Framework Components. This
  18558. can help you if you need to have only single components instead
  18559. of the complete Zend Framework.
  18560. </para>
  18561. <para>
  18562. A dependency of type "hard" indicates that the components or classes
  18563. cannot function properly if the respective dependent component is not available,
  18564. while a dependency of type "soft" indicates that the component may need
  18565. the dependent component in special situations or with special adapters.
  18566. </para>
  18567. <note>
  18568. <para>
  18569. Even if it's possible to seperate single components for
  18570. usage from the complete Zend Framework you should keep
  18571. in mind that this can lead to problems when files are missed
  18572. or components are used dynamically.
  18573. </para>
  18574. </note>
  18575. <table frame="all" id="requirements.dependencies.table-1">
  18576. <title>Zend Framework Components and their dependency to other Zend Framework Components</title>
  18577. <tgroup cols="3">
  18578. <colspec colwidth="2in"/>
  18579. <colspec colwidth="1in"/>
  18580. <colspec colwidth="4in"/>
  18581. <thead>
  18582. <row>
  18583. <entry>Zend Framework Component</entry>
  18584. <entry>Dependency Type</entry>
  18585. <entry>Dependent Zend Framework Component</entry>
  18586. </row>
  18587. </thead>
  18588. <tbody>
  18589. <row>
  18590. <entry><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.acl.html"><code>Zend_Acl</code></ulink></emphasis></entry>
  18591. <entry>Hard</entry>
  18592. <entry><ulink url="http://framework.zend.com/manual/en/zend.exception.html"><code>Zend_Exception</code></ulink></entry>
  18593. </row>
  18594. <row>
  18595. <entry morerows="5" valign="middle"><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.auth.html"><code>Zend_Auth</code></ulink></emphasis></entry>
  18596. <entry>Hard</entry>
  18597. <entry><ulink url="http://framework.zend.com/manual/en/zend.exception.html"><code>Zend_Exception</code></ulink></entry>
  18598. </row>
  18599. <row>
  18600. <entry morerows="4" valign="middle">Soft</entry>
  18601. <entry><ulink url="http://framework.zend.com/manual/en/zend.db.html"><code>Zend_Db</code></ulink></entry>
  18602. </row>
  18603. <row>
  18604. <entry><ulink url="http://framework.zend.com/manual/en/zend.infocard.html"><code>Zend_InfoCard</code></ulink></entry>
  18605. </row>
  18606. <row>
  18607. <entry><ulink url="http://framework.zend.com/manual/en/zend.ldap.html"><code>Zend_Ldap</code></ulink></entry>
  18608. </row>
  18609. <row>
  18610. <entry><ulink url="http://framework.zend.com/manual/en/zend.openid.html"><code>Zend_OpenId</code></ulink></entry>
  18611. </row>
  18612. <row>
  18613. <entry><ulink url="http://framework.zend.com/manual/en/zend.session.html"><code>Zend_Session</code></ulink></entry>
  18614. </row>
  18615. <row>
  18616. <entry morerows="1" valign="middle"><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.cache.html"><code>Zend_Cache</code></ulink></emphasis></entry>
  18617. <entry morerows="1" valign="middle">Hard</entry>
  18618. <entry><ulink url="http://framework.zend.com/manual/en/zend.exception.html"><code>Zend_Exception</code></ulink></entry>
  18619. </row>
  18620. <row>
  18621. <entry><ulink url="http://framework.zend.com/manual/en/zend.loader.html"><code>Zend_Loader</code></ulink></entry>
  18622. </row>
  18623. <row>
  18624. <entry><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.config.html"><code>Zend_Config</code></ulink></emphasis></entry>
  18625. <entry>Hard</entry>
  18626. <entry><ulink url="http://framework.zend.com/manual/en/zend.exception.html"><code>Zend_Exception</code></ulink></entry>
  18627. </row>
  18628. <row>
  18629. <entry morerows="1" valign="middle"><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.console.getopt.html"><code>Zend_Console_Getopt</code></ulink></emphasis></entry>
  18630. <entry morerows="1" valign="middle">Hard</entry>
  18631. <entry><ulink url="http://framework.zend.com/manual/en/zend.exception.html"><code>Zend_Exception</code></ulink></entry>
  18632. </row>
  18633. <row>
  18634. <entry><ulink url="http://framework.zend.com/manual/en/zend.json.html"><code>Zend_Json</code></ulink></entry>
  18635. </row>
  18636. <row>
  18637. <entry morerows="9" valign="middle"><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.controller.html"><code>Zend_Controller</code></ulink></emphasis></entry>
  18638. <entry morerows="9" valign="middle">Hard</entry>
  18639. <entry><ulink url="http://framework.zend.com/manual/en/zend.config.html"><code>Zend_Config</code></ulink></entry>
  18640. </row>
  18641. <row>
  18642. <entry><ulink url="http://framework.zend.com/manual/en/zend.exception.html"><code>Zend_Exception</code></ulink></entry>
  18643. </row>
  18644. <row>
  18645. <entry><ulink url="http://framework.zend.com/manual/en/zend.filter.html"><code>Zend_Filter</code></ulink></entry>
  18646. </row>
  18647. <row>
  18648. <entry><ulink url="http://framework.zend.com/manual/en/zend.json.html"><code>Zend_Json</code></ulink></entry>
  18649. </row>
  18650. <row>
  18651. <entry><ulink url="http://framework.zend.com/manual/en/zend.layout.html"><code>Zend_Layout</code></ulink></entry>
  18652. </row>
  18653. <row>
  18654. <entry><ulink url="http://framework.zend.com/manual/en/zend.loader.html"><code>Zend_Loader</code></ulink></entry>
  18655. </row>
  18656. <row>
  18657. <entry><ulink url="http://framework.zend.com/manual/en/zend.registry.html"><code>Zend_Registry</code></ulink></entry>
  18658. </row>
  18659. <row>
  18660. <entry><ulink url="http://framework.zend.com/manual/en/zend.session.html"><code>Zend_Session</code></ulink></entry>
  18661. </row>
  18662. <row>
  18663. <entry><ulink url="http://framework.zend.com/manual/en/zend.uri.html"><code>Zend_Uri</code></ulink></entry>
  18664. </row>
  18665. <row>
  18666. <entry><ulink url="http://framework.zend.com/manual/en/zend.view.html"><code>Zend_View</code></ulink></entry>
  18667. </row>
  18668. <row>
  18669. <entry morerows="1" valign="middle"><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.currency.html"><code>Zend_Currency</code></ulink></emphasis></entry>
  18670. <entry morerows="1" valign="middle">Hard</entry>
  18671. <entry><ulink url="http://framework.zend.com/manual/en/zend.exception.html"><code>Zend_Exception</code></ulink></entry>
  18672. </row>
  18673. <row>
  18674. <entry><ulink url="http://framework.zend.com/manual/en/zend.locale.html"><code>Zend_Locale</code></ulink></entry>
  18675. </row>
  18676. <row>
  18677. <entry morerows="1" valign="middle"><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.date.html"><code>Zend_Date</code></ulink></emphasis></entry>
  18678. <entry morerows="1" valign="middle">Hard</entry>
  18679. <entry><ulink url="http://framework.zend.com/manual/en/zend.exception.html"><code>Zend_Exception</code></ulink></entry>
  18680. </row>
  18681. <row>
  18682. <entry><ulink url="http://framework.zend.com/manual/en/zend.locale.html"><code>Zend_Locale</code></ulink></entry>
  18683. </row>
  18684. <row>
  18685. <entry morerows="3" valign="middle"><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.db.html"><code>Zend_Db</code></ulink></emphasis></entry>
  18686. <entry morerows="3" valign="middle">Hard</entry>
  18687. <entry><ulink url="http://framework.zend.com/manual/en/zend.config.html"><code>Zend_Config</code></ulink></entry>
  18688. </row>
  18689. <row>
  18690. <entry><ulink url="http://framework.zend.com/manual/en/zend.exception.html"><code>Zend_Exception</code></ulink></entry>
  18691. </row>
  18692. <row>
  18693. <entry><ulink url="http://framework.zend.com/manual/en/zend.loader.html"><code>Zend_Loader</code></ulink></entry>
  18694. </row>
  18695. <row>
  18696. <entry><ulink url="http://framework.zend.com/manual/en/zend.registry.html"><code>Zend_Registry</code></ulink></entry>
  18697. </row>
  18698. <row>
  18699. <entry><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.debug.html"><code>Zend_Debug</code></ulink></emphasis></entry>
  18700. <entry>---</entry>
  18701. <entry>---</entry>
  18702. </row>
  18703. <row>
  18704. <entry><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.exception.html"><code>Zend_Exception</code></ulink></emphasis></entry>
  18705. <entry>---</entry>
  18706. <entry>---</entry>
  18707. </row>
  18708. <row>
  18709. <entry morerows="3" valign="middle"><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.feed.html"><code>Zend_Feed</code></ulink></emphasis></entry>
  18710. <entry morerows="3" valign="middle">Hard</entry>
  18711. <entry><ulink url="http://framework.zend.com/manual/en/zend.exception.html"><code>Zend_Exception</code></ulink></entry>
  18712. </row>
  18713. <row>
  18714. <entry><ulink url="http://framework.zend.com/manual/en/zend.http.html"><code>Zend_Http</code></ulink></entry>
  18715. </row>
  18716. <row>
  18717. <entry><ulink url="http://framework.zend.com/manual/en/zend.loader.html"><code>Zend_Loader</code></ulink></entry>
  18718. </row>
  18719. <row>
  18720. <entry><ulink url="http://framework.zend.com/manual/en/zend.uri.html"><code>Zend_Uri</code></ulink></entry>
  18721. </row>
  18722. <row>
  18723. <entry morerows="3" valign="middle"><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.filter.html"><code>Zend_Filter</code></ulink></emphasis></entry>
  18724. <entry morerows="3" valign="middle">Hard</entry>
  18725. <entry><ulink url="http://framework.zend.com/manual/en/zend.exception.html"><code>Zend_Exception</code></ulink></entry>
  18726. </row>
  18727. <row>
  18728. <entry><ulink url="http://framework.zend.com/manual/en/zend.loader.html"><code>Zend_Loader</code></ulink></entry>
  18729. </row>
  18730. <row>
  18731. <entry><ulink url="http://framework.zend.com/manual/en/zend.locale.html"><code>Zend_Locale</code></ulink></entry>
  18732. </row>
  18733. <row>
  18734. <entry><ulink url="http://framework.zend.com/manual/en/zend.validate.html"><code>Zend_Validate</code></ulink></entry>
  18735. </row>
  18736. <row>
  18737. <entry morerows="7" valign="middle"><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.form.html"><code>Zend_Form</code></ulink></emphasis></entry>
  18738. <entry morerows="7" valign="middle">Hard</entry>
  18739. <entry><ulink url="http://framework.zend.com/manual/en/zend.controller.html"><code>Zend_Controller</code></ulink></entry>
  18740. </row>
  18741. <row>
  18742. <entry><ulink url="http://framework.zend.com/manual/en/zend.exception.html"><code>Zend_Exception</code></ulink></entry>
  18743. </row>
  18744. <row>
  18745. <entry><ulink url="http://framework.zend.com/manual/en/zend.filter.html"><code>Zend_Filter</code></ulink></entry>
  18746. </row>
  18747. <row>
  18748. <entry><ulink url="http://framework.zend.com/manual/en/zend.json.html"><code>Zend_Json</code></ulink></entry>
  18749. </row>
  18750. <row>
  18751. <entry><ulink url="http://framework.zend.com/manual/en/zend.loader.html"><code>Zend_Loader</code></ulink></entry>
  18752. </row>
  18753. <row>
  18754. <entry><ulink url="http://framework.zend.com/manual/en/zend.registry.html"><code>Zend_Registry</code></ulink></entry>
  18755. </row>
  18756. <row>
  18757. <entry><ulink url="http://framework.zend.com/manual/en/zend.session.html"><code>Zend_Session</code></ulink></entry>
  18758. </row>
  18759. <row>
  18760. <entry><ulink url="http://framework.zend.com/manual/en/zend.validate.html"><code>Zend_Validate</code></ulink></entry>
  18761. </row>
  18762. <row>
  18763. <entry morerows="4" valign="middle"><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.gdata.html"><code>Zend_Gdata</code></ulink></emphasis></entry>
  18764. <entry morerows="4" valign="middle">Hard</entry>
  18765. <entry><ulink url="http://framework.zend.com/manual/en/zend.exception.html"><code>Zend_Exception</code></ulink></entry>
  18766. </row>
  18767. <row>
  18768. <entry><ulink url="http://framework.zend.com/manual/en/zend.http.html"><code>Zend_Http</code></ulink></entry>
  18769. </row>
  18770. <row>
  18771. <entry><ulink url="http://framework.zend.com/manual/en/zend.loader.html"><code>Zend_Loader</code></ulink></entry>
  18772. </row>
  18773. <row>
  18774. <entry><ulink url="http://framework.zend.com/manual/en/zend.mime.html"><code>Zend_Mime</code></ulink></entry>
  18775. </row>
  18776. <row>
  18777. <entry><ulink url="http://framework.zend.com/manual/en/zend.version.html"><code>Zend_Version</code></ulink></entry>
  18778. </row>
  18779. <row>
  18780. <entry morerows="2" valign="middle"><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.http.html"><code>Zend_Http</code></ulink></emphasis></entry>
  18781. <entry morerows="2" valign="middle">Hard</entry>
  18782. <entry><ulink url="http://framework.zend.com/manual/en/zend.exception.html"><code>Zend_Exception</code></ulink></entry>
  18783. </row>
  18784. <row>
  18785. <entry><ulink url="http://framework.zend.com/manual/en/zend.loader.html"><code>Zend_Loader</code></ulink></entry>
  18786. </row>
  18787. <row>
  18788. <entry><ulink url="http://framework.zend.com/manual/en/zend.uri.html"><code>Zend_Uri</code></ulink></entry>
  18789. </row>
  18790. <row>
  18791. <entry><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.infocard.html"><code>Zend_InfoCard</code></ulink></emphasis></entry>
  18792. <entry>Hard</entry>
  18793. <entry><ulink url="http://framework.zend.com/manual/en/zend.loader.html"><code>Zend_Loader</code></ulink></entry>
  18794. </row>
  18795. <row>
  18796. <entry><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.json.html"><code>Zend_Json</code></ulink></emphasis></entry>
  18797. <entry>Hard</entry>
  18798. <entry><ulink url="http://framework.zend.com/manual/en/zend.exception.html"><code>Zend_Exception</code></ulink></entry>
  18799. </row>
  18800. <row>
  18801. <entry morerows="4" valign="middle"><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.layout.html"><code>Zend_Layout</code></ulink></emphasis></entry>
  18802. <entry morerows="4" valign="middle">Hard</entry>
  18803. <entry><ulink url="http://framework.zend.com/manual/en/zend.controller.html"><code>Zend_Controller</code></ulink></entry>
  18804. </row>
  18805. <row>
  18806. <entry><ulink url="http://framework.zend.com/manual/en/zend.exception.html"><code>Zend_Exception</code></ulink></entry>
  18807. </row>
  18808. <row>
  18809. <entry><ulink url="http://framework.zend.com/manual/en/zend.filter.html"><code>Zend_Filter</code></ulink></entry>
  18810. </row>
  18811. <row>
  18812. <entry><ulink url="http://framework.zend.com/manual/en/zend.loader.html"><code>Zend_Loader</code></ulink></entry>
  18813. </row>
  18814. <row>
  18815. <entry><ulink url="http://framework.zend.com/manual/en/zend.view.html"><code>Zend_View</code></ulink></entry>
  18816. </row>
  18817. <row>
  18818. <entry><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.ldap.html"><code>Zend_Ldap</code></ulink></emphasis></entry>
  18819. <entry>Hard</entry>
  18820. <entry><ulink url="http://framework.zend.com/manual/en/zend.exception.html"><code>Zend_Exception</code></ulink></entry>
  18821. </row>
  18822. <row>
  18823. <entry><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.loader.html"><code>Zend_Loader</code></ulink></emphasis></entry>
  18824. <entry>Hard</entry>
  18825. <entry><ulink url="http://framework.zend.com/manual/en/zend.exception.html"><code>Zend_Exception</code></ulink></entry>
  18826. </row>
  18827. <row>
  18828. <entry><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.locale.html"><code>Zend_Locale</code></ulink></emphasis></entry>
  18829. <entry>Hard</entry>
  18830. <entry><ulink url="http://framework.zend.com/manual/en/zend.exception.html"><code>Zend_Exception</code></ulink></entry>
  18831. </row>
  18832. <row>
  18833. <entry><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.log.html"><code>Zend_Log</code></ulink></emphasis></entry>
  18834. <entry>Hard</entry>
  18835. <entry><ulink url="http://framework.zend.com/manual/en/zend.exception.html"><code>Zend_Exception</code></ulink></entry>
  18836. </row>
  18837. <row>
  18838. <entry morerows="3" valign="middle"><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.mail.html"><code>Zend_Mail</code></ulink></emphasis></entry>
  18839. <entry morerows="3" valign="middle">Hard</entry>
  18840. <entry><ulink url="http://framework.zend.com/manual/en/zend.exception.html"><code>Zend_Exception</code></ulink></entry>
  18841. </row>
  18842. <row>
  18843. <entry><ulink url="http://framework.zend.com/manual/en/zend.loader.html"><code>Zend_Loader</code></ulink></entry>
  18844. </row>
  18845. <row>
  18846. <entry><ulink url="http://framework.zend.com/manual/en/zend.mime.html"><code>Zend_Mime</code></ulink></entry>
  18847. </row>
  18848. <row>
  18849. <entry><ulink url="http://framework.zend.com/manual/en/zend.validate.html"><code>Zend_Validate</code></ulink></entry>
  18850. </row>
  18851. <row>
  18852. <entry morerows="1" valign="middle"><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.measure.html"><code>Zend_Measure</code></ulink></emphasis></entry>
  18853. <entry morerows="1" valign="middle">Hard</entry>
  18854. <entry><ulink url="http://framework.zend.com/manual/en/zend.exception.html"><code>Zend_Exception</code></ulink></entry>
  18855. </row>
  18856. <row>
  18857. <entry><ulink url="http://framework.zend.com/manual/en/zend.locale.html"><code>Zend_Locale</code></ulink></entry>
  18858. </row>
  18859. <row>
  18860. <entry morerows="1" valign="middle"><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.memory.html"><code>Zend_Memory</code></ulink></emphasis></entry>
  18861. <entry morerows="1" valign="middle">Hard</entry>
  18862. <entry><ulink url="http://framework.zend.com/manual/en/zend.cache.html"><code>Zend_Cache</code></ulink></entry>
  18863. </row>
  18864. <row>
  18865. <entry><ulink url="http://framework.zend.com/manual/en/zend.exception.html"><code>Zend_Exception</code></ulink></entry>
  18866. </row>
  18867. <row>
  18868. <entry><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.mime.html"><code>Zend_Mime</code></ulink></emphasis></entry>
  18869. <entry>Hard</entry>
  18870. <entry><ulink url="http://framework.zend.com/manual/en/zend.exception.html"><code>Zend_Exception</code></ulink></entry>
  18871. </row>
  18872. <row>
  18873. <entry morerows="3" valign="middle"><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.openid.html"><code>Zend_OpenId</code></ulink></emphasis></entry>
  18874. <entry morerows="3" valign="middle">Hard</entry>
  18875. <entry><ulink url="http://framework.zend.com/manual/en/zend.controller.html"><code>Zend_Controller</code></ulink></entry>
  18876. </row>
  18877. <row>
  18878. <entry><ulink url="http://framework.zend.com/manual/en/zend.exception.html"><code>Zend_Exception</code></ulink></entry>
  18879. </row>
  18880. <row>
  18881. <entry><ulink url="http://framework.zend.com/manual/en/zend.http.html"><code>Zend_Http</code></ulink></entry>
  18882. </row>
  18883. <row>
  18884. <entry><ulink url="http://framework.zend.com/manual/en/zend.session.html"><code>Zend_Session</code></ulink></entry>
  18885. </row>
  18886. <row>
  18887. <entry morerows="2" valign="middle"><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.pdf.html"><code>Zend_Pdf</code></ulink></emphasis></entry>
  18888. <entry morerows="2" valign="middle">Hard</entry>
  18889. <entry><ulink url="http://framework.zend.com/manual/en/zend.exception.html"><code>Zend_Exception</code></ulink></entry>
  18890. </row>
  18891. <row>
  18892. <entry><ulink url="http://framework.zend.com/manual/en/zend.log.html"><code>Zend_Log</code></ulink></entry>
  18893. </row>
  18894. <row>
  18895. <entry><ulink url="http://framework.zend.com/manual/en/zend.memory.html"><code>Zend_Memory</code></ulink></entry>
  18896. </row>
  18897. <row>
  18898. <entry morerows="1" valign="middle"><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.registry.html"><code>Zend_Registry</code></ulink></emphasis></entry>
  18899. <entry morerows="1" valign="middle">Hard</entry>
  18900. <entry><ulink url="http://framework.zend.com/manual/en/zend.exception.html"><code>Zend_Exception</code></ulink></entry>
  18901. </row>
  18902. <row>
  18903. <entry><ulink url="http://framework.zend.com/manual/en/zend.loader.html"><code>Zend_Loader</code></ulink></entry>
  18904. </row>
  18905. <row>
  18906. <entry><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.request.html"><code>Zend_Request</code></ulink></emphasis></entry>
  18907. <entry>---</entry>
  18908. <entry>---</entry>
  18909. </row>
  18910. <row>
  18911. <entry morerows="3" valign="middle"><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.rest.html"><code>Zend_Rest</code></ulink></emphasis></entry>
  18912. <entry morerows="3" valign="middle">Hard</entry>
  18913. <entry><ulink url="http://framework.zend.com/manual/en/zend.exception.html"><code>Zend_Exception</code></ulink></entry>
  18914. </row>
  18915. <row>
  18916. <entry><ulink url="http://framework.zend.com/manual/en/zend.server.html"><code>Zend_Server</code></ulink></entry>
  18917. </row>
  18918. <row>
  18919. <entry><ulink url="http://framework.zend.com/manual/en/zend.service.html"><code>Zend_Service</code></ulink></entry>
  18920. </row>
  18921. <row>
  18922. <entry><ulink url="http://framework.zend.com/manual/en/zend.uri.html"><code>Zend_Uri</code></ulink></entry>
  18923. </row>
  18924. <row>
  18925. <entry><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.search.lucene.html"><code>Zend_Search_Lucene</code></ulink></emphasis></entry>
  18926. <entry>Hard</entry>
  18927. <entry><ulink url="http://framework.zend.com/manual/en/zend.exception.html"><code>Zend_Exception</code></ulink></entry>
  18928. </row>
  18929. <row>
  18930. <entry><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.server.reflection.html"><code>Zend_Server_Reflection</code></ulink></emphasis></entry>
  18931. <entry>Hard</entry>
  18932. <entry><ulink url="http://framework.zend.com/manual/en/zend.exception.html"><code>Zend_Exception</code></ulink></entry>
  18933. </row>
  18934. <row>
  18935. <entry morerows="3" valign="middle"><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.service.akismet.html"><code>Zend_Service_Akismet</code></ulink></emphasis></entry>
  18936. <entry morerows="3" valign="middle">Hard</entry>
  18937. <entry><ulink url="http://framework.zend.com/manual/en/zend.exception.html"><code>Zend_Exception</code></ulink></entry>
  18938. </row>
  18939. <row>
  18940. <entry><ulink url="http://framework.zend.com/manual/en/zend.http.html"><code>Zend_Http</code></ulink></entry>
  18941. </row>
  18942. <row>
  18943. <entry><ulink url="http://framework.zend.com/manual/en/zend.uri.html"><code>Zend_Uri</code></ulink></entry>
  18944. </row>
  18945. <row>
  18946. <entry><ulink url="http://framework.zend.com/manual/en/zend.version.html"><code>Zend_Version</code></ulink></entry>
  18947. </row>
  18948. <row>
  18949. <entry morerows="2" valign="middle"><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.service.amazon.html"><code>Zend_Service_Amazon</code></ulink></emphasis></entry>
  18950. <entry morerows="2" valign="middle">Hard</entry>
  18951. <entry><ulink url="http://framework.zend.com/manual/en/zend.exception.html"><code>Zend_Exception</code></ulink></entry>
  18952. </row>
  18953. <row>
  18954. <entry><ulink url="http://framework.zend.com/manual/en/zend.http.html"><code>Zend_Http</code></ulink></entry>
  18955. </row>
  18956. <row>
  18957. <entry><ulink url="http://framework.zend.com/manual/en/zend.rest.html"><code>Zend_Rest</code></ulink></entry>
  18958. </row>
  18959. <row>
  18960. <entry morerows="1" valign="middle"><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.service.audioscrobbler.html"><code>Zend_Service_Audioscrobbler</code></ulink></emphasis></entry>
  18961. <entry morerows="1" valign="middle">Hard</entry>
  18962. <entry><ulink url="http://framework.zend.com/manual/en/zend.exception.html"><code>Zend_Exception</code></ulink></entry>
  18963. </row>
  18964. <row>
  18965. <entry><ulink url="http://framework.zend.com/manual/en/zend.http.html"><code>Zend_Http</code></ulink></entry>
  18966. </row>
  18967. <row>
  18968. <entry morerows="4" valign="middle"><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.service.delicious.html"><code>Zend_Service_Delicious</code></ulink></emphasis></entry>
  18969. <entry morerows="4" valign="middle">Hard</entry>
  18970. <entry><ulink url="http://framework.zend.com/manual/en/zend.date.html"><code>Zend_Date</code></ulink></entry>
  18971. </row>
  18972. <row>
  18973. <entry><ulink url="http://framework.zend.com/manual/en/zend.exception.html"><code>Zend_Exception</code></ulink></entry>
  18974. </row>
  18975. <row>
  18976. <entry><ulink url="http://framework.zend.com/manual/en/zend.http.html"><code>Zend_Http</code></ulink></entry>
  18977. </row>
  18978. <row>
  18979. <entry><ulink url="http://framework.zend.com/manual/en/zend.json.html"><code>Zend_Json</code></ulink></entry>
  18980. </row>
  18981. <row>
  18982. <entry><ulink url="http://framework.zend.com/manual/en/zend.rest.html"><code>Zend_Rest</code></ulink></entry>
  18983. </row>
  18984. <row>
  18985. <entry morerows="3" valign="middle"><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.service.flickr.html"><code>Zend_Service_Flickr</code></ulink></emphasis></entry>
  18986. <entry morerows="3" valign="middle">Hard</entry>
  18987. <entry><ulink url="http://framework.zend.com/manual/en/zend.exception.html"><code>Zend_Exception</code></ulink></entry>
  18988. </row>
  18989. <row>
  18990. <entry><ulink url="http://framework.zend.com/manual/en/zend.http.html"><code>Zend_Http</code></ulink></entry>
  18991. </row>
  18992. <row>
  18993. <entry><ulink url="http://framework.zend.com/manual/en/zend.rest.html"><code>Zend_Rest</code></ulink></entry>
  18994. </row>
  18995. <row>
  18996. <entry><ulink url="http://framework.zend.com/manual/en/zend.validate.html"><code>Zend_Validate</code></ulink></entry>
  18997. </row>
  18998. <row>
  18999. <entry morerows="2" valign="middle"><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.service.nirvanix.html"><code>Zend_Service_Nirvanix</code></ulink></emphasis></entry>
  19000. <entry morerows="2" valign="middle">Hard</entry>
  19001. <entry><ulink url="http://framework.zend.com/manual/en/zend.exception.html"><code>Zend_Exception</code></ulink></entry>
  19002. </row>
  19003. <row>
  19004. <entry><ulink url="http://framework.zend.com/manual/en/zend.http.html"><code>Zend_Http</code></ulink></entry>
  19005. </row>
  19006. <row>
  19007. <entry><ulink url="http://framework.zend.com/manual/en/zend.loader.html"><code>Zend_Loader</code></ulink></entry>
  19008. </row>
  19009. <row>
  19010. <entry morerows="2" valign="middle"><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.service.simpy.html"><code>Zend_Service_Simpy</code></ulink></emphasis></entry>
  19011. <entry morerows="2" valign="middle">Hard</entry>
  19012. <entry><ulink url="http://framework.zend.com/manual/en/zend.exception.html"><code>Zend_Exception</code></ulink></entry>
  19013. </row>
  19014. <row>
  19015. <entry><ulink url="http://framework.zend.com/manual/en/zend.http.html"><code>Zend_Http</code></ulink></entry>
  19016. </row>
  19017. <row>
  19018. <entry><ulink url="http://framework.zend.com/manual/en/zend.rest.html"><code>Zend_Rest</code></ulink></entry>
  19019. </row>
  19020. <row>
  19021. <entry morerows="2" valign="middle"><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.service.slideshare.html"><code>Zend_Service_SlideShare</code></ulink></emphasis></entry>
  19022. <entry morerows="2" valign="middle">Hard</entry>
  19023. <entry><ulink url="http://framework.zend.com/manual/en/zend.cache.html"><code>Zend_Cache</code></ulink></entry>
  19024. </row>
  19025. <row>
  19026. <entry><ulink url="http://framework.zend.com/manual/en/zend.exception.html"><code>Zend_Exception</code></ulink></entry>
  19027. </row>
  19028. <row>
  19029. <entry><ulink url="http://framework.zend.com/manual/en/zend.http.html"><code>Zend_Http</code></ulink></entry>
  19030. </row>
  19031. <row>
  19032. <entry morerows="2" valign="middle"><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.service.strikeiron.html"><code>Zend_Service_StrikeIron</code></ulink></emphasis></entry>
  19033. <entry morerows="2" valign="middle">Hard</entry>
  19034. <entry><ulink url="http://framework.zend.com/manual/en/zend.exception.html"><code>Zend_Exception</code></ulink></entry>
  19035. </row>
  19036. <row>
  19037. <entry><ulink url="http://framework.zend.com/manual/en/zend.http.html"><code>Zend_Http</code></ulink></entry>
  19038. </row>
  19039. <row>
  19040. <entry><ulink url="http://framework.zend.com/manual/en/zend.loader.html"><code>Zend_Loader</code></ulink></entry>
  19041. </row>
  19042. <row>
  19043. <entry morerows="5" valign="middle"><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.service.technorati.html"><code>Zend_Service_Technorati</code></ulink></emphasis></entry>
  19044. <entry morerows="5" valign="middle">Hard</entry>
  19045. <entry><ulink url="http://framework.zend.com/manual/en/zend.date.html"><code>Zend_Date</code></ulink></entry>
  19046. </row>
  19047. <row>
  19048. <entry><ulink url="http://framework.zend.com/manual/en/zend.exception.html"><code>Zend_Exception</code></ulink></entry>
  19049. </row>
  19050. <row>
  19051. <entry><ulink url="http://framework.zend.com/manual/en/zend.http.html"><code>Zend_Http</code></ulink></entry>
  19052. </row>
  19053. <row>
  19054. <entry><ulink url="http://framework.zend.com/manual/en/zend.locale.html"><code>Zend_Locale</code></ulink></entry>
  19055. </row>
  19056. <row>
  19057. <entry><ulink url="http://framework.zend.com/manual/en/zend.rest.html"><code>Zend_Rest</code></ulink></entry>
  19058. </row>
  19059. <row>
  19060. <entry><ulink url="http://framework.zend.com/manual/en/zend.uri.html"><code>Zend_Uri</code></ulink></entry>
  19061. </row>
  19062. <row>
  19063. <entry morerows="3" valign="middle"><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.service.yahoo.html"><code>Zend_Service_Yahoo</code></ulink></emphasis></entry>
  19064. <entry morerows="3" valign="middle">Hard</entry>
  19065. <entry><ulink url="http://framework.zend.com/manual/en/zend.exception.html"><code>Zend_Exception</code></ulink></entry>
  19066. </row>
  19067. <row>
  19068. <entry><ulink url="http://framework.zend.com/manual/en/zend.http.html"><code>Zend_Http</code></ulink></entry>
  19069. </row>
  19070. <row>
  19071. <entry><ulink url="http://framework.zend.com/manual/en/zend.rest.html"><code>Zend_Rest</code></ulink></entry>
  19072. </row>
  19073. <row>
  19074. <entry><ulink url="http://framework.zend.com/manual/en/zend.validate.html"><code>Zend_Validate</code></ulink></entry>
  19075. </row>
  19076. <row>
  19077. <entry morerows="1" valign="middle"><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.session.html"><code>Zend_Session</code></ulink></emphasis></entry>
  19078. <entry morerows="1" valign="middle">Hard</entry>
  19079. <entry><ulink url="http://framework.zend.com/manual/en/zend.exception.html"><code>Zend_Exception</code></ulink></entry>
  19080. </row>
  19081. <row>
  19082. <entry><ulink url="http://framework.zend.com/manual/en/zend.loader.html"><code>Zend_Loader</code></ulink></entry>
  19083. </row>
  19084. <row>
  19085. <entry morerows="2" valign="middle"><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.timesync.html"><code>Zend_TimeSync</code></ulink></emphasis></entry>
  19086. <entry morerows="2" valign="middle">Hard</entry>
  19087. <entry><ulink url="http://framework.zend.com/manual/en/zend.date.html"><code>Zend_Date</code></ulink></entry>
  19088. </row>
  19089. <row>
  19090. <entry><ulink url="http://framework.zend.com/manual/en/zend.exception.html"><code>Zend_Exception</code></ulink></entry>
  19091. </row>
  19092. <row>
  19093. <entry><ulink url="http://framework.zend.com/manual/en/zend.loader.html"><code>Zend_Loader</code></ulink></entry>
  19094. </row>
  19095. <row>
  19096. <entry morerows="2" valign="middle"><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.translate.html"><code>Zend_Translate</code></ulink></emphasis></entry>
  19097. <entry morerows="2" valign="middle">Hard</entry>
  19098. <entry><ulink url="http://framework.zend.com/manual/en/zend.exception.html"><code>Zend_Exception</code></ulink></entry>
  19099. </row>
  19100. <row>
  19101. <entry><ulink url="http://framework.zend.com/manual/en/zend.loader.html"><code>Zend_Loader</code></ulink></entry>
  19102. </row>
  19103. <row>
  19104. <entry><ulink url="http://framework.zend.com/manual/en/zend.locale.html"><code>Zend_Locale</code></ulink></entry>
  19105. </row>
  19106. <row>
  19107. <entry morerows="2" valign="middle"><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.uri.html"><code>Zend_Uri</code></ulink></emphasis></entry>
  19108. <entry morerows="2" valign="middle">Hard</entry>
  19109. <entry><ulink url="http://framework.zend.com/manual/en/zend.exception.html"><code>Zend_Exception</code></ulink></entry>
  19110. </row>
  19111. <row>
  19112. <entry><ulink url="http://framework.zend.com/manual/en/zend.loader.html"><code>Zend_Loader</code></ulink></entry>
  19113. </row>
  19114. <row>
  19115. <entry><ulink url="http://framework.zend.com/manual/en/zend.validate.html"><code>Zend_Validate</code></ulink></entry>
  19116. </row>
  19117. <row>
  19118. <entry morerows="5" valign="middle"><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.validate.html"><code>Zend_Validate</code></ulink></emphasis></entry>
  19119. <entry morerows="3" valign="middle">Soft</entry>
  19120. <entry><ulink url="http://framework.zend.com/manual/en/zend.date.html"><code>Zend_Date</code></ulink></entry>
  19121. </row>
  19122. <row>
  19123. <entry><ulink url="http://framework.zend.com/manual/en/zend.filter.html"><code>Zend_Filter</code></ulink></entry>
  19124. </row>
  19125. <row>
  19126. <entry><ulink url="http://framework.zend.com/manual/en/zend.locale.html"><code>Zend_Locale</code></ulink></entry>
  19127. </row>
  19128. <row>
  19129. <entry><ulink url="http://framework.zend.com/manual/en/zend.registry.html"><code>Zend_Registry</code></ulink></entry>
  19130. </row>
  19131. <row>
  19132. <entry morerows="1" valign="middle">Hard</entry>
  19133. <entry><ulink url="http://framework.zend.com/manual/en/zend.exception.html"><code>Zend_Exception</code></ulink></entry>
  19134. </row>
  19135. <row>
  19136. <entry><ulink url="http://framework.zend.com/manual/en/zend.loader.html"><code>Zend_Loader</code></ulink></entry>
  19137. </row>
  19138. <row>
  19139. <entry><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.version.html"><code>Zend_Version</code></ulink></emphasis></entry>
  19140. <entry>---</entry>
  19141. <entry>---</entry>
  19142. </row>
  19143. <row>
  19144. <entry morerows="6" valign="middle"><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.view.html"><code>Zend_View</code></ulink></emphasis></entry>
  19145. <entry morerows="6" valign="middle">Hard</entry>
  19146. <entry><ulink url="http://framework.zend.com/manual/en/zend.controller.html"><code>Zend_Controller</code></ulink></entry>
  19147. </row>
  19148. <row>
  19149. <entry><ulink url="http://framework.zend.com/manual/en/zend.exception.html"><code>Zend_Exception</code></ulink></entry>
  19150. </row>
  19151. <row>
  19152. <entry><ulink url="http://framework.zend.com/manual/en/zend.json.html"><code>Zend_Json</code></ulink></entry>
  19153. </row>
  19154. <row>
  19155. <entry><ulink url="http://framework.zend.com/manual/en/zend.layout.html"><code>Zend_Layout</code></ulink></entry>
  19156. </row>
  19157. <row>
  19158. <entry><ulink url="http://framework.zend.com/manual/en/zend.loader.html"><code>Zend_Loader</code></ulink></entry>
  19159. </row>
  19160. <row>
  19161. <entry><ulink url="http://framework.zend.com/manual/en/zend.locale.html"><code>Zend_Locale</code></ulink></entry>
  19162. </row>
  19163. <row>
  19164. <entry><ulink url="http://framework.zend.com/manual/en/zend.registry.html"><code>Zend_Registry</code></ulink></entry>
  19165. </row>
  19166. <row>
  19167. <entry morerows="2" valign="middle"><emphasis role="strong"><ulink url="http://framework.zend.com/manual/en/zend.xmlrpc.html"><code>Zend_XmlRpc</code></ulink></emphasis></entry>
  19168. <entry morerows="2" valign="middle">Hard</entry>
  19169. <entry><ulink url="http://framework.zend.com/manual/en/zend.exception.html"><code>Zend_Exception</code></ulink></entry>
  19170. </row>
  19171. <row>
  19172. <entry><ulink url="http://framework.zend.com/manual/en/zend.http.html"><code>Zend_Registry</code></ulink></entry>
  19173. </row>
  19174. <row>
  19175. <entry><ulink url="http://framework.zend.com/manual/en/zend.server.html"><code>Zend_Server</code></ulink></entry>
  19176. </row>
  19177. </tbody>
  19178. </tgroup>
  19179. </table>
  19180. </sect1>
  19181. </appendix><!--
  19182. vim:se ts=4 sw=4 et:
  19183. Note:
  19184. All added classes listed below... all 3 tables use this as reference.
  19185. Acl
  19186. Auth
  19187. Cache
  19188. Config
  19189. Console_GetOpt
  19190. Controller
  19191. Currency
  19192. Date
  19193. Db
  19194. Debug
  19195. Exception
  19196. Feed
  19197. Filter
  19198. Form
  19199. Gdata
  19200. Http
  19201. InfoCard
  19202. Json
  19203. Layout
  19204. Ldap
  19205. Loader
  19206. Locale
  19207. Log
  19208. Mail
  19209. Measure
  19210. Memory
  19211. Mime
  19212. OpenId
  19213. Pdf
  19214. Registry
  19215. Request
  19216. Rest
  19217. Search_Lucene
  19218. Server_Reflection
  19219. Service_Akismet
  19220. Service_Amazon
  19221. Service_Audioscrobbler
  19222. Service_Delicious
  19223. Service_Flickr
  19224. Service_Nirvanix
  19225. Service_Simpy
  19226. Service_SlideShare
  19227. Service_StrikeIron
  19228. Service_Technorati
  19229. Service_Yahoo
  19230. Session
  19231. TimeSync
  19232. Translate
  19233. Uri
  19234. Validate
  19235. Version
  19236. View
  19237. XmlRpc
  19238. -->
  19239. <appendix id="coding-standard" xml:base="ref/coding_standard.xml">
  19240. <title>Est�ndares de c�digo Zend Framework para PHP</title>
  19241. <sect1 id="coding-standard.overview">
  19242. <title>Introducci�n</title>
  19243. <sect2 id="coding-standard.overview.scope">
  19244. <title>Alcance</title>
  19245. <para>
  19246. Este documento provee las pautas para el formato del c�digo y la documentaci�n a personas y equipos que contribuyan con Zend Framework. Muchos de los desarrolladores que usan Zend Framework han encontrado �tiles estos est�ndares debido a que el estilo de su c�digo permanece consistente con otros c�digos fuente basados en Zend Framework. Tambi�n debe resaltarse que especificar completamente los est�ndares de c�digo requiere un esfuerzo significativo.
  19247. Nota: A veces, los desarrolladores consideran el establecimiento de est�ndares m�s importante que lo que el est�ndar sugiere realmente al nivel m�s detallado de dise�o. Estas pautas en los est�ndares de c�digo de Zend Framework han demostrado funcionar bien en otros projectos ZF. Puede modificar estos est�ndares o usarlos en consonancia con los t�rminos de nuestra <ulink url="http://framework.zend.com/license">licencia</ulink>
  19248. </para>
  19249. <para>
  19250. Temas incluidos en los est�ndares de c�digo ZF:
  19251. <itemizedlist>
  19252. <listitem>
  19253. <para>Dar formato a archivos PHP</para>
  19254. </listitem>
  19255. <listitem>
  19256. <para>Convenciones de nombrado</para>
  19257. </listitem>
  19258. <listitem>
  19259. <para>Estilo de c�digo</para>
  19260. </listitem>
  19261. <listitem>
  19262. <para>Documentaci�n integrada</para>
  19263. </listitem>
  19264. </itemizedlist>
  19265. </para>
  19266. </sect2>
  19267. <sect2 id="coding-standard.overview.goals">
  19268. <title>Objetivos</title>
  19269. <para>
  19270. Los est�ndares de c�digo resultan importantes en cualquier proyecto de desarrollo, pero son
  19271. especialmente importantes cuando muchos desarrolladores trabajan en el mismo proyecto. Los
  19272. est�ndares de c�digo ayudan a asegurar que el c�digo tenga una alta calidad, menos errores,
  19273. y pueda ser mantenido f�cilmente.
  19274. </para>
  19275. </sect2>
  19276. </sect1>
  19277. <sect1 id="coding-standard.php-file-formatting">
  19278. <title>Formato de archivos PHP</title>
  19279. <sect2 id="coding-standard.php-file-formatting.general">
  19280. <title>General</title>
  19281. <para>
  19282. Para archivos que contengan �nicamente c�digo PHP, la etiqueta de cierre ("?&gt;") no est� permitida. No es requerida por PHP, y omitirla evita la inyecci�n de espacios en blanco en la respuesta.
  19283. </para>
  19284. <para>
  19285. <emphasis>IMPORTANTE:</emphasis> La inclusi�n de datos binarios arbitrarios permitidos por <code>__HALT_COMPILER()</code>
  19286. est� prohibida en los archivos PHP de Zend Framework, as� como en cualquier fichero derivado. El uso de esta caracter�stica s�lo est� permitido en algunos scripts de instalaci�n.
  19287. </para>
  19288. </sect2>
  19289. <sect2 id="coding-standard.php-file-formatting.indentation">
  19290. <title>Identaci�n</title>
  19291. <para>La identaci�n suele est�r compuesta por 4 espacios. Las tabulaciones no est�n permitidas.</para>
  19292. </sect2>
  19293. <sect2 id="coding-standard.php-file-formatting.max-line-length">
  19294. <title>Tama�o m�ximo de l�nea</title>
  19295. <para>
  19296. La longitud recomendable para una l�nea de c�digo es de 80 caracteres. Esto significa que los desarrolladores de Zend deber�an intentar mantener cada l�nea de su c�digo por debajo de los 80 caracteres, siempre que sea posible. No obstante, l�neas m�s largas pueden ser aceptables en algunas situaciones. El tama�o m�ximo de cualquier l�nea de c�digo PHP es de 120 caracteres.
  19297. </para>
  19298. </sect2>
  19299. <sect2 id="coding-standard.php-file-formatting.line-termination">
  19300. <title>Final de l�nea</title>
  19301. <para>
  19302. El Final de L�nea sigue la convenci�n de archivos de texto Unix. Las l�neas deben acabar con un car�cter linefeed (LF). Los caracteres Linefeed est�n representados con el n�mero 10 ordinal, o el n�mero 0x0A hexadecimal.
  19303. </para>
  19304. <para>
  19305. Nota: No use retornos de carro (carriage returns, CR) como en las fuentes de Apple (0x0D) o la combinaci�n de retorno de carro/linefeed (CRLF) est�ndar para sistemas operativos Windows (0x0D, 0x0A).
  19306. </para>
  19307. </sect2>
  19308. </sect1>
  19309. <sect1 id="coding-standard.naming-conventions">
  19310. <title>Convenciones de nombrado</title>
  19311. <sect2 id="coding-standard.naming-conventions.classes">
  19312. <title>Clases</title>
  19313. <para>
  19314. Zend Framework se estandariza en una convenci�n de nombrado de clases donde los
  19315. nombres de las clases apuntan directamente a las carpetas en las que est�n contenidas.
  19316. La carpeta ra�z de la librer�a est�ndar de ZF es la carpeta "Zend/", mientras que la carpeta ra�z de las
  19317. librer�as extra de ZF es la carpeta "ZendX/". Todas las clases Zend Framework est�n almacenadas
  19318. jer�rquicamente bajo estas carpetas ra�z.
  19319. </para>
  19320. <para>
  19321. Los nombres de clase pueden contener s�lo caracteres alfanum�ricos. Los n�meros est�n permitidos en los nombres de clase, pero desaconsejados en la mayor�a de casos. Las barras bajas (_) est�n permitidas s�lo como separador de ruta (el archivo "Zend/Db/Table.php" debe apuntar al nombre de clase "Zend_Db_Table").
  19322. </para>
  19323. <para>
  19324. Si el nombre de una clase est� compuesto por m�s de una palabra, la primera letra de
  19325. cada palabra debe aparecer en may�sculas. Poner en may�sculas las letras siguientes no est� permitido,
  19326. ej: "Zend_PDF" no est� permitido, mientras que "Zend_Pdf" es admisible.
  19327. </para>
  19328. <para>
  19329. Estas convenciones definen un mecanismo de pseudo-espacio de nombres para Zend Framework. Zend Framework adoptar� la funcionalidad PHP de espacio de nombres cuando est� disponible y sea factible su uso en las aplicaciones de nuestros desarrolladores.
  19330. </para>
  19331. <para>
  19332. Vea los nombres de clase en las librer�as estandar y adicionales (extras) como ejemplos de esta convenci�n de nombres.
  19333. <emphasis>IMPORTANTE:</emphasis> El c�digo que deba distribuirse junto a las librer�as ZF, pero no forma parte de las librer�as est�ndar o extras de Zend (e.g.: c�digo o librer�as que no est�n distribu�das por Zend) no puede empezar nunca por "Zend_" o "ZendX_".
  19334. </para>
  19335. </sect2>
  19336. <sect2 id="coding-standard.naming-conventions.filenames">
  19337. <title>Nombres de archivo</title>
  19338. <para>
  19339. Para cualquier otro archivo, s�lo caracteres alfanum�ricos, barras bajas (_) y guiones (-) est�n permitidos. Los espacios en blanco est�n estrictamente prohibidos.
  19340. </para>
  19341. <para>
  19342. Cualquier archivo que contenga c�digo PHP debe terminar con la extensi�n ".php", con la excepci�n de los scripts de vista. Los siguientes ejemplos muestran nombres de archivo admisibles para clases de Zend Framework..:
  19343. <programlisting role="php"><![CDATA[
  19344. Zend/Db.php
  19345. Zend/Controller/Front.php
  19346. Zend/View/Helper/FormRadio.php
  19347. ]]>
  19348. </programlisting>
  19349. Los nombres de archivo deben apuntar a nombres de clases como se describe arriba.
  19350. </para>
  19351. </sect2>
  19352. <sect2 id="coding-standard.naming-conventions.functions-and-methods">
  19353. <title>Funciones y M�todos</title>
  19354. <para>
  19355. Los nombres de funciones pueden contener �nicamente caracteres alfanum�ricos. Las barras bajas (_)
  19356. no est�n permitidas.
  19357. Los n�meros est�n permitidos en los nombres de funci�n pero no se aconseja en la
  19358. mayor�a de casos.
  19359. </para>
  19360. <para>
  19361. Los nombres de funciones deben empezar siempre con una letra min�scula. Cuando un nombre de funci�n consiste en
  19362. m�s de una palabra, la primera letra de cada nueva palabra debe estar en may�sculas. Esto es llamado com�nmente como formato "camelCase".
  19363. </para>
  19364. <para>
  19365. Por norma general, se recomienda la elocuencia. Los nombres de funci�n deben ser lo suficientemente elocuentes como para describir su prop�sito y comportamiento.
  19366. </para>
  19367. <para>
  19368. Estos son ejemplos de nombres de funciones admisibles:
  19369. <programlisting role="php"><![CDATA[
  19370. filterInput()
  19371. getElementById()
  19372. widgetFactory()
  19373. ]]>
  19374. </programlisting>
  19375. </para>
  19376. <para>
  19377. Para programaci�n orientada a objetos, los accesores para instancia o variables est�ticas deben ir antepuestos con un
  19378. "get" o un "set". Al implementar patrones de dise�o, tales como el patr�n singleton o el patr�n factory, el nombre del m�todo debe contener en la pr�ctica el nombre del patr�n para describir su comportamiento de form�s m�s completa.
  19379. </para>
  19380. <para>
  19381. Para m�todos en objetos que son declarados con el modificador "private" o "protected",
  19382. el primer car�cter del nombre de la variable debe ser una barra baja (_). �ste es el �nico
  19383. uso admisible de una barra baja en un nombre de m�todo. Los m�todos declarados como p�blicos
  19384. no deber�an contener nunca una barra baja.
  19385. </para>
  19386. <para>
  19387. Las funciones de alcance global (tambi�n llamadas "funciones flotantes") est�n permitidas pero desaconsejadas en la mayor�a de casos.
  19388. Considere envolver esas funciones en una clase est�tica.
  19389. </para>
  19390. </sect2>
  19391. <sect2 id="coding-standard.naming-conventions.variables">
  19392. <title>Variables</title>
  19393. <para>
  19394. Los nombres de variables pueden contener caracteres alfanum�ricos. Las barras bajas (_)
  19395. no est�n permitidas.
  19396. Los n�meros est�n permitidos en los nombres de variable pero no se aconseja en la
  19397. mayor�a de casos.
  19398. </para>
  19399. <para>
  19400. Para las variables de instancia que son declaradas con el modificador "private" o "protected",
  19401. el primer car�cter de la variable debe ser una �nica barra baja (_). �ste es el �nico caso admisible de una barra baja en el nombre de una variable. Las variables declaradas como "public" no pueden empezar nunca por barra baja.
  19402. </para>
  19403. <para>
  19404. Al igual que los nombres de funciones (ver secci�n 3.3), los nombres de variables deben empezar siempre con una letra en min�scula y seguir la convenci�n "camelCaps".
  19405. </para>
  19406. <para>
  19407. Por norma general, se recomienda la elocuencia. Las variables deber�an ser siempre tan elocuentes como pr�cticas para describir los datos que el desarrollador pretende almacenar en ellas. Variables escuetas como "$i" y "$n" est�n desaconsejadas, salvo para el contexto de los bucles m�s peque�os. Si un bucle contiene m�s de 20 l�neas de c�digo, las variables de �ndice deber�an tener nombres m�s descriptivos.
  19408. </para>
  19409. </sect2>
  19410. <sect2 id="coding-standard.naming-conventions.constants">
  19411. <title>Constantes</title>
  19412. <para>
  19413. Las constantes pueden contener tanto caracteres alfanum�ricos como barras bajas (_). Los n�meros est�n permitidos.
  19414. </para>
  19415. <para>
  19416. Todos las letras pertenecientes al nombre de una constante deben aparecer en may�sculas.
  19417. </para>
  19418. <para>
  19419. Las palabras dentro del nombre de una constante deben separarse por barras bajas (_). Por ejemplo, <code>EMBED_SUPPRESS_EMBED_EXCEPTION</code> est� permitido, pero
  19420. <code>EMBED_SUPPRESSEMBEDEXCEPTION</code> no.
  19421. </para>
  19422. <para>
  19423. Las constantes deben ser definidas como miembros de clase con el modificador "const". Definir constantes en el alcance global con la funci�n "define" est� permitido pero no recomendado.
  19424. </para>
  19425. </sect2>
  19426. </sect1>
  19427. <sect1 id="coding-standard.coding-style">
  19428. <title>Estilo de c�digo</title>
  19429. <sect2 id="coding-standard.coding-style.php-code-demarcation">
  19430. <title>Demarcaci�n de c�digo PHP</title>
  19431. <para>
  19432. El c�digo PHP debe estar delimitado siempre por la forma completa de las etiquetas PHP est�ndar:
  19433. <programlisting role="php"><![CDATA[
  19434. <?php
  19435. ?>
  19436. ]]>
  19437. </programlisting>
  19438. </para>
  19439. <para>
  19440. Las etiquetas cortas (short tags) no se permiten nunca. Para archivos que contengan �nicamente c�digo PHP, la etiqueta de cierrre debe omitirse siempre (Ver <xref linkend="coding-standard.php-file-formatting.general"/>).
  19441. </para>
  19442. </sect2>
  19443. <sect2 id="coding-standard.coding-style.strings">
  19444. <title>Cadenas</title>
  19445. <sect3 id="coding-standard.coding-style.strings.literals">
  19446. <title>Literales cadena</title>
  19447. <para>
  19448. Cuando una cadena es literal (no contiene sustituci�n de variables), el ap�strofo o "comilla"
  19449. deber�a ser usado siempre para delimitar la cadena:
  19450. <programlisting role="php"><![CDATA[
  19451. $a = 'Example String';
  19452. ]]>
  19453. </programlisting>
  19454. </para>
  19455. </sect3>
  19456. <sect3 id="coding-standard.coding-style.strings.literals-containing-apostrophes">
  19457. <title>Literales Cadena que Contengan Ap�strofos</title>
  19458. <para>
  19459. Cuando el propio literal cadena contega ap�strofos, es permitido delimitar la cadena
  19460. con "dobles comillas". Esto es especialmente �til para sentencias SQL:
  19461. <programlisting role="php"><![CDATA[
  19462. $sql = "SELECT `id`, `name` from `people` WHERE `name`='Fred' OR `name`='Susan'";
  19463. ]]>
  19464. </programlisting>
  19465. Esta sint�xis es preferible a escapar ap�strofes, ya ques mucho m�s f�cil de leer.
  19466. </para>
  19467. </sect3>
  19468. <sect3 id="coding-standard.coding-style.strings.variable-substitution">
  19469. <title>Sustituci�n de Variables</title>
  19470. <para>
  19471. La sustituci�n de variables est� permitida en cualquiera de estas formas:
  19472. <programlisting role="php"><![CDATA[
  19473. $greeting = "Hello $name, welcome back!";
  19474. $greeting = "Hello {$name}, welcome back!";
  19475. ]]>
  19476. </programlisting>
  19477. </para>
  19478. <para>
  19479. Por consistencia, esta forma no est� permitida:
  19480. <programlisting role="php"><![CDATA[
  19481. $greeting = "Hello ${name}, welcome back!";
  19482. ]]>
  19483. </programlisting>
  19484. </para>
  19485. </sect3>
  19486. <sect3 id="coding-standard.coding-style.strings.string-concatenation">
  19487. <title>Concatenaci�n de cadenas</title>
  19488. <para>
  19489. Las cadenas deben ser concatenadas usando el operador punto ("."). Un espacio debe a�adirse
  19490. siempre antes y despu�s del operador "." para mejorar la legibilidad:
  19491. <programlisting role="php"><![CDATA[
  19492. $company = 'Zend' . ' ' . 'Technologies';
  19493. ]]>
  19494. </programlisting>
  19495. </para>
  19496. <para>
  19497. Al concatenar cadenas con el operador ".", se recomienda partir la sentencia en
  19498. m�ltiples l�neas para mejorar la legibilidad. En estos casos, cada linea sucesiva
  19499. debe llevar un margen de espacios en blanco de forma que el operador
  19500. "." est� alineado bajo el operador "=":
  19501. <programlisting role="php"><![CDATA[
  19502. $sql = "SELECT `id`, `name` FROM `people` "
  19503. . "WHERE `name` = 'Susan' "
  19504. . "ORDER BY `name` ASC ";
  19505. ]]>
  19506. </programlisting>
  19507. </para>
  19508. </sect3>
  19509. </sect2>
  19510. <sect2 id="coding-standard.coding-style.arrays">
  19511. <title>Arrays</title>
  19512. <sect3 id="coding-standard.coding-style.arrays.numerically-indexed">
  19513. <title>Arrays Indexados Num�ricamente</title>
  19514. <para>No est�n permitidos n�meros negativos como �ndices.</para>
  19515. <para>
  19516. Un array indexado puede empezar por cualquier valor no negativo, sin embargo, no se recomiendan �ndices base distintos a 0.
  19517. </para>
  19518. <para>
  19519. Al declarar arrays indexados con la funci�n <code>array</code>, un espacio de separaci�n deben a�adirse despu�s de cada delimitador coma para mejorar la legibilidad:
  19520. <programlisting role="php"><![CDATA[
  19521. $sampleArray = array(1, 2, 3, 'Zend', 'Studio');
  19522. ]]>
  19523. </programlisting>
  19524. </para>
  19525. <para>
  19526. Se permite declarar arrays indexados multil�nea usando la construcci�n "array".
  19527. En este caso, cada l�nea sucesiva debe ser tabulada con cuatro espacios de forma que el principio de cada l�nea est� alineado:
  19528. <programlisting role="php"><![CDATA[
  19529. $sampleArray = array(1, 2, 3, 'Zend', 'Studio',
  19530. $a, $b, $c,
  19531. 56.44, $d, 500);
  19532. ]]>
  19533. </programlisting>
  19534. </para>
  19535. </sect3>
  19536. <sect3 id="coding-standard.coding-style.arrays.associative">
  19537. <title>Arrays Asociativos</title>
  19538. <para>
  19539. Al declarar arrays asociativos con la construcci�n <code>array</code>, se recomienda partir la declaraci�n en m�ltiples l�neas. En este caso, cada l�nea sucesiva debe ser tabulada con cuatro espacios de forma que tanto las llaves como los valores est�n alineados:
  19540. <programlisting role="php"><![CDATA[
  19541. $sampleArray = array('firstKey' => 'firstValue',
  19542. 'secondKey' => 'secondValue');
  19543. ]]>
  19544. </programlisting>
  19545. </para>
  19546. </sect3>
  19547. </sect2>
  19548. <sect2 id="coding-standard.coding-style.classes">
  19549. <title>Clases</title>
  19550. <sect3 id="coding-standard.coding-style.classes.declaration">
  19551. <title>Declaraci�n de clases</title>
  19552. <para>
  19553. Las Clases deben ser nombradas de acuerdo a las convenciones de nombrado de Zend Framework.
  19554. </para><para>
  19555. La llave "{" deber� escribirse siempre en la l�nea debajo del nombre de la clase ("one true brace").
  19556. </para><para>
  19557. Cada clase debe contener un bloque de documentaci�n acorde con el est�ndar de PHPDocumentor.
  19558. </para><para>
  19559. Todo el c�digo contenido en una clase debe ser separado con cuatro espacios.
  19560. </para><para>
  19561. �nicamente una clase est� permitida en cada archivo PHP.
  19562. </para><para>
  19563. Incluir c�digo adicional en archivos de clase est� permitido pero desaconsejado.
  19564. En archivos de ese tipo, dos l�neas en blanco deben separar la clase de cualquier c�digo PHP adicional en el archivo de clase.
  19565. </para><para>
  19566. A continuaci�n se muestra un ejemplo de una declaraci�n de clase admisible:
  19567. <programlisting role="php"><![CDATA[
  19568. /**
  19569. * Bloque de Documentaci�n aqu�
  19570. */
  19571. class SampleClass
  19572. {
  19573. // el contenido de la clase
  19574. // debe separarse con cuatro espacios
  19575. }
  19576. ]]>
  19577. </programlisting>
  19578. </para>
  19579. </sect3>
  19580. <sect3 id="coding-standard.coding-style.classes.member-variables">
  19581. <title>Variables de miembros de clase</title>
  19582. <para>
  19583. Las variables de miembros de clase deben ser nombradas de acuerdo con las conveciones de nombrado de variables de Zend Framework.
  19584. </para>
  19585. <para>
  19586. Cualquier variable declarada en una clase debe ser listada en la parte superior de la clase, por encima de las declaraciones de cualquier m�todo.
  19587. </para>
  19588. <para>
  19589. La construcci�n <code>var</code> no est� permitido. Las variables de miembro siempre declaran su visibilidad usando uno los modificadores <code>private</code>, <code>protected</code>,
  19590. o <code>public</code>. Dar acceso a las variables de miembro declar�ndolas directamente como public est� permitido pero no se aconseja en favor de accesor methods (set/get).
  19591. </para>
  19592. </sect3>
  19593. </sect2>
  19594. <sect2 id="coding-standard.coding-style.functions-and-methods">
  19595. <title>Funciones y M�todos</title>
  19596. <sect3 id="coding-standard.coding-style.functions-and-methods.declaration">
  19597. <title>Declaraci�n de Funciones y M�todos</title>
  19598. <para>
  19599. Las Funciones deben ser nombradas de acuerdo a las convenciones de nombrado de Zend Framework.
  19600. </para>
  19601. <para>
  19602. Los m�todos dentro de clases deben declarar siempre su visibilidad usando un modificador <code>private</code>, <code>protected</code>,
  19603. o <code>public</code>.
  19604. </para>
  19605. <para>
  19606. Como en las clases, la llave "{" debe ser escrita en la l�nea siguiente al nombre de la funci�n ("one true brace" form).
  19607. No est� permitido un espacio entre el nombre de la funci�n y el par�ntesis de apertura para los argumentos.
  19608. </para>
  19609. <para>
  19610. Las funciones de alcance global no est�n permitidas.
  19611. </para>
  19612. <para>
  19613. Lo siguiente es un ejemplo de una declaraci�n admisible de una funci�n en una clase:
  19614. <programlisting role="php"><![CDATA[
  19615. /**
  19616. * Bloque de Documentaci�n aqu�
  19617. */
  19618. class Foo
  19619. {
  19620. /**
  19621. * Bloque de Documentaci�n aqu�
  19622. */
  19623. public function bar()
  19624. {
  19625. // el contenido de la funci�n
  19626. // debe separarse con cuatro espacios
  19627. }
  19628. }
  19629. ]]>
  19630. </programlisting>
  19631. </para>
  19632. <para>
  19633. <emphasis>NOTA:</emphasis> El paso por referencia es el �nico mecanismo de paso de par�metros permitido en una declaraci�n de m�todo.
  19634. <programlisting role="php"><![CDATA[
  19635. /**
  19636. * Bloque de Documentaci�n aqu�
  19637. */
  19638. class Foo
  19639. {
  19640. /**
  19641. * Bloque de Documentaci�n aqu�
  19642. */
  19643. public function bar(&$baz)
  19644. {}
  19645. }
  19646. ]]>
  19647. </programlisting>
  19648. </para>
  19649. <para>
  19650. La llamada por referencia est� estrictamente prohibida.
  19651. </para>
  19652. <para>
  19653. El valor de retorno no debe estar indicado entre par�ntesis. Esto podr�a afectar a la legibilidad, adem�s
  19654. de romper el c�digo si un m�todo se modifica posteriormente para que devuelva por referencia.
  19655. <programlisting role="php"><![CDATA[
  19656. /**
  19657. * Bloque de Documentaci�n aqu�
  19658. */
  19659. class Foo
  19660. {
  19661. /**
  19662. * INCORRECTO
  19663. */
  19664. public function bar()
  19665. {
  19666. return($this->bar);
  19667. }
  19668. /**
  19669. * CORRECTO
  19670. */
  19671. public function bar()
  19672. {
  19673. return $this->bar;
  19674. }
  19675. }
  19676. ]]>
  19677. </programlisting>
  19678. </para>
  19679. </sect3>
  19680. <sect3 id="coding-standard.coding-style.functions-and-methods.usage">
  19681. <title>Uso de Funciones y M�todos</title>
  19682. <para>
  19683. Los argumentos de la funci�n tendr�an que estar separados por un �nico espacio posterior despu�s del delimitador coma.
  19684. A continuaci�n se muestra un ejemplo de una invocaci�n admisible de una funci�n que recibe tres argumentos:
  19685. <programlisting role="php"><![CDATA[
  19686. threeArguments(1, 2, 3);
  19687. ]]>
  19688. </programlisting>
  19689. </para>
  19690. <para>
  19691. La llamada por referencia est� estrictamente prohibida. Vea la secci�n de declaraciones de funciones para el m�todo correcto de pasar argumentos por referencia.
  19692. </para>
  19693. <para>
  19694. Al pasar arrays como argumentos a una funci�n, la llamada a la funci�n puede incluir el indicador "hint" y puede separarse en m�ltiples l�neas para aumentar la legibilidad. En esos casos, se aplican las pautas normales para escribir arrays:
  19695. <programlisting role="php"><![CDATA[
  19696. threeArguments(array(1, 2, 3), 2, 3);
  19697. threeArguments(array(1, 2, 3, 'Zend', 'Studio',
  19698. $a, $b, $c,
  19699. 56.44, $d, 500), 2, 3);
  19700. ]]>
  19701. </programlisting>
  19702. </para>
  19703. </sect3>
  19704. </sect2>
  19705. <sect2 id="coding-standard.coding-style.control-statements">
  19706. <title>Sentencias de Control</title>
  19707. <sect3 id="coding-standard.coding-style.control-statements.if-else-elseif">
  19708. <title>If/Else/Elseif</title>
  19709. <para>
  19710. Las sentencias de control basadas en las construcciones <code>if</code> y <code>elseif</code>
  19711. deben tener un solo espacio en blanco antes del par�ntesis de apertura del condicional y un solo espacio en blanco despu�s del par�ntesis de cierre.
  19712. </para>
  19713. <para>
  19714. Dentro de las sentencias condicionales entre par�ntesis, los operadores deben separarse con espacios, por legibilidad. Se aconseja el uso de par�ntesis internos para mejorar la agrupaci�n l�gica en expresiones condicionales m�s largas.
  19715. </para>
  19716. <para>
  19717. La llave de apertura "{" se escribe en la misma l�nea que la sentencia condicional. La llave de cierre "}" se escribe siempre en su propia l�nea. Cualquier contenido dentro de las llaves debe separarse con cuatro espacios en blanco.
  19718. <programlisting role="php"><![CDATA[
  19719. if ($a != 2) {
  19720. $a = 2;
  19721. }
  19722. ]]>
  19723. </programlisting>
  19724. </para>
  19725. <para>
  19726. Para las declaraciones "if" que incluyan "elseif" o "else", las convenciones de formato son similares a la construcci�n "if". Los ejemplos siguientes demuestran el formato correcto para declaraciones "if" con construcciones "else" y/o "elseif":
  19727. <programlisting role="php"><![CDATA[
  19728. if ($a != 2) {
  19729. $a = 2;
  19730. } else {
  19731. $a = 7;
  19732. }
  19733. if ($a != 2) {
  19734. $a = 2;
  19735. } elseif ($a == 3) {
  19736. $a = 4;
  19737. } else {
  19738. $a = 7;
  19739. }
  19740. ]]>
  19741. </programlisting>
  19742. PHP permite escribir sentencias sin llaves -{}- en algunas circunstancias.
  19743. Este est�ndar de c�digo no hace ninguna diferenciaci�n- toda sentencia "if",
  19744. "elseif" o "else" debe usar llaves.
  19745. </para>
  19746. <para>
  19747. El uso de la construcci�n "elseif" est� permitido pero no se aconseja, en favor de
  19748. la combinaci�n "else if".
  19749. </para>
  19750. </sect3>
  19751. <sect3 id="coding-standards.coding-style.control-statements.switch">
  19752. <title>Switch</title>
  19753. <para>
  19754. Las declaraciones de control escritas con la declaraci�n "switch" deben tener un �nico espacio en blanco antes del par�ntesis de apertura del condicional y despu�s del par�ntesis de cierre.
  19755. </para>
  19756. <para>
  19757. Todo contenido dentro de una declaraci�n "switch" debe separarse usando cuatro espacios. El contenido dentro de cada declaraci�n "case" debe separarse usando cuatro espacios adicionales.
  19758. </para>
  19759. <programlisting role="php"><![CDATA[
  19760. switch ($numPeople) {
  19761. case 1:
  19762. break;
  19763. case 2:
  19764. break;
  19765. default:
  19766. break;
  19767. }
  19768. ]]>
  19769. </programlisting>
  19770. <para>
  19771. La construcci�n <code>default</code> no debe omitirse nunca en una declaraci�n <code>switch</code>.
  19772. </para>
  19773. <para>
  19774. <emphasis>NOTA:</emphasis> En ocasiones, resulta �til escribir una declaraci�n <code>case</code> que salta al
  19775. siguiente case al no incluir un <code>break</code> o <code>return</code> dentro de ese case. Para distinguir
  19776. estos casos de posibles errores, cualquier declaraci�n donde <code>break</code> o <code>return</code> sean
  19777. omitidos deber�n contener un comentario indicando que se omitieron intencionadamente.
  19778. </para>
  19779. </sect3>
  19780. </sect2>
  19781. <sect2 id="coding-standards.inline-documentation">
  19782. <title>Documentaci�n integrada</title>
  19783. <sect3 id="coding-standards.inline-documentation.documentation-format">
  19784. <title>Formato de documentaci�n</title>
  19785. <para>
  19786. Todos los bloques de documentaci�n ("docblocks") deben ser compatibles con el formato de phpDocumentor.
  19787. Describir el formato de phpDocumentor est� fuera del alcance de este documento.
  19788. Para m�s informaci�n, visite: <ulink url="http://phpdoc.org/">http://phpdoc.org/</ulink>
  19789. </para>
  19790. <para>
  19791. Todos los archivos de clase deben contener un bloque de documentaci�n "a nivel de archivo" al principio de cada archivo y un bloque de documentaci�n "a nivel de clase" inmediatamente antes de cada clase. Ejemplo de estos bloques de documentaci�n pueden encontrarse debajo.
  19792. </para>
  19793. </sect3>
  19794. <sect3 id="coding-standards.inline-documentation.files">
  19795. <title>Archivo</title>
  19796. <para>
  19797. Cada archivo que contenga c�digo PHP debe tener un bloque de documentaci�n al principio del archivo que contenga como m�nimo las siguientes etiquetas phpDocumentor:
  19798. <programlisting role="php"><![CDATA[
  19799. /**
  19800. * Descripci�n corta del fichero
  19801. *
  19802. * Descripci�n larga del fichero (si la hubiera)...
  19803. *
  19804. * LICENSE: Informaci�n sobre la licencia
  19805. *
  19806. * @copyright 2008 Zend Technologies
  19807. * @license http://framework.zend.com/license BSD License
  19808. * @version $Id:$
  19809. * @link http://framework.zend.com/package/PackageName
  19810. * @since File available since Release 1.5.0
  19811. */
  19812. ]]>
  19813. </programlisting>
  19814. </para>
  19815. </sect3>
  19816. <sect3 id="coding-standards.inline-documentation.classes">
  19817. <title>Clases</title>
  19818. <para>
  19819. Cada clase debe contener un bloque de documentaci�n que contenga como m�nimo las siguientes etiquetas phpDocumentor:
  19820. <programlisting role="php"><![CDATA[
  19821. /**
  19822. * Descripci�n corta de la clase
  19823. *
  19824. * Descripci�n larga de la clase (si la hubiera)...
  19825. *
  19826. * @copyright 2008 Zend Technologies
  19827. * @license http://framework.zend.com/license BSD License
  19828. * @version Release: @package_version@
  19829. * @link http://framework.zend.com/package/PackageName
  19830. * @since Class available since Release 1.5.0
  19831. * @deprecated Class deprecated in Release 2.0.0
  19832. */
  19833. ]]>
  19834. </programlisting>
  19835. </para>
  19836. </sect3>
  19837. <sect3 id="coding-standards.inline-documentation.functions">
  19838. <title>Funciones</title>
  19839. <para>
  19840. Cada funci�n, incluyendo m�todos de objeto, debe contener un bloque de documentaci�n que contenga como m�nimo:
  19841. <itemizedlist>
  19842. <listitem><para>Una descripci�n de la funci�n</para></listitem>
  19843. <listitem><para>Todos los argumentos</para></listitem>
  19844. <listitem><para>Todos los posibles valores de retorno</para></listitem>
  19845. </itemizedlist>
  19846. </para>
  19847. <para>
  19848. No es necesario incluir la etiqueta "@access" si el nivel de acceso es
  19849. conocido de antemano por el modificador "public", "private", o "protected"
  19850. usado para declarar la funci�n.
  19851. </para>
  19852. <para>
  19853. Si una funci�n/m�todo puede lanzar una excepci�n, utilice @throws para todos los tipos
  19854. de excepciones conocidas:
  19855. <programlisting role="php"><![CDATA[
  19856. @throws exceptionclass [description]
  19857. ]]>
  19858. </programlisting>
  19859. </para>
  19860. </sect3>
  19861. </sect2>
  19862. </sect1>
  19863. </appendix><!--
  19864. vim:se ts=4 sw=4 et:
  19865. -->
  19866. <appendix id="performance">
  19867. <title>Guía de rendimiento de Zend Framework</title>
  19868. <sect1 id="performance.introduction" xml:base="ref/performance-introduction.xml">
  19869. <title>Introduction</title>
  19870. <para>
  19871. The purpose of this appendix is to provide some concrete strategies for
  19872. improving the performance of your Zend Framework applications. The guide
  19873. is presented in a "Question:Answer" format, and broken into areas of
  19874. concern.
  19875. </para>
  19876. </sect1><!--
  19877. vim:se ts=4 sw=4 et:
  19878. -->
  19879. <sect1 id="performance.classloading" xml:base="ref/performance-classloading.xml">
  19880. <title>Class Loading</title>
  19881. <para>
  19882. Anyone who ever performs profiling of a Zend Framework application will
  19883. immediately recognize that class loading is relatively expensive in Zend
  19884. Framework. Between the sheer number of class files that need to be
  19885. loaded for many components, to the use of plugins that do not have a 1:1
  19886. relationship between their class name and the filesystem, the various
  19887. calls to <code>include_once</code> and <code>require_once</code> can be
  19888. problematic. This chapter intends to provide some concrete solutions to
  19889. these issues.
  19890. </para>
  19891. <sect2 id="performance.classloading.includepath">
  19892. <title>How can I optimize my include_path?</title>
  19893. <para>
  19894. One trivial optimization you can do to increase the speed of class
  19895. loading is to pay careful attention to your include_path. In
  19896. particular, you should do four things: use absolute paths (or paths
  19897. relative to absolute paths), reduce the number of include paths you
  19898. define, have your Zend Framework include_path as early as possible,
  19899. and only include the current directory path at the end of your
  19900. include_path.
  19901. </para>
  19902. <sect3 id="performance.classloading.includepath.abspath">
  19903. <title>Use absolute paths</title>
  19904. <para>
  19905. While this may seem a micro-optimization, the fact is that if
  19906. you don't, you'll get very little benefit from PHP's realpath
  19907. cache, and as a result, opcode caching will not perform nearly
  19908. as you may expect.
  19909. </para>
  19910. <para>
  19911. There are two easy ways to ensure this. First, you can hardcode
  19912. the paths in your php.ini, httpd.conf, or .htaccess. Second, you
  19913. can use PHP's <code>realpath()</code> function when setting your
  19914. include_path:
  19915. </para>
  19916. <programlisting role="php"><![CDATA[
  19917. $paths = array(
  19918. realpath(dirname(__FILE__) . '/../library'),
  19919. '.',
  19920. );
  19921. set_include_path(implode(PATH_SEPARATOR, $paths);
  19922. ]]></programlisting>
  19923. <para>
  19924. You <emphasis>can</emphasis> use relative paths -- so long as
  19925. they are relative to an absolute path:
  19926. </para>
  19927. <programlisting role="php"><![CDATA[
  19928. define('APPLICATION_PATH', realpath(dirname(__FILE__)));
  19929. $paths = array(
  19930. APPLICATION_PATH . '/../library'),
  19931. '.',
  19932. );
  19933. set_include_path(implode(PATH_SEPARATOR, $paths);
  19934. ]]></programlisting>
  19935. <para>
  19936. However, even so, it's typically a trivial task to simply pass
  19937. the path to <code>realpath()</code>.
  19938. </para>
  19939. </sect3>
  19940. <sect3 id="performance.classloading.includepath.reduce">
  19941. <title>Reduce the number of include paths you define</title>
  19942. <para>
  19943. Include paths are scanned in the order in which they appear in
  19944. the include_path. Obviously, this means that you'll get a result
  19945. faster if the file is found on the first scan rather than the
  19946. last. Thus, a rather obvious enhancement is to simply reduce the
  19947. number of paths in your include_path to only what you need. Look
  19948. through each include_path you've defined, and determine if you
  19949. actually have any functionality in that path that is used in
  19950. your application; if not, remove it.
  19951. </para>
  19952. <para>
  19953. Another optimization is to combine paths. For instance, Zend
  19954. Framework follows PEAR naming conventions; thus, if you are
  19955. using PEAR libraries (or libraries from another framework or
  19956. component library that follows PEAR CS), try to put all of these
  19957. libraries on the same include_path. This can often be achieved
  19958. by something as simple as symlinking one or more libraries into
  19959. a common directory.
  19960. </para>
  19961. </sect3>
  19962. <sect3 id="performance.classloading.includepath.early">
  19963. <title>Define your Zend Framework include_path as early as possible</title>
  19964. <para>
  19965. Continuing from the previous suggestion, another obvious
  19966. optimization is to define your Zend Framework include_path as
  19967. early as possible in your include_path. In most cases, it should
  19968. be the first path in the list. This ensures that files included
  19969. from Zend Framework are found on the first scan.
  19970. </para>
  19971. </sect3>
  19972. <sect3 id="performance.classloading.includepath.currentdir">
  19973. <title>Define the current directory last, or not at all</title>
  19974. <para>
  19975. Most include_path examples show using the current directory, or
  19976. '.'. This is convenient for ensuring that scripts in the same
  19977. directory as the file requiring them can be loaded. However,
  19978. these same examples typically show this path item as the first
  19979. item in the include_path -- which means that the current
  19980. directory tree is always scanned first. In most cases, with Zend
  19981. Framework applications, this is not desired, and the path may be
  19982. safely pushed to the last item in the list.
  19983. </para>
  19984. <example id="performance.classloading.includepath.example">
  19985. <title>Example: Optimized include_path</title>
  19986. <para>
  19987. Let's put all of these suggestions together. Our assumption will
  19988. be that you are using one or more PEAR libraries in conjunction
  19989. with Zend Framework -- perhaps the PHPUnit and Archive_Tar
  19990. libraries -- and that you occasionally need to include
  19991. files relative to the current file.
  19992. </para>
  19993. <para>
  19994. First, we'll create a library directory in our project. Inside
  19995. that directory, we'll symlink our Zend Framework's library/Zend
  19996. directory, as well as the necessary directories from our PEAR
  19997. installation:
  19998. </para>
  19999. <programlisting role="php"><![CDATA[
  20000. library
  20001. Archive/
  20002. PEAR/
  20003. PHPUnit/
  20004. Zend/
  20005. ]]></programlisting>
  20006. <para>
  20007. This allows us to add our own library code if necessary, while
  20008. keeping shared libraries intact.
  20009. </para>
  20010. <para>
  20011. Next, we'll opt to create our include_path programmatically
  20012. within our public/index.php file. This allows us to move our
  20013. code around on the filesystem, without needing to edit the
  20014. include_path every time.
  20015. </para>
  20016. <para>
  20017. We'll borrow ideas from each of the suggestions above: we'll use
  20018. absolute paths, as determined using <code>realpath()</code>;
  20019. we'll include the Zend Framework include path early; we've
  20020. already consolidated include_paths; and we'll put the current
  20021. directory as the last path. In fact, we're doing really well
  20022. here -- we're going to end up with only two paths.
  20023. </para>
  20024. <programlisting role="php"><![CDATA[
  20025. $paths = array(
  20026. realpath(dirname(__FILE__) . '/../library'),
  20027. '.'
  20028. );
  20029. set_include_path(implode(PATH_SEPARATOR, $paths));
  20030. ]]></programlisting>
  20031. </example>
  20032. </sect3>
  20033. </sect2>
  20034. <sect2 id="performance.classloading.striprequires">
  20035. <title>How can I eliminate unnecessary require_once statements?</title>
  20036. <para>
  20037. Lazy loading is an optimization technique designed to push the
  20038. expensive operation of loading a class file until the last possible
  20039. moment -- i.e., when instantiating an object of that class, calling
  20040. a static class method, or referencing a class constant or static
  20041. property. PHP supports this via autoloading, which allows you to
  20042. define one or more callbacks to execute in order to map a class name
  20043. to a file.
  20044. </para>
  20045. <para>
  20046. However, most benefits you may reap from autoloading are negated if
  20047. your library code is still performing require_once calls -- which is
  20048. precisely the case with Zend Framework. So, the question is: how can
  20049. you eliminate those require_once calls in order to maximize
  20050. autoloader performance?
  20051. </para>
  20052. <sect3 id="performance.classloading.striprequires.sed">
  20053. <title>Strip require_once calls with find and sed</title>
  20054. <para>
  20055. An easy way to strip require_once calls is to use the unix
  20056. utilities 'find' and 'sed' in conjunction to comment out each
  20057. call. Try executing the following statements (where '%'
  20058. indicates the shell prompt):
  20059. </para>
  20060. <programlisting role="shell"><![CDATA[
  20061. % cd path/to/ZendFramework/library
  20062. % find . -name '*.php' -print0 | xargs -0 \
  20063. sed --regexp-extended --in-place 's/(require_once)/\/\/ \1/g'
  20064. ]]></programlisting>
  20065. <para>
  20066. This one-liner (broken into two lines for readability) iterates
  20067. through each PHP file and tells it to replace each instance of
  20068. 'require_once' with '// require_once', effectively commenting
  20069. out each such statement.
  20070. </para>
  20071. <para>
  20072. This command could be added to an automated build or release
  20073. process trivially, helping boost performance in your production
  20074. application. It should be noted, however, that if you use this
  20075. technique, you <emphasis>must</emphasis> utilize autoloading;
  20076. you can do that from your "public/index.php" file with the
  20077. following code:
  20078. </para>
  20079. <programlisting role="php"><![CDATA[
  20080. require_once 'Zend/Loader.php'; // one require_once is still necessary
  20081. Zend_Loader::registerAutoload();
  20082. ]]></programlisting>
  20083. </sect3>
  20084. </sect2>
  20085. <sect2 id="performance.classloading.pluginloader">
  20086. <title>How can I speed up plugin loading?</title>
  20087. <para>
  20088. Many components have plugins, which allow you to create your own
  20089. classes to utilize with the component, as well as to override
  20090. existing, standard plugins shipped with Zend Framework. This
  20091. provides important flexibility to the framework, but at a price:
  20092. plugin loading is a fairly expensive task.
  20093. </para>
  20094. <para>
  20095. The plugin loader allows you to register class prefix / path pairs,
  20096. allowing you to specify class files in non-standard paths. Each
  20097. prefix can have multiple paths associated with it.
  20098. Internally, the plugin loader loops through each prefix, and then
  20099. through each path attached to it, testing to see if the file exists
  20100. and is readable on that path. It then loads it, and tests to see
  20101. that the class it is looking for is available. As you might imagine,
  20102. this can lead to many stat calls on the filesystem.
  20103. </para>
  20104. <para>
  20105. Multiply this by the number of components that use the PluginLoader,
  20106. and you get an idea of the scope of this issue. At the time of this
  20107. writing, the following components made use of the PluginLoader:
  20108. </para>
  20109. <itemizedlist>
  20110. <listitem><para>
  20111. <code>Zend_Controller_Action_HelperBroker</code>: helpers
  20112. </para></listitem>
  20113. <listitem><para>
  20114. <code>Zend_Dojo</code>: view helpers, form elements and decorators
  20115. </para></listitem>
  20116. <listitem><para>
  20117. <code>Zend_File_Transfer</code>: adapters
  20118. </para></listitem>
  20119. <listitem><para>
  20120. <code>Zend_Filter_Inflector</code>: filters (used by the
  20121. ViewRenderer action helper and Zend_Layout)
  20122. </para></listitem>
  20123. <listitem><para>
  20124. <code>Zend_Filter_Input</code>: filters and validators
  20125. </para></listitem>
  20126. <listitem><para>
  20127. <code>Zend_Form</code>: elements, validators, filters,
  20128. decorators, captcha and file transfer adapters
  20129. </para></listitem>
  20130. <listitem><para>
  20131. <code>Zend_Paginator</code>: adapters
  20132. </para></listitem>
  20133. <listitem><para>
  20134. <code>Zend_View</code>: helpers, filters
  20135. </para></listitem>
  20136. </itemizedlist>
  20137. <para>
  20138. How can you reduce the number of such calls made?
  20139. </para>
  20140. <sect3 id="performance.classloading.pluginloader.includefilecache">
  20141. <title>Use the PluginLoader include file cache</title>
  20142. <para>
  20143. Zend Framework 1.7.0 adds an include file cache to the
  20144. PluginLoader. This functionality writes "include_once" calls to
  20145. a file, which you can then include in your bootstrap. While this
  20146. introduces extra include_once calls to your code, it also
  20147. ensures that the PluginLoader returns as early as possible.
  20148. </para>
  20149. <para>
  20150. The PluginLoader documentation <link linkend="zend.loader.pluginloader.performance.example">includes
  20151. a complete example of its use</link>.
  20152. </para>
  20153. </sect3>
  20154. </sect2>
  20155. </sect1><!--
  20156. vim:se ts=4 sw=4 et:
  20157. -->
  20158. <sect1 id="performance.localization" xml:base="ref/performance-localization.xml">
  20159. <title>Internationalization (i18n) and Localization (l10n)</title>
  20160. <para>
  20161. Internationalizing and localizing a site are fantastic ways to expand
  20162. your audience and ensure that all visitors can get to the information
  20163. they need. However, it often comes with a performance penalty. Below
  20164. are some strategies you can employ to reduce the overhead of i18n and
  20165. l10n.
  20166. </para>
  20167. <sect2 id="performance.localization.translationadapter">
  20168. <title>Which translation adapter should I use?</title>
  20169. <para>
  20170. Not all translation adapters are made equal. Some have more
  20171. features than others, and some are more performant than others.
  20172. Additionally, you may have business requirements that force you to
  20173. use a particular adapter. However, if you have a choice, which
  20174. adapters are fastest?
  20175. </para>
  20176. <sect3 id="performance.localization.translationadapter.fastest">
  20177. <title>Use non-XML translation adapters for greatest speed</title>
  20178. <para>
  20179. Zend Framework ships with a variety of translation adapters.
  20180. Fully half of them utilize an XML format, incurring memory and
  20181. performance overhead. Fortunately, there are several adapters
  20182. that utilize other formats that can be parsed much more
  20183. quickly. In order of speed, from fastest to slowest, they are:
  20184. </para>
  20185. <itemizedlist>
  20186. <listitem><para>
  20187. <emphasis>Array</emphasis>: this is the fastest, as it is,
  20188. by definition, parsed into a native PHP format immediately
  20189. on inclusion.
  20190. </para></listitem>
  20191. <listitem><para>
  20192. <emphasis>CSV</emphasis>: uses <code>fgetcsv()</code> to
  20193. parse a CSV file and transform it into a native PHP format.
  20194. </para></listitem>
  20195. <listitem><para>
  20196. <emphasis>INI</emphasis>: uses
  20197. <code>parse_ini_file()</code> to parse an INI file and
  20198. transform it into a native PHP format. This and the CSV
  20199. adapter are roughly equivalent performance-wise.
  20200. </para></listitem>
  20201. <listitem><para>
  20202. <emphasis>Gettext</emphasis>: the Zend Framework gettext
  20203. adapter does <emphasis>not</emphasis> use the gettext
  20204. extension as it is not threadsafe and does not allow
  20205. specifying more than one locale per server. As a result, it
  20206. is slower than using the gettext extension directly, but,
  20207. because the gettext format is binary, it's faster to parse
  20208. than XML.
  20209. </para></listitem>
  20210. </itemizedlist>
  20211. <para>
  20212. If high performance is one of your concerns, we suggest
  20213. utilizing one of the above adapters.
  20214. </para>
  20215. </sect3>
  20216. </sect2>
  20217. <sect2 id="performance.localization.cache">
  20218. <title>How can I make translation and localization even faster?</title>
  20219. <para>
  20220. Maybe, for business reasons, you're limited to an XML-based
  20221. translation adapter. Or perhaps you'd like to speed things up even
  20222. more. Or perhaps you want to make l10n operations faster. How can
  20223. you do this?
  20224. </para>
  20225. <sect3 id="performance.localization.cache.usage">
  20226. <title>Use translation and localization caches</title>
  20227. <para>
  20228. Both <code>Zend_Translate</code> and <code>Zend_Locale</code>
  20229. implement caching functionality that can greatly affect
  20230. performance. In the case of each, the major bottleneck is
  20231. typically reading the files, not the actual lookups; using a
  20232. cache eliminates the need to read the translation and/or
  20233. localization files.
  20234. </para>
  20235. <para>
  20236. You can read about caching of translation and localization
  20237. strings in the following locations:
  20238. </para>
  20239. <itemizedlist>
  20240. <listitem>
  20241. <para>
  20242. <link linkend="zend.translate.adapter.caching"><code>Zend_Translate</code>
  20243. adapter caching</link>
  20244. </para>
  20245. </listitem>
  20246. <listitem>
  20247. <para>
  20248. <link linkend="zend.locale.cache"><code>Zend_Locale</code>
  20249. caching</link>
  20250. </para>
  20251. </listitem>
  20252. </itemizedlist>
  20253. </sect3>
  20254. </sect2>
  20255. </sect1><!--
  20256. vim:se ts=4 sw=4 et:
  20257. -->
  20258. <sect1 id="performance.view" xml:base="ref/performance-view.xml">
  20259. <title>View Rendering</title>
  20260. <para>
  20261. When using Zend Framework's MVC layer, chances are you will be using
  20262. <code>Zend_View</code>. <code>Zend_View</code> is relatively performant
  20263. when compared to other view or templating engines; since view scripts
  20264. are written in PHP, you do not incur the overhead of compiling custom
  20265. markup to PHP, nor do you need to worry that the compiled PHP is
  20266. unoptimized. However, <code>Zend_View</code> presents its own issues:
  20267. extension is done via overloading (view helpers), and a number of view
  20268. helpers, while carrying out key functionality do so with a performance
  20269. cost.
  20270. </para>
  20271. <sect2 id="performance.view.pluginloader">
  20272. <title>How can I speed up resolution of view helpers?</title>
  20273. <para>
  20274. Most <code>Zend_View</code> "methods" are actually provided via
  20275. overloading to the helper system. This provides important
  20276. flexibility to Zend_View; instead of needing to extend Zend_View and
  20277. provide all the helper methods you may utilize in your application,
  20278. you can define your helper methods in separate classes and consume
  20279. them at will as if they were direct methods of Zend_View. This keeps
  20280. the view object itself relatively thin, and ensures that objects are
  20281. created only when needed.
  20282. </para>
  20283. <para>
  20284. Internally, <code>Zend_View</code> uses the <link linkend="zend.loader.pluginloader">PluginLoader</link> to look
  20285. up helper classes. This means that for each helper you call,
  20286. <code>Zend_View</code> needs to pass the helper name to the
  20287. PluginLoader, which then needs to determine the class name, load the
  20288. class file if necessary, and then return the class name so it may be
  20289. instantiated. Subsequent uses of the helper are much faster, as
  20290. <code>Zend_View</code> keeps an internal registry of loaded helpers,
  20291. but if you use many helpers, the calls add up.
  20292. </para>
  20293. <para>
  20294. The question, then, is: how can you speed up helper resolution?
  20295. </para>
  20296. <sect3 id="performance.view.pluginloader.cache">
  20297. <title>Use the PluginLoader include file cache</title>
  20298. <para>
  20299. The simplest, cheapest solution is the same as for <link linkend="performance.classloading.pluginloader">general
  20300. PluginLoader performance</link>: <link linkend="zend.loader.pluginloader.performance.example">use
  20301. the PluginLoader include file cache</link>. Anecdotal
  20302. evidence has shown this technique to provide a 25-30%
  20303. performance gain on systems without an opcode cache, and a
  20304. 40-65% gain on systems with an opcode cache.
  20305. </para>
  20306. </sect3>
  20307. <sect3 id="performance.view.pluginloader.extend">
  20308. <title>Extend Zend_View to provide often used helper methods</title>
  20309. <para>
  20310. Another solution for those seeking to tune performance even
  20311. further is to extend <code>Zend_View</code> to manually add the
  20312. helper methods they most use in their application. Such helper
  20313. methods may simply manually instantiate the appropriate helper
  20314. class and proxy to it, or stuff the full helper implementation
  20315. into the method.
  20316. </para>
  20317. <programlisting role="php"><![CDATA[
  20318. class My_View extends Zend_View
  20319. {
  20320. /**
  20321. * @var array Registry of helper classes used
  20322. */
  20323. protected $_localHelperObjects = array();
  20324. /**
  20325. * Proxy to url view helper
  20326. *
  20327. * @param array $urlOptions Options passed to the assemble method of the Route object.
  20328. * @param mixed $name The name of a Route to use. If null it will use the current Route
  20329. * @param bool $reset Whether or not to reset the route defaults with those provided
  20330. * @return string Url for the link href attribute.
  20331. */
  20332. public function url(array $urlOptions = array(), $name = null,
  20333. $reset = false, $encode = true
  20334. ) {
  20335. if (!array_key_exists('url', $this->_localHelperObjects)) {
  20336. $this->_localHelperObjects['url'] = new Zend_View_Helper_Url();
  20337. $this->_localHelperObjects['url']->setView($view);
  20338. }
  20339. $helper = $this->_localHelperObjects['url'];
  20340. return $helper->url($urlOptions, $name, $reset, $encode);
  20341. }
  20342. /**
  20343. * Echo a message
  20344. *
  20345. * Direct implementation.
  20346. *
  20347. * @param string $string
  20348. * @return string
  20349. */
  20350. public function message($string)
  20351. {
  20352. return "<h1>" . $this->escape($message) . "</h1>\n";
  20353. }
  20354. }
  20355. ]]></programlisting>
  20356. <para>
  20357. Either way, this technique will substantially reduce the
  20358. overhead of the helper system by avoiding calls to the
  20359. PluginLoader entirely, and either benefiting from autoloading or
  20360. bypassing it altogether.
  20361. </para>
  20362. </sect3>
  20363. </sect2>
  20364. <sect2 id="performance.view.partial">
  20365. <title>How can I speed up view partials?</title>
  20366. <para>
  20367. Those who use partials heavily and who profile their applications
  20368. will often immediately notice that the <code>partial()</code> view
  20369. helper incurs a lot of overhead, due to the need to clone the view
  20370. object. Is it possible to speed this up?
  20371. </para>
  20372. <sect3 id="performance.view.partial.render">
  20373. <title>Use partial() only when really necessary</title>
  20374. <para>
  20375. The <code>partial()</code> view helper accepts three arguments:
  20376. </para>
  20377. <itemizedlist>
  20378. <listitem><para>
  20379. <code>$name</code>: the name of the view script to render
  20380. </para></listitem>
  20381. <listitem><para>
  20382. <code>$module</code>: the name of the module in which the
  20383. view script resides; or, if no third argument is provided
  20384. and this is an array or object, it will be the
  20385. <code>$model</code> argument.
  20386. </para></listitem>
  20387. <listitem><para>
  20388. <code>$model</code>: an array or object to pass to the
  20389. partial representing the clean data to assign to the view.
  20390. </para></listitem>
  20391. </itemizedlist>
  20392. <para>
  20393. The power and use of <code>partial()</code> come from the second
  20394. and third arguments. The <code>$module</code> argument allows
  20395. <code>partial()</code> to temporarily add a script path for the
  20396. given module so that the partial view script will resolve to
  20397. that module; the <code>$model</code> argument allows you to
  20398. explicitly pass variables for use with the partial view.
  20399. If you're not passing either argument, <emphasis>use
  20400. <code>render()</code> instead</emphasis>!
  20401. </para>
  20402. <para>
  20403. Basically, unless you are actually passing variables to the
  20404. partial and need the clean variable scope, or rendering a view
  20405. script from another MVC module, there is no reason to incur the
  20406. overhead of <code>partial()</code>; instead, use
  20407. <code>Zend_View</code>'s built-in <code>render()</code> method
  20408. to render the view script.
  20409. </para>
  20410. </sect3>
  20411. </sect2>
  20412. <sect2 id="performance.view.action">
  20413. <title>How can I speed up calls to the action() view helper?</title>
  20414. <para>
  20415. Version 1.5.0 introduced the <code>action()</code> view helper,
  20416. which allows you to dispatch an MVC action and capture its rendered
  20417. content. This provides an important step towards the DRY principle,
  20418. and promotes code reuse. However, as those who profile their
  20419. applications will quickly realize, it, too, is an expensive
  20420. operation. Internally, the <code>action()</code> view helper needs
  20421. to clone new request and response objects, invoke the dispatcher,
  20422. invoke the requested controller and action, etc.
  20423. </para>
  20424. <para>
  20425. How can you speed it up?
  20426. </para>
  20427. <sect3 id="performance.view.action.actionstack">
  20428. <title>Use the ActionStack when possible</title>
  20429. <para>
  20430. Introduced at the same time as the <code>action()</code> view
  20431. helper, the <link linkend="zend.controller.actionhelpers.actionstack">ActionStack</link>
  20432. consists of an action helper and a front controller plugin.
  20433. Together, they allow you to push additional actions to invoke
  20434. during the dispatch cycle onto a stack. If you are calling
  20435. <code>action()</code> from your layout view scripts, you may
  20436. want to instead use the ActionStack, and render your views to
  20437. discrete response segments. As an example, you could write a
  20438. <code>dispatchLoopStartup()</code> plugin like the following to
  20439. add a login form box to each page:
  20440. </para>
  20441. <programlisting role="php"><![CDATA[
  20442. class LoginPlugin extends Zend_Controller_Plugin_Abstract
  20443. {
  20444. protected $_stack;
  20445. public function dispatchLoopStartup(
  20446. Zend_Controller_Request_Abstract $request
  20447. ) {
  20448. $stack = $this->getStack();
  20449. $loginRequest = new Zend_Controller_Request_Simple();
  20450. $loginRequest->setControllerName('user')
  20451. ->setActionName('index')
  20452. ->setParam('responseSegment', 'login');
  20453. $stack->pushStack($loginRequest);
  20454. }
  20455. public function getStack()
  20456. {
  20457. if (null === $this->_stack) {
  20458. $front = Zend_Controller_Front::getInstance();
  20459. if (!$front->hasPlugin('Zend_Controller_Plugin_ActionStack')) {
  20460. $stack = new Zend_Controller_Plugin_ActionStack();
  20461. $front->registerPlugin($stack);
  20462. } else {
  20463. $stack = $front->getPlugin('ActionStack')
  20464. }
  20465. $this->_stack = $stack;
  20466. }
  20467. return $this->_stack;
  20468. }
  20469. }
  20470. ]]></programlisting>
  20471. <para>
  20472. The <code>UserController::indexAction()</code> method might then
  20473. use the <code>responseSegment</code> parameter to indicate which
  20474. response segment to render to. In the layout script, you would
  20475. then simply render that response segment:
  20476. </para>
  20477. <programlisting role="php"><![CDATA[
  20478. <?= $this->layout()->login ?>
  20479. ]]></programlisting>
  20480. <para>
  20481. While the ActionStack still requires a dispatch cycle, this is
  20482. still cheaper than the <code>action()</code> view helper as it
  20483. does not need to clone objects and reset internal state.
  20484. Additionally, it ensures that all pre/post dispatch plugins are
  20485. invoked, which may be of particular concern if you are using
  20486. front controller plugins for handling ACLs to particular
  20487. actions.
  20488. </para>
  20489. </sect3>
  20490. <sect3 id="performance.view.action.model">
  20491. <title>Favor helpers that query the model over action()</title>
  20492. <para>
  20493. In most cases, using <code>action()</code> is simply overkill.
  20494. If you have most business logic nested in your models and are
  20495. simply querying the model and passing the results to a view
  20496. script, it will typically be faster and cleaner to simply write
  20497. a view helper that pulls the model, queries it, and does
  20498. something with that information.
  20499. </para>
  20500. <para>
  20501. As an example, consider the following controller action and view
  20502. script:
  20503. </para>
  20504. <programlisting role="php"><![CDATA[
  20505. class BugController extends Zend_Controller_Action
  20506. {
  20507. public function listAction()
  20508. {
  20509. $model = new Bug();
  20510. $this->view->bugs = $model->fetchActive();
  20511. }
  20512. }
  20513. // bug/list.phtml:
  20514. echo "<ul>\n";
  20515. foreach ($this->bugs as $bug) {
  20516. printf("<li><b>%s</b>: %s</li>\n", $this->escape($bug->id), $this->escape($bug->summary));
  20517. }
  20518. echo "</ul>\n";
  20519. ]]></programlisting>
  20520. <para>
  20521. Using <code>action()</code>, you would then invoke it with the
  20522. following:
  20523. </para>
  20524. <programlisting role="php"><![CDATA[
  20525. <?= $this->action('list', 'bug') ?>
  20526. ]]></programlisting>
  20527. <para>
  20528. This could be refactored to a view helper that looks like the
  20529. following:
  20530. </para>
  20531. <programlisting role="php"><![CDATA[
  20532. class My_View_Helper_BugList extends Zend_View_Helper_Abstract
  20533. {
  20534. public function direct()
  20535. {
  20536. $model = new Bug();
  20537. $html = "<ul>\n";
  20538. foreach ($model->fetchActive() as $bug) {
  20539. $html .= sprintf(
  20540. "<li><b>%s</b>: %s</li>\n",
  20541. $this->view->escape($bug->id),
  20542. $this->view->escape($bug->summary)
  20543. );
  20544. }
  20545. $html .= "</ul>\n";
  20546. return $html;
  20547. }
  20548. }
  20549. ]]></programlisting>
  20550. <para>
  20551. You would then invoke the helper as follows:
  20552. </para>
  20553. <programlisting role="php"><![CDATA[
  20554. <?= $this->bugList() ?>
  20555. ]]></programlisting>
  20556. <para>
  20557. This has two benefits: it no longer incurs the overhead of the
  20558. <code>action()</code> view helper, and also presents a more
  20559. semantically understandable API.
  20560. </para>
  20561. </sect3>
  20562. </sect2>
  20563. </sect1><!--
  20564. vim:se ts=4 sw=4 et:
  20565. -->
  20566. </appendix>
  20567. <appendix id="copyrights" xml:base="ref/copyrights.xml">
  20568. <title>Copyright Information</title>
  20569. <para>
  20570. The following copyrights are applicable to portions of Zend Framework.
  20571. </para>
  20572. <para>
  20573. Copyright © 2005-<?dbtimestamp format="Y"?> Zend Technologies Inc.
  20574. (<ulink url="http://www.zend.com"/>)
  20575. </para>
  20576. </appendix><!--
  20577. vim:se ts=4 sw=4 et:
  20578. -->
  20579. <index id="the.index"/>
  20580. </book>
  20581. <!--
  20582. vim:se ts=4 sw=4 et:
  20583. -->