| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561 |
- <?php
- /**
- * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
- * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
- *
- * Licensed under The MIT License
- * For full copyright and license information, please see the LICENSE.txt
- * Redistributions of files must retain the above copyright notice.
- *
- * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
- * @link https://cakephp.org CakePHP(tm) Project
- * @since 3.0.0
- * @license https://opensource.org/licenses/mit-license.php MIT License
- */
- namespace Cake\Test\TestCase\ORM;
- use Cake\Database\Expression\IdentifierExpression;
- use Cake\Event\Event;
- use Cake\I18n\Time;
- use Cake\ORM\Entity;
- use Cake\ORM\Marshaller;
- use Cake\ORM\Table;
- use Cake\TestSuite\TestCase;
- use Cake\Validation\Validator;
- /**
- * Test entity for mass assignment.
- */
- class OpenEntity extends Entity
- {
- protected $_accessible = [
- '*' => true,
- ];
- }
- /**
- * Test entity for mass assignment.
- */
- class Tag extends Entity
- {
- protected $_accessible = [
- 'tag' => true,
- ];
- }
- /**
- * Test entity for mass assignment.
- */
- class ProtectedArticle extends Entity
- {
- protected $_accessible = [
- 'title' => true,
- 'body' => true,
- ];
- }
- /**
- * Test stub for greedy find operations.
- */
- class GreedyCommentsTable extends Table
- {
- /**
- * initialize hook
- *
- * @param array $config Config data.
- * @return void
- */
- public function initialize(array $config)
- {
- $this->setTable('comments');
- $this->setAlias('Comments');
- }
- /**
- * Overload find to cause issues.
- *
- * @param string $type Find type
- * @param array $options find options
- * @return object
- */
- public function find($type = 'all', $options = [])
- {
- if (empty($options['conditions'])) {
- $options['conditions'] = [];
- }
- $options['conditions'] = array_merge($options['conditions'], ['Comments.published' => 'Y']);
- return parent::find($type, $options);
- }
- }
- /**
- * Marshaller test case
- */
- class MarshallerTest extends TestCase
- {
- public $fixtures = [
- 'core.Articles',
- 'core.ArticlesTags',
- 'core.Comments',
- 'core.SpecialTags',
- 'core.Tags',
- 'core.Users',
- ];
- /**
- * @var Table
- */
- protected $articles;
- /**
- * @var Table
- */
- protected $comments;
- /**
- * @var Table
- */
- protected $users;
- /**
- * @var Table
- */
- protected $tags;
- /**
- * @var Table
- */
- protected $articleTags;
- /**
- * setup
- *
- * @return void
- */
- public function setUp()
- {
- parent::setUp();
- $this->articles = $this->getTableLocator()->get('Articles');
- $this->articles->belongsTo('Users', [
- 'foreignKey' => 'author_id',
- ]);
- $this->articles->hasMany('Comments');
- $this->articles->belongsToMany('Tags');
- $this->comments = $this->getTableLocator()->get('Comments');
- $this->users = $this->getTableLocator()->get('Users');
- $this->tags = $this->getTableLocator()->get('Tags');
- $this->articleTags = $this->getTableLocator()->get('ArticlesTags');
- $this->comments->belongsTo('Articles');
- $this->comments->belongsTo('Users');
- $this->articles->setEntityClass(__NAMESPACE__ . '\OpenEntity');
- $this->comments->setEntityClass(__NAMESPACE__ . '\OpenEntity');
- $this->users->setEntityClass(__NAMESPACE__ . '\OpenEntity');
- $this->tags->setEntityClass(__NAMESPACE__ . '\OpenEntity');
- $this->articleTags->setEntityClass(__NAMESPACE__ . '\OpenEntity');
- }
- /**
- * Teardown
- *
- * @return void
- */
- public function tearDown()
- {
- parent::tearDown();
- unset($this->articles, $this->comments, $this->users, $this->tags);
- }
- /**
- * Test one() in a simple use.
- *
- * @return void
- */
- public function testOneSimple()
- {
- $data = [
- 'title' => 'My title',
- 'body' => 'My content',
- 'author_id' => 1,
- 'not_in_schema' => true,
- ];
- $marshall = new Marshaller($this->articles);
- $result = $marshall->one($data, []);
- $this->assertInstanceOf('Cake\ORM\Entity', $result);
- $this->assertEquals($data, $result->toArray());
- $this->assertTrue($result->isDirty(), 'Should be a dirty entity.');
- $this->assertTrue($result->isNew(), 'Should be new');
- $this->assertEquals('Articles', $result->getSource());
- }
- /**
- * Test that marshalling an entity with '' for pk values results
- * in no pk value being set.
- *
- * @return void
- */
- public function testOneEmptyStringPrimaryKey()
- {
- $data = [
- 'id' => '',
- 'username' => 'superuser',
- 'password' => 'root',
- 'created' => new Time('2013-10-10 00:00'),
- 'updated' => new Time('2013-10-10 00:00'),
- ];
- $marshall = new Marshaller($this->articles);
- $result = $marshall->one($data, []);
- $this->assertFalse($result->isDirty('id'));
- $this->assertNull($result->id);
- }
- /**
- * Test marshalling datetime/date field.
- *
- * @return void
- */
- public function testOneWithDatetimeField()
- {
- $data = [
- 'comment' => 'My Comment text',
- 'created' => [
- 'year' => '2014',
- 'month' => '2',
- 'day' => 14,
- ],
- ];
- $marshall = new Marshaller($this->comments);
- $result = $marshall->one($data, []);
- $this->assertEquals(new Time('2014-02-14 00:00:00'), $result->created);
- $data['created'] = [
- 'year' => '2014',
- 'month' => '2',
- 'day' => 14,
- 'hour' => 9,
- 'minute' => 25,
- 'meridian' => 'pm',
- ];
- $result = $marshall->one($data, []);
- $this->assertEquals(new Time('2014-02-14 21:25:00'), $result->created);
- $data['created'] = [
- 'year' => '2014',
- 'month' => '2',
- 'day' => 14,
- 'hour' => 9,
- 'minute' => 25,
- ];
- $result = $marshall->one($data, []);
- $this->assertEquals(new Time('2014-02-14 09:25:00'), $result->created);
- $data['created'] = '2014-02-14 09:25:00';
- $result = $marshall->one($data, []);
- $this->assertEquals(new Time('2014-02-14 09:25:00'), $result->created);
- $data['created'] = 1392387900;
- $result = $marshall->one($data, []);
- $this->assertEquals($data['created'], $result->created->getTimestamp());
- }
- /**
- * Ensure that marshalling casts reasonably.
- *
- * @return void
- */
- public function testOneOnlyCastMatchingData()
- {
- $data = [
- 'title' => 'My title',
- 'body' => 'My content',
- 'author_id' => 'derp',
- 'created' => 'fale',
- ];
- $this->articles->setEntityClass(__NAMESPACE__ . '\OpenEntity');
- $marshall = new Marshaller($this->articles);
- $result = $marshall->one($data, []);
- $this->assertSame($data['title'], $result->title);
- $this->assertNull($result->author_id, 'No cast on bad data.');
- $this->assertSame($data['created'], $result->created, 'No cast on bad data.');
- }
- /**
- * Test one() follows mass-assignment rules.
- *
- * @return void
- */
- public function testOneAccessibleProperties()
- {
- $data = [
- 'title' => 'My title',
- 'body' => 'My content',
- 'author_id' => 1,
- 'not_in_schema' => true,
- ];
- $this->articles->setEntityClass(__NAMESPACE__ . '\ProtectedArticle');
- $marshall = new Marshaller($this->articles);
- $result = $marshall->one($data, []);
- $this->assertInstanceOf(__NAMESPACE__ . '\ProtectedArticle', $result);
- $this->assertNull($result->author_id);
- $this->assertNull($result->not_in_schema);
- }
- /**
- * Test one() supports accessibleFields option
- *
- * @return void
- */
- public function testOneAccessibleFieldsOption()
- {
- $data = [
- 'title' => 'My title',
- 'body' => 'My content',
- 'author_id' => 1,
- 'not_in_schema' => true,
- ];
- $this->articles->setEntityClass(__NAMESPACE__ . '\ProtectedArticle');
- $marshall = new Marshaller($this->articles);
- $result = $marshall->one($data, ['accessibleFields' => ['body' => false]]);
- $this->assertNull($result->body);
- $result = $marshall->one($data, ['accessibleFields' => ['author_id' => true]]);
- $this->assertEquals($data['author_id'], $result->author_id);
- $this->assertNull($result->not_in_schema);
- $result = $marshall->one($data, ['accessibleFields' => ['*' => true]]);
- $this->assertEquals($data['author_id'], $result->author_id);
- $this->assertTrue($result->not_in_schema);
- }
- /**
- * Test one() with an invalid association
- *
- * @return void
- */
- public function testOneInvalidAssociation()
- {
- $this->expectException(\InvalidArgumentException::class);
- $this->expectExceptionMessage('Cannot marshal data for "Derp" association. It is not associated with "Articles".');
- $data = [
- 'title' => 'My title',
- 'body' => 'My content',
- 'derp' => [
- 'id' => 1,
- 'username' => 'mark',
- ],
- ];
- $marshall = new Marshaller($this->articles);
- $marshall->one($data, [
- 'associated' => ['Derp'],
- ]);
- }
- /**
- * Test that one() correctly handles an association beforeMarshal
- * making the association empty.
- *
- * @return void
- */
- public function testOneAssociationBeforeMarshalMutation()
- {
- $users = $this->getTableLocator()->get('Users');
- $articles = $this->getTableLocator()->get('Articles');
- $users->hasOne('Articles', [
- 'foreignKey' => 'author_id',
- ]);
- $articles->getEventManager()->on('Model.beforeMarshal', function ($event, $data, $options) {
- // Blank the association, so it doesn't become dirty.
- unset($data['not_a_real_field']);
- });
- $data = [
- 'username' => 'Jen',
- 'article' => [
- 'not_a_real_field' => 'whatever',
- ],
- ];
- $marshall = new Marshaller($users);
- $entity = $marshall->one($data, ['associated' => ['Articles']]);
- $this->assertTrue($entity->isDirty('username'));
- $this->assertFalse($entity->isDirty('article'));
- // Ensure consistency with merge()
- $entity = new Entity([
- 'username' => 'Jenny',
- ]);
- // Make the entity think it is new.
- $entity->setAccess('*', true);
- $entity->clean();
- $entity = $marshall->merge($entity, $data, ['associated' => ['Articles']]);
- $this->assertTrue($entity->isDirty('username'));
- $this->assertFalse($entity->isDirty('article'));
- }
- /**
- * Test one() supports accessibleFields option for associations
- *
- * @return void
- */
- public function testOneAccessibleFieldsOptionForAssociations()
- {
- $data = [
- 'title' => 'My title',
- 'body' => 'My content',
- 'user' => [
- 'id' => 1,
- 'username' => 'mark',
- ],
- ];
- $this->articles->setEntityClass(__NAMESPACE__ . '\ProtectedArticle');
- $this->users->setEntityClass(__NAMESPACE__ . '\ProtectedArticle');
- $marshall = new Marshaller($this->articles);
- $result = $marshall->one($data, [
- 'associated' => [
- 'Users' => ['accessibleFields' => ['id' => true]],
- ],
- 'accessibleFields' => ['body' => false, 'user' => true],
- ]);
- $this->assertNull($result->body);
- $this->assertNull($result->user->username);
- $this->assertEquals(1, $result->user->id);
- }
- /**
- * test one() with a wrapping model name.
- *
- * @return void
- */
- public function testOneWithAdditionalName()
- {
- $data = [
- 'title' => 'Original Title',
- 'Articles' => [
- 'title' => 'My title',
- 'body' => 'My content',
- 'author_id' => 1,
- 'not_in_schema' => true,
- 'user' => [
- 'username' => 'mark',
- ],
- ],
- ];
- $marshall = new Marshaller($this->articles);
- $result = $marshall->one($data, ['associated' => ['Users']]);
- $this->assertInstanceOf('Cake\ORM\Entity', $result);
- $this->assertTrue($result->isDirty(), 'Should be a dirty entity.');
- $this->assertTrue($result->isNew(), 'Should be new');
- $this->assertFalse($result->has('Articles'), 'No prefixed field.');
- $this->assertEquals($data['title'], $result->title, 'Data from prefix should be merged.');
- $this->assertEquals($data['Articles']['user']['username'], $result->user->username);
- }
- /**
- * test one() with association data.
- *
- * @return void
- */
- public function testOneAssociationsSingle()
- {
- $data = [
- 'title' => 'My title',
- 'body' => 'My content',
- 'author_id' => 1,
- 'comments' => [
- ['comment' => 'First post', 'user_id' => 2],
- ['comment' => 'Second post', 'user_id' => 2],
- ],
- 'user' => [
- 'username' => 'mark',
- 'password' => 'secret',
- ],
- ];
- $marshall = new Marshaller($this->articles);
- $result = $marshall->one($data, ['associated' => ['Users']]);
- $this->assertEquals($data['title'], $result->title);
- $this->assertEquals($data['body'], $result->body);
- $this->assertEquals($data['author_id'], $result->author_id);
- $this->assertInternalType('array', $result->comments);
- $this->assertEquals($data['comments'], $result->comments);
- $this->assertTrue($result->isDirty('comments'));
- $this->assertInstanceOf('Cake\ORM\Entity', $result->user);
- $this->assertTrue($result->isDirty('user'));
- $this->assertEquals($data['user']['username'], $result->user->username);
- $this->assertEquals($data['user']['password'], $result->user->password);
- }
- /**
- * test one() with association data.
- *
- * @return void
- */
- public function testOneAssociationsMany()
- {
- $data = [
- 'title' => 'My title',
- 'body' => 'My content',
- 'author_id' => 1,
- 'comments' => [
- ['comment' => 'First post', 'user_id' => 2],
- ['comment' => 'Second post', 'user_id' => 2],
- ],
- 'user' => [
- 'username' => 'mark',
- 'password' => 'secret',
- ],
- ];
- $marshall = new Marshaller($this->articles);
- $result = $marshall->one($data, ['associated' => ['Comments']]);
- $this->assertEquals($data['title'], $result->title);
- $this->assertEquals($data['body'], $result->body);
- $this->assertEquals($data['author_id'], $result->author_id);
- $this->assertInternalType('array', $result->comments);
- $this->assertCount(2, $result->comments);
- $this->assertInstanceOf('Cake\ORM\Entity', $result->comments[0]);
- $this->assertInstanceOf('Cake\ORM\Entity', $result->comments[1]);
- $this->assertEquals($data['comments'][0]['comment'], $result->comments[0]->comment);
- $this->assertInternalType('array', $result->user);
- $this->assertEquals($data['user'], $result->user);
- }
- /**
- * Test building the _joinData entity for belongstomany associations.
- *
- * @return void
- */
- public function testOneBelongsToManyJoinData()
- {
- $data = [
- 'title' => 'My title',
- 'body' => 'My content',
- 'author_id' => 1,
- 'tags' => [
- ['tag' => 'news', '_joinData' => ['active' => 1]],
- ['tag' => 'cakephp', '_joinData' => ['active' => 0]],
- ],
- ];
- $marshall = new Marshaller($this->articles);
- $result = $marshall->one($data, [
- 'associated' => ['Tags'],
- ]);
- $this->assertEquals($data['title'], $result->title);
- $this->assertEquals($data['body'], $result->body);
- $this->assertInternalType('array', $result->tags);
- $this->assertInstanceOf('Cake\ORM\Entity', $result->tags[0]);
- $this->assertEquals($data['tags'][0]['tag'], $result->tags[0]->tag);
- $this->assertInstanceOf(
- 'Cake\ORM\Entity',
- $result->tags[0]->_joinData,
- '_joinData should be an entity.'
- );
- $this->assertEquals(
- $data['tags'][0]['_joinData']['active'],
- $result->tags[0]->_joinData->active,
- '_joinData should be an entity.'
- );
- }
- /**
- * Test that the onlyIds option restricts to only accepting ids for belongs to many associations.
- *
- * @return void
- */
- public function testOneBelongsToManyOnlyIdsRejectArray()
- {
- $data = [
- 'title' => 'My title',
- 'body' => 'My content',
- 'author_id' => 1,
- 'tags' => [
- ['tag' => 'news'],
- ['tag' => 'cakephp'],
- ],
- ];
- $marshall = new Marshaller($this->articles);
- $result = $marshall->one($data, [
- 'associated' => ['Tags' => ['onlyIds' => true]],
- ]);
- $this->assertEmpty($result->tags, 'Only ids should be marshalled.');
- }
- /**
- * Test that the onlyIds option restricts to only accepting ids for belongs to many associations.
- *
- * @return void
- */
- public function testOneBelongsToManyOnlyIdsWithIds()
- {
- $data = [
- 'title' => 'My title',
- 'body' => 'My content',
- 'author_id' => 1,
- 'tags' => [
- '_ids' => [1, 2],
- ['tag' => 'news'],
- ],
- ];
- $marshall = new Marshaller($this->articles);
- $result = $marshall->one($data, [
- 'associated' => ['Tags' => ['onlyIds' => true]],
- ]);
- $this->assertCount(2, $result->tags, 'Ids should be marshalled.');
- }
- /**
- * Test marshalling nested associations on the _joinData structure.
- *
- * @return void
- */
- public function testOneBelongsToManyJoinDataAssociated()
- {
- $data = [
- 'title' => 'My title',
- 'body' => 'My content',
- 'author_id' => 1,
- 'tags' => [
- [
- 'tag' => 'news',
- '_joinData' => [
- 'active' => 1,
- 'user' => ['username' => 'Bill'],
- ],
- ],
- [
- 'tag' => 'cakephp',
- '_joinData' => [
- 'active' => 0,
- 'user' => ['username' => 'Mark'],
- ],
- ],
- ],
- ];
- $articlesTags = $this->getTableLocator()->get('ArticlesTags');
- $articlesTags->belongsTo('Users');
- $marshall = new Marshaller($this->articles);
- $result = $marshall->one($data, ['associated' => ['Tags._joinData.Users']]);
- $this->assertInstanceOf(
- 'Cake\ORM\Entity',
- $result->tags[0]->_joinData->user,
- 'joinData should contain a user entity.'
- );
- $this->assertEquals('Bill', $result->tags[0]->_joinData->user->username);
- $this->assertInstanceOf(
- 'Cake\ORM\Entity',
- $result->tags[1]->_joinData->user,
- 'joinData should contain a user entity.'
- );
- $this->assertEquals('Mark', $result->tags[1]->_joinData->user->username);
- }
- /**
- * Test one() with with id and _joinData.
- *
- * @return void
- */
- public function testOneBelongsToManyJoinDataAssociatedWithIds()
- {
- $data = [
- 'title' => 'My title',
- 'body' => 'My content',
- 'author_id' => 1,
- 'tags' => [
- 3 => [
- 'id' => 1,
- '_joinData' => [
- 'active' => 1,
- 'user' => ['username' => 'MyLux'],
- ],
- ],
- 5 => [
- 'id' => 2,
- '_joinData' => [
- 'active' => 0,
- 'user' => ['username' => 'IronFall'],
- ],
- ],
- ],
- ];
- $articlesTags = $this->getTableLocator()->get('ArticlesTags');
- $tags = $this->getTableLocator()->get('Tags');
- $t1 = $tags->find('all')->where(['id' => 1])->first();
- $t2 = $tags->find('all')->where(['id' => 2])->first();
- $articlesTags->belongsTo('Users');
- $marshall = new Marshaller($this->articles);
- $result = $marshall->one($data, ['associated' => ['Tags._joinData.Users']]);
- $this->assertInstanceOf(
- 'Cake\ORM\Entity',
- $result->tags[0]
- );
- $this->assertInstanceOf(
- 'Cake\ORM\Entity',
- $result->tags[1]
- );
- $this->assertInstanceOf(
- 'Cake\ORM\Entity',
- $result->tags[0]->_joinData->user
- );
- $this->assertInstanceOf(
- 'Cake\ORM\Entity',
- $result->tags[1]->_joinData->user
- );
- $this->assertFalse($result->tags[0]->isNew(), 'Should not be new, as id is in db.');
- $this->assertFalse($result->tags[1]->isNew(), 'Should not be new, as id is in db.');
- $this->assertEquals($t1->tag, $result->tags[0]->tag);
- $this->assertEquals($t2->tag, $result->tags[1]->tag);
- $this->assertEquals($data['tags'][3]['_joinData']['user']['username'], $result->tags[0]->_joinData->user->username);
- $this->assertEquals($data['tags'][5]['_joinData']['user']['username'], $result->tags[1]->_joinData->user->username);
- }
- /**
- * Test belongsToMany association with mixed data and _joinData
- *
- * @return void
- */
- public function testOneBelongsToManyWithMixedJoinData()
- {
- $data = [
- 'title' => 'My title',
- 'body' => 'My content',
- 'author_id' => 1,
- 'tags' => [
- [
- 'id' => 1,
- '_joinData' => [
- 'active' => 0,
- ],
- ],
- [
- 'name' => 'tag5',
- '_joinData' => [
- 'active' => 1,
- ],
- ],
- ],
- ];
- $marshall = new Marshaller($this->articles);
- $result = $marshall->one($data, ['associated' => ['Tags._joinData']]);
- $this->assertEquals($data['tags'][0]['id'], $result->tags[0]->id);
- $this->assertEquals($data['tags'][1]['name'], $result->tags[1]->name);
- $this->assertEquals(0, $result->tags[0]->_joinData->active);
- $this->assertEquals(1, $result->tags[1]->_joinData->active);
- }
- public function testOneBelongsToManyWithNestedAssociations()
- {
- $this->tags->belongsToMany('Articles');
- $data = [
- 'name' => 'new tag',
- 'articles' => [
- // This nested article exists, and we want to update it.
- [
- 'id' => 1,
- 'title' => 'New tagged article',
- 'body' => 'New tagged article',
- 'user' => [
- 'id' => 1,
- 'username' => 'newuser',
- ],
- 'comments' => [
- ['comment' => 'New comment', 'user_id' => 1],
- ['comment' => 'Second comment', 'user_id' => 1],
- ],
- ],
- ],
- ];
- $marshaller = new Marshaller($this->tags);
- $tag = $marshaller->one($data, ['associated' => ['Articles.Users', 'Articles.Comments']]);
- $this->assertNotEmpty($tag->articles);
- $this->assertCount(1, $tag->articles);
- $this->assertTrue($tag->isDirty('articles'), 'Updated prop should be dirty');
- $this->assertInstanceOf('Cake\ORM\Entity', $tag->articles[0]);
- $this->assertSame('New tagged article', $tag->articles[0]->title);
- $this->assertFalse($tag->articles[0]->isNew());
- $this->assertNotEmpty($tag->articles[0]->user);
- $this->assertInstanceOf('Cake\ORM\Entity', $tag->articles[0]->user);
- $this->assertTrue($tag->articles[0]->isDirty('user'), 'Updated prop should be dirty');
- $this->assertSame('newuser', $tag->articles[0]->user->username);
- $this->assertTrue($tag->articles[0]->user->isNew());
- $this->assertNotEmpty($tag->articles[0]->comments);
- $this->assertCount(2, $tag->articles[0]->comments);
- $this->assertTrue($tag->articles[0]->isDirty('comments'), 'Updated prop should be dirty');
- $this->assertInstanceOf('Cake\ORM\Entity', $tag->articles[0]->comments[0]);
- $this->assertTrue($tag->articles[0]->comments[0]->isNew());
- $this->assertTrue($tag->articles[0]->comments[1]->isNew());
- }
- /**
- * Test belongsToMany association with mixed data and _joinData
- *
- * @return void
- */
- public function testBelongsToManyAddingNewExisting()
- {
- $this->tags->setEntityClass(__NAMESPACE__ . '\Tag');
- $data = [
- 'title' => 'My title',
- 'body' => 'My content',
- 'author_id' => 1,
- 'tags' => [
- [
- 'id' => 1,
- '_joinData' => [
- 'active' => 0,
- ],
- ],
- ],
- ];
- $marshall = new Marshaller($this->articles);
- $result = $marshall->one($data, ['associated' => ['Tags._joinData']]);
- $data = [
- 'title' => 'New Title',
- 'tags' => [
- [
- 'id' => 1,
- '_joinData' => [
- 'active' => 0,
- ],
- ],
- [
- 'id' => 2,
- '_joinData' => [
- 'active' => 1,
- ],
- ],
- ],
- ];
- $result = $marshall->merge($result, $data, ['associated' => ['Tags._joinData']]);
- $this->assertEquals($data['title'], $result->title);
- $this->assertEquals($data['tags'][0]['id'], $result->tags[0]->id);
- $this->assertEquals($data['tags'][1]['id'], $result->tags[1]->id);
- $this->assertNotEmpty($result->tags[0]->_joinData);
- $this->assertNotEmpty($result->tags[1]->_joinData);
- $this->assertTrue($result->isDirty('tags'), 'Modified prop should be dirty');
- $this->assertEquals(0, $result->tags[0]->_joinData->active);
- $this->assertEquals(1, $result->tags[1]->_joinData->active);
- }
- /**
- * Test belongsToMany association with mixed data and _joinData
- *
- * @return void
- */
- public function testBelongsToManyWithMixedJoinDataOutOfOrder()
- {
- $data = [
- 'title' => 'My title',
- 'body' => 'My content',
- 'author_id' => 1,
- 'tags' => [
- [
- 'name' => 'tag5',
- '_joinData' => [
- 'active' => 1,
- ],
- ],
- [
- 'id' => 1,
- '_joinData' => [
- 'active' => 0,
- ],
- ],
- [
- 'name' => 'tag3',
- '_joinData' => [
- 'active' => 1,
- ],
- ],
- ],
- ];
- $marshall = new Marshaller($this->articles);
- $result = $marshall->one($data, ['associated' => ['Tags._joinData']]);
- $this->assertEquals($data['tags'][0]['name'], $result->tags[0]->name);
- $this->assertEquals($data['tags'][1]['id'], $result->tags[1]->id);
- $this->assertEquals($data['tags'][2]['name'], $result->tags[2]->name);
- $this->assertEquals(1, $result->tags[0]->_joinData->active);
- $this->assertEquals(0, $result->tags[1]->_joinData->active);
- $this->assertEquals(1, $result->tags[2]->_joinData->active);
- }
- /**
- * Test belongsToMany association with scalars
- *
- * @return void
- */
- public function testBelongsToManyInvalidData()
- {
- $data = [
- 'title' => 'My title',
- 'body' => 'My content',
- 'author_id' => 1,
- 'tags' => [
- 'id' => 1,
- ],
- ];
- $article = $this->articles->newEntity($data, [
- 'associated' => ['Tags'],
- ]);
- $this->assertEmpty($article->tags, 'No entity should be created');
- $data['tags'] = 1;
- $article = $this->articles->newEntity($data, [
- 'associated' => ['Tags'],
- ]);
- $this->assertEmpty($article->tags, 'No entity should be created');
- }
- /**
- * Test belongsToMany association with mixed data array
- *
- * @return void
- */
- public function testBelongsToManyWithMixedData()
- {
- $data = [
- 'title' => 'My title',
- 'body' => 'My content',
- 'author_id' => 1,
- 'tags' => [
- [
- 'name' => 'tag4',
- ],
- [
- 'name' => 'tag5',
- ],
- [
- 'id' => 1,
- ],
- ],
- ];
- $tags = $this->getTableLocator()->get('Tags');
- $marshaller = new Marshaller($this->articles);
- $article = $marshaller->one($data, ['associated' => ['Tags']]);
- $this->assertEquals($data['tags'][0]['name'], $article->tags[0]->name);
- $this->assertEquals($data['tags'][1]['name'], $article->tags[1]->name);
- $this->assertEquals($article->tags[2], $tags->get(1));
- $this->assertTrue($article->tags[0]->isNew());
- $this->assertTrue($article->tags[1]->isNew());
- $this->assertFalse($article->tags[2]->isNew());
- $tagCount = $tags->find()->count();
- $this->articles->save($article);
- $this->assertEquals($tagCount + 2, $tags->find()->count());
- }
- /**
- * Test belongsToMany association with the ForceNewTarget to force saving
- * new records on the target tables with BTM relationships when the primaryKey(s)
- * of the target table is specified.
- *
- * @return void
- */
- public function testBelongsToManyWithForceNew()
- {
- $data = [
- 'title' => 'Fourth Article',
- 'body' => 'Fourth Article Body',
- 'author_id' => 1,
- 'tags' => [
- [
- 'id' => 3,
- ],
- [
- 'id' => 4,
- 'name' => 'tag4',
- ],
- ],
- ];
- $marshaller = new Marshaller($this->articles);
- $article = $marshaller->one($data, [
- 'associated' => ['Tags'],
- 'forceNew' => true,
- ]);
- $this->assertFalse($article->tags[0]->isNew(), 'The tag should not be new');
- $this->assertTrue($article->tags[1]->isNew(), 'The tag should be new');
- $this->assertSame('tag4', $article->tags[1]->name, 'Property should match request data.');
- }
- /**
- * Test HasMany association with _ids attribute
- *
- * @return void
- */
- public function testOneHasManyWithIds()
- {
- $data = [
- 'title' => 'article',
- 'body' => 'some content',
- 'comments' => [
- '_ids' => [1, 2],
- ],
- ];
- $marshaller = new Marshaller($this->articles);
- $article = $marshaller->one($data, ['associated' => ['Comments']]);
- $this->assertEquals($article->comments[0], $this->comments->get(1));
- $this->assertEquals($article->comments[1], $this->comments->get(2));
- }
- /**
- * Test that the onlyIds option restricts to only accepting ids for hasmany associations.
- *
- * @return void
- */
- public function testOneHasManyOnlyIdsRejectArray()
- {
- $data = [
- 'title' => 'article',
- 'body' => 'some content',
- 'comments' => [
- ['comment' => 'first comment'],
- ['comment' => 'second comment'],
- ],
- ];
- $marshaller = new Marshaller($this->articles);
- $article = $marshaller->one($data, [
- 'associated' => ['Comments' => ['onlyIds' => true]],
- ]);
- $this->assertEmpty($article->comments);
- }
- /**
- * Test that the onlyIds option restricts to only accepting ids for hasmany associations.
- *
- * @return void
- */
- public function testOneHasManyOnlyIdsWithIds()
- {
- $data = [
- 'title' => 'article',
- 'body' => 'some content',
- 'comments' => [
- '_ids' => [1, 2],
- ['comment' => 'first comment'],
- ],
- ];
- $marshaller = new Marshaller($this->articles);
- $article = $marshaller->one($data, [
- 'associated' => ['Comments' => ['onlyIds' => true]],
- ]);
- $this->assertCount(2, $article->comments);
- }
- /**
- * Test HasMany association with invalid data
- *
- * @return void
- */
- public function testOneHasManyInvalidData()
- {
- $data = [
- 'title' => 'new title',
- 'body' => 'some content',
- 'comments' => [
- 'id' => 1,
- ],
- ];
- $marshaller = new Marshaller($this->articles);
- $article = $marshaller->one($data, ['associated' => ['Comments']]);
- $this->assertEmpty($article->comments);
- $data['comments'] = 1;
- $article = $marshaller->one($data, ['associated' => ['Comments']]);
- $this->assertEmpty($article->comments);
- }
- /**
- * Test one() with deeper associations.
- *
- * @return void
- */
- public function testOneDeepAssociations()
- {
- $data = [
- 'comment' => 'First post',
- 'user_id' => 2,
- 'article' => [
- 'title' => 'Article title',
- 'body' => 'Article body',
- 'user' => [
- 'username' => 'mark',
- 'password' => 'secret',
- ],
- ],
- ];
- $marshall = new Marshaller($this->comments);
- $result = $marshall->one($data, ['associated' => ['Articles.Users']]);
- $this->assertEquals(
- $data['article']['title'],
- $result->article->title
- );
- $this->assertEquals(
- $data['article']['user']['username'],
- $result->article->user->username
- );
- }
- /**
- * Test many() with a simple set of data.
- *
- * @return void
- */
- public function testManySimple()
- {
- $data = [
- ['comment' => 'First post', 'user_id' => 2],
- ['comment' => 'Second post', 'user_id' => 2],
- ];
- $marshall = new Marshaller($this->comments);
- $result = $marshall->many($data);
- $this->assertCount(2, $result);
- $this->assertInstanceOf('Cake\ORM\Entity', $result[0]);
- $this->assertInstanceOf('Cake\ORM\Entity', $result[1]);
- $this->assertEquals($data[0]['comment'], $result[0]->comment);
- $this->assertEquals($data[1]['comment'], $result[1]->comment);
- }
- /**
- * Test many() with some invalid data
- *
- * @return void
- */
- public function testManyInvalidData()
- {
- $data = [
- ['id' => 2, 'comment' => 'Changed 2', 'user_id' => 2],
- ['id' => 1, 'comment' => 'Changed 1', 'user_id' => 1],
- '_csrfToken' => 'abc123',
- ];
- $marshall = new Marshaller($this->comments);
- $result = $marshall->many($data);
- $this->assertCount(2, $result);
- }
- /**
- * test many() with nested associations.
- *
- * @return void
- */
- public function testManyAssociations()
- {
- $data = [
- [
- 'comment' => 'First post',
- 'user_id' => 2,
- 'user' => [
- 'username' => 'mark',
- ],
- ],
- [
- 'comment' => 'Second post',
- 'user_id' => 2,
- 'user' => [
- 'username' => 'jose',
- ],
- ],
- ];
- $marshall = new Marshaller($this->comments);
- $result = $marshall->many($data, ['associated' => ['Users']]);
- $this->assertCount(2, $result);
- $this->assertInstanceOf('Cake\ORM\Entity', $result[0]);
- $this->assertInstanceOf('Cake\ORM\Entity', $result[1]);
- $this->assertEquals(
- $data[0]['user']['username'],
- $result[0]->user->username
- );
- $this->assertEquals(
- $data[1]['user']['username'],
- $result[1]->user->username
- );
- }
- /**
- * Test if exception is raised when called with [associated => NonExistingAssociation]
- * Previously such association were simply ignored
- *
- * @return void
- */
- public function testManyInvalidAssociation()
- {
- $this->expectException(\InvalidArgumentException::class);
- $data = [
- [
- 'comment' => 'First post',
- 'user_id' => 2,
- 'user' => [
- 'username' => 'mark',
- ],
- ],
- [
- 'comment' => 'Second post',
- 'user_id' => 2,
- 'user' => [
- 'username' => 'jose',
- ],
- ],
- ];
- $marshall = new Marshaller($this->comments);
- $marshall->many($data, ['associated' => ['Users', 'People']]);
- }
- /**
- * Test generating a list of entities from a list of ids.
- *
- * @return void
- */
- public function testOneGenerateBelongsToManyEntitiesFromIds()
- {
- $data = [
- 'title' => 'Haz tags',
- 'body' => 'Some content here',
- 'tags' => ['_ids' => ''],
- ];
- $marshall = new Marshaller($this->articles);
- $result = $marshall->one($data, ['associated' => ['Tags']]);
- $this->assertCount(0, $result->tags);
- $data = [
- 'title' => 'Haz tags',
- 'body' => 'Some content here',
- 'tags' => ['_ids' => false],
- ];
- $result = $marshall->one($data, ['associated' => ['Tags']]);
- $this->assertCount(0, $result->tags);
- $data = [
- 'title' => 'Haz tags',
- 'body' => 'Some content here',
- 'tags' => ['_ids' => null],
- ];
- $result = $marshall->one($data, ['associated' => ['Tags']]);
- $this->assertCount(0, $result->tags);
- $data = [
- 'title' => 'Haz tags',
- 'body' => 'Some content here',
- 'tags' => ['_ids' => []],
- ];
- $result = $marshall->one($data, ['associated' => ['Tags']]);
- $this->assertCount(0, $result->tags);
- $data = [
- 'title' => 'Haz tags',
- 'body' => 'Some content here',
- 'tags' => ['_ids' => [1, 2, 3]],
- ];
- $marshall = new Marshaller($this->articles);
- $result = $marshall->one($data, ['associated' => ['Tags']]);
- $this->assertCount(3, $result->tags);
- $this->assertInstanceOf('Cake\ORM\Entity', $result->tags[0]);
- $this->assertInstanceOf('Cake\ORM\Entity', $result->tags[1]);
- $this->assertInstanceOf('Cake\ORM\Entity', $result->tags[2]);
- }
- /**
- * Test merge() in a simple use.
- *
- * @return void
- */
- public function testMergeSimple()
- {
- $data = [
- 'title' => 'My title',
- 'author_id' => 1,
- 'not_in_schema' => true,
- ];
- $marshall = new Marshaller($this->articles);
- $entity = new Entity([
- 'title' => 'Foo',
- 'body' => 'My Content',
- ]);
- $entity->setAccess('*', true);
- $entity->setNew(false);
- $entity->clean();
- $result = $marshall->merge($entity, $data, []);
- $this->assertSame($entity, $result);
- $this->assertEquals($data + ['body' => 'My Content'], $result->toArray());
- $this->assertTrue($result->isDirty(), 'Should be a dirty entity.');
- $this->assertFalse($result->isNew(), 'Should not change the entity state');
- }
- /**
- * Test merge() with accessibleFields options
- *
- * @return void
- */
- public function testMergeAccessibleFields()
- {
- $data = [
- 'title' => 'My title',
- 'body' => 'New content',
- 'author_id' => 1,
- 'not_in_schema' => true,
- ];
- $marshall = new Marshaller($this->articles);
- $entity = new Entity([
- 'title' => 'Foo',
- 'body' => 'My Content',
- ]);
- $entity->setAccess('*', false);
- $entity->setNew(false);
- $entity->clean();
- $result = $marshall->merge($entity, $data, ['accessibleFields' => ['body' => true]]);
- $this->assertSame($entity, $result);
- $this->assertEquals(['title' => 'Foo', 'body' => 'New content'], $result->toArray());
- $this->assertTrue($entity->isAccessible('body'));
- }
- /**
- * Provides empty values.
- *
- * @return array
- */
- public function emptyProvider()
- {
- return [
- [0],
- ['0'],
- ];
- }
- /**
- * Test merging empty values into an entity.
- *
- * @dataProvider emptyProvider
- * @return void
- */
- public function testMergeFalseyValues($value)
- {
- $marshall = new Marshaller($this->articles);
- $entity = new Entity();
- $entity->setAccess('*', true);
- $entity->clean();
- $entity = $marshall->merge($entity, ['author_id' => $value]);
- $this->assertTrue($entity->isDirty('author_id'), 'Field should be dirty');
- $this->assertSame(0, $entity->get('author_id'), 'Value should be zero');
- }
- /**
- * Test merge() doesn't dirty values that were null and are null again.
- *
- * @return void
- */
- public function testMergeUnchangedNullValue()
- {
- $data = [
- 'title' => 'My title',
- 'author_id' => 1,
- 'body' => null,
- ];
- $marshall = new Marshaller($this->articles);
- $entity = new Entity([
- 'title' => 'Foo',
- 'body' => null,
- ]);
- $entity->setAccess('*', true);
- $entity->setNew(false);
- $entity->clean();
- $result = $marshall->merge($entity, $data, []);
- $this->assertFalse($entity->isDirty('body'), 'unchanged null should not be dirty');
- }
- /**
- * Tests that merge respects the entity accessible methods
- *
- * @return void
- */
- public function testMergeWhitelist()
- {
- $data = [
- 'title' => 'My title',
- 'author_id' => 1,
- 'not_in_schema' => true,
- ];
- $marshall = new Marshaller($this->articles);
- $entity = new Entity([
- 'title' => 'Foo',
- 'body' => 'My Content',
- ]);
- $entity->setAccess('*', false);
- $entity->setAccess('author_id', true);
- $entity->setNew(false);
- $entity->clean();
- $result = $marshall->merge($entity, $data, []);
- $expected = [
- 'title' => 'Foo',
- 'body' => 'My Content',
- 'author_id' => 1,
- ];
- $this->assertEquals($expected, $result->toArray());
- }
- /**
- * Test merge() with an invalid association
- *
- * @return void
- */
- public function testMergeInvalidAssociation()
- {
- $this->expectException(\InvalidArgumentException::class);
- $this->expectExceptionMessage('Cannot marshal data for "Derp" association. It is not associated with "Articles".');
- $data = [
- 'title' => 'My title',
- 'body' => 'My content',
- 'derp' => [
- 'id' => 1,
- 'username' => 'mark',
- ],
- ];
- $article = new Entity([
- 'title' => 'title for post',
- 'body' => 'body',
- ]);
- $marshall = new Marshaller($this->articles);
- $marshall->merge($article, $data, [
- 'associated' => ['Derp'],
- ]);
- }
- /**
- * Test merge when fields contains an association.
- *
- * @param $fields
- * @return void
- */
- public function testMergeWithSingleAssociationAndFields()
- {
- $user = new Entity([
- 'username' => 'user',
- ]);
- $article = new Entity([
- 'title' => 'title for post',
- 'body' => 'body',
- 'user' => $user,
- ]);
- $user->setAccess('*', true);
- $article->setAccess('*', true);
- $data = [
- 'title' => 'Chelsea',
- 'user' => [
- 'username' => 'dee',
- ],
- ];
- $marshall = new Marshaller($this->articles);
- $marshall->merge($article, $data, [
- 'fields' => ['title', 'user'],
- 'associated' => ['Users' => []],
- ]);
- $this->assertSame($user, $article->user);
- $this->assertTrue($article->isDirty('user'));
- }
- /**
- * Tests that fields with the same value are not marked as dirty
- *
- * @return void
- */
- public function testMergeDirty()
- {
- $marshall = new Marshaller($this->articles);
- $entity = new Entity([
- 'title' => 'Foo',
- 'author_id' => 1,
- ]);
- $data = [
- 'title' => 'Foo',
- 'author_id' => 1,
- 'crazy' => true,
- ];
- $entity->setAccess('*', true);
- $entity->clean();
- $result = $marshall->merge($entity, $data, []);
- $expected = [
- 'title' => 'Foo',
- 'author_id' => 1,
- 'crazy' => true,
- ];
- $this->assertEquals($expected, $result->toArray());
- $this->assertFalse($entity->isDirty('title'));
- $this->assertFalse($entity->isDirty('author_id'));
- $this->assertTrue($entity->isDirty('crazy'));
- }
- /**
- * Tests merging data into an associated entity
- *
- * @return void
- */
- public function testMergeWithSingleAssociation()
- {
- $user = new Entity([
- 'username' => 'mark',
- 'password' => 'secret',
- ]);
- $entity = new Entity([
- 'title' => 'My Title',
- 'user' => $user,
- ]);
- $user->setAccess('*', true);
- $entity->setAccess('*', true);
- $entity->clean();
- $data = [
- 'body' => 'My Content',
- 'user' => [
- 'password' => 'not a secret',
- ],
- ];
- $marshall = new Marshaller($this->articles);
- $marshall->merge($entity, $data, ['associated' => ['Users']]);
- $this->assertTrue($entity->isDirty('user'), 'association should be dirty');
- $this->assertTrue($entity->isDirty('body'), 'body should be dirty');
- $this->assertEquals('My Content', $entity->body);
- $this->assertSame($user, $entity->user);
- $this->assertEquals('mark', $entity->user->username);
- $this->assertEquals('not a secret', $entity->user->password);
- }
- /**
- * Tests that new associated entities can be created when merging data into
- * a parent entity
- *
- * @return void
- */
- public function testMergeCreateAssociation()
- {
- $entity = new Entity([
- 'title' => 'My Title',
- ]);
- $entity->setAccess('*', true);
- $entity->clean();
- $data = [
- 'body' => 'My Content',
- 'user' => [
- 'username' => 'mark',
- 'password' => 'not a secret',
- ],
- ];
- $marshall = new Marshaller($this->articles);
- $marshall->merge($entity, $data, ['associated' => ['Users']]);
- $this->assertEquals('My Content', $entity->body);
- $this->assertInstanceOf('Cake\ORM\Entity', $entity->user);
- $this->assertEquals('mark', $entity->user->username);
- $this->assertEquals('not a secret', $entity->user->password);
- $this->assertTrue($entity->isDirty('user'));
- $this->assertTrue($entity->isDirty('body'));
- $this->assertTrue($entity->user->isNew());
- }
- /**
- * Test merge when an association has been replaced with null
- *
- * @return void
- */
- public function testMergeAssociationNullOut()
- {
- $user = new Entity([
- 'id' => 1,
- 'username' => 'user',
- ]);
- $article = new Entity([
- 'title' => 'title for post',
- 'user_id' => 1,
- 'user' => $user,
- ]);
- $user->setAccess('*', true);
- $article->setAccess('*', true);
- $data = [
- 'title' => 'Chelsea',
- 'user_id' => '',
- 'user' => '',
- ];
- $marshall = new Marshaller($this->articles);
- $marshall->merge($article, $data, [
- 'associated' => ['Users'],
- ]);
- $this->assertNull($article->user);
- $this->assertSame('', $article->user_id);
- $this->assertTrue($article->isDirty('user'));
- }
- /**
- * Tests merging one to many associations
- *
- * @return void
- */
- public function testMergeMultipleAssociations()
- {
- $user = new Entity(['username' => 'mark', 'password' => 'secret']);
- $comment1 = new Entity(['id' => 1, 'comment' => 'A comment']);
- $comment2 = new Entity(['id' => 2, 'comment' => 'Another comment']);
- $entity = new Entity([
- 'title' => 'My Title',
- 'user' => $user,
- 'comments' => [$comment1, $comment2],
- ]);
- $user->setAccess('*', true);
- $comment1->setAccess('*', true);
- $comment2->setAccess('*', true);
- $entity->setAccess('*', true);
- $entity->clean();
- $data = [
- 'title' => 'Another title',
- 'user' => ['password' => 'not so secret'],
- 'comments' => [
- ['comment' => 'Extra comment 1'],
- ['id' => 2, 'comment' => 'Altered comment 2'],
- ['id' => 1, 'comment' => 'Altered comment 1'],
- ['id' => 3, 'comment' => 'Extra comment 3'],
- ['id' => 4, 'comment' => 'Extra comment 4'],
- ['comment' => 'Extra comment 2'],
- ],
- ];
- $marshall = new Marshaller($this->articles);
- $result = $marshall->merge($entity, $data, ['associated' => ['Users', 'Comments']]);
- $this->assertSame($entity, $result);
- $this->assertSame($user, $result->user);
- $this->assertTrue($result->isDirty('user'), 'association should be dirty');
- $this->assertEquals('not so secret', $entity->user->password);
- $this->assertTrue($result->isDirty('comments'));
- $this->assertSame($comment1, $entity->comments[0]);
- $this->assertSame($comment2, $entity->comments[1]);
- $this->assertEquals('Altered comment 1', $entity->comments[0]->comment);
- $this->assertEquals('Altered comment 2', $entity->comments[1]->comment);
- $thirdComment = $this->articles->Comments
- ->find()
- ->where(['id' => 3])
- ->enableHydration(false)
- ->first();
- $this->assertEquals(
- ['comment' => 'Extra comment 3'] + $thirdComment,
- $entity->comments[2]->toArray()
- );
- $forthComment = $this->articles->Comments
- ->find()
- ->where(['id' => 4])
- ->enableHydration(false)
- ->first();
- $this->assertEquals(
- ['comment' => 'Extra comment 4'] + $forthComment,
- $entity->comments[3]->toArray()
- );
- $this->assertEquals(
- ['comment' => 'Extra comment 1'],
- $entity->comments[4]->toArray()
- );
- $this->assertEquals(
- ['comment' => 'Extra comment 2'],
- $entity->comments[5]->toArray()
- );
- }
- /**
- * Tests that merging data to a hasMany association with _ids works.
- *
- * @return void
- */
- public function testMergeHasManyEntitiesFromIds()
- {
- $entity = $this->articles->get(1, ['contain' => ['Comments']]);
- $this->assertNotEmpty($entity->comments);
- $marshall = new Marshaller($this->articles);
- $data = ['comments' => ['_ids' => [1, 2, 3]]];
- $result = $marshall->merge($entity, $data, ['associated' => ['Comments']]);
- $this->assertCount(3, $result->comments);
- $this->assertTrue($result->isDirty('comments'), 'Updated prop should be dirty');
- $this->assertInstanceOf(Entity::class, $result->comments[0]);
- $this->assertEquals(1, $result->comments[0]->id);
- $this->assertInstanceOf(Entity::class, $result->comments[1]);
- $this->assertEquals(2, $result->comments[1]->id);
- $this->assertInstanceOf(Entity::class, $result->comments[2]);
- $this->assertEquals(3, $result->comments[2]->id);
- }
- /**
- * Tests that merging data to a hasMany association using onlyIds restricts operations.
- *
- * @return void
- */
- public function testMergeHasManyEntitiesFromIdsOnlyIds()
- {
- $entity = $this->articles->get(1, ['contain' => ['Comments']]);
- $this->assertNotEmpty($entity->comments);
- $marshall = new Marshaller($this->articles);
- $data = [
- 'comments' => [
- '_ids' => [1],
- [
- 'comment' => 'Nope',
- ],
- ],
- ];
- $result = $marshall->merge($entity, $data, ['associated' => ['Comments' => ['onlyIds' => true]]]);
- $this->assertCount(1, $result->comments);
- $this->assertTrue($result->isDirty('comments'), 'Updated prop should be dirty');
- $this->assertInstanceOf(Entity::class, $result->comments[0]);
- $this->assertNotEquals('Nope', $result->comments[0]);
- }
- /**
- * Tests that merging data to an entity containing belongsToMany and _ids
- * will just overwrite the data
- *
- * @return void
- */
- public function testMergeBelongsToManyEntitiesFromIds()
- {
- $entity = new Entity([
- 'title' => 'Haz tags',
- 'body' => 'Some content here',
- 'tags' => [
- new Entity(['id' => 1, 'name' => 'Cake']),
- new Entity(['id' => 2, 'name' => 'PHP']),
- ],
- ]);
- $data = [
- 'title' => 'Haz moar tags',
- 'tags' => ['_ids' => [1, 2, 3]],
- ];
- $entity->setAccess('*', true);
- $entity->clean();
- $marshall = new Marshaller($this->articles);
- $result = $marshall->merge($entity, $data, ['associated' => ['Tags']]);
- $this->assertCount(3, $result->tags);
- $this->assertTrue($result->isDirty('tags'), 'Updated prop should be dirty');
- $this->assertInstanceOf('Cake\ORM\Entity', $result->tags[0]);
- $this->assertInstanceOf('Cake\ORM\Entity', $result->tags[1]);
- $this->assertInstanceOf('Cake\ORM\Entity', $result->tags[2]);
- }
- /**
- * Tests that merging data to an entity containing belongsToMany and _ids
- * will not generate conflicting queries when associations are automatically selected
- *
- * @return void
- */
- public function testMergeFromIdsWithAutoAssociation()
- {
- $entity = new Entity([
- 'title' => 'Haz tags',
- 'body' => 'Some content here',
- 'tags' => [
- new Entity(['id' => 1, 'name' => 'Cake']),
- new Entity(['id' => 2, 'name' => 'PHP']),
- ],
- ]);
- $data = [
- 'title' => 'Haz moar tags',
- 'tags' => ['_ids' => [1, 2, 3]],
- ];
- $entity->setAccess('*', true);
- $entity->clean();
- // Adding a forced join to have another table with the same column names
- $this->articles->Tags->getEventManager()->on('Model.beforeFind', function ($e, $query) {
- $left = new IdentifierExpression('Tags.id');
- $right = new IdentifierExpression('a.id');
- $query->leftJoin(['a' => 'tags'], $query->newExpr()->eq($left, $right));
- });
- $marshall = new Marshaller($this->articles);
- $result = $marshall->merge($entity, $data, ['associated' => ['Tags']]);
- $this->assertCount(3, $result->tags);
- $this->assertTrue($result->isDirty('tags'));
- }
- /**
- * Tests that merging data to an entity containing belongsToMany and _ids
- * with additional association conditions works.
- *
- * @return void
- */
- public function testMergeBelongsToManyFromIdsWithConditions()
- {
- $this->articles->belongsToMany('Tags', [
- 'conditions' => ['ArticleTags.article_id' => 1],
- ]);
- $entity = new Entity([
- 'title' => 'No tags',
- 'body' => 'Some content here',
- 'tags' => [],
- ]);
- $data = [
- 'title' => 'Haz moar tags',
- 'tags' => ['_ids' => [1, 2, 3]],
- ];
- $entity->setAccess('*', true);
- $entity->clean();
- $marshall = new Marshaller($this->articles);
- $result = $marshall->merge($entity, $data, ['associated' => ['Tags']]);
- $this->assertCount(3, $result->tags);
- $this->assertTrue($result->isDirty('tags'));
- $this->assertInstanceOf('Cake\ORM\Entity', $result->tags[0]);
- $this->assertInstanceOf('Cake\ORM\Entity', $result->tags[1]);
- $this->assertInstanceOf('Cake\ORM\Entity', $result->tags[2]);
- }
- /**
- * Tests that merging data to an entity containing belongsToMany as an array
- * with additional association conditions works.
- *
- * @return void
- */
- public function testMergeBelongsToManyFromArrayWithConditions()
- {
- $this->articles->belongsToMany('Tags', [
- 'conditions' => ['ArticleTags.article_id' => 1],
- ]);
- $this->articles->Tags->getEventManager()
- ->on('Model.beforeFind', function (Event $event, $query) use (&$called) {
- $called = true;
- return $query->where(['Tags.id >=' => 1]);
- });
- $entity = new Entity([
- 'title' => 'No tags',
- 'body' => 'Some content here',
- 'tags' => [],
- ]);
- $data = [
- 'title' => 'Haz moar tags',
- 'tags' => [
- ['id' => 1],
- ['id' => 2],
- ],
- ];
- $entity->setAccess('*', true);
- $marshall = new Marshaller($this->articles);
- $result = $marshall->merge($entity, $data, ['associated' => ['Tags']]);
- $this->assertCount(2, $result->tags);
- $this->assertInstanceOf('Cake\ORM\Entity', $result->tags[0]);
- $this->assertInstanceOf('Cake\ORM\Entity', $result->tags[1]);
- $this->assertTrue($called);
- }
- /**
- * Tests that merging data to an entity containing belongsToMany and _ids
- * will ignore empty values.
- *
- * @return void
- */
- public function testMergeBelongsToManyEntitiesFromIdsEmptyValue()
- {
- $entity = new Entity([
- 'title' => 'Haz tags',
- 'body' => 'Some content here',
- 'tags' => [
- new Entity(['id' => 1, 'name' => 'Cake']),
- new Entity(['id' => 2, 'name' => 'PHP']),
- ],
- ]);
- $data = [
- 'title' => 'Haz moar tags',
- 'tags' => ['_ids' => ''],
- ];
- $entity->setAccess('*', true);
- $marshall = new Marshaller($this->articles);
- $result = $marshall->merge($entity, $data, ['associated' => ['Tags']]);
- $this->assertCount(0, $result->tags);
- $data = [
- 'title' => 'Haz moar tags',
- 'tags' => ['_ids' => false],
- ];
- $result = $marshall->merge($entity, $data, ['associated' => ['Tags']]);
- $this->assertCount(0, $result->tags);
- $data = [
- 'title' => 'Haz moar tags',
- 'tags' => ['_ids' => null],
- ];
- $result = $marshall->merge($entity, $data, ['associated' => ['Tags']]);
- $this->assertCount(0, $result->tags);
- $this->assertTrue($result->isDirty('tags'));
- }
- /**
- * Test that the ids option restricts to only accepting ids for belongs to many associations.
- *
- * @return void
- */
- public function testMergeBelongsToManyOnlyIdsRejectArray()
- {
- $entity = new Entity([
- 'title' => 'Haz tags',
- 'body' => 'Some content here',
- 'tags' => [
- new Entity(['id' => 1, 'name' => 'Cake']),
- new Entity(['id' => 2, 'name' => 'PHP']),
- ],
- ]);
- $data = [
- 'title' => 'Haz moar tags',
- 'tags' => [
- ['name' => 'new'],
- ['name' => 'awesome'],
- ],
- ];
- $entity->setAccess('*', true);
- $marshall = new Marshaller($this->articles);
- $result = $marshall->merge($entity, $data, [
- 'associated' => ['Tags' => ['onlyIds' => true]],
- ]);
- $this->assertCount(0, $result->tags);
- $this->assertTrue($result->isDirty('tags'));
- }
- /**
- * Test that the ids option restricts to only accepting ids for belongs to many associations.
- *
- * @return void
- */
- public function testMergeBelongsToManyOnlyIdsWithIds()
- {
- $entity = new Entity([
- 'title' => 'Haz tags',
- 'body' => 'Some content here',
- 'tags' => [
- new Entity(['id' => 1, 'name' => 'Cake']),
- new Entity(['id' => 2, 'name' => 'PHP']),
- ],
- ]);
- $data = [
- 'title' => 'Haz moar tags',
- 'tags' => [
- '_ids' => [3],
- ],
- ];
- $entity->setAccess('*', true);
- $marshall = new Marshaller($this->articles);
- $result = $marshall->merge($entity, $data, [
- 'associated' => ['Tags' => ['ids' => true]],
- ]);
- $this->assertCount(1, $result->tags);
- $this->assertEquals('tag3', $result->tags[0]->name);
- $this->assertTrue($result->isDirty('tags'));
- }
- /**
- * Test that invalid _joinData (scalar data) is not marshalled.
- *
- * @return void
- */
- public function testMergeBelongsToManyJoinDataScalar()
- {
- $this->getTableLocator()->clear();
- $articles = $this->getTableLocator()->get('Articles');
- $articles->belongsToMany('Tags', [
- 'through' => 'SpecialTags',
- ]);
- $entity = $articles->get(1, ['contain' => 'Tags']);
- $data = [
- 'title' => 'Haz data',
- 'tags' => [
- ['id' => 3, 'tag' => 'Cake', '_joinData' => 'Invalid'],
- ],
- ];
- $marshall = new Marshaller($articles);
- $result = $marshall->merge($entity, $data, ['associated' => 'Tags._joinData']);
- $articles->save($entity, ['associated' => ['Tags._joinData']]);
- $this->assertFalse($entity->tags[0]->isDirty('_joinData'));
- $this->assertEmpty($entity->tags[0]->_joinData);
- }
- /**
- * Test merging the _joinData entity for belongstomany associations when * is not
- * accessible.
- *
- * @return void
- */
- public function testMergeBelongsToManyJoinDataNotAccessible()
- {
- $this->getTableLocator()->clear();
- $articles = $this->getTableLocator()->get('Articles');
- $articles->belongsToMany('Tags', [
- 'through' => 'SpecialTags',
- ]);
- $entity = $articles->get(1, ['contain' => 'Tags']);
- // Make only specific fields accessible, but not _joinData.
- $entity->tags[0]->setAccess('*', false);
- $entity->tags[0]->setAccess(['article_id', 'tag_id'], true);
- $data = [
- 'title' => 'Haz data',
- 'tags' => [
- ['id' => 3, 'tag' => 'Cake', '_joinData' => ['highlighted' => '1', 'author_id' => '99']],
- ],
- ];
- $marshall = new Marshaller($articles);
- $result = $marshall->merge($entity, $data, ['associated' => 'Tags._joinData']);
- $this->assertTrue($entity->isDirty('tags'), 'Association data changed');
- $this->assertTrue($entity->tags[0]->isDirty('_joinData'));
- $this->assertTrue($result->tags[0]->_joinData->isDirty('author_id'), 'Field not modified');
- $this->assertTrue($result->tags[0]->_joinData->isDirty('highlighted'), 'Field not modified');
- $this->assertSame(99, $result->tags[0]->_joinData->author_id);
- $this->assertTrue($result->tags[0]->_joinData->highlighted);
- }
- /**
- * Test that _joinData is marshalled consistently with both
- * new and existing records
- *
- * @return void
- */
- public function testMergeBelongsToManyHandleJoinDataConsistently()
- {
- $this->getTableLocator()->clear();
- $articles = $this->getTableLocator()->get('Articles');
- $articles->belongsToMany('Tags', [
- 'through' => 'SpecialTags',
- ]);
- $entity = $articles->get(1);
- $data = [
- 'title' => 'Haz data',
- 'tags' => [
- ['id' => 3, 'tag' => 'Cake', '_joinData' => ['highlighted' => true]],
- ],
- ];
- $marshall = new Marshaller($articles);
- $result = $marshall->merge($entity, $data, ['associated' => 'Tags']);
- $this->assertTrue($entity->isDirty('tags'));
- $this->assertInstanceOf('Cake\ORM\Entity', $result->tags[0]->_joinData);
- $this->assertTrue($result->tags[0]->_joinData->highlighted);
- // Also ensure merge() overwrites existing data.
- $entity = $articles->get(1, ['contain' => 'Tags']);
- $data = [
- 'title' => 'Haz data',
- 'tags' => [
- ['id' => 3, 'tag' => 'Cake', '_joinData' => ['highlighted' => true]],
- ],
- ];
- $marshall = new Marshaller($articles);
- $result = $marshall->merge($entity, $data, ['associated' => 'Tags']);
- $this->assertTrue($entity->isDirty('tags'), 'association data changed');
- $this->assertInstanceOf('Cake\ORM\Entity', $result->tags[0]->_joinData);
- $this->assertTrue($result->tags[0]->_joinData->highlighted);
- }
- /**
- * Test merging belongsToMany data doesn't create 'new' entities.
- *
- * @return void
- */
- public function testMergeBelongsToManyJoinDataAssociatedWithIds()
- {
- $data = [
- 'title' => 'My title',
- 'tags' => [
- [
- 'id' => 1,
- '_joinData' => [
- 'active' => 1,
- 'user' => ['username' => 'MyLux'],
- ],
- ],
- [
- 'id' => 2,
- '_joinData' => [
- 'active' => 0,
- 'user' => ['username' => 'IronFall'],
- ],
- ],
- ],
- ];
- $articlesTags = $this->getTableLocator()->get('ArticlesTags');
- $articlesTags->belongsTo('Users');
- $marshall = new Marshaller($this->articles);
- $article = $this->articles->get(1, ['associated' => 'Tags']);
- $result = $marshall->merge($article, $data, ['associated' => ['Tags._joinData.Users']]);
- $this->assertTrue($result->isDirty('tags'));
- $this->assertInstanceOf('Cake\ORM\Entity', $result->tags[0]);
- $this->assertInstanceOf('Cake\ORM\Entity', $result->tags[1]);
- $this->assertInstanceOf('Cake\ORM\Entity', $result->tags[0]->_joinData->user);
- $this->assertInstanceOf('Cake\ORM\Entity', $result->tags[1]->_joinData->user);
- $this->assertFalse($result->tags[0]->isNew(), 'Should not be new, as id is in db.');
- $this->assertFalse($result->tags[1]->isNew(), 'Should not be new, as id is in db.');
- $this->assertEquals(1, $result->tags[0]->id);
- $this->assertEquals(2, $result->tags[1]->id);
- $this->assertEquals(1, $result->tags[0]->_joinData->active);
- $this->assertEquals(0, $result->tags[1]->_joinData->active);
- $this->assertEquals(
- $data['tags'][0]['_joinData']['user']['username'],
- $result->tags[0]->_joinData->user->username
- );
- $this->assertEquals(
- $data['tags'][1]['_joinData']['user']['username'],
- $result->tags[1]->_joinData->user->username
- );
- }
- /**
- * Test merging the _joinData entity for belongstomany associations.
- *
- * @return void
- */
- public function testMergeBelongsToManyJoinData()
- {
- $data = [
- 'title' => 'My title',
- 'body' => 'My content',
- 'author_id' => 1,
- 'tags' => [
- [
- 'id' => 1,
- 'tag' => 'news',
- '_joinData' => [
- 'active' => 0,
- ],
- ],
- [
- 'id' => 2,
- 'tag' => 'cakephp',
- '_joinData' => [
- 'active' => 0,
- ],
- ],
- ],
- ];
- $options = ['associated' => ['Tags._joinData']];
- $marshall = new Marshaller($this->articles);
- $entity = $marshall->one($data, $options);
- $entity->setAccess('*', true);
- $data = [
- 'title' => 'Haz data',
- 'tags' => [
- ['id' => 1, 'tag' => 'Cake', '_joinData' => ['foo' => 'bar']],
- ['tag' => 'new tag', '_joinData' => ['active' => 1, 'foo' => 'baz']],
- ],
- ];
- $tag1 = $entity->tags[0];
- $result = $marshall->merge($entity, $data, $options);
- $this->assertEquals($data['title'], $result->title);
- $this->assertEquals('My content', $result->body);
- $this->assertTrue($result->isDirty('tags'));
- $this->assertSame($tag1, $entity->tags[0]);
- $this->assertSame($tag1->_joinData, $entity->tags[0]->_joinData);
- $this->assertSame(
- ['active' => 0, 'foo' => 'bar'],
- $entity->tags[0]->_joinData->toArray()
- );
- $this->assertSame(
- ['active' => 1, 'foo' => 'baz'],
- $entity->tags[1]->_joinData->toArray()
- );
- $this->assertEquals('new tag', $entity->tags[1]->tag);
- $this->assertTrue($entity->tags[0]->isDirty('_joinData'));
- $this->assertTrue($entity->tags[1]->isDirty('_joinData'));
- }
- /**
- * Test merging associations inside _joinData
- *
- * @return void
- */
- public function testMergeJoinDataAssociations()
- {
- $data = [
- 'title' => 'My title',
- 'body' => 'My content',
- 'author_id' => 1,
- 'tags' => [
- [
- 'id' => 1,
- 'tag' => 'news',
- '_joinData' => [
- 'active' => 0,
- 'user' => ['username' => 'Bill'],
- ],
- ],
- [
- 'id' => 2,
- 'tag' => 'cakephp',
- '_joinData' => [
- 'active' => 0,
- ],
- ],
- ],
- ];
- $articlesTags = $this->getTableLocator()->get('ArticlesTags');
- $articlesTags->belongsTo('Users');
- $options = ['associated' => ['Tags._joinData.Users']];
- $marshall = new Marshaller($this->articles);
- $entity = $marshall->one($data, $options);
- $entity->setAccess('*', true);
- $data = [
- 'title' => 'Haz data',
- 'tags' => [
- [
- 'id' => 1,
- 'tag' => 'news',
- '_joinData' => [
- 'foo' => 'bar',
- 'user' => ['password' => 'secret'],
- ],
- ],
- [
- 'id' => 2,
- '_joinData' => [
- 'active' => 1,
- 'foo' => 'baz',
- 'user' => ['username' => 'ber'],
- ],
- ],
- ],
- ];
- $tag1 = $entity->tags[0];
- $result = $marshall->merge($entity, $data, $options);
- $this->assertEquals($data['title'], $result->title);
- $this->assertEquals('My content', $result->body);
- $this->assertTrue($entity->isDirty('tags'));
- $this->assertSame($tag1, $entity->tags[0]);
- $this->assertTrue($tag1->isDirty('_joinData'));
- $this->assertSame($tag1->_joinData, $entity->tags[0]->_joinData);
- $this->assertEquals('Bill', $entity->tags[0]->_joinData->user->username);
- $this->assertEquals('secret', $entity->tags[0]->_joinData->user->password);
- $this->assertEquals('ber', $entity->tags[1]->_joinData->user->username);
- }
- /**
- * Tests that merging belongsToMany association doesn't erase _joinData
- * on existing objects.
- *
- * @return void
- */
- public function testMergeBelongsToManyIdsRetainJoinData()
- {
- $this->articles->belongsToMany('Tags');
- $entity = $this->articles->get(1, ['contain' => ['Tags']]);
- $entity->setAccess('*', true);
- $original = $entity->tags[0]->_joinData;
- $this->assertInstanceOf('Cake\ORM\Entity', $entity->tags[0]->_joinData);
- $data = [
- 'title' => 'Haz moar tags',
- 'tags' => [
- ['id' => 1],
- ],
- ];
- $marshall = new Marshaller($this->articles);
- $result = $marshall->merge($entity, $data, ['associated' => ['Tags']]);
- $this->assertCount(1, $result->tags);
- $this->assertTrue($result->isDirty('tags'));
- $this->assertInstanceOf('Cake\ORM\Entity', $result->tags[0]);
- $this->assertInstanceOf('Cake\ORM\Entity', $result->tags[0]->_joinData);
- $this->assertSame($original, $result->tags[0]->_joinData, 'Should be same object');
- }
- /**
- * Test mergeMany() with a simple set of data.
- *
- * @return void
- */
- public function testMergeManySimple()
- {
- $entities = [
- new OpenEntity(['id' => 1, 'comment' => 'First post', 'user_id' => 2]),
- new OpenEntity(['id' => 2, 'comment' => 'Second post', 'user_id' => 2]),
- ];
- $entities[0]->clean();
- $entities[1]->clean();
- $data = [
- ['id' => 2, 'comment' => 'Changed 2', 'user_id' => 2],
- ['id' => 1, 'comment' => 'Changed 1', 'user_id' => 1],
- ];
- $marshall = new Marshaller($this->comments);
- $result = $marshall->mergeMany($entities, $data);
- $this->assertSame($entities[0], $result[0]);
- $this->assertSame($entities[1], $result[1]);
- $this->assertEquals('Changed 1', $result[0]->comment);
- $this->assertEquals(1, $result[0]->user_id);
- $this->assertEquals('Changed 2', $result[1]->comment);
- $this->assertTrue($result[0]->isDirty('user_id'));
- $this->assertFalse($result[1]->isDirty('user_id'));
- }
- /**
- * Test mergeMany() with some invalid data
- *
- * @return void
- */
- public function testMergeManyInvalidData()
- {
- $entities = [
- new OpenEntity(['id' => 1, 'comment' => 'First post', 'user_id' => 2]),
- new OpenEntity(['id' => 2, 'comment' => 'Second post', 'user_id' => 2]),
- ];
- $entities[0]->clean();
- $entities[1]->clean();
- $data = [
- ['id' => 2, 'comment' => 'Changed 2', 'user_id' => 2],
- ['id' => 1, 'comment' => 'Changed 1', 'user_id' => 1],
- '_csrfToken' => 'abc123',
- ];
- $marshall = new Marshaller($this->comments);
- $result = $marshall->mergeMany($entities, $data);
- $this->assertSame($entities[0], $result[0]);
- $this->assertSame($entities[1], $result[1]);
- }
- /**
- * Tests that only records found in the data array are returned, those that cannot
- * be matched are discarded
- *
- * @return void
- */
- public function testMergeManyWithAppend()
- {
- $entities = [
- new OpenEntity(['comment' => 'First post', 'user_id' => 2]),
- new OpenEntity(['id' => 2, 'comment' => 'Second post', 'user_id' => 2]),
- ];
- $entities[0]->clean();
- $entities[1]->clean();
- $data = [
- ['id' => 2, 'comment' => 'Changed 2', 'user_id' => 2],
- ['id' => 1, 'comment' => 'Comment 1', 'user_id' => 1],
- ];
- $marshall = new Marshaller($this->comments);
- $result = $marshall->mergeMany($entities, $data);
- $this->assertCount(2, $result);
- $this->assertNotSame($entities[0], $result[0]);
- $this->assertSame($entities[1], $result[0]);
- $this->assertEquals('Changed 2', $result[0]->comment);
- $this->assertEquals('Comment 1', $result[1]->comment);
- }
- /**
- * Test that mergeMany() handles composite key associations properly.
- *
- * The articles_tags table has a composite primary key, and should be
- * handled correctly.
- *
- * @return void
- */
- public function testMergeManyCompositeKey()
- {
- $articlesTags = $this->getTableLocator()->get('ArticlesTags');
- $entities = [
- new OpenEntity(['article_id' => 1, 'tag_id' => 2]),
- new OpenEntity(['article_id' => 1, 'tag_id' => 1]),
- ];
- $entities[0]->clean();
- $entities[1]->clean();
- $data = [
- ['article_id' => 1, 'tag_id' => 1],
- ['article_id' => 1, 'tag_id' => 2],
- ];
- $marshall = new Marshaller($articlesTags);
- $result = $marshall->mergeMany($entities, $data);
- $this->assertCount(2, $result, 'Should have two records');
- $this->assertSame($entities[0], $result[0], 'Should retain object');
- $this->assertSame($entities[1], $result[1], 'Should retain object');
- }
- /**
- * Test mergeMany() with forced contain to ensure aliases are used in queries.
- *
- * @return void
- */
- public function testMergeManyExistingQueryAliases()
- {
- $entities = [
- new OpenEntity(['id' => 1, 'comment' => 'First post', 'user_id' => 2], ['markClean' => true]),
- ];
- $data = [
- ['id' => 1, 'comment' => 'Changed 1', 'user_id' => 1],
- ['id' => 2, 'comment' => 'Changed 2', 'user_id' => 2],
- ];
- $this->comments->getEventManager()->on('Model.beforeFind', function (Event $event, $query) {
- return $query->contain(['Articles']);
- });
- $marshall = new Marshaller($this->comments);
- $result = $marshall->mergeMany($entities, $data);
- $this->assertSame($entities[0], $result[0]);
- }
- /**
- * Test mergeMany() when the exist check returns nothing.
- *
- * @return void
- */
- public function testMergeManyExistQueryFails()
- {
- $entities = [
- new Entity(['id' => 1, 'comment' => 'First post', 'user_id' => 2]),
- new Entity(['id' => 2, 'comment' => 'Second post', 'user_id' => 2]),
- ];
- $entities[0]->clean();
- $entities[1]->clean();
- $data = [
- ['id' => 2, 'comment' => 'Changed 2', 'user_id' => 2],
- ['id' => 1, 'comment' => 'Changed 1', 'user_id' => 1],
- ['id' => 3, 'comment' => 'New 1'],
- ];
- $comments = $this->getTableLocator()->get('GreedyComments', [
- 'className' => __NAMESPACE__ . '\\GreedyCommentsTable',
- ]);
- $marshall = new Marshaller($comments);
- $result = $marshall->mergeMany($entities, $data);
- $this->assertCount(3, $result);
- $this->assertEquals('Changed 1', $result[0]->comment);
- $this->assertEquals(1, $result[0]->user_id);
- $this->assertEquals('Changed 2', $result[1]->comment);
- $this->assertEquals('New 1', $result[2]->comment);
- }
- /**
- * Tests merge with data types that need to be marshalled
- *
- * @return void
- */
- public function testMergeComplexType()
- {
- $entity = new Entity(
- ['comment' => 'My Comment text'],
- ['markNew' => false, 'markClean' => true]
- );
- $data = [
- 'created' => [
- 'year' => '2014',
- 'month' => '2',
- 'day' => 14,
- ],
- ];
- $marshall = new Marshaller($this->comments);
- $result = $marshall->merge($entity, $data);
- $this->assertInstanceOf('DateTime', $entity->created);
- $this->assertEquals('2014-02-14', $entity->created->format('Y-m-d'));
- }
- /**
- * Tests that it is possible to pass a fields option to the marshaller
- *
- * @group deprecated
- * @return void
- */
- public function testOneWithFieldList()
- {
- $this->deprecated(function () {
- $data = [
- 'title' => 'My title',
- 'body' => 'My content',
- 'author_id' => null,
- ];
- $marshall = new Marshaller($this->articles);
- $result = $marshall->one($data, ['fieldList' => ['title', 'author_id']]);
- $this->assertInstanceOf('Cake\ORM\Entity', $result);
- unset($data['body']);
- $this->assertEquals($data, $result->toArray());
- });
- }
- /**
- * Tests that it is possible to pass a fields option to the marshaller
- *
- * @return void
- */
- public function testOneWithFields()
- {
- $data = [
- 'title' => 'My title',
- 'body' => 'My content',
- 'author_id' => null,
- ];
- $marshall = new Marshaller($this->articles);
- $result = $marshall->one($data, ['fields' => ['title', 'author_id']]);
- $this->assertInstanceOf('Cake\ORM\Entity', $result);
- unset($data['body']);
- $this->assertEquals($data, $result->toArray());
- }
- /**
- * Test one() with translations
- *
- * @return void
- */
- public function testOneWithTranslations()
- {
- $this->articles->addBehavior('Translate', [
- 'fields' => ['title', 'body'],
- ]);
- $data = [
- 'author_id' => 1,
- '_translations' => [
- 'en' => [
- 'title' => 'English Title',
- 'body' => 'English Content',
- ],
- 'es' => [
- 'title' => 'Titulo Español',
- 'body' => 'Contenido Español',
- ],
- ],
- 'user' => [
- 'id' => 1,
- 'username' => 'mark',
- ],
- ];
- $marshall = new Marshaller($this->articles);
- $result = $marshall->one($data, ['associated' => ['Users']]);
- $this->assertEmpty($result->getErrors());
- $this->assertEquals(1, $result->author_id);
- $this->assertInstanceOf(__NAMESPACE__ . '\OpenEntity', $result->user);
- $this->assertEquals('mark', $result->user->username);
- $translations = $result->get('_translations');
- $this->assertCount(2, $translations);
- $this->assertInstanceOf(__NAMESPACE__ . '\OpenEntity', $translations['en']);
- $this->assertInstanceOf(__NAMESPACE__ . '\OpenEntity', $translations['es']);
- $this->assertEquals($data['_translations']['en'], $translations['en']->toArray());
- }
- /**
- * Tests that it is possible to pass a fields option to the merge method
- *
- * @group deprecated
- * @return void
- */
- public function testMergeWithFieldList()
- {
- $this->deprecated(function () {
- $data = [
- 'title' => 'My title',
- 'body' => null,
- 'author_id' => 1,
- ];
- $marshall = new Marshaller($this->articles);
- $entity = new Entity([
- 'title' => 'Foo',
- 'body' => 'My content',
- 'author_id' => 2,
- ]);
- $entity->setAccess('*', false);
- $entity->isNew(false);
- $entity->clean();
- $result = $marshall->merge($entity, $data, ['fieldList' => ['title', 'body']]);
- $expected = [
- 'title' => 'My title',
- 'body' => null,
- 'author_id' => 2,
- ];
- $this->assertSame($entity, $result);
- $this->assertEquals($expected, $result->toArray());
- $this->assertFalse($entity->isAccessible('*'));
- });
- }
- /**
- * Tests that it is possible to pass a fields option to the merge method
- *
- * @return void
- */
- public function testMergeWithFields()
- {
- $data = [
- 'title' => 'My title',
- 'body' => null,
- 'author_id' => 1,
- ];
- $marshall = new Marshaller($this->articles);
- $entity = new Entity([
- 'title' => 'Foo',
- 'body' => 'My content',
- 'author_id' => 2,
- ]);
- $entity->setAccess('*', false);
- $entity->setNew(false);
- $entity->clean();
- $result = $marshall->merge($entity, $data, ['fields' => ['title', 'body']]);
- $expected = [
- 'title' => 'My title',
- 'body' => null,
- 'author_id' => 2,
- ];
- $this->assertSame($entity, $result);
- $this->assertEquals($expected, $result->toArray());
- $this->assertFalse($entity->isAccessible('*'));
- }
- /**
- * Test that many() also receives a fields option
- *
- * @return void
- */
- public function testManyFields()
- {
- $data = [
- ['comment' => 'First post', 'user_id' => 2, 'foo' => 'bar'],
- ['comment' => 'Second post', 'user_id' => 2, 'foo' => 'bar'],
- ];
- $marshall = new Marshaller($this->comments);
- $result = $marshall->many($data, ['fields' => ['comment', 'user_id']]);
- $this->assertCount(2, $result);
- unset($data[0]['foo'], $data[1]['foo']);
- $this->assertEquals($data[0], $result[0]->toArray());
- $this->assertEquals($data[1], $result[1]->toArray());
- }
- /**
- * Test that many() also receives a fields option
- *
- * @return void
- */
- public function testMergeManyFields()
- {
- $entities = [
- new OpenEntity(['id' => 1, 'comment' => 'First post', 'user_id' => 2]),
- new OpenEntity(['id' => 2, 'comment' => 'Second post', 'user_id' => 2]),
- ];
- $entities[0]->clean();
- $entities[1]->clean();
- $data = [
- ['id' => 2, 'comment' => 'Changed 2', 'user_id' => 10],
- ['id' => 1, 'comment' => 'Changed 1', 'user_id' => 20],
- ];
- $marshall = new Marshaller($this->comments);
- $result = $marshall->mergeMany($entities, $data, ['fields' => ['id', 'comment']]);
- $this->assertSame($entities[0], $result[0]);
- $this->assertSame($entities[1], $result[1]);
- $expected = ['id' => 2, 'comment' => 'Changed 2', 'user_id' => 2];
- $this->assertEquals($expected, $entities[1]->toArray());
- $expected = ['id' => 1, 'comment' => 'Changed 1', 'user_id' => 2];
- $this->assertEquals($expected, $entities[0]->toArray());
- }
- /**
- * test marshalling association data while passing a fields
- *
- * @return void
- */
- public function testAssociationsFields()
- {
- $data = [
- 'title' => 'My title',
- 'body' => 'My content',
- 'author_id' => 1,
- 'user' => [
- 'username' => 'mark',
- 'password' => 'secret',
- 'foo' => 'bar',
- ],
- ];
- $marshall = new Marshaller($this->articles);
- $result = $marshall->one($data, [
- 'fields' => ['title', 'body', 'user'],
- 'associated' => [
- 'Users' => ['fields' => ['username', 'foo']],
- ],
- ]);
- $this->assertEquals($data['title'], $result->title);
- $this->assertEquals($data['body'], $result->body);
- $this->assertNull($result->author_id);
- $this->assertInstanceOf('Cake\ORM\Entity', $result->user);
- $this->assertEquals($data['user']['username'], $result->user->username);
- $this->assertNull($result->user->password);
- }
- /**
- * Tests merging associated data with a fields
- *
- * @return void
- */
- public function testMergeAssociationWithfields()
- {
- $user = new Entity([
- 'username' => 'mark',
- 'password' => 'secret',
- ]);
- $entity = new Entity([
- 'tile' => 'My Title',
- 'user' => $user,
- ]);
- $user->setAccess('*', true);
- $entity->setAccess('*', true);
- $data = [
- 'body' => 'My Content',
- 'something' => 'else',
- 'user' => [
- 'password' => 'not a secret',
- 'extra' => 'data',
- ],
- ];
- $marshall = new Marshaller($this->articles);
- $marshall->merge($entity, $data, [
- 'fields' => ['something'],
- 'associated' => ['Users' => ['fields' => ['extra']]],
- ]);
- $this->assertNull($entity->body);
- $this->assertEquals('else', $entity->something);
- $this->assertSame($user, $entity->user);
- $this->assertEquals('mark', $entity->user->username);
- $this->assertEquals('secret', $entity->user->password);
- $this->assertEquals('data', $entity->user->extra);
- $this->assertTrue($entity->isDirty('user'));
- }
- /**
- * Test marshalling nested associations on the _joinData structure
- * while having a fields
- *
- * @return void
- */
- public function testJoinDataWhiteList()
- {
- $data = [
- 'title' => 'My title',
- 'body' => 'My content',
- 'author_id' => 1,
- 'tags' => [
- [
- 'tag' => 'news',
- '_joinData' => [
- 'active' => 1,
- 'crazy' => 'data',
- 'user' => ['username' => 'Bill'],
- ],
- ],
- [
- 'tag' => 'cakephp',
- '_joinData' => [
- 'active' => 0,
- 'crazy' => 'stuff',
- 'user' => ['username' => 'Mark'],
- ],
- ],
- ],
- ];
- $articlesTags = $this->getTableLocator()->get('ArticlesTags');
- $articlesTags->belongsTo('Users');
- $marshall = new Marshaller($this->articles);
- $result = $marshall->one($data, [
- 'associated' => [
- 'Tags._joinData' => ['fields' => ['active', 'user']],
- 'Tags._joinData.Users',
- ],
- ]);
- $this->assertInstanceOf(
- 'Cake\ORM\Entity',
- $result->tags[0]->_joinData->user,
- 'joinData should contain a user entity.'
- );
- $this->assertEquals('Bill', $result->tags[0]->_joinData->user->username);
- $this->assertInstanceOf(
- 'Cake\ORM\Entity',
- $result->tags[1]->_joinData->user,
- 'joinData should contain a user entity.'
- );
- $this->assertEquals('Mark', $result->tags[1]->_joinData->user->username);
- $this->assertNull($result->tags[0]->_joinData->crazy);
- $this->assertNull($result->tags[1]->_joinData->crazy);
- }
- /**
- * Test merging the _joinData entity for belongstomany associations
- * while passing a whitelist
- *
- * @return void
- */
- public function testMergeJoinDataWithFields()
- {
- $data = [
- 'title' => 'My title',
- 'body' => 'My content',
- 'author_id' => 1,
- 'tags' => [
- [
- 'id' => 1,
- 'tag' => 'news',
- '_joinData' => [
- 'active' => 0,
- ],
- ],
- [
- 'id' => 2,
- 'tag' => 'cakephp',
- '_joinData' => [
- 'active' => 0,
- ],
- ],
- ],
- ];
- $options = ['associated' => ['Tags' => ['associated' => ['_joinData']]]];
- $marshall = new Marshaller($this->articles);
- $entity = $marshall->one($data, $options);
- $entity->setAccess('*', true);
- $data = [
- 'title' => 'Haz data',
- 'tags' => [
- ['id' => 1, 'tag' => 'Cake', '_joinData' => ['foo' => 'bar', 'crazy' => 'something']],
- ['tag' => 'new tag', '_joinData' => ['active' => 1, 'foo' => 'baz']],
- ],
- ];
- $tag1 = $entity->tags[0];
- $result = $marshall->merge($entity, $data, [
- 'associated' => ['Tags._joinData' => ['fields' => ['foo']]],
- ]);
- $this->assertEquals($data['title'], $result->title);
- $this->assertEquals('My content', $result->body);
- $this->assertSame($tag1, $entity->tags[0]);
- $this->assertSame($tag1->_joinData, $entity->tags[0]->_joinData);
- $this->assertSame(
- ['active' => 0, 'foo' => 'bar'],
- $entity->tags[0]->_joinData->toArray()
- );
- $this->assertSame(
- ['foo' => 'baz'],
- $entity->tags[1]->_joinData->toArray()
- );
- $this->assertEquals('new tag', $entity->tags[1]->tag);
- $this->assertTrue($entity->tags[0]->isDirty('_joinData'));
- $this->assertTrue($entity->tags[1]->isDirty('_joinData'));
- }
- /**
- * Tests marshalling with validation errors
- *
- * @return void
- */
- public function testValidationFail()
- {
- $data = [
- 'title' => 'Thing',
- 'body' => 'hey',
- ];
- $this->articles->getValidator()->requirePresence('thing');
- $marshall = new Marshaller($this->articles);
- $entity = $marshall->one($data);
- $this->assertNotEmpty($entity->getError('thing'));
- }
- /**
- * Test that invalid validate options raise exceptions
- *
- * @return void
- */
- public function testValidateInvalidType()
- {
- $this->expectException(\RuntimeException::class);
- $data = ['title' => 'foo'];
- $marshaller = new Marshaller($this->articles);
- $marshaller->one($data, [
- 'validate' => ['derp'],
- ]);
- }
- /**
- * Tests that associations are validated and custom validators can be used
- *
- * @return void
- */
- public function testValidateWithAssociationsAndCustomValidator()
- {
- $data = [
- 'title' => 'foo',
- 'body' => 'bar',
- 'user' => [
- 'name' => 'Susan',
- ],
- 'comments' => [
- [
- 'comment' => 'foo',
- ],
- ],
- ];
- $validator = (new Validator())->add('body', 'numeric', ['rule' => 'numeric']);
- $this->articles->setValidator('custom', $validator);
- $validator2 = (new Validator())->requirePresence('thing');
- $this->articles->Users->setValidator('customThing', $validator2);
- $this->articles->Comments->setValidator('default', $validator2);
- $entity = (new Marshaller($this->articles))->one($data, [
- 'validate' => 'custom',
- 'associated' => ['Users', 'Comments'],
- ]);
- $this->assertNotEmpty($entity->getError('body'), 'custom was not used');
- $this->assertNull($entity->body);
- $this->assertEmpty($entity->user->getError('thing'));
- $this->assertNotEmpty($entity->comments[0]->getError('thing'));
- $entity = (new Marshaller($this->articles))->one($data, [
- 'validate' => 'custom',
- 'associated' => ['Users' => ['validate' => 'customThing'], 'Comments'],
- ]);
- $this->assertNotEmpty($entity->getError('body'));
- $this->assertNull($entity->body);
- $this->assertNotEmpty($entity->user->getError('thing'), 'customThing was not used');
- $this->assertNotEmpty($entity->comments[0]->getError('thing'));
- }
- /**
- * Tests that validation can be bypassed
- *
- * @return void
- */
- public function testSkipValidation()
- {
- $data = [
- 'title' => 'foo',
- 'body' => 'bar',
- 'user' => [
- 'name' => 'Susan',
- ],
- ];
- $validator = (new Validator())->requirePresence('thing');
- $this->articles->setValidator('default', $validator);
- $this->articles->Users->setValidator('default', $validator);
- $entity = (new Marshaller($this->articles))->one($data, [
- 'validate' => false,
- 'associated' => ['Users'],
- ]);
- $this->assertEmpty($entity->getError('thing'));
- $this->assertNotEmpty($entity->user->getError('thing'));
- $entity = (new Marshaller($this->articles))->one($data, [
- 'associated' => ['Users' => ['validate' => false]],
- ]);
- $this->assertNotEmpty($entity->getError('thing'));
- $this->assertEmpty($entity->user->getError('thing'));
- }
- /**
- * Tests that it is possible to pass a validator directly in the options
- *
- * @return void
- */
- public function testPassingCustomValidator()
- {
- $data = [
- 'title' => 'Thing',
- 'body' => 'hey',
- ];
- $validator = clone $this->articles->getValidator();
- $validator->requirePresence('thing');
- $marshall = new Marshaller($this->articles);
- $entity = $marshall->one($data, ['validate' => $validator]);
- $this->assertNotEmpty($entity->getError('thing'));
- }
- /**
- * Tests that invalid property is being filled when data cannot be patched into an entity.
- *
- * @return void
- */
- public function testValidationWithInvalidFilled()
- {
- $data = [
- 'title' => 'foo',
- 'number' => 'bar',
- ];
- $validator = (new Validator())->add('number', 'numeric', ['rule' => 'numeric']);
- $marshall = new Marshaller($this->articles);
- $entity = $marshall->one($data, ['validate' => $validator]);
- $this->assertNotEmpty($entity->getError('number'));
- $this->assertNull($entity->number);
- $this->assertSame(['number' => 'bar'], $entity->getInvalid());
- }
- /**
- * Test merge with validation error
- *
- * @return void
- */
- public function testMergeWithValidation()
- {
- $data = [
- 'title' => 'My title',
- 'author_id' => 'foo',
- ];
- $marshall = new Marshaller($this->articles);
- $entity = new Entity([
- 'id' => 1,
- 'title' => 'Foo',
- 'body' => 'My Content',
- 'author_id' => 1,
- ]);
- $this->assertEmpty($entity->getInvalid());
- $entity->setAccess('*', true);
- $entity->setNew(false);
- $entity->clean();
- $this->articles->getValidator()
- ->requirePresence('thing', 'update')
- ->requirePresence('id', 'update')
- ->add('author_id', 'numeric', ['rule' => 'numeric'])
- ->add('id', 'numeric', ['rule' => 'numeric', 'on' => 'update']);
- $expected = clone $entity;
- $result = $marshall->merge($expected, $data, []);
- $this->assertSame($expected, $result);
- $this->assertSame(1, $result->author_id);
- $this->assertNotEmpty($result->getError('thing'));
- $this->assertEmpty($result->getError('id'));
- $this->articles->getValidator()->requirePresence('thing', 'create');
- $result = $marshall->merge($entity, $data, []);
- $this->assertEmpty($result->getError('thing'));
- $this->assertSame(['author_id' => 'foo'], $result->getInvalid());
- }
- /**
- * Test merge with validation and create or update validation rules
- *
- * @return void
- */
- public function testMergeWithCreate()
- {
- $data = [
- 'title' => 'My title',
- 'author_id' => 'foo',
- ];
- $marshall = new Marshaller($this->articles);
- $entity = new Entity([
- 'title' => 'Foo',
- 'body' => 'My Content',
- 'author_id' => 1,
- ]);
- $entity->setAccess('*', true);
- $entity->setNew(true);
- $entity->clean();
- $this->articles->getValidator()
- ->requirePresence('thing', 'update')
- ->add('author_id', 'numeric', ['rule' => 'numeric', 'on' => 'update']);
- $expected = clone $entity;
- $result = $marshall->merge($expected, $data, []);
- $this->assertEmpty($result->getError('author_id'));
- $this->assertEmpty($result->getError('thing'));
- $entity->clean();
- $entity->setNew(false);
- $result = $marshall->merge($entity, $data, []);
- $this->assertNotEmpty($result->getError('author_id'));
- $this->assertNotEmpty($result->getError('thing'));
- }
- /**
- * Test merge() with translate behavior integration
- *
- * @return void
- */
- public function testMergeWithTranslations()
- {
- $this->articles->addBehavior('Translate', [
- 'fields' => ['title', 'body'],
- ]);
- $data = [
- 'author_id' => 1,
- '_translations' => [
- 'en' => [
- 'title' => 'English Title',
- 'body' => 'English Content',
- ],
- 'es' => [
- 'title' => 'Titulo Español',
- 'body' => 'Contenido Español',
- ],
- ],
- ];
- $marshall = new Marshaller($this->articles);
- $entity = $this->articles->newEntity();
- $result = $marshall->merge($entity, $data, []);
- $this->assertSame($entity, $result);
- $this->assertEmpty($result->getErrors());
- $this->assertTrue($result->isDirty('_translations'));
- $translations = $result->get('_translations');
- $this->assertCount(2, $translations);
- $this->assertInstanceOf(__NAMESPACE__ . '\OpenEntity', $translations['en']);
- $this->assertInstanceOf(__NAMESPACE__ . '\OpenEntity', $translations['es']);
- $this->assertEquals($data['_translations']['en'], $translations['en']->toArray());
- }
- /**
- * Test Model.beforeMarshal event.
- *
- * @return void
- */
- public function testBeforeMarshalEvent()
- {
- $data = [
- 'title' => 'My title',
- 'body' => 'My content',
- 'user' => [
- 'name' => 'Robert',
- 'username' => 'rob',
- ],
- ];
- $marshall = new Marshaller($this->articles);
- $this->articles->getEventManager()->on(
- 'Model.beforeMarshal',
- function ($e, $data, $options) {
- $this->assertArrayHasKey('validate', $options);
- $data['title'] = 'Modified title';
- $data['user']['username'] = 'robert';
- $options['associated'] = ['Users'];
- }
- );
- $entity = $marshall->one($data);
- $this->assertEquals('Modified title', $entity->title);
- $this->assertEquals('My content', $entity->body);
- $this->assertEquals('Robert', $entity->user->name);
- $this->assertEquals('robert', $entity->user->username);
- }
- /**
- * Test Model.beforeMarshal event on associated tables.
- *
- * @return void
- */
- public function testBeforeMarshalEventOnAssociations()
- {
- $data = [
- 'title' => 'My title',
- 'body' => 'My content',
- 'author_id' => 1,
- 'user' => [
- 'username' => 'mark',
- 'password' => 'secret',
- ],
- 'comments' => [
- ['comment' => 'First post', 'user_id' => 2],
- ['comment' => 'Second post', 'user_id' => 2],
- ],
- 'tags' => [
- ['tag' => 'news', '_joinData' => ['active' => 1]],
- ['tag' => 'cakephp', '_joinData' => ['active' => 0]],
- ],
- ];
- $marshall = new Marshaller($this->articles);
- // Assert event options are correct
- $this->articles->users->getEventManager()->on(
- 'Model.beforeMarshal',
- function ($e, $data, $options) {
- $this->assertArrayHasKey('validate', $options);
- $this->assertTrue($options['validate']);
- $this->assertArrayHasKey('associated', $options);
- $this->assertSame([], $options['associated']);
- $this->assertArrayHasKey('association', $options);
- $this->assertInstanceOf('Cake\ORM\Association', $options['association']);
- }
- );
- $this->articles->users->getEventManager()->on(
- 'Model.beforeMarshal',
- function ($e, $data, $options) {
- $data['secret'] = 'h45h3d';
- }
- );
- $this->articles->comments->getEventManager()->on(
- 'Model.beforeMarshal',
- function ($e, $data) {
- $data['comment'] .= ' (modified)';
- }
- );
- $this->articles->tags->getEventManager()->on(
- 'Model.beforeMarshal',
- function ($e, $data) {
- $data['tag'] .= ' (modified)';
- }
- );
- $this->articles->tags->junction()->getEventManager()->on(
- 'Model.beforeMarshal',
- function ($e, $data) {
- $data['modified_by'] = 1;
- }
- );
- $entity = $marshall->one($data, [
- 'associated' => ['Users', 'Comments', 'Tags'],
- ]);
- $this->assertEquals('h45h3d', $entity->user->secret);
- $this->assertEquals('First post (modified)', $entity->comments[0]->comment);
- $this->assertEquals('Second post (modified)', $entity->comments[1]->comment);
- $this->assertEquals('news (modified)', $entity->tags[0]->tag);
- $this->assertEquals('cakephp (modified)', $entity->tags[1]->tag);
- $this->assertEquals(1, $entity->tags[0]->_joinData->modified_by);
- $this->assertEquals(1, $entity->tags[1]->_joinData->modified_by);
- }
- /**
- * Test Model.afterMarshal event.
- *
- * @return void
- */
- public function testAfterMarshalEvent()
- {
- $data = [
- 'title' => 'original title',
- 'body' => 'original content',
- 'user' => [
- 'name' => 'Robert',
- 'username' => 'rob',
- ],
- ];
- $marshall = new Marshaller($this->articles);
- $this->articles->getEventManager()->on(
- 'Model.afterMarshal',
- function ($e, $entity, $data, $options) {
- $this->assertInstanceOf('Cake\ORM\Entity', $entity);
- $this->assertArrayHasKey('validate', $options);
- $this->assertFalse($options['isMerge']);
- $data['title'] = 'Modified title';
- $data['user']['username'] = 'robert';
- $options['associated'] = ['Users'];
- $entity->body = 'Modified body';
- }
- );
- $entity = $marshall->one($data);
- $this->assertSame('original title', $entity->title, '$data is immutable');
- $this->assertSame('Modified body', $entity->body);
- // both $options and $data are unchangeable
- $this->assertTrue(is_array($entity->user), '$options[\'associated\'] is ignored');
- $this->assertSame('Robert', $entity->user['name']);
- $this->assertSame('rob', $entity->user['username']);
- }
- /**
- * Test Model.afterMarshal event on patchEntity.
- * when $options['fields'] is set and is empty
- *
- * @return void
- */
- public function testAfterMarshalEventOnPatchEntity()
- {
- $data = [
- 'title' => 'original title',
- 'body' => 'original content',
- 'user' => [
- 'name' => 'Robert',
- 'username' => 'rob',
- ],
- ];
- $marshall = new Marshaller($this->articles);
- $this->articles->getEventManager()->on(
- 'Model.afterMarshal',
- function ($e, $entity, $data, $options) {
- $this->assertInstanceOf('Cake\ORM\Entity', $entity);
- $this->assertArrayHasKey('validate', $options);
- $this->assertTrue($options['isMerge']);
- $data['title'] = 'Modified title';
- $data['user']['username'] = 'robert';
- $options['associated'] = ['Users'];
- $entity->body = 'options[fields] is empty';
- if (isset($options['fields'])) {
- $entity->body = 'options[fields] is set';
- }
- }
- );
- //test when $options['fields'] is empty
- $entity = $this->articles->newEntity();
- $result = $marshall->merge($entity, $data, []);
- $this->assertSame('original title', $entity->title, '$data is immutable');
- $this->assertSame('options[fields] is empty', $entity->body);
- // both $options and $data are unchangeable
- $this->assertTrue(is_array($entity->user), '$options[\'associated\'] is ignored');
- $this->assertSame('Robert', $entity->user['name']);
- $this->assertSame('rob', $entity->user['username']);
- //test when $options['fields'] is set
- $entity = $this->articles->newEntity();
- $result = $marshall->merge($entity, $data, ['fields' => ['title', 'body']]);
- $this->assertSame('original title', $entity->title, '$data is immutable');
- $this->assertSame('options[fields] is set', $entity->body);
- }
- /**
- * Tests that patching an association resulting in no changes, will
- * not mark the parent entity as dirty
- *
- * @return void
- */
- public function testAssociationNoChanges()
- {
- $options = ['markClean' => true, 'isNew' => false];
- $entity = new Entity([
- 'title' => 'My Title',
- 'user' => new Entity([
- 'username' => 'mark',
- 'password' => 'not a secret',
- ], $options),
- ], $options);
- $data = [
- 'body' => 'My Content',
- 'user' => [
- 'username' => 'mark',
- 'password' => 'not a secret',
- ],
- ];
- $marshall = new Marshaller($this->articles);
- $marshall->merge($entity, $data, ['associated' => ['Users']]);
- $this->assertEquals('My Content', $entity->body);
- $this->assertInstanceOf('Cake\ORM\Entity', $entity->user);
- $this->assertEquals('mark', $entity->user->username);
- $this->assertEquals('not a secret', $entity->user->password);
- $this->assertFalse($entity->isDirty('user'));
- $this->assertTrue($entity->user->isNew());
- }
- /**
- * Test that primary key meta data is being read from the table
- * and not the schema reflection when handling belongsToMany associations.
- *
- * @return void
- */
- public function testEnsurePrimaryKeyBeingReadFromTableForHandlingEmptyStringPrimaryKey()
- {
- $data = [
- 'id' => '',
- ];
- $articles = $this->getTableLocator()->get('Articles');
- $articles->getSchema()->dropConstraint('primary');
- $articles->setPrimaryKey('id');
- $marshall = new Marshaller($articles);
- $result = $marshall->one($data);
- $this->assertFalse($result->isDirty('id'));
- $this->assertNull($result->id);
- }
- /**
- * Test that primary key meta data is being read from the table
- * and not the schema reflection when handling belongsToMany associations.
- *
- * @return void
- */
- public function testEnsurePrimaryKeyBeingReadFromTableWhenLoadingBelongsToManyRecordsByPrimaryKey()
- {
- $data = [
- 'tags' => [
- [
- 'id' => 1,
- ],
- [
- 'id' => 2,
- ],
- ],
- ];
- $tags = $this->getTableLocator()->get('Tags');
- $tags->getSchema()->dropConstraint('primary');
- $tags->setPrimaryKey('id');
- $marshall = new Marshaller($this->articles);
- $result = $marshall->one($data, ['associated' => ['Tags']]);
- $expected = [
- 'tags' => [
- [
- 'id' => 1,
- 'name' => 'tag1',
- 'description' => 'A big description',
- 'created' => new Time('2016-01-01 00:00'),
- ],
- [
- 'id' => 2,
- 'name' => 'tag2',
- 'description' => 'Another big description',
- 'created' => new Time('2016-01-01 00:00'),
- ],
- ],
- ];
- $this->assertEquals($expected, $result->toArray());
- }
- }
|